1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
| Shader "Unity Shaders Learn/Chapter18/CustomPBR" { Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex ("Albedo (RGB)", 2D) = "white" {} _Glossiness ("Smoothness", Range(0,1)) = 0.5 _SpecularColor ("Specular", Color) = (0.2, 0.2, 0.2) _SpecGlossMap ("Specular (RGB) Smoothness (A)", 2D) = "white" {} _BumpScale ("Bump Scale", Float) = 1.0 _BumpMap ("Normal Map", 2D) = "bump" {} _EmissionColor ("Emission Color", Color) = (0,0,0) _EmissionMap ("Eission", 2D) = "white" {} } SubShader { Tags {"RenderType"="Opaque"} LOD 300 CGINCLUDE #include "UnityCG.cginc" #include "AutoLight.cginc" #include "Lighting.cginc"
fixed4 _Color; sampler2D _MainTex; float4 _MainTex_ST; fixed _Glossiness; fixed4 _SpecularColor; sampler2D _SpecGlossMap; float _BumpScale; sampler2D _BumpMap; fixed4 _EmissionColor; sampler2D _EmissionMap;
// 迪士尼漫反射项 inline half3 CustomDisneyDiffuseTerm(half NdotV, half NdotL, half LdotH, half roughness, half3 baseColor) { half fd90 = 0.5 + 2 * LdotH * LdotH * roughness; // Two schlick fresnel term half lightScatter = (1 + (fd90 - 1) * pow(1 - NdotL, 5)); half viewScatter = (1 + (fd90 - 1) * pow(1 - NdotV, 5));
return baseColor * UNITY_INV_PI * lightScatter * viewScatter; }
// 依照 Eric Heitz 提出的按 Height-Correlated Masking and Shadowing 方式组合的 Smith-Joint 阴影-遮掩函数 inline half CustomSmithJointGGXVisibilityTerm(half NdotL, half NdotV, half roughness) { half a2 = roughness * roughness; // Original formulation: // half lambda_v = (-1 + sqrt(a2 * (1 - NdotL*NdotL) / NdotL * NdotL + 1)) * 0.5f; // half lambda_l = (-1 + sqrt(a2 * (1 - NdotV*NdotV) / NdotV * NdotV + 1)) * 0.5f; // G = 1 / (1 + lambda_v + lambda_l);
// Approximation of the above formulation (simplify the sqrt, not mathematically correct but close enough) half lambdaV = NdotL * (NdotV * (1 - a2) + a2); half lambdaL = NdotV * (NdotL * (1 - a2) + a2);
return 0.5f / (lambdaL + lambdaV + 1e-5f); }
// 法线分布项 D,CustomGGXTerm 函数的实现(依照基于 GGX 模型的法线分布函数) inline half CustomGGXTerm(half NdotH, half roughness) { half a2 = roughness * roughness; half d = (NdotH * a2 - NdotH) * NdotH + 1.0f; return UNITY_INV_PI * a2 / (d * d + 1e-7f); }
// 菲涅耳反射项 F,CustomFresnelTerm 函数(依照 Schlick 菲涅耳近似等式)的实现 inline half3 CustomFresnelTerm(half3 c, half cosA) { half t = pow(1 - cosA, 5); return c + (1 - c) * t; }
// 菲涅耳插值 inline half3 CustomFresnelLerp(half3 c0, half3 c1, half cosA) { half t = pow(1 - cosA, 5); return lerp(c0, c1, t); } ENDCG Pass { Tags {"LightMode" = "ForwardBase"} CGPROGRAM #pragma target 3.0
#pragma multi_compile_fwdbase #pragma multi_compole_fog
#pragma vertex vert; #pragma fragment frag;
struct a2v { float4 vertex : POSITION; float4 texcoord : TEXCOORD0; float3 normal : NORMAL; float4 tangent : TANGENT; };
struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; float4 TtoW0 : TEXCOORD1; float4 TtoW1 : TEXCOORD2; float4 TtoW2 : TEXCOORD3; SHADOW_COORDS(4) UNITY_FOG_COORDS(5) };
v2f vert(a2v v) { v2f o; UNITY_INITIALIZE_OUTPUT(v2f, o);
o.pos = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; float3 worldNormal = UnityObjectToWorldNormal(v.normal); float3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz); float3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w;
o.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x); o.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y); o.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
TRANSFER_SHADOW(o); UNITY_TRANSFER_FOG(o, o.pos);
return o; }
half4 frag(v2f i) : SV_Target { //// 准备好输入数据 half4 specGloss = tex2D(_SpecGlossMap, i.uv); specGloss.a *= _Glossiness; half3 specColor = specGloss.rgb * _SpecularColor.rgb; half roughness = 1 - specGloss.a;
//这个变量并不是我们之前到的 BRDF 中需要的变量,它主要是为了计算掠射角的反射颜色,从而得到效果更好的菲涅耳反射效果。 half oneMinusReflectivity = 1 - max(max(specColor.r, specColor.g), specColor.b);
half3 diffColor = _Color.rgb * tex2D(_MainTex, i.uv).rgb * oneMinusReflectivity;
half3 normalTangent = UnpackNormal(tex2D(_BumpMap, i.uv)); normalTangent.xy *= _BumpScale; normalTangent.z = sqrt(1.0 - saturate(dot(normalTangent.xy, normalTangent.xy))); half3 worldNormal = normalize(half3(dot(i.TtoW0.xyz, normalTangent), dot(i.TtoW1.xyz, normalTangent), dot(i.TtoW2.xyz, normalTangent)));
float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w); half3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos)); half3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos)); half3 reflDir = reflect(-viewDir, worldNormal);
UNITY_LIGHT_ATTENUATION(atten, i, worldPos);
//// 计算 BRDF 项 half3 halfDir = normalize(lightDir + viewDir); half nv = saturate(dot(worldNormal, viewDir)); half nl = saturate(dot(worldNormal, lightDir)); half nh = saturate(dot(worldNormal, halfDir)); half lv = saturate(dot(lightDir, viewDir)); half lh = saturate(dot(lightDir, halfDir));
// diffuse term half3 diffuseTerm = CustomDisneyDiffuseTerm(nv, nl, lh, roughness, diffColor);
// specular term half V = CustomSmithJointGGXVisibilityTerm(nl, nv, roughness); half D = CustomGGXTerm(nh, roughness * roughness); half3 F = CustomFresnelTerm(specColor, lh); half3 specularTerm = F * V * D;
// Emission term half3 emissionTerm = tex2D(_EmissionMap, i.uv).rgb * _EmissionColor.rgb;
// IBL 使用材质粗糙度对环境贴图进行 LOD(Level Of Detail)采样 half perceptualRoughness = roughness * (1.7 - 0.7 * roughness); //为了计算需要采样的多级渐远纹理的级数,我们将材质粗糙度乘以某个常数(在上述实现中该常数为 6),这个常数表明了整个粗糙度范围内多级渐远纹理的总级数。 half mip = perceptualRoughness * 6; //unity_SpecCube0 包含了该物体周围当前活跃的反射探针(ReflectionProbe)中所包含的环境贴图。 half4 envMap = UNITY_SAMPLE_TEXCUBE_LOD(unity_SpecCube0, reflDir, mip); half grazingTerm = saturate((1 - roughness) + (1 - oneMinusReflectivity)); half surfaceReduction = 1.0 / (roughness * roughness + 1.0); //使用掠射角度进行菲涅耳插值的好处是,我们可以在掠射角得到更加真实的菲涅耳反射效果,同时还考虑了材质粗糙度的影响。 //尽管 grazingTerm 被声明为单一维数的 half 变量,在传递给 CustomFresnelLerp 时它会自动被转换成 half3 类型的变量,这在 Cg 中被称为是"Smearing" Of Scalars To Vectors。 half3 indirectSpecular = surfaceReduction * envMap.rgb * CustomFresnelLerp(specColor, grazingTerm, nv);
half3 col = emissionTerm + UNITY_PI * (diffuseTerm + specularTerm) * _LightColor0.rgb * nl * atten + indirectSpecular;
UNITY_APPLY_FOG(i.fogCpprd, c.rgb); return half4(col, 1); } ENDCG } Pass { Tags {"LightMode" = "ForwardAdd"} Blend One One CGPROGRAM #pragma target 3.0
#pragma multi_compile_fwdadd
#pragma vertex vert; #pragma fragment frag;
struct a2v { float4 vertex : POSITION; float4 texcoord : TEXCOORD0; float3 normal : NORMAL; float4 tangent : TANGENT; };
struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; float4 TtoW0 : TEXCOORD1; float4 TtoW1 : TEXCOORD2; float4 TtoW2 : TEXCOORD3; SHADOW_COORDS(4) };
v2f vert(a2v v) { v2f o; UNITY_INITIALIZE_OUTPUT(v2f, o);
o.pos = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; float3 worldNormal = UnityObjectToWorldNormal(v.normal); float3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz); float3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w;
o.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x); o.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y); o.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
TRANSFER_SHADOW(o); return o; }
half4 frag(v2f i) : SV_Target { //// 准备好输入数据 half4 specGloss = tex2D(_SpecGlossMap, i.uv); specGloss.a *= _Glossiness; half3 specColor = specGloss.rgb * _SpecularColor.rgb; half roughness = 1 - specGloss.a;
//这个变量并不是我们之前到的 BRDF 中需要的变量,它主要是为了计算掠射角的反射颜色,从而得到效果更好的菲涅耳反射效果。 half oneMinusReflectivity = 1 - max(max(specColor.r, specColor.g), specColor.b);
half3 diffColor = _Color.rgb * tex2D(_MainTex, i.uv).rgb * oneMinusReflectivity;
half3 normalTangent = UnpackNormal(tex2D(_BumpMap, i.uv)); normalTangent.xy *= _BumpScale; normalTangent.z = sqrt(1.0 - saturate(dot(normalTangent.xy, normalTangent.xy))); half3 worldNormal = normalize(half3(dot(i.TtoW0.xyz, normalTangent), dot(i.TtoW1.xyz, normalTangent), dot(i.TtoW2.xyz, normalTangent)));
float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w); half3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos)); half3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos)); half3 reflDir = reflect(-viewDir, worldNormal);
UNITY_LIGHT_ATTENUATION(atten, i, worldPos);
//// 计算 BRDF 项 half3 halfDir = normalize(lightDir + viewDir); half nv = saturate(dot(worldNormal, viewDir)); half nl = saturate(dot(worldNormal, lightDir)); half nh = saturate(dot(worldNormal, halfDir)); half lv = saturate(dot(lightDir, viewDir)); half lh = saturate(dot(lightDir, halfDir));
// diffuse term half3 diffuseTerm = CustomDisneyDiffuseTerm(nv, nl, lh, roughness, diffColor);
// specular term half V = CustomSmithJointGGXVisibilityTerm(nl, nv, roughness); half D = CustomGGXTerm(nh, roughness * roughness); half3 F = CustomFresnelTerm(specColor, lh); half3 specularTerm = F * V * D; half3 col = UNITY_PI * (diffuseTerm + specularTerm) * _LightColor0.rgb * nl * atten; return half4(col, 1); } ENDCG } } FallBack "VertexLit" }
|