源码 / Ch15/Gooch.shader
Ch15/Gooch.shader
// Gooch 冷暖着色:用“冷→暖”的色相变化代替“暗→亮”的明度变化来表达朝向, // 暗部不再是死黑,形体在技术插图里依旧清楚。附带白色高光与背面外扩描边。 Shader "Cookbook/Ch15/Gooch" { Properties { _BaseColor ("Base Color (k_d)", Color) = (0.8, 0.25, 0.2, 1) _CoolColor ("Cool Color (b)", Color) = (0.0, 0.05, 0.45, 1) _WarmColor ("Warm Color (y)", Color) = (0.45, 0.4, 0.0, 1) _Alpha ("Alpha (cool mix)", Range(0, 1)) = 0.25 _Beta ("Beta (warm mix)", Range(0, 1)) = 0.55 _SpecPower ("Specular Power", Range(4, 256)) = 48 _SpecStrength ("Specular Strength", Range(0, 1)) = 0.8 _ShadowCool ("Shadow pushes to cool", Range(0, 1)) = 0.6 _OutlineWidth ("Outline Width", Range(0, 0.05)) = 0.012 _OutlineColor ("Outline Color", Color) = (0.05, 0.05, 0.08, 1) } SubShader { Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" "Queue"="Geometry" } HLSLINCLUDE #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" CBUFFER_START(UnityPerMaterial) half4 _BaseColor, _CoolColor, _WarmColor, _OutlineColor; half _Alpha, _Beta, _SpecPower, _SpecStrength, _ShadowCool; float _OutlineWidth; CBUFFER_END ENDHLSL Pass { Name "ForwardLit" Tags { "LightMode"="UniversalForwardOnly" } HLSLPROGRAM #pragma vertex NprVert #pragma fragment frag #pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN #pragma multi_compile_fragment _ _SHADOWS_SOFT _SHADOWS_SOFT_LOW _SHADOWS_SOFT_MEDIUM _SHADOWS_SOFT_HIGH #pragma multi_compile_fog #include "Assets/Cookbook/Ch15/NPRCommon.hlsl" half4 frag(NprVaryings i) : SV_Target { float3 N = normalize(i.normalWS); float3 V = GetWorldSpaceNormalizeViewDir(i.positionWS); NprLight L = GetNprLight(i.positionWS, N); // 1) 冷暖两端:纯冷/暖色 + 一部分物体本色 half3 kCool = _CoolColor.rgb + _Alpha * _BaseColor.rgb; half3 kWarm = _WarmColor.rgb + _Beta * _BaseColor.rgb; // 2) 用 (1 + N·L) / 2 在两端之间插值:背光面不是“没有光”,而是“偏冷” half t = (1.0h + L.ndotl) * 0.5h; // 落在投影里的部分往冷端推一些(原始 Gooch 模型没有阴影,这是工程上的补充) t *= lerp(1.0h - _ShadowCool, 1.0h, L.shadow); half3 col = lerp(kCool, kWarm, t); // 3) 白色高光:Blinn-Phong,只在受光面出现 float3 H = normalize(L.direction + V); half spec = pow(saturate(dot(N, H)), _SpecPower) * _SpecStrength * L.shadow * step(0, L.ndotl); col += spec; col = MixFog(col, i.fogFactor); return half4(col, 1); } ENDHLSL } // 背面外扩描边(第 14 章讲过的方法,这里只作为技术插图的黑色轮廓线) Pass { Name "Outline" Tags { "LightMode"="SRPDefaultUnlit" } Cull Front HLSLPROGRAM #pragma vertex vert #pragma fragment frag struct A { float4 positionOS : POSITION; float3 normalOS : NORMAL; }; float4 vert(A v) : SV_POSITION { float4 positionCS = TransformObjectToHClip(v.positionOS.xyz); float3 normalCS = mul((float3x3)UNITY_MATRIX_VP, TransformObjectToWorldNormal(v.normalOS)); // 在裁剪空间沿法线外扩,乘 w 抵消透视除法,使线宽与距离无关 float2 offset = normalize(normalCS.xy) * _OutlineWidth * positionCS.w; offset.x *= _ScreenParams.y / _ScreenParams.x; // 纠正宽高比 positionCS.xy += offset; return positionCS; } half4 frag() : SV_Target { return _OutlineColor; } ENDHLSL } Pass { Name "ShadowCaster" Tags { "LightMode"="ShadowCaster" } ZWrite On ZTest LEqual ColorMask 0 HLSLPROGRAM #pragma vertex NprShadowVert #pragma fragment NprNullFrag #pragma multi_compile_vertex _ _CASTING_PUNCTUAL_LIGHT_SHADOW #include "Assets/Cookbook/Ch15/NPRCommon.hlsl" ENDHLSL } Pass { Name "DepthOnly" Tags { "LightMode"="DepthOnly" } ZWrite On ColorMask R HLSLPROGRAM #pragma vertex NprDepthVert #pragma fragment NprNullFrag #include "Assets/Cookbook/Ch15/NPRCommon.hlsl" ENDHLSL } } }