Unity - Normal mapping - Reoriented normal mapping - 重定向法线、混合法线


目的

备份、拾遗


核心代码

half3 blended_normal = normalize(half3(n1.xy + n2.xy, n1.z*n2.z));

PBR - Filament - Normal mapping

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


Shader

// jave.lin : 测试 法线重定向 (混合)

Shader "Test/TestingNormalmapBlending"
{
    
    
    Properties
    {
    
    
        _MainTex ("Texture", 2D) = "white" {
    
    }
        _BumpMap ("Normal Map", 2D) = "bump" {
    
    }
        _BumpDetailMap ("Normal Detail Map", 2D) = "bump" {
    
    }
        _BumpBlending ("Bump Blending", Range(0.0, 1.0)) = 1.0
    }
    SubShader
    {
    
    
        Tags {
    
     "RenderType"="Opaque" }
        LOD 100

        Pass
        {
    
    
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
    
    
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                half3 normal :  NORMAL;
                half4 tangent : TANGENT; // xyz : dir, w : sign
            };

            struct v2f
            {
    
    
                float4 vertex : SV_POSITION;
                float2 uv : TEXCOORD0;
                half3 tangentWS :   TEXCOORD1;  // xyz : dir, w : view dir.y
                half3 normalWS :    TEXCOORD2;  // xyz : dir, w : view dir.x
                half3 binormalWS :  TEXCOORD3;  // xyz : dir, w : view dir.z
                float3 posWS : TEXCOORD4;       // xyz : world position
            };

            sampler2D _MainTex;
            sampler2D _BumpMap;
            sampler2D _BumpDetailMap;
            float4 _MainTex_ST;
            fixed _BumpBlending;
            fixed4 _LightColor0;

            half3 CustomUnpackScaleNormal(half4 packednormal, half bumpScale)
            {
    
    
                #if defined(UNITY_NO_DXT5nm)
                    half3 normal = packednormal.xyz * 2 - 1;
                    #if (SHADER_TARGET >= 30)
                        // SM2.0: instruction count limitation
                        // SM2.0: normal scaler is not supported
                        normal.xy *= bumpScale;
                    #endif
                    return normal;
                #elif defined(UNITY_ASTC_NORMALMAP_ENCODING)
                    half3 normal;
                    normal.xy = (packednormal.wy * 2 - 1);
                    normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy)));
                    normal.xy *= bumpScale;
                    return normal;
                #else
                    // This do the trick
                    packednormal.x *= packednormal.w;

                    half3 normal;
                    normal.xy = (packednormal.xy * 2 - 1);
                    #if (SHADER_TARGET >= 30)
                        // SM2.0: instruction count limitation
                        // SM2.0: normal scaler is not supported
                        normal.xy *= bumpScale;
                    #endif
                    normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy)));
                    return normal;
                #endif
            } // end custom unpack scale normal

            v2f vert (appdata v)
            {
    
    
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);

                float4 posWS = mul(unity_ObjectToWorld, v.vertex);

                half3 normalWS = UnityObjectToWorldNormal(v.normal);

                half4 tangentWS = half4(UnityObjectToWorldDir(v.tangent.xyz), v.tangent.w);
                half sign = tangentWS.w * unity_WorldTransformParams.w;
                half3 binormalWS = cross(normalWS, tangentWS) * sign;

                o.tangentWS     = tangentWS.xyz;
                o.normalWS      = normalWS.xyz;
                o.binormalWS    = binormalWS.xyz;

                o.posWS.xyz = posWS.xyz;

                return o;
            }

            half3 BlendNormal_Hill12(half3 N1, half3 N2)
            {
    
    
                return normalize(N1 * dot(N1, N2) - N2 * N1.z);
            }

            half3 BlendNormal_UDN(half3 N1, half3 N2)
            {
    
    
                return normalize(half3(N1.xy + N2.xy, N1.z));
            }

            half3 BlendNormals_Unity_Native(half3 n1, half3 n2)
            {
    
    
                return normalize(half3(n1.xy + n2.xy, n1.z*n2.z));
            }

            fixed4 frag (v2f i, fixed isFrontFace : VFACE) : SV_Target
            {
    
    
                half3 N = normalize(i.normalWS);
                N = isFrontFace >= 0 ? N : -N;

                half3 V = normalize(_WorldSpaceCameraPos - i.posWS.xyz);
                half3 T = normalize(i.tangentWS);
                half3 B = normalize(i.binormalWS);

                half3x3 TBN = half3x3(T, B, N);

                half3 N1_ts = CustomUnpackScaleNormal(tex2D(_BumpMap, i.uv.xy), 1.0);
                half3 N1 = mul(N1_ts, TBN);
                // return half4(N1.xyz, 1.0);

                half3 N2_ts = CustomUnpackScaleNormal(tex2D(_BumpDetailMap, i.uv.xy), 1.0);
                half3 N2 = mul(N2_ts, TBN);
                // return half4(N2.xyz, 1.0);

                // N = BlendNormal_Hill12(N1, N2);
                // N = BlendNormal_UDN(N1, N2);
                N = BlendNormals_Unity_Native(N1, N2); // jave.lin : 目前看着是: unity native 的效果是最好的
                N = lerp(N1, N, _BumpBlending);
                // return half4(N.xyz, 1.0);

                half3 L = _WorldSpaceLightPos0.xyz;

                half3 H = normalize(L + V);

                half NdotL = saturate(dot(N, L));
                half NdotH = saturate(dot(N, H));

                half diffuse = (NdotL);
                // return diffuse;
                half specular = pow((NdotH), 32) * 4.0;
                // return specular;

                fixed4 baseCol = tex2D(_MainTex, i.uv.xy);
                // half kd = 1 - specular;
                // diffuse *= kd;

                // return diffuse + specular;
                half3 finalCol = (diffuse + specular) * baseCol.rgb * _LightColor0.rgb + UNITY_LIGHTMODEL_AMBIENT.rgb * baseCol.rgb;

                return half4(finalCol.xyz, 1.0);
            }
            ENDCG
        }
    }
}


效果

                half3 N1_ts = CustomUnpackScaleNormal(tex2D(_BumpMap, i.uv.xy), 1.0);
                half3 N1 = mul(N1_ts, TBN);
                // return half4(N1.xyz, 1.0);

                half3 N2_ts = CustomUnpackScaleNormal(tex2D(_BumpDetailMap, i.uv.xy), 1.0);
                half3 N2 = mul(N2_ts, TBN);
                // return half4(N2.xyz, 1.0);

                N = BlendNormal_Hill12(N1, N2);
                // N = BlendNormal_UDN(N1, N2);
                // N = BlendNormals_Unity_Native(N1, N2); // jave.lin : 目前看着是: unity native 的效果是最好的
                N = lerp(N1, N, _BumpBlending);
                return half4(N.xyz, 1.0);

BlendNormal_Hill12

            half3 BlendNormal_Hill12(half3 N1, half3 N2)
            {
    
    
                return normalize(N1 * dot(N1, N2) - N2 * N1.z);
            }

在这里插入图片描述


BlendNormal_UDN

            half3 BlendNormal_UDN(half3 N1, half3 N2)
            {
    
    
                return normalize(half3(N1.xy + N2.xy, N1.z));
            }

在这里插入图片描述


BlendNormals_Unity_Native - 效果目前最好

            half3 BlendNormals_Unity_Native(half3 n1, half3 n2)
            {
    
    
                return normalize(half3(n1.xy + n2.xy, n1.z*n2.z));
            }

在这里插入图片描述


unity standard 里面的 lerp(n1, n2, t)

另外除了上面的方式,其实也可以 lerp 直接过度
unity BRP 中的 standard 相关的 pbr shader 中也有使用到此类方式
在这里插入图片描述


Project

Testing_NormalMap_Blending_2023.3.37f1_BRP.rar
提取码:ozgt


References

猜你喜欢

转载自blog.csdn.net/linjf520/article/details/133788040