Gradient of Two Textures Based on Height

Hi all,

I am current writing a shader to blend two textures based on world height and a blend height, I am pretty close but i’m having trouble doing a gradient where the two textures meet and blending from one texture to another. I assume i have to use a lerp between the two textures but I am unsure of how to continue.

Anyone have any pointers or have any better suggestions of how to accomplish this? I’m farily new to shaders and am trying to pick up a few tricks and tips, any advice would be greatly appreciated.

I have pasted the full shader code below as well as a screen capture of the current output, as you can see Im having problems in seamlessly blending between the two textures.

Shader "Custom/HeightTerrain"
{
    Properties
    {
        _Color("Color",Color) = (1.0,1.0,1.0,1.0)
        _GroundHeight("GroundHeight", Float) = 0
        _DirtBlendHeight("DirtBlendHeight", Float) = 2
        _DirtTex("DirtTex", 2D) = "white"{}
        _BaseTex("BaseTex", 2D) = "white"{}

        _Blend("Blend", Range(0,1)) = 0.5
    }
    SubShader
    {
        Tags{ "Queue" = "Transparent+1" }
        LOD 200
        CGPROGRAM
#pragma surface surf Lambert alpha


    float _GroundHeight;
    float _DirtBlendHeight;
    float4 _Color;
    sampler2D _DirtTex;
    sampler2D _BaseTex;
    float _Blend;
    struct Input
    {
        float3 customColor;
        float3 worldPos;
        float2 uv_DirtTex;
        float2 uv_BaseTex;
    };

    void surf(Input IN, inout SurfaceOutput o)
    {
        half4 c = tex2D(_DirtTex, IN.uv_DirtTex);
        half4 b = tex2D(_BaseTex, IN.uv_BaseTex);
        o.Albedo = c.rgb;
        o.Alpha = 0;

        if (IN.worldPos.y > _GroundHeight &&  IN.worldPos.y < _DirtBlendHeight)
        {
            //Gradient between the two textures
            half4 c = tex2D(_BaseTex, IN.uv_BaseTex);
            half4 g = tex2D(_DirtTex, IN.uv_DirtTex);
            c.rgb *= lerp(0, 1, (IN.worldPos.y) + _Blend);
            g.rgb *= lerp(0, 1, (IN.worldPos.y) + _Blend);
            o.Albedo = c.rgb + g.rgb;
            o.Alpha = c.a + g.a;
       
            //1 texture alpha gradient example
            //o.Albedo = b.rgb;
            //o.Alpha = 1 - (((_DirtBlendHeight - _GroundHeight) - IN.worldPos.y) / _DirtBlendHeight);
        }
        else if (IN.worldPos.y > _GroundHeight)
        {
            o.Alpha = c.a;
        }
        else
        {
           
            o.Albedo = b.rgb;
            o.Alpha = b.a;
           

        }
        o.Albedo *= _Color.rgb;
    }
    ENDCG
    }

        FallBack "Diffuse"
}

lerp performs a linear interpolation of the first and second argument, using the third one as weight.
The range of the third parameter ‘weight’ should be within 0…1 range.

lerp(a, b, weight);

lerp(a,b,0); // all a
lerp(a,b,1); // all b
lerp(a,b,0.5); // 'half a, half b'

Where ‘a’ and ‘b’ represent your two color values. If you want to blend between them depending on the y-position, you need to transform that y-position into a weight factor within the 0…1 range.

For the simplest case: if you want color ‘a’ at y-position 0 and color ‘b’ at y-position 10 and a blend in-between, you could do something like this:

weight = saturate(y / 10);
lerp(a, b, weight);

saturate just clamps the value within the 0…1 range.

This might be of interest: