Search Unity

combining a Surface and Vert Frag shader

Discussion in 'Shaders' started by eco_bach, Aug 28, 2017.

  1. eco_bach

    eco_bach

    Joined:
    Jul 8, 2013
    Posts:
    1,601
    Having a problem combining 2 shaders.
    I have a vertex shader that I need to combine with water basic (part of Standard Assets).

    Can anyone help?
    This is the surface shader
    Code (csharp):
    1.  
    2. // Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
    3.  
    4. Shader "sidefx/vertex_fluid_shader" {
    5.     Properties {
    6.         _Color ("Color", Color) = (1,1,1,1)
    7.         _MainTex ("Albedo (RGB)", 2D) = "white" {}
    8.         _Glossiness ("Smoothness", Range(0,1)) = 0.5
    9.         _Metallic ("Metallic", Range(0,1)) = 0.0
    10.         _boundingMax("Bounding Max", Float) = 1.0
    11.         _boundingMin("Bounding Min", Float) = 1.0
    12.         _numOfFrames("Number Of Frames", int) = 240
    13.         _speed("Speed", Float) = 0.33
    14.         [MaterialToggle] _pack_normal ("Pack Normal", Float) = 0
    15.         _posTex ("Position Map (RGB)", 2D) = "white" {}
    16.         _nTex ("Normal Map (RGB)", 2D) = "grey" {}
    17.         _colorTex ("Colour Map (RGB)", 2D) = "white" {}
    18.     }
    19.     SubShader {
    20.         Tags { "RenderType"="Opaque" }
    21.         LOD 200
    22.    
    23.         CGPROGRAM
    24.         // Physically based Standard lighting model, and enable shadows on all light types
    25.         #pragma surface surf Standard addshadow vertex:vert
    26.  
    27.         // Use shader model 3.0 target, to get nicer looking lighting
    28.         #pragma target 3.0
    29.  
    30.         sampler2D _MainTex;
    31.         sampler2D _posTex;
    32.         sampler2D _nTex;
    33.         sampler2D _colorTex;
    34.         uniform float _pack_normal;
    35.         uniform float _boundingMax;
    36.         uniform float _boundingMin;
    37.         uniform float _speed;
    38.         uniform int _numOfFrames;
    39.  
    40.         struct Input {
    41.             float2 uv_MainTex;
    42.             float4 vcolor : COLOR ;
    43.         };
    44.  
    45.         half _Glossiness;
    46.         half _Metallic;
    47.         fixed4 _Color;
    48.  
    49.         // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
    50.         // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
    51.         // #pragma instancing_options assumeuniformscaling
    52.         UNITY_INSTANCING_CBUFFER_START(Props)
    53.             // put more per-instance properties here
    54.         UNITY_INSTANCING_CBUFFER_END
    55.  
    56.         //vertex function
    57.         void vert(inout appdata_full v){
    58.             //calculate uv coordinates
    59.             float timeInFrames = ((ceil(frac(-_Time.y * _speed) * _numOfFrames))/_numOfFrames) + (1.0/_numOfFrames);
    60.        
    61.             //get position, normal and colour from textures
    62.             float4 texturePos = tex2Dlod(_posTex,float4(v.texcoord.x, (timeInFrames + v.texcoord.y), 0, 0));
    63.             float3 textureN = tex2Dlod(_nTex,float4(v.texcoord.x, (timeInFrames + v.texcoord.y), 0, 0));
    64.             float3 textureCd = tex2Dlod(_colorTex,float4(v.texcoord.x, (timeInFrames + v.texcoord.y), 0, 0));
    65.  
    66.             //expand normalised position texture values to world space
    67.             float expand = _boundingMax - _boundingMin;
    68.             texturePos.xyz *= expand;
    69.             texturePos.xyz += _boundingMin;
    70.             texturePos.x *= -1;  //flipped to account for right-handedness of unity
    71.             v.vertex.xyz = texturePos.xzy;  //swizzle y and z because textures are exported with z-up
    72.  
    73.             //calculate normal
    74.             if (_pack_normal){
    75.                 //decode float to float2
    76.                 float alpha = texturePos.w * 1023;
    77.                 float2 f2;
    78.                 f2.x = floor(alpha / 32.0) / 31.0;
    79.                 f2.y = (alpha - (floor(alpha / 32.0)*32.0)) / 31.0;
    80.  
    81.                 //decode float2 to float3
    82.                 float3 f3;
    83.                 f2 *= 4;
    84.                 f2 -= 2;
    85.                 float f2dot = dot(f2,f2);
    86.                 f3.xy = sqrt(1 - (f2dot/4.0)) * f2;
    87.                 f3.z = 1 - (f2dot/2.0);
    88.                 f3 = clamp(f3, -1.0, 1.0);
    89.                 f3 = f3.xzy;
    90.                 f3.x *= -1;
    91.                 v.normal = f3;
    92.             } else {
    93.                 textureN = textureN.xzy;
    94.                 textureN *= 2;
    95.                 textureN -= 1;
    96.                 textureN.x *= -1;
    97.                 v.normal = textureN;
    98.             }
    99.  
    100.             //set vertex colour
    101.             v.color.rgb = textureCd;
    102.         }
    103.  
    104.         void surf (Input IN, inout SurfaceOutputStandard o) {
    105.             // Albedo comes from a texture tinted by color
    106.             fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    107.             o.Albedo = c.rgb * IN.vcolor.rgb;  //multiply existing albedo map by vertex colour
    108.             // Metallic and smoothness come from slider variables
    109.             o.Metallic = _Metallic;
    110.             o.Smoothness = _Glossiness;
    111.             o.Alpha = c.a;
    112.         }
    113.         ENDCG
    114.     }
    115.     FallBack "Diffuse"
    116. }
    117.  
    and here is the 2nd vert frag shader (water basic)
    Code (csharp):
    1.  
    2. // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
    3.  
    4. Shader "FX/Water (Basic)" {
    5. Properties {
    6.     _horizonColor ("Horizon color", COLOR)  = ( .172 , .463 , .435 , 0)
    7.     _WaveScale ("Wave scale", Range (0.02,0.15)) = .07
    8.     [NoScaleOffset] _ColorControl ("Reflective color (RGB) fresnel (A) ", 2D) = "" { }
    9.     [NoScaleOffset] _BumpMap ("Waves Normalmap ", 2D) = "" { }
    10.     WaveSpeed ("Wave speed (map1 x,y; map2 x,y)", Vector) = (19,9,-16,-7)
    11.     }
    12.  
    13. CGINCLUDE
    14.  
    15. #include "UnityCG.cginc"
    16.  
    17. uniform float4 _horizonColor;
    18.  
    19. uniform float4 WaveSpeed;
    20. uniform float _WaveScale;
    21. uniform float4 _WaveOffset;
    22.  
    23. struct appdata {
    24.     float4 vertex : POSITION;
    25.     float3 normal : NORMAL;
    26. };
    27.  
    28. struct v2f {
    29.     float4 pos : SV_POSITION;
    30.     float2 bumpuv[2] : TEXCOORD0;
    31.     float3 viewDir : TEXCOORD2;
    32.     UNITY_FOG_COORDS(3)
    33. };
    34.  
    35. v2f vert(appdata v)
    36. {
    37.     v2f o;
    38.     float4 s;
    39.  
    40.     o.pos = UnityObjectToClipPos(v.vertex);
    41.  
    42.     // scroll bump waves
    43.     float4 temp;
    44.     float4 wpos = mul (unity_ObjectToWorld, v.vertex);
    45.     temp.xyzw = wpos.xzxz * _WaveScale + _WaveOffset;
    46.     o.bumpuv[0] = temp.xy * float2(.4, .45);
    47.     o.bumpuv[1] = temp.wz;
    48.  
    49.     // object space view direction
    50.     o.viewDir.xzy = normalize( WorldSpaceViewDir(v.vertex) );
    51.  
    52.     UNITY_TRANSFER_FOG(o,o.pos);
    53.     return o;
    54. }
    55.  
    56. ENDCG
    57.  
    58.  
    59. Subshader {
    60.     Tags { "RenderType"="Opaque" }
    61.     Pass {
    62.  
    63. CGPROGRAM
    64. #pragma vertex vert
    65. #pragma fragment frag
    66. #pragma multi_compile_fog
    67.  
    68. sampler2D _BumpMap;
    69. sampler2D _ColorControl;
    70.  
    71. half4 frag( v2f i ) : COLOR
    72. {
    73.     half3 bump1 = UnpackNormal(tex2D( _BumpMap, i.bumpuv[0] )).rgb;
    74.     half3 bump2 = UnpackNormal(tex2D( _BumpMap, i.bumpuv[1] )).rgb;
    75.     half3 bump = (bump1 + bump2) * 0.5;
    76.  
    77.     half fresnel = dot( i.viewDir, bump );
    78.     half4 water = tex2D( _ColorControl, float2(fresnel,fresnel) );
    79.  
    80.     half4 col;
    81.     col.rgb = lerp( water.rgb, _horizonColor.rgb, water.a );
    82.     col.a = _horizonColor.a;
    83.  
    84.     UNITY_APPLY_FOG(i.fogCoord, col);
    85.     return col;
    86. }
    87. ENDCG
    88.     }
    89. }
    90.  
    91. }
    92.  
     
    Last edited: Aug 29, 2017
  2. Fabian-Haquin

    Fabian-Haquin

    Joined:
    Dec 3, 2012
    Posts:
    231
    What is your problem exactly ? You just can't figure out how to merge them ? On what are you blocking ?
     
  3. eco_bach

    eco_bach

    Joined:
    Jul 8, 2013
    Posts:
    1,601
    see revised question.Yes. Not sure how to merge. If its simply a matter of copy paste then what takes precedence?
     
    Last edited: Aug 29, 2017
  4. Fabian-Haquin

    Fabian-Haquin

    Joined:
    Dec 3, 2012
    Posts:
    231
    In a classic shader vert/frag, the vertex shader have an input and an output.
    Code (CSharp):
    1. v2f vert(appdata v)
    appdata is the input and v2f is the output sent to the fragment shader.

    In the surface shader, appdata_full is the input and your class named INPUT is the output of the vertex shader but the input of the surface shader. (confusing isn't ?)
    Wait it's not finished, appdata_full is ALSO THE OUTPUT, but for your fragment shader.
    Code (CSharp):
    1. void vert(inout appdata_full v){
    The problem here is you don't fill the INPUT in your vertex shader. see theses examples: https://docs.unity3d.com/Manual/SL-SurfaceShaderExamples.html

    In summary, in the vertex shader of your surface shader, you can use INPUT to send something to the surf function and appdata_full for the fragment shader.

    In your surface shader, the fragment shader is hided in this line:
    Code (CSharp):
    1. #pragma surface surf Standard addshadow vertex:vert
    The Standard word is the lighting method used, therefore the fragment shader used.

    The Standard lighting for surface shader can be found in UnityPBSLighting.cginc but you may not need it anyway.

    The way you should merge this depend of what your surface shader does.
    I would try to remove the content of the vertex shader in your surface shader and first try to adapt the water vertex shader in it then add your own features.

    You must dig a bit and understand what both vertex shaders does if you want to merge it.

    The thing you should understand is the input class is filled with the mesh datas (POSITION keyword is the local position of the vertex, TEXCOORD0 is the UV0 coordinate, COLOR is the vertex color...).

    The thing is, it's just a keyword to tell "fill me this with theses datas" but what you do after is your own business.

    You can have
    Code (CSharp):
    1. float3 vertexWorldPosition : TEXCOORD3
    At first, vertexWorldPosition will contains the UV3 of the mesh if there is one, otherwise the values will be 0 and you change theses values to be the vertex world position by transforming the vertex local position with the builtin matrix _Object2World. (Then you can use is in the fragment shader for lighting or another purpose...).

    Unity created the surface shaders to ease the creation of shaders but it get really more complicated for an advanced usage than a classic vert/frag shader.

    Tell me if there is something not clear.
     
    Last edited: Aug 29, 2017
  5. eco_bach

    eco_bach

    Joined:
    Jul 8, 2013
    Posts:
    1,601
    jacksonkr likes this.
  6. Fabian-Haquin

    Fabian-Haquin

    Joined:
    Dec 3, 2012
    Posts:
    231