自定义双面混合Shader显示异常:纹理暗淡、法线反射弱
解决你的纹理混合Shader问题
嘿,作为Shader新手能写出这样的代码已经很棒啦!咱们来看看你遇到的几个问题,一步步修复它们:
问题根源分析
你的Shader出现纹理暗淡、法线反射失效、金属度异常的核心原因是法线处理错误,还有一些小细节需要调整:
- 你直接将法线纹理的颜色值(还乘以了
_Color)赋值给o.Normal,但法线纹理的RGB是压缩的切线空间方向信息,必须用UnpackNormal函数转换才能被光照系统正确识别 - 法线方向不能被颜色 tint,这会破坏法线的方向向量,导致光照计算完全出错
- 冗余的UV声明可能会导致不必要的性能开销(如果不需要独立的UV缩放/偏移的话)
修正后的Shader代码
Shader "Custom/TextureBlend" { Properties { _Color ("Color", Color) = (1,1,1,1) _Blend ("Texture Blend", Range(0,1)) = 0.0 _MainTex ("Albedo (RGB)", 2D) = "white" {} _MainTex2 ("Albedo 2 (RGB)", 2D) = "white" {} _Glossiness ("Smoothness", Range(0,1)) = 0.5 _Metallic ("Metallic", Range(0,1)) = 0.0 _BumpMap ("Bumpmap", 2D) = "bump" {} _BumpMap2 ("Bumpmap 2", 2D) = "bump" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 200 Cull Off // 实现双面显示 ZTest LEqual CGPROGRAM #pragma surface surf Standard fullforwardshadows #pragma target 3.0 sampler2D _MainTex; sampler2D _MainTex2; sampler2D _BumpMap; sampler2D _BumpMap2; struct Input { float2 uv_MainTex; // 复用该UV给所有纹理,若需独立UV可自行添加 }; half _Blend; half _Glossiness; half _Metallic; fixed4 _Color; void surf (Input IN, inout SurfaceOutputStandard o) { // 混合两张Albedo纹理并叠加颜色 fixed4 c = lerp(tex2D(_MainTex, IN.uv_MainTex), tex2D(_MainTex2, IN.uv_MainTex), _Blend) * _Color; o.Albedo = c.rgb; o.Alpha = c.a; // 正确处理法线:先解包再混合 fixed3 normal1 = UnpackNormal(tex2D(_BumpMap, IN.uv_MainTex)); fixed3 normal2 = UnpackNormal(tex2D(_BumpMap2, IN.uv_MainTex)); o.Normal = lerp(normal1, normal2, _Blend); // 金属度与光滑度设置 o.Metallic = _Metallic; o.Smoothness = _Glossiness; } ENDCG } FallBack "Diffuse" }
关键修改点说明
法线处理修复:
- 使用
UnpackNormal函数分别解包两张法线纹理,得到正确的切线空间法线向量 - 对解包后的法线向量进行lerp混合,而非混合纹理颜色后再处理
- 移除了法线乘以
_Color的错误操作——法线是方向信息,不能被颜色染色
- 使用
UV优化:
- 移除冗余的
uv_MainTex2和uv_BumpMap2,复用uv_MainTex给所有纹理(若需给第二张纹理单独设置UV缩放/偏移,可重新添加这些UV,并在Properties中补充对应的_MainTex2_ST等属性)
- 移除冗余的
属性命名修正:
- 将
_BumpMap2的属性名改为Bumpmap 2,避免与第一个法线图名称重复,在Inspector面板中更清晰
- 将
原问题效果参考
修复前自定义Shader与Standard Shader对比

修复前金属度滑块右调后的异常效果

修复后,你的Shader应该能和Standard Shader表现一致:法线反射正常、金属度调整无异常,同时保留双面显示的功能~
内容的提问来源于stack exchange,提问作者Rumata




