Ok once again, is it possible to combine a surface shader with vertex and frag shader?

Ok I have seen this topic come up before but it still has me stumped.

I have tried combining this vertex and frag shader with a surface shader using one pass for the vertex and frag shader and then the surface shader below.

Here is the vertex and frag shader on it’s own:

Shader "ShaderMan/PlanetSurface"
{
    Properties
    {
        _MainTex ("MainTex", 2D) = "white" {}
        _FractalDivergance("Fractal Divergance", Range(0, 4)) = 1.0
    }
    SubShader
    {
    Tags { "RenderType" = "Transparent" "Queue" = "Transparent" }
    Pass
    {
    ZWrite Off
    Blend SrcAlpha OneMinusSrcAlpha
    CGPROGRAM
    #pragma  vertex vert
    #pragma fragment frag
    #include "UnityCG.cginc"
    struct VertexInput {
    fixed4 vertex : POSITION;
    fixed2 uv:TEXCOORD0;
    fixed4 tangent : TANGENT;
    fixed3 normal : NORMAL;
    //VertexInput
    };
    struct VertexOutput {
    fixed4 pos : SV_POSITION;
    fixed2 uv:TEXCOORD0;
    //VertexOutput
    };
    //Variables
    sampler2D _MainTex;
    float _FractalDivergance;
    // One way to avoid tex2D tile repetition one using one small tex2D to cover a huge area.
    // Based on Voronoise (https://www.shadertoy.com/view/Xd23Dh), a random offset is applied to
    // the tex2D UVs per Voronoi cell. Distance to the cell is used to smooth the transitions
    // between cells.
    // More info here: http://www.iquilezles.org/www/articles/tex2Drepetition/tex2Drepetition.htm
    fixed4 hash4( fixed2 p ) { return frac(sin(fixed4( 1.0+dot(p,fixed2(37.0,17.0)),
                                                  2.0+dot(p,fixed2(11.0,47.0)),
                                                  3.0+dot(p,fixed2(41.0,29.0)),
                                                  4.0+dot(p,fixed2(23.0,31.0)))) * _FractalDivergance); }
    fixed3 tex2DNoTile( sampler2D samp, in fixed2 uv, fixed v )
    {
        fixed2 p = floor( uv );
        fixed2 f = frac( uv );
        // derivatives (for correct mipmapping)
        fixed2 _ddx = ddx( uv );
        fixed2 _ddy = ddy( uv );
        fixed3 va = fixed3(0.0,0.0,0.0);
        fixed w1 = 0.0;
        fixed w2 = 0.0;
        [unroll(3)]
        for (int j = -1; j <= 1; j++)
        {
            [unroll(3)]
            for (int i = -1; i <= 1; i++)
            {
                fixed2 g = fixed2(fixed(i), fixed(j));
                fixed4 o = hash4(p + g);
                fixed2 r = g - f + o.xy;
                fixed d = dot(r, r);
                fixed w = exp(-5.0*d);
                fixed3 c = tex2D(samp, uv + v * o.zw, _ddx, _ddy).xyz;
                va += w * c;
                w1 += w;
                w2 += w * w;
            }
        }
        // normal averaging --> lowers contrasts
        //return va/w1;
        // contrast preserving average
        fixed mean = 0;// tex2DGrad( samp, uv, ddx*16.0, ddy*16.0 ).x;
        fixed3 res = mean + (va-w1*mean)/sqrt(w2);
        return lerp( va/w1, res, v );
    }
    VertexOutput vert (VertexInput v)
    {
        VertexOutput o;
        o.pos = UnityObjectToClipPos (v.vertex);
        o.uv = v.uv;
        return o;
    }
    fixed4 frag(VertexOutput i) : SV_Target
    {
        fixed2 uv = i.uv /1;
        fixed f = 1;
        fixed s = 1;
        fixed3 col = tex2DNoTile( _MainTex, 10 * uv, 1).xyz;
        return fixed4( col, 1.0 );
    }
    ENDCG
    }
  }
}

And here is my attempt at combining the vertex and frag shader with a Lambert surface shader:

