源码 / shaders/Ch15/NPRCommon.glsl
shaders/Ch15/NPRCommon.glsl
// 第 15 章各个风格化 Shader 共用的顶点结构、主光获取,以及 ShadowCaster / DepthOnly 的通用实现。(GLSL 版,对应 Ch15/NPRCommon.hlsl) // 用法:Shader 先声明自己的 uniform(对应 CBUFFER(UnityPerMaterial)),再 #include 本文件。 // GLSL 版额外约定:着色 Pass 先 #define NPR_VARYINGS 再 include,得到 NprVaryings 对应的 varying 变量和 NprVert(); // 投影/深度 Pass 先 #define NPR_SHADOW_PASS 或 NPR_DEPTH_PASS,直接得到整个 Pass 的 main()。 #ifndef COOKBOOK_CH15_NPR_COMMON_INCLUDED #define COOKBOOK_CH15_NPR_COMMON_INCLUDED #ifdef NPR_VARYINGS // NprVaryings(WebGL 不允许结构体做 varying,拆成单独的变量) VARYING vec2 uv; VARYING vec3 positionWS; VARYING vec3 normalWS; VARYING vec4 vertexColor; // 顶点输入已占用 color 这个名字 VARYING float fogFactor; #ifdef VERTEX void NprVert() { VertexPositionInputs pos = GetVertexPositionInputs(positionOS.xyz); gl_Position = pos.positionCS; positionWS = pos.positionWS; normalWS = TransformObjectToWorldNormal(normalOS); uv = texcoord0.xy; vertexColor = color; fogFactor = ComputeFogFactor(pos.positionCS.z); } #endif #endif // 风格化着色只需要“原料”:未截断的 N·L(-1..1)、阴影衰减、光的颜色和方向。 // 怎么把它们变成颜色,交给各个 Shader 自己决定。 struct NprLight { vec3 direction; vec3 color; float ndotl; // 未 saturate,Gooch/Hatching 需要背光面的信息 float shadow; // 0 = 完全在阴影里,1 = 受光 }; NprLight GetNprLight(vec3 posWS, vec3 nrmWS) { vec4 shadowCoord = TransformWorldToShadowCoord(posWS); // 逐像素算,级联阴影也正确 Light l = GetMainLight(shadowCoord); NprLight o; o.direction = l.direction; o.color = l.color; o.ndotl = dot(nrmWS, l.direction); o.shadow = l.shadowAttenuation; return o; } // ---------------- ShadowCaster / DepthOnly ---------------- // _LightDirection / _LightPosition 由引擎在渲染阴影时设置(Lighting.glsl 里已声明) #ifdef VERTEX vec4 NprShadowVert() { vec3 posWS = TransformObjectToWorld(positionOS.xyz); vec3 nrmWS = TransformObjectToWorldNormal(normalOS); // _CASTING_PUNCTUAL_LIGHT_SHADOW 关键字在 GLSL 版里是个 uniform vec3 lightDir = _CastingPunctualLightShadow > 0.5 ? normalize(_LightPosition - posWS) : _LightDirection; vec4 positionCS = TransformWorldToHClip(ApplyShadowBias(posWS, nrmWS, lightDir)); // WebGL 深度不反转(UNITY_REVERSED_Z = 0):把近平面之前的投影物压到近平面上 positionCS.z = max(positionCS.z, UNITY_NEAR_CLIP_VALUE * positionCS.w); return positionCS; } vec4 NprDepthVert() { return TransformObjectToHClip(positionOS.xyz); } #endif #ifdef FRAGMENT vec4 NprNullFrag() { return vec4(0.0); } #endif #ifdef NPR_SHADOW_PASS #ifdef VERTEX void main() { gl_Position = NprShadowVert(); } #endif #ifdef FRAGMENT void main() { fragColor = NprNullFrag(); } #endif #endif #ifdef NPR_DEPTH_PASS #ifdef VERTEX void main() { gl_Position = NprDepthVert(); } #endif #ifdef FRAGMENT void main() { fragColor = vec4(gl_FragCoord.z); } // 与 URP DepthOnlyPass 一致:深度写进 R 通道 #endif #endif #endif