Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Adding Vertex Effect To Surface Shader

Discussion in 'Shaders' started by JBlythDC, Feb 24, 2022.

  1. JBlythDC

    JBlythDC

    Joined:
    Apr 9, 2019
    Posts:
    3
    I have used code from here https://www.bitshiftprogrammer.com/2018/04/curved-surface-shader-unity.html to set up a curved world effect using vertices. I have now tried to combine the vertex effect with the standard surface shader to allow for glossiness and metallic.

    I ran in to compiler issues but managed to resolve them using this forum post https://forum.unity.com/threads/mixed-vert-frag-surf-shader-error-redefinition-_maintex_st.502940/ and now it is compiling fine but it is rendering twice with the surface pass not matching the position that is generated by the vertex pass. Does anyone know how to get the surface pass render position to match the vertex pass position? Or if this is even possible.

    Below is the code for the shader that I have set up.

    Code (CSharp):
    1. Shader "Custom/CurvedSurfaceShader"
    2. {
    3.     Properties
    4.     {
    5.         _Color ("Colour", Color) = (1,1,1,1)
    6.         _MainTex ("Albedo (RGB)", 2D) = "white" {}
    7.         _Glossiness ("Smoothness", Range(0,1)) = 0.5
    8.         _Metallic ("Metallic", Range(0,1)) = 0.0
    9.     }
    10.     SubShader
    11.     {
    12.         Tags { "RenderType"="Opaque" }
    13.  
    14.         GrabPass{}
    15.  
    16.         Pass
    17.         {
    18.             CGPROGRAM
    19.             #pragma target 3.0
    20.  
    21.             #include "UnityCG.cginc"
    22.  
    23.             #pragma vertex vert
    24.             #pragma fragment frag
    25.             // make fog work
    26.             #pragma multi_compile_fog
    27.  
    28.             float3 _BendAmount;
    29.             float3 _BendOrigin;
    30.             float _BendFallOff;
    31.             float _BendFallOffStr;
    32.  
    33.             fixed4 _Color;      
    34.            
    35.             sampler2D _MainTex;
    36.             float4 _MainTex_ST;
    37.  
    38.             struct appdata
    39.             {
    40.                 float4 vertex : POSITION;
    41.                 float2 uv : TEXCOORD0;
    42.             };
    43.  
    44.             struct v2f
    45.             {
    46.                 float2 uv : TEXCOORD0;
    47.                 UNITY_FOG_COORDS(1)
    48.                 float4 vertex : SV_POSITION;
    49.             };          
    50.  
    51.             v2f vert (appdata v)
    52.             {
    53.                 v2f o;
    54.  
    55.                 /*1*/float4 world = mul(unity_ObjectToWorld, v.vertex);
    56.                 /*2*/float dist = length(world.xyz - _BendOrigin.xyz);
    57.                 /*3*/dist = max(0, dist - _BendFallOff);
    58.                
    59.                 /*4*/dist = pow(dist, _BendFallOffStr);
    60.                 /*5*/world.xyz += dist * _BendAmount;
    61.                 /*6*/float4 vertex = mul(unity_WorldToObject, world);
    62.  
    63.                 o.vertex = UnityObjectToClipPos(vertex);
    64.                 o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    65.                 UNITY_TRANSFER_FOG(o,o.vertex);
    66.                 return o;
    67.             }
    68.  
    69.             fixed4 frag (v2f i) : SV_Target
    70.             {
    71.                 // sample the texture
    72.                 fixed4 col = tex2D(_MainTex, i.uv) * _Color;
    73.                 // apply fog
    74.                 UNITY_APPLY_FOG(i.fogCoord, col);
    75.                 return col;
    76.             }
    77.             ENDCG
    78.         }
    79.  
    80.         GrabPass{}
    81.  
    82.         Tags { "RenderType"="Opaque" }
    83.  
    84.         CGPROGRAM
    85.         // Physically based Standard lighting model, and enable shadows on all light types
    86.         #pragma surface surf Standard fullforwardshadows
    87.  
    88.         // Use shader model 3.0 target, to get nicer looking lighting
    89.         #pragma target 3.0
    90.  
    91.         sampler2D _MainTex;
    92.  
    93.         struct Input
    94.         {
    95.             float2 uv_MainTex;
    96.         };
    97.  
    98.         half _Glossiness;
    99.         half _Metallic;
    100.         fixed4 _Color;
    101.  
    102.         void surf (Input IN, inout SurfaceOutputStandard o)
    103.         {
    104.             // Albedo comes from a texture tinted by colour
    105.             fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    106.             o.Albedo = c.rgb;
    107.             // Metallic and smoothness come from slider variables
    108.             o.Metallic = _Metallic;
    109.             o.Smoothness = _Glossiness;
    110.             o.Alpha = c.a;
    111.         }
    112.         ENDCG
    113.     }
    114.     FallBack "Diffuse"
    115. }
     
  2. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,497
    Shader passes are self contained. A vertex shader isn't changing the vertex data of the mesh, it's simply being *given* vertex values and allowing you to use those values in whatever way you want before them being passed to the frag/surf function. They have no connection to the source of the data.

    So, you either need to include the custom vertex program in each pass of the shader, or in the case of your shader, I'm not seeing anything different happening between the two shader's fragment outputs, so realistically this should just be one shader pass.

    https://docs.unity3d.com/Manual/SL-SurfaceShaderExamples.html

    Scroll down to the "Normal Extrusion" section and you can see an example of adding a custom vertex pass to a surface shader. Then all you should need is the Tags and second CGPROGRAM.

    Also, add
    addshadow
    to the
    #pragma surface surf
    line of the surface shader so that the surface shader uses your custom vertex program for all the pipeline shader passes it generates.
     
  3. JBlythDC

    JBlythDC

    Joined:
    Apr 9, 2019
    Posts:
    3
    Thank you for pointing me in the right direction. After some trial and error I have now got the vertex affect working with the surface shader.

    For anyone who wants to know here is my shader that is working as I want it to:
    Code (CSharp):
    1. Shader "Custom/CurvedSurfaceShader"
    2. {
    3.     Properties
    4.     {
    5.         _Color ("Colour", Color) = (1,1,1,1)
    6.         _MainTex ("Albedo (RGB)", 2D) = "white" {}
    7.         _Glossiness ("Smoothness", Range(0,1)) = 0.5
    8.         _Metallic ("Metallic", Range(0,1)) = 0.0
    9.     }
    10.     SubShader
    11.     {
    12.         Tags { "RenderType"="Opaque" }
    13.  
    14.         CGPROGRAM
    15.         #pragma target 3.0
    16.  
    17.         #include "UnityCG.cginc"      
    18.  
    19.         //Physically based Standard lighting model, and enable shadows on all light types.
    20.         #pragma surface surf Standard fullforwardshadows addshadow
    21.         //Vertex needed to generate curve effect.
    22.         #pragma vertex vert
    23.  
    24.         float3 _BendAmount;
    25.         float3 _BendOrigin;
    26.         float _BendFallOff;
    27.         float _BendFallOffStr;
    28.  
    29.         void vert (inout appdata_full v)
    30.         {
    31.             //Getting world space location of a particular vertex.
    32.             float4 world = mul(unity_ObjectToWorld, v.vertex);
    33.             //Calculating the distance between the vertex position and where the _BendOrigin is.
    34.             float dist = length(world.xyz - _BendOrigin.xyz);
    35.             //Distance value is prevented from going below 0, This prevents undefined behaviour when using power function (negative values don't work with power).
    36.             dist = max(0, dist - _BendFallOff);
    37.            
    38.             //Distance value is raised to _BendFallOffStr value, which defines the steepness of the curve itself.
    39.             dist = pow(dist, _BendFallOffStr);
    40.             //_BendAmount should be dependent on the distance value so as to have a falloff curve, So we simply multiply it with distance and add to 'world'.
    41.             world.xyz += dist * _BendAmount;
    42.             //Convert the new world space of vertex and convert back to local space.
    43.             float4 vertex = mul(unity_WorldToObject, world);
    44.  
    45.             v.vertex = vertex;
    46.         }
    47.  
    48.         sampler2D _MainTex;
    49.  
    50.         struct Input
    51.         {
    52.             float2 uv_MainTex;
    53.         };
    54.  
    55.         half _Glossiness;
    56.         half _Metallic;
    57.         fixed4 _Color;
    58.  
    59.         void surf (Input IN, inout SurfaceOutputStandard o)
    60.         {
    61.             // Albedo comes from a texture tinted by colour
    62.             fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    63.             o.Albedo = c.rgb;
    64.             // Metallic and smoothness come from slider variables
    65.             o.Metallic = _Metallic;
    66.             o.Smoothness = _Glossiness;
    67.             o.Alpha = c.a;
    68.         }
    69.         ENDCG
    70.     }
    71.     FallBack "Diffuse"
    72. }