如何将简单的高度贴图实现到 Unity Shader

How to implement a simple height map to an Unity Shader

首先让我说我对着色器编程知之甚少。我这里的很多东西都是从在线资源和现有资产中缝合在一起的。我只需要知道如何将高度图正确地集成到统一着色器中。它不必比标准 Unity 着色器复杂。我不能使用标准着色器,因为我需要一个将多个纹理平铺在一起的着色器,这可能就是我尚未找到解决此问题的方法的原因。

我混合并移动了代码,删除了一些变量,重命名了一些变量,并在网上查找有类似问题的人。

Shader "Unlit/TRUE_EARTH"
{
    Properties
    {
        _TexA1 ("Tex A1", 2D) = "white" {}
        _TexA2 ("Tex A2", 2D) = "white" {}
        _TexB1 ("Tex B1", 2D) = "white" {}
        _TexB2 ("Tex B2", 2D) = "white" {}
        _TexC1 ("Tex C1", 2D) = "white" {}
        _TexC2 ("Tex C2", 2D) = "white" {}
        _TexD1 ("Tex D1", 2D) = "white" {}
        _TexD2 ("Tex D2", 2D) = "white" {}
    _BumpScale("Scale", Float) = 1.0
    [Normal] _BumpMap("Normal Map", 2D) = "bump" {}

    _Height("Height Scale", Range(0.005, 0.08)) = 0.02
    _HeightMap("Height Map", 2D) = "black" {}

    _OcclusionStrength("Strength", Range(0.0, 1.0)) = 1.0
    _OcclusionMap("Occlusion", 2D) = "white" {}
}
SubShader
{
    Tags { "RenderType"="Opaque" }
    Lighting Off
    ZWrite Off

    Pass
    {
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        // make fog work
        #pragma multi_compile_fog

        #include "UnityCG.cginc"

        sampler2D _TexA1;
        sampler2D _TexA2;   
        sampler2D _TexB1;
        sampler2D _TexB2;
        sampler2D _TexC1;
        sampler2D _TexC2;   
        sampler2D _TexD1;
        sampler2D _TexD2;
        sampler2D _NormalMap;
        sampler2D _HeightMap;
        half _BumpAmount;
        half _Height;

        struct v2f
        {
           float4 pos     : SV_POSITION;
           float2 uv      : TEXCOORD0;
           half3 normal: TEXCOORD1;
           #if WPM_BUMPMAP_ENABLED
           half3 tspace0 : TEXCOORD2; // tangent.x, bitangent.x, normal.x
           half3 tspace1 : TEXCOORD3; // tangent.y, bitangent.y, normal.y
           half3 tspace2 : TEXCOORD4; // tangent.z, bitangent.z, normal.z
           #endif
        };


        v2f vert (float4 vertex : POSITION, half3 normal : NORMAL, half4 tangent : TANGENT, float2 uv : TEXCOORD5, appdata_full v) {
            v2f o;
            float4 heightMap = tex2Dlod(_HeightMap, float4(v.texcoord.xy, 0, 0));
            vertex.z += heightMap.b * _Height;
            o.pos               = UnityObjectToClipPos (vertex);
            o.uv                = uv;
            half3 wNormal       = UnityObjectToWorldNormal(normal);
            o.normal            = wNormal;


            #if WPM_BUMPMAP_ENABLED
            half3 wTangent = UnityObjectToWorldDir(tangent.xyz);
            half tangentSign = tangent.w * unity_WorldTransformParams.w;
            half3 wBitangent = cross(wNormal, wTangent) * tangentSign;
            //output the tangent space matrix
            o.tspace0 = half3(wTangent.x, wBitangent.x, wNormal.x);
            o.tspace1 = half3(wTangent.y, wBitangent.y, wNormal.y);
            o.tspace2 = half3(wTangent.z, wBitangent.z, wNormal.z);
            #endif

            return o;
        }

        half4 frag (v2f i) : SV_Target
        {
            // compute Earth pixel color
                half4 color;

                // compute Earth pixel color
                if (i.uv.x<0.25) 
                {
                    if (i.uv.y>0.4999) 
                    {
                        color = tex2Dlod(_TexA1, float4(i.uv.x * 4.0, (i.uv.y - 0.5) * 2.0, 0, 0));
                    } 
                    else 
                    {
                        color = tex2Dlod(_TexA2, float4(i.uv.x * 4.0, i.uv.y * 2.0, 0, 0));
                    }
                } 
                else if (i.uv.x < 0.5) 
                {
                    if (i.uv.y>0.4999) 
                    {
                        color = tex2Dlod(_TexB1, float4((i.uv.x - 0.25) * 4.0f, (i.uv.y - 0.5) * 2.0, 0, 0));
                    } 
                    else 
                    {
                        color = tex2Dlod(_TexB2, float4((i.uv.x - 0.25) * 4.0f, i.uv.y * 2.0, 0, 0));
                    }
                }
                else if (i.uv.x < 0.75) 
                {
                    if (i.uv.y>0.4999) 
                    {
                        color = tex2Dlod(_TexC1, float4((i.uv.x - 0.50) * 4.0f, (i.uv.y - 0.5) * 2.0, 0, 0));
                    } 
                    else 
                    {
                        color = tex2Dlod(_TexC2, float4((i.uv.x - 0.50) * 4.0f, i.uv.y * 2.0, 0, 0));
                    }
                }
                else if (i.uv.x < 1.01) 
                {
                    if (i.uv.y>0.4999) 
                    {
                        color = tex2Dlod(_TexD1, float4((i.uv.x - 0.75) * 4.0f, (i.uv.y - 0.5) * 2.0, 0, 0));
                    } 
                    else 
                    {
                        color = tex2Dlod(_TexD2, float4((i.uv.x - 0.75) * 4.0f, i.uv.y * 2.0, 0, 0));
                    }
                }

                // sphere normal (without bump-map)
                half3 snormal = normalize(i.normal);

                // transform normal from tangent to world space
                #if WPM_BUMPMAP_ENABLED
                half3 tnormal = UnpackNormal(tex2D(_NormalMap, i.uv)); 
                half3 worldNormal;
                worldNormal.x = dot(i.tspace0, tnormal);
                worldNormal.y = dot(i.tspace1, tnormal);
                worldNormal.z = dot(i.tspace2, tnormal);
                half3 normal = normalize(lerp(snormal, worldNormal, _BumpAmount));
                #else
                half3 normal = snormal;
                #endif

                return color;
        }
        ENDCG
    }
}
}

贴图效果不错,但没有高度贴图的假象。都是平的。

有 3 个部分需要更改。

  1. 确保您的属性与您的变量匹配:

    _Height("Height Scale", Range(0.005, 0.08)) = 0.02
    _HeightMap("Height Map", 2D) = "black" {}
    
    ....
    
    sampler2D _HeightMap;
    half _Height;
    
  2. 在存储到 o

  3. 之前对顶点进行修改
  4. 修改顶点的y分量而不是z:

    float4 heightMap = tex2Dlod(_HeightMap, float4(v.texcoord.xy, 0, 0));
    vertex.y += heightMap.b * _Height;
    o.pos               = UnityObjectToClipPos (vertex);