[UnityShader] bump mapping

Another common application of texture is bump mapping. The purpose is to use a texture to modify the normal of the model surface. Make the model look 'bumpy'.

There are two main methods: one is height texture and the other is normal texture. Here we mainly introduce normal texture.

Since the component range in the normal direction is [- 1,1], but the pixel range is [0,1], a mapping should be made: normal = pixel*2-1

In actual production, we generally use the tangent space of the model vertex. The normal is generally z-axis, the tangent is x-axis, and the sub tangent composed of the cross product of normal and tangent is y-axis.

The following describes how to calculate the texture in tangent space: in the slice shader, the normal of tangent space is obtained through texture sampling, which is to calculate the viewing angle direction and illumination direction in tangent space to obtain the final illumination result.

Therefore, we need a change matrix to convert the parameters of model space into tangent space.

The transformation matrix of tangent space is easy to obtain. You only need to arrange the coordinate axes of tangent space in columns. The mathematical principle is omitted here. If you are interested, you can deduce it yourself.

Shader "Custom/Chapter7-NormalMapTangentSpace"
{
    Properties{
        _Color ("Color Tint", Color) = (1, 1, 1, 1)
        _MainTex ("Main Tex", 2D) = "white" {}
        _BumpMap ("Normal Map", 2D) = "bump" {}
        _BumpScale ("Bump Scale", Float) = 1.0
        _Specular ("Specular", Color) = (1, 1, 1, 1)
        _Gloss ("Gloss", Range(8.0, 256)) = 20
    }
    SubShader{
        pass{
            Tags{"LightMode" = "ForwardBase"}
        
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag

        #include "Lighting.cginc"

        fixed4 _Color;
        sampler2D _MainTex;
        sampler2D _BumpMap;
        float4 _BumpMap_ST;
        float _BumpScale;
        fixed4 _Specular;
        float _Gloss;
        float4 _MainTex_ST;//Texture type attribute

        struct a2v{
            float4 vertex:POSITION;
            float3 normal:NORMAL;
            float4 tangent:TANGENT; //Vertex tangent direction filling, four-dimensional reason is to use w Determines the directionality of the subtangents
            float4 texcoord:TEXCOORD0;//Store texture coordinates  
        };

        struct v2f{
            float4 pos:SV_POSITION;
            float4 uv:TEXCOORD0;//Texture sampling uses two textures float4
            float3 lightDir:TEXCOORD1;
            float3 viewDir:TEXCOORD2;
        };

        v2f vert(a2v v){
            v2f o;
            o.pos = UnityObjectToClipPos(v.vertex);

            o.uv.xy = v.texcoord.xy*_MainTex_ST.xy+_MainTex_ST.zw;
            o.uv.zw = v.texcoord.xy*_BumpMap_ST.xy+_BumpMap_ST.zw;  //Two textures, storing texture coordinates respectively
            
            float3 binormal = cross(normalize(v.normal),normalize(v.tangent.xyz))*v.tangent.w;//Calculate binormal
            float3x3 rotation = float3x3(v.tangent.xyz,binormal,v.normal);

            o.lightDir = mul(rotation,ObjSpaceLightDir(v.vertex)).xyz;
            o.viewDir =  mul(rotation,ObjSpaceViewDir(v.vertex)).xyz;

            return o;
        }

        fixed4 frag(v2f i):SV_Target{
           fixed3 tangentLightDir = normalize(i.lightDir);
           fixed3 tangentViewDir = normalize(i.viewDir);
           //First, sample the normal texture
           fixed4 packedNormal = tex2D(_BumpMap,i.uv.zw);
           //Reflect the pixel to get the original discovery direction,Because the tangent space is guaranteed first z Positive
           fixed3 tangentNormal;
           //Texture type is not Normal map Time  Unity Generally Normal map Therefore, if calculated in the following way, the result will be business trip
           //tangentNormal.xy = (packedNormal.xy*2-1)*_BumpScale;
           //tangentNormal.z = sqrt(1.0-saturate(dot(tangentNormal.xy,tangentNormal.xy)));//Because it's a unit vector, you can xy calculation z
         
           tangentNormal = UnpackNormal(packedNormal);  
           tangentNormal.xy *=_BumpScale;
           tangentNormal.z = sqrt(1.0-saturate(dot(tangentNormal.xy,tangentNormal.xy)));
           
           fixed3 albedo = tex2D(_MainTex,i.uv).rgb*_Color.rgb;
           fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz*albedo;
           fixed3 diffuse = _LightColor0.rgb*albedo*max(0,dot(tangentNormal,tangentLightDir));

           fixed3 halfDir = normalize(tangentLightDir+tangentViewDir);

           fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(max(0,dot(tangentNormal,halfDir)),_Gloss);

           return fixed4(ambient+diffuse+specular,1.0);
        }
         ENDCG
      }
    }
    FallBack "Diffuse"
}

Because the normals and tangents of the model can be obtained, all sub normals can be obtained easily, and then the transformation matrix can be obtained easily.

It should be noted that_ BumpMap is the normal texture and bump is the default value_ BumpScale controls the degree of bump.

Since there are two textures, the uv declaration is stored as float4.xy_ MainTex texture coordinates, zw storage_ BumpMap texture coordinates.

The reason why the tangent of tangent is float4 is that the w component determines the direction of the binormal.

Two textures generally use the same texture coordinate textcoord.

Note that if the normal texture type is Normal map, you need to use UnpackNormal provided by Unity to map, because Unity will compress the texture according to different platforms, and then sample through this function.

Here is_ When BumpScale is - 0.8 and 0.8:

 

Tags: Shader

Posted on Thu, 02 Dec 2021 17:51:12 -0500 by cs1h