Help with Custom Terrain AddPass Shader

I’ve been adventuring myself in scripting shaders for unity, followed some tutorials, made some on my own and finally tried to adventure into making a terrain shader.

So I’ve looked into this tutorial :

Looked the builtin shaders…

And found this article on Gamasutra:

And tried to make a new terrain shader.
But I’m having trouble with the AddPass shader, it’s not working. Tried a lot of things and still didn’t work. It seems like it’s falling back and when I remove the fallback it just paints all the textures from the first pass all mixed up.

Here’s a screenshot:

Is there a way to fix these so I can have more than 4 textures in my terrain?

Here are the shaders (did not apply normal maps yet):
FirstPass shader:

Shader "Raed Wulf/Terrain/BlendTexture" {
    Properties{
        //control splat map
        [HideInInspector] _Control("Control (RGBA)", 2D) = "red" {}

        //textures Alpha is height
        [HideInInspector] _Splat3("Layer 3 (A)", 2D) = "white" {}
        [HideInInspector] _Splat2("Layer 2 (B)", 2D) = "white" {}
        [HideInInspector] _Splat1("Layer 1 (G)", 2D) = "white" {}
        [HideInInspector] _Splat0("Layer 0 (R)", 2D) = "white" {}

        //normal maps
        [HideInInspector] _Normal3("Normal 3 (A)", 2D) = "bump" {}
        [HideInInspector] _Normal2("Normal 2 (B)", 2D) = "bump" {}
        [HideInInspector] _Normal1("Normal 1 (G)", 2D) = "bump" {}
        [HideInInspector] _Normal0("Normal 0 (R)", 2D) = "bump" {}

        // used in fallback on old cards & base map
        [HideInInspector] _MainTex("BaseMap (RGB)", 2D) = "white" {}
        [HideInInspector] _Color("Main Color", Color) = (1,1,1,1)
    }

    SubShader{
        Tags{
            "SplatCount" = "4"
            "Queue" = "Geometry-100"
            "RenderType" = "Opaque"
        }

        CGPROGRAM
        #pragma surface surf Lambert exclude_path:forward
        #pragma multi_compile_fog
        #pragma target 3.0
        // needs more than 8 texcoords
        #pragma exclude_renderers gles
        #include "UnityPBSLighting.cginc"

        // Access the Shaderlab properties
        uniform sampler2D _Control;
        uniform sampler2D _Splat0,_Splat1,_Splat2,_Splat3;
    

        // Surface shader input structure
        struct Input {
            float2 uv_Control : TEXCOORD0;
            float2 uv_Splat0 : TEXCOORD1;
            float2 uv_Splat1 : TEXCOORD2;
            float2 uv_Splat2 : TEXCOORD3;
            float2 uv_Splat3 : TEXCOORD4;
        };

        float4 blend(float4 texA, float aA, float4 texB, float aB)
        {

            float depth = 0.1;
            float ma = max(texA.a + aA, texB.a + aB) - depth;

            float b1 = max(texA.a + aA - ma, 0.0);
            float b2 = max(texB.a + aB - ma, 0.0);

            return (texA * b1 + texB * b2) / (b1 + b2);

        }

        
        // Surface Shader function
        void surf(Input IN, inout SurfaceOutput o) {
            fixed4 tex0 = tex2D(_Splat0, IN.uv_Splat0);
            fixed4 tex1 = tex2D(_Splat1, IN.uv_Splat1);
            fixed4 tex2 = tex2D(_Splat2, IN.uv_Splat2);
            fixed4 tex3 = tex2D(_Splat3, IN.uv_Splat3);

            fixed4 splat_control = tex2D(_Control, IN.uv_Control);
            fixed4 col;

            col = blend(tex0, splat_control.r, tex1, splat_control.g);
            col = blend(col, splat_control.r + splat_control.g, tex2, splat_control.b);
            col = blend(col, splat_control.r + splat_control.g + splat_control.b, tex3, splat_control.a);

            o.Albedo = col.rgb;
            o.Alpha = col.a;        

        }
        ENDCG
    }

        Dependency "AddPassShader" = "Hidden/Raed Wulf/Terrain/BlendTexture-AddPass"
        Dependency "BaseMapShader" = "Diffuse"

        Fallback "Nature/Terrain/Diffuse"
}

