渲染

【翻译】通过Unity学习PBR算法 ⑥

组装你的PBRShader Part4:将所有东西组合起来

组合算法

现在我们有很多版本的NDF、GSF以及菲涅尔方程,我们需要将它们组合起来,然后我们就可以看到BRDF PBR Shader的最终效果。我们组合这些算法的方式非常简单:将这些算式相乘然后除以4 * NdotL * NdotV。

float3 specularity = (SpecularDistribution * FresnelFunction * GeometricShadow) / (4 * (  NdotL * NdotV));

当你组合了这些算法你可以将你的diffuse颜色简单做加法,然后你就得到了最终结果。

float3 lightingModel = (diffuseColor + specularity);
lightingModel *= NdotL;
float4 finalDiffuse = float4(lightingModel * attenColor,1);
return finalDiffuse;

使Unity光照信息参与计算

为了取样环境光,你需要在Unity以及你的shader中做几个比较重要的步骤。首先,添加reflection probe到你的场景中并且进行烘焙。然后你要将下面的方程放入你的shader:

UnityGI GetUnityGI(float3 lightColor, float3 lightDirection, float3 normalDirection,float3 viewDirection, 
float3 viewReflectDirection, float attenuation, float roughness, float3 worldPos){
 //Unity light Setup ::
    UnityLight light;
    light.color = lightColor;
    light.dir = lightDirection;
    light.ndotl = max(0.0h,dot( normalDirection, lightDirection));
    UnityGIInput d;
    d.light = light;
    d.worldPos = worldPos;
    d.worldViewDir = viewDirection;
    d.atten = attenuation;
    d.ambient = 0.0h;
    d.boxMax[0] = unity_SpecCube0_BoxMax;
    d.boxMin[0] = unity_SpecCube0_BoxMin;
    d.probePosition[0] = unity_SpecCube0_ProbePosition;
    d.probeHDR[0] = unity_SpecCube0_HDR;
    d.boxMax[1] = unity_SpecCube1_BoxMax;
    d.boxMin[1] = unity_SpecCube1_BoxMin;
    d.probePosition[1] = unity_SpecCube1_ProbePosition;
    d.probeHDR[1] = unity_SpecCube1_HDR;
    Unity_GlossyEnvironmentData ugls_en_data;
    ugls_en_data.roughness = roughness;
    ugls_en_data.reflUVW = viewReflectDirection;
    UnityGI gi = UnityGlobalIllumination(d, 1.0h, normalDirection, ugls_en_data );
    return gi;
}

你能在你的片段程序中调用这个函数,然后它使用环境采样数据来近似环境光。

UnityGI gi =  GetUnityGI(_LightColor0.rgb, lightDirection, 
normalDirection, viewDirection, viewReflectDirection, attenuation, 1- _Glossiness, i.posWorld.xyz);

    float3 indirectDiffuse = gi.indirect.diffuse.rgb ;
    float3 indirectSpecular = gi.indirect.specular.rgb;

为了使用这些值,你会将他们放到我们最终的结果当中,将我们shader中diffuse相关的几行替换一下。这会允许我们采样环境光,当环境数据可用的时候我们就可以直接采样到环境数据。

float grazingTerm = saturate(roughness + _Metallic);
float3 unityIndirectSpecularity =  indirectSpecular * FresnelLerp(specColor,grazingTerm,NdotV) * 
max(0.15,_Metallic) * (1-roughness*roughness* roughness);

float3 lightingModel = (diffuseColor + specularity + (unityIndirectSpecularity *_UnityLightingContribution));

Debug你的Shader

为了Debug我们的算式,你可以通过unity的功能来开关材质的属性。

[Toggle] _ENABLE_NDF ("Normal Distribution Enabled?", Float) = 0
[Toggle] _ENABLE_G ("Geometric Shadow Enabled?", Float) = 0
[Toggle] _ENABLE_F ("Fresnel Enabled?", Float) = 0
[Toggle] _ENABLE_D ("Diffuse Enabled?", Float) = 0

这些toggle会开启或者关闭Shader的Keyword,更多信息可以在这个[页面](MaterialPropertyDrawer)上看到,如下所示:

    #ifdef _ENABLE_NDF_ON
 	 return float4(float3(1,1,1)* SpecularDistribution,1);
    #endif
    #ifdef _ENABLE_G_ON 
 	 return float4(float3(1,1,1) * GeometricShadow,1) ;
    #endif
    #ifdef _ENABLE_F_ON 
 	 return float4(float3(1,1,1)* FresnelFunction,1);
    #endif
    #ifdef _ENABLE_D_ON 
 	 return float4(float3(1,1,1)* diffuseColor,1);
    #endif

这种方式允许你在不同的效果之间切换你的shader,然后你就可以自己测试效果。

创建一个允许你自己选择算法的Shader

通过使用Keyword枚举,你可以让你的shader有能力自由切换你的算法,完全不需要注释来进行切换。Keyword枚举被限制在9个Keywords,所以我们必须创建我们自己的切换逻辑。

