Search Unity

Gradient Shader breaks on second instance

Discussion in 'Shaders' started by georgi-ivanov, Mar 19, 2017.

  1. georgi-ivanov

    georgi-ivanov

    Joined:
    Oct 13, 2013
    Posts:
    2
    Hi guys,

    I'm writing a gradient shader that lerps between 2 colors over time. It's all fine until I introduce a second instance of an object having a material with this shader. It works as expected in the scene view, but in-game something really weird happens - only one color appears. Also, when moving one of the objects down on the Y axis the second color starts to show.

    What am I missing here? Also, I'm pretty new to writing shaders, is there a better approach?

    Here's the shader itself:
    Code (CSharp):
    1. Shader "Shaders/Gradient Shader"
    2. {
    3.   Properties
    4.   {
    5.     _Color1 ("Color 1", Color) = (1, 1, 1, 1)
    6.     _Color2 ("Color 2", Color) = (0, 0, 0, 0)
    7.   }
    8.   SubShader
    9.   {
    10.     Pass
    11.     {
    12.       CGPROGRAM
    13.       #pragma vertex vert
    14.       #pragma fragment frag
    15.      
    16.       #include "UnityCG.cginc"
    17.  
    18.       struct appdata
    19.       {
    20.         float4 vertex : POSITION;
    21.       };
    22.  
    23.       struct v2f
    24.       {
    25.         float4 vertex : SV_POSITION;
    26.         float wave : PSIZE0;
    27.       };
    28.  
    29.       float4 _Color1;
    30.       float4 _Color2;
    31.      
    32.       v2f vert (appdata v)
    33.       {
    34.         v2f o;
    35.         o.vertex = UnityObjectToClipPos(v.vertex);
    36.         o.wave = (v.vertex.y * (sin(_Time[3]) + 2)) * 2;
    37.  
    38.         return o;
    39.       }
    40.      
    41.       fixed4 frag (v2f i) : SV_Target
    42.       {
    43.         float l = clamp(i.wave, 0 , 1);
    44.         fixed4 col = lerp(_Color1, _Color2, l);
    45.         return col;
    46.       }
    47.       ENDCG
    48.     }
    49.   }
    50. }
    51.  

    Here's how things look when I duplicate the cube object in the scene:
    Nooooo.png Screen Shot 2017-03-19 at 15.54.58.png
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,336
    This is caused by dynamic batching. When a mesh is batched, either dynamically or statically, Unity combines multiple meshes together into a single larger mesh with the vertex locations positioned in works space. So when you just have one object v.vertex.y = 0 is centered on the object, but as soon as you add the second Unity is batching them and v.vertex.y = 0 is now at the center of the world.

    The options are disable batching on the shader, or don't use the vertex position and instead use a mesh with a custom additional UV channel.
    https://docs.unity3d.com/Manual/SL-SubShaderTags.html

    You can also try using an instanced shader.
    https://docs.unity3d.com/Manual/GPUInstancing.html
     
    georgi-ivanov likes this.
  3. georgi-ivanov

    georgi-ivanov

    Joined:
    Oct 13, 2013
    Posts:
    2
    Setting the DisableBatching tag to True worked great, thanks!