Search Unity

Question GPU Instancing: Getting Colour of Background at Bottom of Mesh

Discussion in 'General Graphics' started by soiledparsley, Jul 12, 2021.

  1. soiledparsley

    soiledparsley

    Joined:
    Jun 17, 2021
    Posts:
    2
    Hey,

    This is my first time posting, I'm working on a shader for grass that takes on the base colour of the terrain that it is sitting on. My grass is created using a bunch of 8x8 sprites instantiated on start. My terrain has a simple toon shader applied to it. I have it working without instancing/batching. Right now for my grass shader I:
    • use a grab pass to get background texture
    • use positionBottomMiddle = UnityObjectToClipPos(float4(0.5,0,0,1)) to get bottom middle position of grass
    • then use ComputeScreenPos(positionBottomMiddle) to get that position on the screen
    • then I can get uv coordinates and sample the background texture
    This works fine without instancing. So now I am trying to speed things up by using gpu instancing. I moved the grabpass to a different game object and sample that texture instead. From the frame debug I can see that the background texture sampled has not changed. However, now my grass is a singular colour. I believe this has something to do with instancing and each blade of grass using the same position because when I output the positionBottomMiddle with instancing enabled it is all the same colour.

    This is how my scene looks without instancing:
    upload_2021-7-12_16-1-25.png

    And then when I enable instancing the grass is all the same colour:
    upload_2021-7-12_16-2-2.png

    So i'm wondering what I can do to fix this position issue. I am also open to feedback in other approaches I can take to get this effect in a performant way. I have been searching around for some time now for other options. One alternative is to pass the depth and normal data to the grass shader and shade the grass the same way the terrain is shaded. I might try that if this doesn't pan out.

    Shader code for getting grabpass data:
    Code (Boo):
    1. Shader "Custom/GrabPassTrick"
    2. {
    3.     Properties
    4.     {}
    5.  
    6.     SubShader
    7.     {
    8.         Tags { "Queue" = "Transparent" }
    9.  
    10.         Cull Off
    11.         Lighting Off
    12.         ZWrite Off
    13.         Blend SrcAlpha OneMinusSrcAlpha
    14.  
    15.         GrabPass
    16.         {
    17.             "_TerrainGrab"
    18.         }
    19.  
    20.         Pass
    21.         {
    22.         CGPROGRAM
    23.             #pragma vertex vert
    24.             #pragma fragment frag
    25.  
    26.             float4 vert(void) : SV_POSITION
    27.             {
    28.                 return (0.0).xxxx;
    29.             }
    30.  
    31.             float4 frag(void) : COLOR
    32.             {
    33.                 return (0.0).xxxx;
    34.             }
    35.         ENDCG
    36.         }
    37.     }
    38. }
    Grass shader code (uncommenting the grabpass section on line 12 will disable instancing/batching):
    Code (Boo):
    1. Shader "Custom/GrassShader" {
    2.     Properties{
    3.         _MainTex ("Texture", 2D) = "white" {}
    4.     }
    5.  
    6.     SubShader
    7.     {
    8.         // Draw after all opaque geometry
    9.         Tags { "Queue" = "Transparent" }
    10.  
    11.         // Grab the screen behind the object into _BackgroundTexture
    12.         // GrabPass
    13.         // {
    14.         //     "_BackgroundTexture"
    15.         // }
    16.  
    17.         Blend SrcAlpha OneMinusSrcAlpha
    18.         Lighting Off
    19.         ZWrite Off
    20.         Cull Off
    21.  
    22.         // Render the object with the texture generated above, and invert the colors
    23.         Pass
    24.         {
    25.             CGPROGRAM
    26.             // Upgrade NOTE: excluded shader from DX11; has structs without semantics (struct v2f members worldPos,objectPos)
    27.             #pragma exclude_renderers d3d11
    28.             #pragma vertex vert
    29.             #pragma fragment frag
    30.             #pragma multi_compile_instancing
    31.             #include "UnityCG.cginc"
    32.  
    33.             sampler2D _MainTex;
    34.             //This comes from GrabPass shader and material to get this once
    35.             sampler2D _TerrainGrab;
    36.             sampler2D _BackgroundTexture;
    37.             float4 _MainTex_ST;
    38.  
    39.  
    40.             //the object data that's put into the vertex shader
    41.             struct appdata{
    42.                 float4 vertex : POSITION;
    43.                 float2 uv : TEXCOORD0;
    44.                 UNITY_VERTEX_INPUT_INSTANCE_ID
    45.             };
    46.  
    47.             //the data that's used to generate fragments and can be read by the fragment shader
    48.             struct v2f{
    49.                 float4 position : SV_POSITION;
    50.                 float2 uv : TEXCOORD0;
    51.                 float4 vertex : TEXCOORD3;
    52.                 float4 screenPos : TEXCOORD1;
    53.                 float4 objPos : TEXCOORD2;
    54.                 UNITY_VERTEX_INPUT_INSTANCE_ID
    55.             };
    56.  
    57.             //using this to hold pixel data
    58.             struct pixel{
    59.                 float depth;
    60.                 float3 normal;
    61.             };
    62.  
    63.             //the vertex shader
    64.             v2f vert(appdata v){
    65.                 v2f o;
    66.  
    67.                 UNITY_SETUP_INSTANCE_ID(v);
    68.                 UNITY_TRANSFER_INSTANCE_ID(v, o);
    69.                 //convert the vertex positions from object space to clip space so they can be rendered
    70.                 o.vertex = v.vertex;
    71.                 o.position = UnityObjectToClipPos(v.vertex);
    72.                 o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    73.                 // o.uv = v.uv;
    74.  
    75.                 // o.position = UnityObjectToClipPos(v.vertex);
    76.                 float4 positionBottomMiddle = UnityObjectToClipPos(float4(0.5,0,0,1));
    77.                 // positionBottomMiddle = UnityObjectToClipPos(v.vertex);
    78.  
    79.                 // use ComputeGrabScreenPos function from UnityCG.cginc
    80.                 // to get the correct texture coordinate
    81.                 o.screenPos = ComputeScreenPos(positionBottomMiddle);
    82.                 // o.screenPos = positionBottomMiddle;
    83.  
    84.                 // o.objPos = mul(unity_ObjectToWorld, v.vertex);
    85.                 // o.objPos = mul(unity_ObjectToWorld, float4(0,0,0,1));
    86.  
    87.                 o.objPos = v.vertex;
    88.                 o.objPos = mul(unity_WorldToObject, o.objPos);
    89.  
    90.                 // float3 worldPos = mul(unity_ObjectToWorld, float4(v.vertex.xyz, 1)).xyz;
    91.                 // float3 playerToVertexVec = worldPos - _PlayerPos.xyz;
    92.                 // float3 playerToVertexDir = normalize(playerToVertexVec);
    93.                 // float playerToVertexDist = length(playerToVertexVec);
    94.                 // worldPos += playerToVertexDir * (1 - saturate(playerToVertexDist / _BendRange)) * _BendStrength;
    95.                 // o.objPos = float4(worldPos, 1);
    96.  
    97.                 return o;
    98.              
    99.             }
    100.  
    101.             // sampler2D _BackgroundTexture;
    102.  
    103.             half4 frag(v2f i) : SV_Target
    104.             {
    105.                 UNITY_SETUP_INSTANCE_ID(i);
    106.                 // half4 bgcolor = tex2Dproj(_TerrainGrab, float4(i.grabPos.x,i.grabPos.y,i.grabPos.z,i.grabPos.a));
    107.                 // Linear01
    108.                 float2 uv = i.screenPos.xy / i.screenPos.w;
    109.                 // uv = trunc(uv);
    110.  
    111.                 float4 bgcolor = tex2D(_TerrainGrab, uv);
    112.                 // bgcolor = tex2D(_BackgroundTexture, uv);
    113.                 bgcolor.a = bgcolor.a * tex2D(_MainTex, i.uv).a;
    114.                 // return float4(uv,0,1);
    115.                 // return i.vertex;
    116.                 // return float4(i.position.rgb*0.01,1);
    117.                 // return i.screenPos;
    118.                 // return float4()
    119.                 return bgcolor;
    120.              
    121.             }
    122.             ENDCG
    123.         }
    124.  
    125.     }
    126. }
    Also some additional images... If I enable instancing the grass position is all the same:
    upload_2021-7-12_16-8-55.png

    Without instancing it is as expected.
    upload_2021-7-12_16-9-23.png
     
    Last edited: Jul 12, 2021