[KeywordEnum(BlinnPhong,Phong,Beckmann,Gaussian,GGX,TrowbridgeReitz,TrowbridgeReitzAnisotropic, Ward)] _NormalDistModel("Normal Distribution Model;", Float) = 0
[KeywordEnum(AshikhminShirley,AshikhminPremoze,Duer,Neumann,Kelemen,ModifiedKelemen,Cook,Ward,Kurt)]_GeoShadowModel("Geometric Shadow Model;", Float) = 0
[KeywordEnum(None,Walter,Beckman,GGX,Schlick,SchlickBeckman,SchlickGGX, Implicit)]_SmithGeoShadowModel("Smith Geometric Shadow Model; None if above is Used;", Float) = 0
[KeywordEnum(Schlick,SchlickIOR, SphericalGaussian)]_FresnelModel("Normal Distribution Model;", Float) = 0
        //Normal Distribution Function/Specular Distribution-----------------------------------------------------	      
           
	#ifdef _NORMALDISTMODEL_BLINNPHONG 
		 SpecularDistribution *=  BlinnPhongNormalDistribution(NdotH, _Glossiness,  max(1,_Glossiness * 40));
 	#elif _NORMALDISTMODEL_PHONG
		 SpecularDistribution *=  PhongNormalDistribution(RdotV, _Glossiness, max(1,_Glossiness * 40));
 	#elif _NORMALDISTMODEL_BECKMANN
		 SpecularDistribution *=  BeckmannNormalDistribution(roughness, NdotH);
 	#elif _NORMALDISTMODEL_GAUSSIAN
		 SpecularDistribution *=  GaussianNormalDistribution(roughness, NdotH);
 	#elif _NORMALDISTMODEL_GGX
		 SpecularDistribution *=  GGXNormalDistribution(roughness, NdotH);
 	#elif _NORMALDISTMODEL_TROWBRIDGEREITZ
		 SpecularDistribution *=  TrowbridgeReitzNormalDistribution(NdotH, roughness);
 	#elif _NORMALDISTMODEL_TROWBRIDGEREITZANISOTROPIC
		 SpecularDistribution *=  TrowbridgeReitzAnisotropicNormalDistribution(_Anisotropic,NdotH, dot(halfDirection, i.tangentDir), dot(halfDirection,  i.bitangentDir));
	#elif _NORMALDISTMODEL_WARD
	 	 SpecularDistribution *=  WardAnisotropicNormalDistribution(_Anisotropic,NdotL, NdotV, NdotH, dot(halfDirection, i.tangentDir), dot(halfDirection,  i.bitangentDir));
	#else
		SpecularDistribution *=  GGXNormalDistribution(roughness, NdotH);
	#endif


	 //Geometric Shadowing term----------------------------------------------------------------------------------
	#ifdef _SMITHGEOSHADOWMODEL_NONE
	#ifdef _GEOSHADOWMODEL_ASHIKHMINSHIRLEY
		GeometricShadow *= AshikhminShirleyGeometricShadowingFunction (NdotL, NdotV, LdotH);
	#elif _GEOSHADOWMODEL_ASHIKHMINPREMOZE
		GeometricShadow *= AshikhminPremozeGeometricShadowingFunction (NdotL, NdotV);
	#elif _GEOSHADOWMODEL_DUER
		GeometricShadow *= DuerGeometricShadowingFunction (lightDirection, viewDirection, normalDirection, NdotL, NdotV);
	#elif _GEOSHADOWMODEL_NEUMANN
		GeometricShadow *= NeumannGeometricShadowingFunction (NdotL, NdotV);
	#elif _GEOSHADOWMODEL_KELEMAN
		GeometricShadow *= KelemenGeometricShadowingFunction (NdotL, NdotV, LdotH,  VdotH);
	#elif _GEOSHADOWMODEL_MODIFIEDKELEMEN
		GeometricShadow *=  ModifiedKelemenGeometricShadowingFunction (NdotV, NdotL, roughness);
	#elif _GEOSHADOWMODEL_COOK
		GeometricShadow *= CookTorrenceGeometricShadowingFunction (NdotL, NdotV, VdotH, NdotH);
	#elif _GEOSHADOWMODEL_WARD
		GeometricShadow *= WardGeometricShadowingFunction (NdotL, NdotV, VdotH, NdotH);
	#elif _GEOSHADOWMODEL_KURT
		GeometricShadow *= KurtGeometricShadowingFunction (NdotL, NdotV, VdotH, roughness);
	#else 			
 		GeometricShadow *= ImplicitGeometricShadowingFunction (NdotL, NdotV);
        #endif
	////SmithModelsBelow
	////Gs = F(NdotL) * F(NdotV);
  	#elif _SMITHGEOSHADOWMODEL_WALTER
		GeometricShadow *= WalterEtAlGeometricShadowingFunction (NdotL, NdotV, roughness);
	#elif _SMITHGEOSHADOWMODEL_BECKMAN
		GeometricShadow *= BeckmanGeometricShadowingFunction (NdotL, NdotV, roughness);
 	#elif _SMITHGEOSHADOWMODEL_GGX
		GeometricShadow *= GGXGeometricShadowingFunction (NdotL, NdotV, roughness);
	#elif _SMITHGEOSHADOWMODEL_SCHLICK
		GeometricShadow *= SchlickGeometricShadowingFunction (NdotL, NdotV, roughness);
 	#elif _SMITHGEOSHADOWMODEL_SCHLICKBECKMAN
		GeometricShadow *= SchlickBeckmanGeometricShadowingFunction (NdotL, NdotV, roughness);
 	#elif _SMITHGEOSHADOWMODEL_SCHLICKGGX
		GeometricShadow *= SchlickGGXGeometricShadowingFunction (NdotL, NdotV, roughness);
	#elif _SMITHGEOSHADOWMODEL_IMPLICIT
		GeometricShadow *= ImplicitGeometricShadowingFunction (NdotL, NdotV);
	#else
		GeometricShadow *= ImplicitGeometricShadowingFunction (NdotL, NdotV);
 	#endif
	 //Fresnel Function-------------------------------------------------------------------------------------------------

	#ifdef _FRESNELMODEL_SCHLICK
		FresnelFunction *=  SchlickFresnelFunction(specColor, LdotH);
	#elif _FRESNELMODEL_SCHLICKIOR
		FresnelFunction *=  SchlickIORFresnelFunction(_Ior, LdotH);
	#elif _FRESNELMODEL_SPHERICALGAUSSIAN
		FresnelFunction *= SphericalGaussianFresnelFunction(LdotH, specColor);
 	#else
		FresnelFunction *=  SchlickIORFresnelFunction(_Ior, LdotH);	
 	#endif

