源码 / shaders/Ch10/LitBreakdown.glsl
shaders/Ch10/LitBreakdown.glsl
// 第 10 章:把 URP Lit 的光照拆开看。(GLSL 版,对应 Ch10/LitBreakdown.shader) // 按 UniversalFragmentPBR 的流程逐项重算,但把四个分量分开累加: // 直接漫反射 / 直接高光 / 间接漫反射(SH)/ 间接高光(反射探针), // 用 _Component 选择输出哪一项。Full 模式直接调用 URP 原函数,Sum 模式输出四项之和,两者应当一致。 Shader "Cookbook/Ch10/LitBreakdown" { SubShader { Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" "Queue"="Geometry" } GLSLINCLUDE // 写在 GLSLINCLUDE 里的内容会拼到本 SubShader 每个 Pass 的最前面,三个 Pass 的 uniform 自然一致 uniform vec4 _BaseMap_ST; uniform vec4 _BaseColor; uniform vec4 _EmissionColor; uniform float _Cutoff; uniform float _Metallic; uniform float _Smoothness; uniform float _BumpScale; uniform float _Component; // ---- SurfaceInput.hlsl 的贴图与采样函数 ---- uniform sampler2D _BaseMap; uniform sampler2D _BumpMap; vec4 SampleAlbedoAlpha(vec2 uv) { return texture(_BaseMap, uv); } float Alpha(float albedoAlpha, vec4 color, float cutoff) { float alpha = albedoAlpha * color.a; #ifdef _ALPHATEST_ON if (alpha - cutoff < 0.0) discard; #endif return alpha; } vec3 SampleNormal(vec2 uv, float scale) { #ifdef _NORMALMAP return UnpackNormalScale(texture(_BumpMap, uv), scale); #else return vec3(0.0, 0.0, 1.0); #endif } ENDGLSL Pass { Name "ForwardLit" Tags { "LightMode"="UniversalForward" } GLSLPROGRAM #pragma shader_feature_local _NORMALMAP // 管线关键字(阴影、附加光、SSAO)网页版引擎始终提供;Forward+、反射探针混合、Instancing 网页版没有 VARYING vec2 uv; VARYING vec3 positionWS; VARYING vec3 normalWS; VARYING vec4 tangentWS; #ifdef VERTEX void main() { VertexPositionInputs pos = GetVertexPositionInputs(positionOS.xyz); VertexNormalInputs nrm = GetVertexNormalInputs(normalOS, tangentOS); gl_Position = pos.positionCS; positionWS = pos.positionWS; normalWS = nrm.normalWS; tangentWS = vec4(nrm.tangentWS, tangentOS.w * GetOddNegativeScale()); uv = TransformTex(texcoord0.xy, _BaseMap_ST); } #endif #ifdef FRAGMENT void BuildData(out SurfaceData s, out InputData d) { s = InitSurfaceData(); s.albedo = SampleAlbedoAlpha(uv).rgb * _BaseColor.rgb; s.alpha = 1.0; s.metallic = _Metallic; s.smoothness = _Smoothness; s.occlusion = 1.0; s.normalTS = SampleNormal(uv, _BumpScale); s.emission = _EmissionColor.rgb; d = InitInputData(); d.positionWS = positionWS; d.positionCS = gl_FragCoord; #if defined(_NORMALMAP) vec3 bitangent = tangentWS.w * cross(normalWS, tangentWS.xyz); d.normalWS = TransformTangentToWorld(s.normalTS, mat3(tangentWS.xyz, bitangent, normalWS)); #else d.normalWS = normalWS; #endif d.normalWS = NormalizeNormalPerPixel(d.normalWS); d.viewDirectionWS = GetWorldSpaceNormalizeViewDir(positionWS); d.shadowCoord = TransformWorldToShadowCoord(positionWS); d.bakedGI = SampleSH(d.normalWS); d.normalizedScreenSpaceUV = GetNormalizedScreenSpaceUV(gl_FragCoord); d.shadowMask = vec4(1.0); } // URP Lighting.hlsl 里 GetMainLight(inputData, shadowMask, aoFactor) / GetAdditionalLight(i, inputData, shadowMask, aoFactor) // 这两个重载的 GLSL 写法:取灯 + 按 SSAO 的 Direct Lighting Strength 压一点直接光(没开 SSAO 时 directAmbientOcclusion = 1) Light GetMainLight(InputData inputData, vec4 shadowMask, AmbientOcclusionFactor aoFactor) { Light light = GetMainLight(inputData.shadowCoord, inputData.positionWS, shadowMask); light.color *= aoFactor.directAmbientOcclusion; return light; } Light GetAdditionalLight(int i, InputData inputData, vec4 shadowMask, AmbientOcclusionFactor aoFactor) { Light light = GetAdditionalLight(i, inputData.positionWS, shadowMask); light.color *= aoFactor.directAmbientOcclusion; return light; } // 与 LightingPhysicallyBased 相同的计算,只是把漫反射和高光分开累加 void AccumulateDirect(BRDFData brdf, Light light, InputData inputData, inout vec3 diffuse, inout vec3 specular) { float NdotL = saturate(dot(inputData.normalWS, light.direction)); vec3 radiance = light.color * (light.distanceAttenuation * light.shadowAttenuation * NdotL); diffuse += brdf.diffuse * radiance; specular += brdf.specular * DirectBRDFSpecular(brdf, inputData.normalWS, light.direction, inputData.viewDirectionWS) * radiance; } void main() { SurfaceData surfaceData; InputData inputData; BuildData(surfaceData, inputData); if (_Component < 0.5) { fragColor = UniversalFragmentPBR(inputData, surfaceData); // 原版,作为对照 return; } BRDFData brdf; InitializeBRDFData(surfaceData.albedo, surfaceData.metallic, surfaceData.specular, surfaceData.smoothness, surfaceData.alpha, brdf); vec4 shadowMask = vec4(1.0); // CalculateShadowMask:没有 Shadowmask 时是 1 AmbientOcclusionFactor aoFactor = CreateAmbientOcclusionFactor(inputData, surfaceData); Light mainLight = GetMainLight(inputData, shadowMask, aoFactor); // MixRealtimeAndBakedGI:没有光照贴图时什么都不做 // ---- 间接光:与 GlobalIllumination() 相同,只是拆成两项 ---- vec3 reflectVector = reflect(-inputData.viewDirectionWS, inputData.normalWS); float NoV = saturate(dot(inputData.normalWS, inputData.viewDirectionWS)); float fresnelTerm = Pow4(1.0 - NoV); vec3 envSpecular = GlossyEnvironmentReflection(reflectVector, inputData.positionWS, brdf.perceptualRoughness, 1.0); vec3 indirectDiffuse = inputData.bakedGI * brdf.diffuse * aoFactor.indirectAmbientOcclusion; vec3 indirectSpecular = envSpecular * EnvironmentBRDFSpecular(brdf, fresnelTerm) * aoFactor.indirectAmbientOcclusion; // ---- 直接光:主光 + 附加光 ---- vec3 directDiffuse = vec3(0.0), directSpecular = vec3(0.0); AccumulateDirect(brdf, mainLight, inputData, directDiffuse, directSpecular); // 网页版只有 Forward:附加光就是普通循环(HLSL 版的 Forward+ 分支与 LIGHT_LOOP_BEGIN 宏不需要) int pixelLightCount = GetAdditionalLightsCount(); for (int lightIndex = 0; lightIndex < pixelLightCount; lightIndex++) { Light light = GetAdditionalLight(lightIndex, inputData, shadowMask, aoFactor); AccumulateDirect(brdf, light, inputData, directDiffuse, directSpecular); } vec3 c; if (_Component < 1.5) c = directDiffuse; else if (_Component < 2.5) c = directSpecular; else if (_Component < 3.5) c = indirectDiffuse; else if (_Component < 4.5) c = indirectSpecular; else if (_Component < 5.5) c = directDiffuse + directSpecular + indirectDiffuse + indirectSpecular + surfaceData.emission; else c = vec3(mainLight.shadowAttenuation); fragColor = vec4(c, 1.0); } #endif ENDGLSL } Pass { Name "ShadowCaster" Tags { "LightMode"="ShadowCaster" } ZWrite On ZTest LEqual ColorMask 0 GLSLPROGRAM // URP 的 ShadowCasterPass.hlsl(GLSL 写法) VARYING vec2 uv; #ifdef VERTEX void main() // ShadowPassVertex { uv = TransformTex(texcoord0.xy, _BaseMap_ST); gl_Position = GetShadowPositionHClip(positionOS.xyz, normalOS); } #endif #ifdef FRAGMENT void main() // ShadowPassFragment { Alpha(SampleAlbedoAlpha(uv).a, _BaseColor, _Cutoff); fragColor = vec4(0.0); } #endif ENDGLSL } Pass { Name "DepthOnly" Tags { "LightMode"="DepthOnly" } ZWrite On ColorMask R GLSLPROGRAM // URP 的 DepthOnlyPass.hlsl(GLSL 写法) VARYING vec2 uv; #ifdef VERTEX void main() // DepthOnlyVertex { uv = TransformTex(texcoord0.xy, _BaseMap_ST); gl_Position = TransformObjectToHClip(positionOS.xyz); } #endif #ifdef FRAGMENT void main() // DepthOnlyFragment { Alpha(SampleAlbedoAlpha(uv).a, _BaseColor, _Cutoff); fragColor = vec4(gl_FragCoord.z); } #endif ENDGLSL } } }