Shader "ShaderMan/PlanetSurface"
{
    Properties
    {
        _MainTex ("MainTex", 2D) = "white" {}
        _Nor1 ("Normal 0", 2D) = "bump" {}
        _FractalDivergance("Fractal Divergance", Range(0, 4)) = 1.0
     
        _myColor ("Example Color", Color) = (1,1,1,1)
    }
    SubShader
    {
    Tags { "RenderType" = "Opaque" }
    LOD 200

 
    Pass
    {
    ZWrite Off
    Blend SrcAlpha OneMinusSrcAlpha
    CGPROGRAM
    #pragma  vertex vert
    #pragma fragment frag
    #include "UnityCG.cginc"
    struct VertexInput {
    fixed4 vertex : POSITION;
    fixed2 uv:TEXCOORD0;
    fixed4 tangent : TANGENT;
    fixed3 normal : NORMAL;
    //VertexInput
    };
    struct VertexOutput {
    fixed4 pos : SV_POSITION;
    fixed2 uv:TEXCOORD0;
    //VertexOutput
    };
    //Variables
    sampler2D _MainTex;
    float _FractalDivergance;
    float _Scale;
    // One way to avoid tex2D tile repetition one using one small tex2D to cover a huge area.
    // Based on Voronoise (https://www.shadertoy.com/view/Xd23Dh), a random offset is applied to
    // the tex2D UVs per Voronoi cell. Distance to the cell is used to smooth the transitions
    // between cells.
    // More info here: http://www.iquilezles.org/www/articles/tex2Drepetition/tex2Drepetition.htm
    fixed4 hash4( fixed2 p ) { return frac(sin(fixed4( 1.0+dot(p,fixed2(37.0,17.0)),
                                                  2.0+dot(p,fixed2(11.0,47.0)),
                                                  3.0+dot(p,fixed2(41.0,29.0)),
                                                  4.0+dot(p,fixed2(23.0,31.0)))) * _FractalDivergance); }
    fixed3 tex2DNoTile( sampler2D samp, in fixed2 uv, fixed v )
    {
        fixed2 p = floor( uv );
        fixed2 f = frac( uv );
        // derivatives (for correct mipmapping)
        fixed2 _ddx = ddx( uv );
        fixed2 _ddy = ddy( uv );
        fixed3 va = fixed3(0.0,0.0,0.0);
        fixed w1 = 0.0;
        fixed w2 = 0.001;


        [unroll(3)]
        for (int j = -1; j <= 1; j++)
        {
            [unroll(3)]
            for (int i = -1; i <= 1; i++)
            {
                fixed2 g = fixed2(fixed(i), fixed(j));
                fixed4 o = hash4(p + g);
                fixed2 r = g - f + o.xy;
                fixed d = dot(r, r);
                fixed w = exp(-5.0*d);
                fixed3 c = tex2D(samp, uv + v * o.zw, _ddx, _ddy).xyz;
                va += w * c;
                w1 += w;
                w2 += w * w;
            }
        }
        // normal averaging --> lowers contrasts
        //return va/w1;
        // contrast preserving average
        fixed mean = 0;// tex2DGrad( samp, uv, ddx*16.0, ddy*16.0 ).x;
        fixed3 res = mean + (va-w1*mean)/sqrt(w2);
        return lerp( va/w1, res, v );
    }
    VertexOutput vert (VertexInput v)
    {
        VertexOutput o;
        o.pos = UnityObjectToClipPos (v.vertex);
        o.uv = v.uv;
        return o;
    }
    fixed4 frag(VertexOutput i) : SV_Target
    {
        fixed2 uv = i.uv /1;
        fixed f = 1;
        fixed s = 1;
        fixed3 col = tex2DNoTile( _MainTex, 10 * uv, 1).rgb;
        return fixed4( col, 1.0 );
    }
    ENDCG

 
    }
    CGPROGRAM
            #pragma surface surf Lambert

            struct Input {
                float2 uvMainTex;
                float3 worldRefl;
            };

            sampler2D _MainTex;

            fixed4 _myColor;
            fixed4 _myEmisiion;
            fixed4 _myNormal;
     
         
            void surf (Input IN, inout SurfaceOutput o){
                o.Albedo = (tex2D(_MainTex, IN.uvMainTex)* _myColor).rgb;
         
            }
     
        ENDCG
  }
  Fallback "Diffuse"
}

What happens here is that the surface shader completely overwrites the vertex and frag shader and the texture is no longer produced as well. If I instead place the surface shader on top of the pile then the vertex and frag shader in the pass below completely overwrites the surface shader.