现在我们选择Keyword的时候我们可以实时地切换效果。通过这个你的shader应该可以完美运行了。我推荐拷贝一下下面的代码,你就可以得到完整shader的效果了,自己写的话有可能会有些凌乱。

完整代码

(译注:建议直接拷贝到编辑器里面看,网页上看着实有些恶心了)

Shader "Physically-Based-Lighting" {
    Properties {
	_Color ("Main Color", Color) = (1,1,1,1)
	_SpecularColor ("Specular Color", Color) = (1,1,1,1)
	_SpecularPower("Specular Power", Range(0,1)) = 1
	_SpecularRange("Specular Gloss",  Range(1,40)) = 0
	_Glossiness("Smoothness",Range(0,1)) = 1
	_Metallic("Metallicness",Range(0,1)) = 0
	_Anisotropic("Anisotropic",  Range(-20,1)) = 0
	_Ior("Ior",  Range(1,4)) = 1.5
	_UnityLightingContribution("Unity Reflection Contribution", Range(0,1)) = 1
	[KeywordEnum(BlinnPhong,Phong,Beckmann,Gaussian,GGX,TrowbridgeReitz,TrowbridgeReitzAnisotropic, Ward)] _NormalDistModel("Normal Distribution Model;", Float) = 0
	[KeywordEnum(AshikhminShirley,AshikhminPremoze,Duer,Neumann,Kelemen,ModifiedKelemen,Cook,Ward,Kurt)]_GeoShadowModel("Geometric Shadow Model;", Float) = 0
	[KeywordEnum(None,Walter,Beckman,GGX,Schlick,SchlickBeckman,SchlickGGX, Implicit)]_SmithGeoShadowModel("Smith Geometric Shadow Model; None if above is Used;", Float) = 0
	[KeywordEnum(Schlick,SchlickIOR, SphericalGaussian)]_FresnelModel("Normal Distribution Model;", Float) = 0
	[Toggle] _ENABLE_NDF ("Normal Distribution Enabled?", Float) = 0
	[Toggle] _ENABLE_G ("Geometric Shadow Enabled?", Float) = 0
	[Toggle] _ENABLE_F ("Fresnel Enabled?", Float) = 0
	[Toggle] _ENABLE_D ("Diffuse Enabled?", Float) = 0
    }
    SubShader {
	Tags {
            "RenderType"="Opaque"  "Queue"="Geometry"
        } 
        Pass {
            Name "FORWARD"
            Tags {
                "LightMode"="ForwardBase"
            }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #define UNITY_PASS_FORWARDBASE
            #include "UnityCG.cginc"
            #include "AutoLight.cginc"
            #include "Lighting.cginc"
            #pragma multi_compile_fwdbase_fullshadows
            #pragma multi_compile _NORMALDISTMODEL_BLINNPHONG _NORMALDISTMODEL_PHONG _NORMALDISTMODEL_BECKMANN _NORMALDISTMODEL_GAUSSIAN _NORMALDISTMODEL_GGX _NORMALDISTMODEL_TROWBRIDGEREITZ _NORMALDISTMODEL_TROWBRIDGEREITZANISOTROPIC _NORMALDISTMODEL_WARD
            #pragma multi_compile _GEOSHADOWMODEL_ASHIKHMINSHIRLEY _GEOSHADOWMODEL_ASHIKHMINPREMOZE _GEOSHADOWMODEL_DUER_GEOSHADOWMODEL_NEUMANN _GEOSHADOWMODEL_KELEMAN _GEOSHADOWMODEL_MODIFIEDKELEMEN _GEOSHADOWMODEL_COOK _GEOSHADOWMODEL_WARD _GEOSHADOWMODEL_KURT 
            #pragma multi_compile _SMITHGEOSHADOWMODEL_NONE _SMITHGEOSHADOWMODEL_WALTER _SMITHGEOSHADOWMODEL_BECKMAN _SMITHGEOSHADOWMODEL_GGX _SMITHGEOSHADOWMODEL_SCHLICK _SMITHGEOSHADOWMODEL_SCHLICKBECKMAN _SMITHGEOSHADOWMODEL_SCHLICKGGX _SMITHGEOSHADOWMODEL_IMPLICIT
            #pragma multi_compile _FRESNELMODEL_SCHLICK _FRESNELMODEL_SCHLICKIOR _FRESNELMODEL_SPHERICALGAUSSIAN
            #pragma multi_compile  _ENABLE_NDF_OFF _ENABLE_NDF_ON
            #pragma multi_compile  _ENABLE_G_OFF _ENABLE_G_ON
            #pragma multi_compile  _ENABLE_F_OFF _ENABLE_F_ON
            #pragma multi_compile  _ENABLE_D_OFF _ENABLE_D_ON
            #pragma target 3.0
            
float4 _Color;
float4 _SpecularColor;
float _SpecularPower;
float _SpecularRange;
float _Glossiness;
float _Metallic;
float _Anisotropic;
float _Ior;
float _NormalDistModel;
float _GeoShadowModel;
float _FresnelModel;
float _UnityLightingContribution;

struct VertexInput {
    float4 vertex : POSITION;       //local vertex position
    float3 normal : NORMAL;         //normal direction
    float4 tangent : TANGENT;       //tangent direction    
    float2 texcoord0 : TEXCOORD0;   //uv coordinates
    float2 texcoord1 : TEXCOORD1;   //lightmap uv coordinates
};

struct VertexOutput {
    float4 pos : SV_POSITION;              //screen clip space position and depth
    float2 uv0 : TEXCOORD0;                //uv coordinates
    float2 uv1 : TEXCOORD1;                //lightmap uv coordinates

//below we create our own variables with the texcoord semantic. 
    float3 normalDir : TEXCOORD3;          //normal direction   
    float3 posWorld : TEXCOORD4;          //normal direction   
    float3 tangentDir : TEXCOORD5;
    float3 bitangentDir : TEXCOORD6;
    LIGHTING_COORDS(7,8)                   //this initializes the unity lighting and shadow
    UNITY_FOG_COORDS(9)                    //this initializes the unity fog
};

VertexOutput vert (VertexInput v) {
     VertexOutput o = (VertexOutput)0;           
     o.uv0 = v.texcoord0;
     o.uv1 = v.texcoord1;
     o.normalDir = UnityObjectToWorldNormal(v.normal);
     o.tangentDir = normalize( mul( _Object2World, float4( Corporate governance and insider trading resources, 0.0 ) ).xyz );
     o.bitangentDir = normalize(cross(o.normalDir, o.tangentDir) * v.tangent.w);
     o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
     o.posWorld = mul(_Object2World, v.vertex);
     UNITY_TRANSFER_FOG(o,o.pos);
     TRANSFER_VERTEX_TO_FRAGMENT(o)
     return o;
}

UnityGI GetUnityGI(float3 lightColor, float3 lightDirection, float3 normalDirection,float3 viewDirection, float3 viewReflectDirection, float attenuation, float roughness, float3 worldPos){
 //Unity light Setup ::
    UnityLight light;
    light.color = lightColor;
    light.dir = lightDirection;
    light.ndotl = max(0.0h,dot( normalDirection, lightDirection));
    UnityGIInput d;
    d.light = light;
    d.worldPos = worldPos;
    d.worldViewDir = viewDirection;
    d.atten = attenuation;
    d.ambient = 0.0h;
    d.boxMax[0] = unity_SpecCube0_BoxMax;
    d.boxMin[0] = unity_SpecCube0_BoxMin;
    d.probePosition[0] = unity_SpecCube0_ProbePosition;
    d.probeHDR[0] = unity_SpecCube0_HDR;
    d.boxMax[1] = unity_SpecCube1_BoxMax;
    d.boxMin[1] = unity_SpecCube1_BoxMin;
    d.probePosition[1] = unity_SpecCube1_ProbePosition;
    d.probeHDR[1] = unity_SpecCube1_HDR;
    Unity_GlossyEnvironmentData ugls_en_data;
    ugls_en_data.roughness = roughness;
    ugls_en_data.reflUVW = viewReflectDirection;
    UnityGI gi = UnityGlobalIllumination(d, 1.0h, normalDirection, ugls_en_data );
    return gi;
}


//---------------------------
//helper functions
float MixFunction(float i, float j, float x) {
	 return  j * x + i * (1.0 - x);
} 
float2 MixFunction(float2 i, float2 j, float x){
	 return  j * x + i * (1.0h - x);
}   
float3 MixFunction(float3 i, float3 j, float x){
	 return  j * x + i * (1.0h - x);
}   
float MixFunction(float4 i, float4 j, float x){
	 return  j * x + i * (1.0h - x);
} 
float sqr(float x){
	return x*x; 
}
//------------------------------


//------------------------------------------------
//schlick functions
float SchlickFresnel(float i){
    float x = clamp(1.0-i, 0.0, 1.0);
    float x2 = x*x;
    return x2*x2*x;
}
float3 FresnelLerp (float3 x, float3 y, float d)
{
	float t = SchlickFresnel(d);	
	return lerp (x, y, t);
}

float3 SchlickFresnelFunction(float3 SpecularColor,float LdotH){
    return SpecularColor + (1 - SpecularColor)* SchlickFresnel(LdotH);
}

float SchlickIORFresnelFunction(float ior,float LdotH){
    float f0 = pow((ior-1)/(ior+1),2);
    return f0 +  (1 - f0) * SchlickFresnel(LdotH);
}
float SphericalGaussianFresnelFunction(float LdotH,float SpecularColor)
{	
	float power = ((-5.55473 * LdotH) - 6.98316) * LdotH;
    return SpecularColor + (1 - SpecularColor)  * pow(2,power);
}

//-----------------------------------------------



//-----------------------------------------------
//normal incidence reflection calculation
float F0 (float NdotL, float NdotV, float LdotH, float roughness){
// Diffuse fresnel
    float FresnelLight = SchlickFresnel(NdotL); 
    float FresnelView = SchlickFresnel(NdotV);
    float FresnelDiffuse90 = 0.5 + 2.0 * LdotH*LdotH * roughness;
   return  MixFunction(1, FresnelDiffuse90, FresnelLight) * MixFunction(1, FresnelDiffuse90, FresnelView);
}

//-----------------------------------------------




//-----------------------------------------------
//Normal Distribution Functions

float BlinnPhongNormalDistribution(float NdotH, float specularpower, float speculargloss){
    float Distribution = pow(NdotH,speculargloss) * specularpower;
    Distribution *= (2+specularpower) / (2*3.1415926535);
    return Distribution;
}
float PhongNormalDistribution(float RdotV, float specularpower, float speculargloss){
    float Distribution = pow(RdotV,speculargloss) * specularpower;
    Distribution *= (2+specularpower) / (2*3.1415926535);
    return Distribution;
}

float BeckmannNormalDistribution(float roughness, float NdotH)
{
    float roughnessSqr = roughness*roughness;
    float NdotHSqr = NdotH*NdotH;
    return max(0.000001,(1.0 / (3.1415926535*roughnessSqr*NdotHSqr*NdotHSqr))* exp((NdotHSqr-1)/(roughnessSqr*NdotHSqr)));
}

float GaussianNormalDistribution(float roughness, float NdotH)
{
    float roughnessSqr = roughness*roughness;
	float thetaH = acos(NdotH);
    return exp(-thetaH*thetaH/roughnessSqr);
}

float GGXNormalDistribution(float roughness, float NdotH)
{
    float roughnessSqr = roughness*roughness;
    float NdotHSqr = NdotH*NdotH;
    float TanNdotHSqr = (1-NdotHSqr)/NdotHSqr;
    return (1.0/3.1415926535) * sqr(roughness/(NdotHSqr * (roughnessSqr + TanNdotHSqr)));
//    float denom = NdotHSqr * (roughnessSqr-1)

}

float TrowbridgeReitzNormalDistribution(float NdotH, float roughness){
    float roughnessSqr = roughness*roughness;
    float Distribution = NdotH*NdotH * (roughnessSqr-1.0) + 1.0;
    return roughnessSqr / (3.1415926535 * Distribution*Distribution);
}

float TrowbridgeReitzAnisotropicNormalDistribution(float anisotropic, float NdotH, float HdotX, float HdotY){
	float aspect = sqrt(1.0h-anisotropic * 0.9h);
	float X = max(.001, sqr(1.0-_Glossiness)/aspect) * 5;
 	float Y = max(.001, sqr(1.0-_Glossiness)*aspect) * 5;
    return 1.0 / (3.1415926535 * X*Y * sqr(sqr(HdotX/X) + sqr(HdotY/Y) + NdotH*NdotH));
}

float WardAnisotropicNormalDistribution(float anisotropic, float NdotL, float NdotV, float NdotH, float HdotX, float HdotY){
    float aspect = sqrt(1.0h-anisotropic * 0.9h);
    float X = max(.001, sqr(1.0-_Glossiness)/aspect) * 5;
 	float Y = max(.001, sqr(1.0-_Glossiness)*aspect) * 5;
    float exponent = -(sqr(HdotX/X) + sqr(HdotY/Y)) / sqr(NdotH);
    float Distribution = 1.0 / ( 3.14159265 * X * Y * sqrt(NdotL * NdotV));
    Distribution *= exp(exponent);
    return Distribution;
}
//--------------------------



//-----------------------------------------------
//Geometric Shadowing Functions

float ImplicitGeometricShadowingFunction (float NdotL, float NdotV){
	float Gs =  (NdotL*NdotV);       
	return Gs;
}

float AshikhminShirleyGeometricShadowingFunction (float NdotL, float NdotV, float LdotH){
	float Gs = NdotL*NdotV/(LdotH*max(NdotL,NdotV));
	return  (Gs);
}

float AshikhminPremozeGeometricShadowingFunction (float NdotL, float NdotV){
	float Gs = NdotL*NdotV/(NdotL+NdotV - NdotL*NdotV);
	return  (Gs);
}

float DuerGeometricShadowingFunction (float3 lightDirection,float3 viewDirection, float3 normalDirection,float NdotL, float NdotV){
    float3 LpV = lightDirection + viewDirection;
    float Gs = dot(LpV,LpV) * pow(dot(LpV,normalDirection),-4);
    return  (Gs);
}

float NeumannGeometricShadowingFunction (float NdotL, float NdotV){
	float Gs = (NdotL*NdotV)/max(NdotL, NdotV);       
	return  (Gs);
}

float KelemenGeometricShadowingFunction (float NdotL, float NdotV, float LdotH, float VdotH){
//	float Gs = (NdotL*NdotV)/ (LdotH * LdotH);           //this
	float Gs = (NdotL*NdotV)/(VdotH * VdotH);       //or this?
	return   (Gs);
}

float ModifiedKelemenGeometricShadowingFunction (float NdotV, float NdotL, float roughness)
{
	float c = 0.797884560802865; // c = sqrt(2 / Pi)
	float k = roughness * roughness * c;
	float gH = NdotV  * k +(1-k);
	return (gH * gH * NdotL);
}

float CookTorrenceGeometricShadowingFunction (float NdotL, float NdotV, float VdotH, float NdotH){
	float Gs = min(1.0, min(2*NdotH*NdotV / VdotH, 2*NdotH*NdotL / VdotH));
	return  (Gs);
}

float WardGeometricShadowingFunction (float NdotL, float NdotV, float VdotH, float NdotH){
	float Gs = pow( NdotL * NdotV, 0.5);
	return  (Gs);
}

float KurtGeometricShadowingFunction (float NdotL, float NdotV, float VdotH, float alpha){
	float Gs =  (VdotH*pow(NdotL*NdotV, alpha))/ NdotL * NdotV;
	return  (Gs);
}

//SmithModelsBelow
//Gs = F(NdotL) * F(NdotV);

float WalterEtAlGeometricShadowingFunction (float NdotL, float NdotV, float alpha){
    float alphaSqr = alpha*alpha;
    float NdotLSqr = NdotL*NdotL;
    float NdotVSqr = NdotV*NdotV;
    float SmithL = 2/(1 + sqrt(1 + alphaSqr * (1-NdotLSqr)/(NdotLSqr)));
    float SmithV = 2/(1 + sqrt(1 + alphaSqr * (1-NdotVSqr)/(NdotVSqr)));
	float Gs =  (SmithL * SmithV);
	return Gs;
}

float BeckmanGeometricShadowingFunction (float NdotL, float NdotV, float roughness){
    float roughnessSqr = roughness*roughness;
    float NdotLSqr = NdotL*NdotL;
    float NdotVSqr = NdotV*NdotV;
    float calulationL = (NdotL)/(roughnessSqr * sqrt(1- NdotLSqr));
    float calulationV = (NdotV)/(roughnessSqr * sqrt(1- NdotVSqr));
    float SmithL = calulationL < 1.6 ? (((3.535 * calulationL) + (2.181 * calulationL * calulationL))/(1 + (2.276 * calulationL) + (2.577 * calulationL * calulationL))) : 1.0;
    float SmithV = calulationV < 1.6 ? (((3.535 * calulationV) + (2.181 * calulationV * calulationV))/(1 + (2.276 * calulationV) + (2.577 * calulationV * calulationV))) : 1.0;
	float Gs =  (SmithL * SmithV);
	return Gs;
}

float GGXGeometricShadowingFunction (float NdotL, float NdotV, float roughness){
    float roughnessSqr = roughness*roughness;
    float NdotLSqr = NdotL*NdotL;
    float NdotVSqr = NdotV*NdotV;
    float SmithL = (2 * NdotL)/ (NdotL + sqrt(roughnessSqr + ( 1-roughnessSqr) * NdotLSqr));
    float SmithV = (2 * NdotV)/ (NdotV + sqrt(roughnessSqr + ( 1-roughnessSqr) * NdotVSqr));
	float Gs =  (SmithL * SmithV) ;
	return Gs;
}

float SchlickGeometricShadowingFunction (float NdotL, float NdotV, float roughness)
{
    float roughnessSqr = roughness*roughness;
	float SmithL = (NdotL)/(NdotL * (1-roughnessSqr) + roughnessSqr);
	float SmithV = (NdotV)/(NdotV * (1-roughnessSqr) + roughnessSqr);
	return (SmithL * SmithV); 
}


float SchlickBeckmanGeometricShadowingFunction (float NdotL, float NdotV, float roughness){
    float roughnessSqr = roughness*roughness;
    float k = roughnessSqr * 0.797884560802865;
    float SmithL = (NdotL)/ (NdotL * (1- k) + k);
    float SmithV = (NdotV)/ (NdotV * (1- k) + k);
	float Gs =  (SmithL * SmithV);
	return Gs;
}

float SchlickGGXGeometricShadowingFunction (float NdotL, float NdotV, float roughness){
    float k = roughness / 2;
    float SmithL = (NdotL)/ (NdotL * (1- k) + k);
    float SmithV = (NdotV)/ (NdotV * (1- k) + k);
	float Gs =  (SmithL * SmithV);
	return Gs;
}

//--------------------------


float4 frag(VertexOutput i) : COLOR {

//normal direction calculations
     float3 normalDirection = normalize(i.normalDir);
	 float3 viewDirection = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz);
     float shiftAmount = dot(i.normalDir, viewDirection);
	 normalDirection = shiftAmount < 0.0f ? normalDirection + viewDirection * (-shiftAmount + 1e-5f) : normalDirection;

//light calculations
	 float3 lightDirection = normalize(lerp(_WorldSpaceLightPos0.xyz, _WorldSpaceLightPos0.xyz - i.posWorld.xyz,_WorldSpaceLightPos0.w));
	 float3 lightReflectDirection = reflect( -lightDirection, normalDirection );
	 float3 viewReflectDirection = normalize(reflect( -viewDirection, normalDirection ));
     float NdotL = max(0.0, dot( normalDirection, lightDirection ));
     float3 halfDirection = normalize(viewDirection+lightDirection); 
     float NdotH =  max(0.0,dot( normalDirection, halfDirection));
     float NdotV =  max(0.0,dot( normalDirection, viewDirection));
     float VdotH = max(0.0,dot( viewDirection, halfDirection));
     float LdotH =  max(0.0,dot(lightDirection, halfDirection)); 
     float LdotV = max(0.0,dot(lightDirection, viewDirection)); 
     float RdotV = max(0.0, dot( lightReflectDirection, viewDirection ));
     float attenuation = LIGHT_ATTENUATION(i);
     float3 attenColor = attenuation * _LightColor0.rgb;
     
     //get Unity Scene lighting data
     UnityGI gi =  GetUnityGI(_LightColor0.rgb, lightDirection, normalDirection, viewDirection, viewReflectDirection, attenuation, 1- _Glossiness, i.posWorld.xyz);
     float3 indirectDiffuse = gi.indirect.diffuse.rgb ;
	 float3 indirectSpecular = gi.indirect.specular.rgb;

	 //diffuse color calculations
	 float roughness = 1-(_Glossiness * _Glossiness);
	 roughness = roughness * roughness;
     float3 diffuseColor = _Color.rgb * (1.0 - _Metallic) ;
 	 float f0 = F0(NdotL, NdotV, LdotH, roughness);
	 diffuseColor *= f0;
	 diffuseColor+=indirectDiffuse;
	 


	//Specular calculations


	 float3 specColor = lerp(_SpecularColor.rgb, _Color.rgb, _Metallic * 0.5);

	 float3 SpecularDistribution = specColor;
	 float GeometricShadow = 1;
	 float3 FresnelFunction = specColor;

	 //Normal Distribution Function/Specular Distribution-----------------------------------------------------	      

           
	#ifdef _NORMALDISTMODEL_BLINNPHONG 
		 SpecularDistribution *=  BlinnPhongNormalDistribution(NdotH, _Glossiness,  max(1,_Glossiness * 40));
 	#elif _NORMALDISTMODEL_PHONG
		 SpecularDistribution *=  PhongNormalDistribution(RdotV, _Glossiness, max(1,_Glossiness * 40));
 	#elif _NORMALDISTMODEL_BECKMANN
		 SpecularDistribution *=  BeckmannNormalDistribution(roughness, NdotH);
 	#elif _NORMALDISTMODEL_GAUSSIAN
		 SpecularDistribution *=  GaussianNormalDistribution(roughness, NdotH);
 	#elif _NORMALDISTMODEL_GGX
		 SpecularDistribution *=  GGXNormalDistribution(roughness, NdotH);
 	#elif _NORMALDISTMODEL_TROWBRIDGEREITZ
		 SpecularDistribution *=  TrowbridgeReitzNormalDistribution(NdotH, roughness);
 	#elif _NORMALDISTMODEL_TROWBRIDGEREITZANISOTROPIC
		 SpecularDistribution *=  TrowbridgeReitzAnisotropicNormalDistribution(_Anisotropic,NdotH, dot(halfDirection, i.tangentDir), dot(halfDirection,  i.bitangentDir));
	#elif _NORMALDISTMODEL_WARD
	 	 SpecularDistribution *=  WardAnisotropicNormalDistribution(_Anisotropic,NdotL, NdotV, NdotH, dot(halfDirection, i.tangentDir), dot(halfDirection,  i.bitangentDir));
	#else
		SpecularDistribution *=  GGXNormalDistribution(roughness, NdotH);
	#endif


	 //Geometric Shadowing term----------------------------------------------------------------------------------
	#ifdef _SMITHGEOSHADOWMODEL_NONE
	#ifdef _GEOSHADOWMODEL_ASHIKHMINSHIRLEY
		GeometricShadow *= AshikhminShirleyGeometricShadowingFunction (NdotL, NdotV, LdotH);
	#elif _GEOSHADOWMODEL_ASHIKHMINPREMOZE
		GeometricShadow *= AshikhminPremozeGeometricShadowingFunction (NdotL, NdotV);
	#elif _GEOSHADOWMODEL_DUER
		GeometricShadow *= DuerGeometricShadowingFunction (lightDirection, viewDirection, normalDirection, NdotL, NdotV);
	#elif _GEOSHADOWMODEL_NEUMANN
		GeometricShadow *= NeumannGeometricShadowingFunction (NdotL, NdotV);
	#elif _GEOSHADOWMODEL_KELEMAN
		GeometricShadow *= KelemenGeometricShadowingFunction (NdotL, NdotV, LdotH,  VdotH);
	#elif _GEOSHADOWMODEL_MODIFIEDKELEMEN
		GeometricShadow *=  ModifiedKelemenGeometricShadowingFunction (NdotV, NdotL, roughness);
	#elif _GEOSHADOWMODEL_COOK
		GeometricShadow *= CookTorrenceGeometricShadowingFunction (NdotL, NdotV, VdotH, NdotH);
	#elif _GEOSHADOWMODEL_WARD
		GeometricShadow *= WardGeometricShadowingFunction (NdotL, NdotV, VdotH, NdotH);
	#elif _GEOSHADOWMODEL_KURT
		GeometricShadow *= KurtGeometricShadowingFunction (NdotL, NdotV, VdotH, roughness);
	#else 			
 		GeometricShadow *= ImplicitGeometricShadowingFunction (NdotL, NdotV);
 	#endif
	////SmithModelsBelow
	////Gs = F(NdotL) * F(NdotV);
  	#elif _SMITHGEOSHADOWMODEL_WALTER
		GeometricShadow *= WalterEtAlGeometricShadowingFunction (NdotL, NdotV, roughness);
	#elif _SMITHGEOSHADOWMODEL_BECKMAN
		GeometricShadow *= BeckmanGeometricShadowingFunction (NdotL, NdotV, roughness);
 	#elif _SMITHGEOSHADOWMODEL_GGX
		GeometricShadow *= GGXGeometricShadowingFunction (NdotL, NdotV, roughness);
	#elif _SMITHGEOSHADOWMODEL_SCHLICK
		GeometricShadow *= SchlickGeometricShadowingFunction (NdotL, NdotV, roughness);
 	#elif _SMITHGEOSHADOWMODEL_SCHLICKBECKMAN
		GeometricShadow *= SchlickBeckmanGeometricShadowingFunction (NdotL, NdotV, roughness);
 	#elif _SMITHGEOSHADOWMODEL_SCHLICKGGX
		GeometricShadow *= SchlickGGXGeometricShadowingFunction (NdotL, NdotV, roughness);
	#elif _SMITHGEOSHADOWMODEL_IMPLICIT
		GeometricShadow *= ImplicitGeometricShadowingFunction (NdotL, NdotV);
	#else
		GeometricShadow *= ImplicitGeometricShadowingFunction (NdotL, NdotV);
 	#endif
	 //Fresnel Function-------------------------------------------------------------------------------------------------

	#ifdef _FRESNELMODEL_SCHLICK
		FresnelFunction *=  SchlickFresnelFunction(specColor, LdotH);
	#elif _FRESNELMODEL_SCHLICKIOR
		FresnelFunction *=  SchlickIORFresnelFunction(_Ior, LdotH);
	#elif _FRESNELMODEL_SPHERICALGAUSSIAN
		FresnelFunction *= SphericalGaussianFresnelFunction(LdotH, specColor);
 	#else
		FresnelFunction *=  SchlickIORFresnelFunction(_Ior, LdotH);	
 	#endif


 	#ifdef _ENABLE_NDF_ON
 	 return float4(float3(1,1,1)* SpecularDistribution,1);
    #endif
    #ifdef _ENABLE_G_ON 
 	 return float4(float3(1,1,1) * GeometricShadow,1) ;
    #endif
    #ifdef _ENABLE_F_ON 
 	 return float4(float3(1,1,1)* FresnelFunction,1);
    #endif
	#ifdef _ENABLE_D_ON 
 	 return float4(float3(1,1,1)* diffuseColor,1);
    #endif

	 //PBR
	 float3 specularity = (SpecularDistribution * FresnelFunction * GeometricShadow) / (4 * (  NdotL * NdotV));
     float grazingTerm = saturate(roughness + _Metallic);
	 float3 unityIndirectSpecularity =  indirectSpecular * FresnelLerp(specColor,grazingTerm,NdotV) * max(0.15,_Metallic) * (1-roughness*roughness* roughness);

     float3 lightingModel = ((diffuseColor) + specularity + (unityIndirectSpecularity *_UnityLightingContribution));
     lightingModel *= NdotL;
     float4 finalDiffuse = float4(lightingModel * attenColor,1);
     UNITY_APPLY_FOG(i.fogCoord, finalDiffuse);
     return finalDiffuse;
}
ENDCG
}
}
FallBack "Legacy Shaders/Diffuse"
}

发表评论

邮箱地址不会被公开。 必填项已用*标注