Converting/Rewriting a Standard shader in the ShaderGraph

Hello,

I am currently very, very gingerly looking into porting an existing project to the HDRP. It will take a lot of work, but I have decided to look at the feasibility of converting my custom shaders. My project is basically a perpetual research project, and I am worried that if I don’t port to HDRP eventually the built-in pipeline will become obsolete.

I have made some progress, but I have never used the shadergraph before, so I would appreciate some general advice.

This is my current shader. It uses some code from the proprietary Stix Games Grass shader, which I have removed, but the rest of the code I have written myself, so it should be fine to show here.

Basically, it is used to procedurally texture a large planet, which has been divided into chunks.

I am sending in the planet textures, and a “planet height” value, as well as a “relative terrain height” value.

I am then very crudely blending between the textures using the relative terrain height, to texture the planet chunk based on the height of the vertices.

I have posted the shader below.

This image:


Is a proof of concept that I made in shader graph. It is based on a resource that I found online here:

I am applying it to a sphere, and it seems to split the sphere into two textures, but it doesn’t blend them, and it doesn’t take into account the “relative height” of the pixels.

Is there any shader graph example that would cover this? Or, more seriously, is there anything that my original shader does that the shader graph is incapable of?

Thanks!

Shader "Stix Games/Terrainnormal2"
{
    Properties
    {
        _planetheight("planetheight" , float) = 0.5
        _firsttex("First Texture", 2D) = "white" {}
        _secondtex("Second Texture", 2D) = "white" {}
        _thirdtex("Third Texture", 2D) = "white" {}
        _fourthtex("fourth Texture", 2D) = "white" {}
        _fifthtex("Fifth Texture", 2D) = "white" {}
        _sixthtex("Sixth Texture", 2D) = "white" {}
        _seventhtex("Seventh Texture", 2D) = "white" {}
        _sixthnormal("sixthnormal", 2D) = "bump" {}
        _seventhnormal("seventhnormal", 2D) = "bump" {}
       //Snipped, Grass specific code

        _GrassTex00("Grass Texture", 2D) = "white" {}
     //Snipped, Grass specific code

        _GrassTex01("Grass Texture", 2D) = "white" {}     
     //Snipped, Grass specific code

        _GrassTex02("Grass Texture", 2D) = "white" {}
     //Snipped, Grass specific code

        _GrassTex03("Grass Texture", 2D) = "white" {}
     //Snipped, Grass specific code

        _GrassTex04("Grass Texture", 2D) = "white" {}
     //Snipped, Grass specific code

        _GrassTex05("Grass Texture", 2D) = "white" {}
     //Snipped, Grass specific code
    }
        SubShader
        {
            Tags{ "Queue" = "Geometry" "RenderType" = "StixGamesGrass" "RenderPipeline" = "HDRP"}
            LOD 1000
            CGPROGRAM
            #pragma surface surf Lambert vertex:vert
            #pragma target 5.0

            struct Input {
                float2 uv_firsttex;
                float2 uv_secondtex;
                float2 uv_thirdtex;
                float2 uv_fourthtex;
                float2 uv_fifthtex;
                float2 uv_sixthtex;
                float2 uv_seventhtex;
                float2 uv_sixthnormal;
                float2 uv_seventhnormal;
                float3 worldPos;
                float relativeTerrainHeight;
            };

        void vert(inout appdata_full v, out Input o) {
            UNITY_INITIALIZE_OUTPUT(Input, o);
            o.relativeTerrainHeight = v.texcoord1.x;
        }

            sampler2D _firsttex;
            sampler2D _secondtex;
            sampler2D _thirdtex;
            sampler2D _fourthtex;
            sampler2D _fifthtex;
            sampler2D _sixthtex;
            sampler2D _seventhtex;
            sampler2D _sixthnormal;
            sampler2D _seventhnormal;
            float _planetheight;

            void surf(Input IN, inout SurfaceOutput o) {
                float4 tex1 = tex2D(_firsttex, IN.uv_firsttex);
                float4 tex2 = tex2D(_secondtex, IN.uv_secondtex);
                float4 tex3 = tex2D(_thirdtex, IN.uv_thirdtex);
                float4 tex4 = tex2D(_fourthtex, IN.uv_fourthtex);
                float4 tex5 = tex2D(_fifthtex, IN.uv_fifthtex);
                float4 tex6 = tex2D(_sixthtex, IN.uv_sixthtex);
                float4 tex7 = tex2D(_seventhtex, IN.uv_seventhtex);
                float terrainheight = IN.relativeTerrainHeight;
                float terrainminheight = 0;
                float terrainmaxheight = _planetheight;
                float scaledmin = 0;
                float scaledmax = 50;
                float scaledheight = (((terrainheight - terrainminheight) * (scaledmax - scaledmin)) / (terrainmaxheight - terrainminheight)) + scaledmin;
                float blendregion = 2.5;

                if (scaledheight > 40) {
                    if (scaledheight > 40 + blendregion)
                    o.Albedo = tex2D(_firsttex, IN.uv_firsttex).rgb;
                    else {//blend
                        float OldMin = 40;
                        float OldMax = 40 + blendregion;
                        float NewValue = (((scaledheight - OldMin) * (1 - 0)) / (OldMax - OldMin)) + 0;
                        float a1 = 1 - NewValue;
                        float a2 = NewValue;
                        o.Albedo = (tex2*a1) + (tex1*a2);
                    }
                }
                else if (scaledheight > 30) {
                    if (scaledheight > 30 + blendregion)
                    o.Albedo = tex2D(_secondtex, IN.uv_secondtex).rgb;
                    else {//blend
                        float OldMin = 30;
                        float OldMax = 30 + blendregion;
                        float NewValue = (((scaledheight - OldMin) * (1 - 0)) / (OldMax - OldMin)) + 0;
                        float a1 = 1 - NewValue;
                        float a2 = NewValue;
                        o.Albedo = (tex3*a1) + (tex2*a2);
                    }
                }
                else if (scaledheight > 20) {
                    if (scaledheight > 20 + blendregion)
                    o.Albedo = tex2D(_thirdtex, IN.uv_thirdtex).rgb;
                    else {//blend
                        float OldMin = 20;
                        float OldMax = 20 + blendregion;
                        float NewValue = (((scaledheight - OldMin) * (1 - 0)) / (OldMax - OldMin)) + 0;
                        float a1 = 1 - NewValue;
                        float a2 = NewValue;
                        o.Albedo = (tex4*a1) + (tex3*a2);
                    }
                }
                else if (scaledheight > 10) {
                    if (scaledheight > 10 + blendregion)
                    o.Albedo = tex2D(_fourthtex, IN.uv_fourthtex).rgb;
                    else {//blend
                        float OldMin = 10;
                        float OldMax = 10 + blendregion;
                        float NewValue = (((scaledheight - OldMin) * (1 - 0)) / (OldMax - OldMin)) + 0;
                        float a1 = 1 - NewValue;
                        float a2 = NewValue;
                        o.Albedo = (tex5*a1) + (tex4*a2);
                    }
                }
                else if (scaledheight > 1) {
                    if (scaledheight > 1 + blendregion)
                    o.Albedo = tex2D(_fifthtex, IN.uv_fifthtex).rgb;
                    else {//blend
                        float OldMin = 1;
                        float OldMax = 1 + blendregion;
                        float NewValue = (((scaledheight - OldMin) * (1 - 0)) / (OldMax - OldMin)) + 0;
                        float a1 = 1 - NewValue;
                        float a2 = NewValue;
                        o.Albedo = (tex6*a1) + (tex5*a2);
                    }
                }
                else if (scaledheight > 0.01) {
                    if (scaledheight > 0.5 + blendregion)
                    o.Albedo = tex2D(_sixthtex, IN.uv_sixthtex).rgb;
                    else {//blend      
                        float OldMin = 0.5;
                        float OldMax = 0.5 + 0.5;
                        float NewValue = (((scaledheight - OldMin) * (1 - 0)) / (OldMax - OldMin)) + 0.0;
                        float4 col = lerp(tex7,tex6,NewValue);
                        o.Albedo = col.rgb;
                        half3 n1 = UnpackScaleNormal(tex2D(_sixthnormal,IN.uv_sixthnormal),3);
                        half3 n2 = UnpackScaleNormal(tex2D(_seventhnormal,IN.uv_seventhnormal),3);
                        half3 norm = lerp(n2,n1,NewValue);
                        o.Normal = norm;
                    }
                }
                else              
                    o.Albedo = tex2D(_seventhtex, IN.uv_seventhtex).rgb;              
            }
            ENDCG
        }
            CustomEditor "GrassEditor"
}

I have made some progress with this.

I haven’t tested it with an actual terrain object yet, so the normal mapping, UV mapping, etc, could be very wrong, and it also only works for three textures.

This is what I have so far:

Imgur

I can add and blend the textures, but the texture at the middle of the three (the sand one) shows over the texture at the top (the grass). This doesn’t happen for the rock texture at the bottom.

Before I add any more textures, I would like to try to solve this.

I’m also not sure if using a multiple node at the end is correct. I tried a “branch” node, but it left a visible seam in the middle of the texture. Is this the correct way to “combine” two textures together?

Thanks!