Now my question is simple, is it possible to combine these two types of shaders with passes? Or do they both just completely overwrite each other?

I would really appreciate a response.

Thanks

Yes, but…

Because that what the shader is being told to do. Both the vertex fragment shader and the surface shader are opaque, so they’ll just draw over the other. The fragment shader may have a blend mode set, but you’re using alpha blending and outputting an alpha of 1, which means it’ll act like it’s opaque.

Even if you change the blend mode, there’s really no reason to have this be two passes. Instead you should be copying the tex2DNoTile function into the CGPROGRAM block of the surface shader and use that instead of tex2D in the surf function.

yes but the #pragma of the surface shader does not accept vertex, frag and surface together?

So write the surface shader in a seperate pass?

You don’t need the vertex fragment. If I understood correctly, you want to use “tex2DNoTile” to have a non tiling texture on a planet, right ?
Like bdolus said, what you need to do is to move the needed functions for tex2DNoTile from your vertex fragment code to and include, or directly in the surface shader, and in there, use tex2DNoTile instead of tex2D to sample the main texture.

1 Like

This is what

Exactly. The the vert and frag functions themselves aren’t the important part here. They do exist to make the mesh render, but otherwise don’t do anything special. Literally you just want to delete that pass entirely. The surface shader doesn’t have them since it generates those functions automatically behind the scenes.

Yeah I have tried doing that and I just run into a ton of errors.

The surface shader seems to have a huge issue with this part of the code:

 [unroll(3)]
        for (int j = -1; j <= 1; j++)
        {
            [unroll(3)]
            for (int i = -1; i <= 1; i++)
            {
                fixed2 g = fixed2(fixed(i), fixed(j));
                fixed4 o = hash4(p + g);
                fixed2 r = g - f + o.xy;
                fixed d = dot(r, r);
                fixed w = exp(-5.0*d);
                fixed3 c = tex2D(samp, uv + v * o.zw, _ddx, _ddy).xyz;
                va += w * c;
                w1 += w;
                w2 += w * w;
            }
        }

Here is my attempt so far at trying to write this into a surface shader but I get stuck at the part below:

Shader "Custom/TerrainSurface" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _FractalDivergance("Fractal Divergance", Range(0, 4)) = 1.0
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        sampler2D _MainTex;

        struct Input {
            float2 uv_MainTex;
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;
        float _FractalDivergance;

fixed4 hash4( fixed2 p ) { return frac(sin(fixed4( 1.0+dot(p,fixed2(37.0,17.0)),
                                                  2.0+dot(p,fixed2(11.0,47.0)),
                                                  3.0+dot(p,fixed2(41.0,29.0)),
                                                  4.0+dot(p,fixed2(23.0,31.0)))) * _FractalDivergance); }


fixed3 tex2DNoTile( sampler2D samp, in fixed2 uv, fixed v )
    {
    fixed2 p = floor( uv );
        fixed2 f = frac( uv );
        // derivatives (for correct mipmapping)
        fixed2 _ddx = ddx( uv );
        fixed2 _ddy = ddy( uv );
        fixed3 va = fixed3(0.0,0.0,0.0);
        fixed w1 = 0.0;
        fixed w2 = 0.0;
      
        //This is where I run into lots of errors:
        /*
         [unroll(3)]
        for (int j = -1; j <= 1; j++)
        {
            [unroll(3)]
            for (int i = -1; i <= 1; i++)
            {
                fixed2 g = fixed2(fixed(i), fixed(j));
                fixed4 o = hash4(p + g);
                fixed2 r = g - f + o.xy;
                fixed d = dot(r, r);
                fixed w = exp(-5.0*d);
                fixed3 c = tex2D(samp, uv + v * o.zw, _ddx, _ddy).xyz;
                va += w * c;
                w1 += w;
                w2 += w * w;
            }
        }*/

        fixed mean = 0;
        fixed3 res = mean + (va-w1*mean)/sqrt(w2);
        return lerp( va/w1, res, v );
    }


        // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
        // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
        // #pragma instancing_options assumeuniformscaling
        UNITY_INSTANCING_BUFFER_START(Props)
            // put more per-instance properties here
        UNITY_INSTANCING_BUFFER_END(Props)

        void surf (Input IN, inout SurfaceOutputStandard o) {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; 
            o.Albedo = c.rgb;
            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}