AddPass Shader:

Shader "Hidden/Raed Wulf/Terrain/BlendTexture-AddPass" {
    Properties{
        //control splat map
        [HideInInspector] _Control("Control (RGBA)", 2D) = "red" {}

        //textures Alpha is height
        [HideInInspector] _Splat3("Layer 3 (A)", 2D) = "white" {}
        [HideInInspector] _Splat2("Layer 2 (B)", 2D) = "white" {}
        [HideInInspector] _Splat1("Layer 1 (G)", 2D) = "white" {}
        [HideInInspector] _Splat0("Layer 0 (R)", 2D) = "white" {}

        //normal maps
        [HideInInspector] _Normal3("Normal 3 (A)", 2D) = "bump" {}
        [HideInInspector] _Normal2("Normal 2 (B)", 2D) = "bump" {}
        [HideInInspector] _Normal1("Normal 1 (G)", 2D) = "bump" {}
        [HideInInspector] _Normal0("Normal 0 (R)", 2D) = "bump" {}

        // used in fallback on old cards & base map
        [HideInInspector] _MainTex("BaseMap (RGB)", 2D) = "white" {}
        [HideInInspector] _Color("Main Color", Color) = (1,1,1,1)
    
    }

    SubShader{
        Tags{
            "SplatCount" = "4"
            "Queue" = "Geometry-99"
            "IgnoreProjector" = "True"
            "RenderType" = "Opaque"
        }

        CGPROGRAM
        #pragma surface surf Lambert exclude_path:forward decal:add
        #pragma multi_compile_fog
        #pragma target 3.0
        // needs more than 8 texcoords
        #pragma exclude_renderers gles
        #include "UnityPBSLighting.cginc"
    
        // Access the Shaderlab properties
        uniform sampler2D _Control;
        uniform sampler2D _Splat0,_Splat1,_Splat2,_Splat3;

        // Surface shader input structure
        struct Input {
            float2 uv_Control : TEXCOORD0;
            float2 uv_Splat0 : TEXCOORD1;
            float2 uv_Splat1 : TEXCOORD2;
            float2 uv_Splat2 : TEXCOORD3;
            float2 uv_Splat3 : TEXCOORD4;
        };

        float4 blend(float4 texA, float aA, float4 texB, float aB)
        {

            float depth = 0.1;
            float ma = max(texA.a + aA, texB.a + aB) - depth;

            float b1 = max(texA.a + aA - ma, 0.0);
            float b2 = max(texB.a + aB - ma, 0.0);

            return (texA * b1 + texB * b2) / (b1 + b2);

        }

        
        // Surface Shader function
        void surf(Input IN, inout SurfaceOutput o) {
            fixed4 tex0 = tex2D(_Splat0, IN.uv_Splat0);
            fixed4 tex1 = tex2D(_Splat1, IN.uv_Splat1);
            fixed4 tex2 = tex2D(_Splat2, IN.uv_Splat2);
            fixed4 tex3 = tex2D(_Splat3, IN.uv_Splat3);

            fixed4 splat_control = tex2D(_Control, IN.uv_Control);
            fixed4 col;

            col = blend(tex0, splat_control.r, tex1, splat_control.g);
            col = blend(col, splat_control.r + splat_control.g, tex2, splat_control.b);
            col = blend(col, splat_control.r + splat_control.g + splat_control.b, tex3, splat_control.a);

            o.Albedo = col.rgb;
            o.Alpha = 0.0;
                    
        }
        ENDCG
    }

        Fallback "Hidden/TerrainEngine/Splatmap/Diffuse-AddPass"
        //Fallback off
}

Thanks in Advanced!

addpass will blend firstpass pixel alpha
you can change this line:
o.Alpha = 0.0;
to:
o.Alpha=dot(float4(tex0.a,tex1.a,tex2.a,tex3.a),splat_control);
good luck!

2 Likes