源码 / Ch08/AmbientSH.shader
Ch08/AmbientSH.shader
// 只显示球谐环境光(间接漫反射),可以选择只用 L0、L0+L1、或完整的 L0+L1+L2。 Shader "Cookbook/Ch08/AmbientSH" { Properties { [MainColor] _BaseColor("Albedo", Color) = (0.8, 0.8, 0.8, 1) [Enum(L0,0,L0L1,1,L0L1L2,2)] _Bands("Bands", Float) = 2 } SubShader { Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" "Queue"="Geometry" } HLSLINCLUDE #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" CBUFFER_START(UnityPerMaterial) half4 _BaseColor; half _Bands; CBUFFER_END ENDHLSL Pass { Name "ForwardLit" Tags { "LightMode"="UniversalForwardOnly" } HLSLPROGRAM #pragma vertex vert #pragma fragment frag #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" struct Attributes { float4 positionOS : POSITION; float3 normalOS : NORMAL; }; struct Varyings { float4 positionCS : SV_POSITION; float3 normalWS : TEXCOORD0; }; Varyings vert(Attributes input) { Varyings o; o.positionCS = TransformObjectToHClip(input.positionOS.xyz); o.normalWS = TransformObjectToWorldNormal(input.normalOS); return o; } // unity_SHAr/Ag/Ab:xyz = L1 三个系数,w = L0 系数“减去”L2 里 Y20 的常数部分; // unity_SHBr/Bg/Bb:L2 中 xy、yz、zz、zx 四项;unity_SHC:L2 中 x²-y² 一项(rgb 三通道)。 // 这些系数已经乘上了“余弦卷积”因子并除以 π,所以直接算出来的就是 URP 约定下的间接漫反射。 half3 EvaluateSHBands(half3 N, int bands) { // L2 在整个球面上积分为 0,但 zz 项的平均值是 1/3。Unity 把 Y20 的常数部分挪进了 w, // 想要“纯 L0”,就把 zz 项的平均值 SHB.z/3 加回去。 half3 L0 = half3(unity_SHAr.w + unity_SHBr.z / 3.0, unity_SHAg.w + unity_SHBg.z / 3.0, unity_SHAb.w + unity_SHBb.z / 3.0); if (bands == 0) return L0; half3 L1 = half3(dot(unity_SHAr.xyz, N), dot(unity_SHAg.xyz, N), dot(unity_SHAb.xyz, N)); if (bands == 1) return max(0, L0 + L1); // 完整三阶:与 URP 的 SampleSH(N) 完全相同(SHEvalLinearL0L1 + SHEvalLinearL2) return SampleSH(N); } half4 frag(Varyings i) : SV_Target { half3 N = normalize(i.normalWS); half3 irradiance = EvaluateSHBands(N, (int)round(_Bands)); return half4(irradiance * _BaseColor.rgb, 1); } ENDHLSL } Pass { Name "DepthOnly" Tags { "LightMode"="DepthOnly" } ZWrite On ColorMask R HLSLPROGRAM #pragma vertex v #pragma fragment f float4 v(float4 p : POSITION) : SV_POSITION { return TransformObjectToHClip(p.xyz); } half4 f() : SV_Target { return 0; } ENDHLSL } } }