Search Unity

Shuriken GPU Instancing

Discussion in 'General Graphics' started by ifurkend, Jul 20, 2018.

  1. ifurkend

    ifurkend

    Joined:
    Sep 4, 2012
    Posts:
    350
    I am stuck writing VF shader for Particle System GPU instancing. My shader fetches normal for calculating lighting, bizarrely with the UnityObjectToWorldNormal macro, the normal seems to retain in the local space in fragment shader, but is otherwise OK in vertex shader.

    The following 2 particle systems are mostly identical except for the Enabling GPU Instancing property. They have randomized 3D rotations.

    Diffuse lighting done in vertex shader:
    vertex shader normal.PNG

    Diffuse lighting done in fragment shader:
    frag shader normal.PNG

    Code (CSharp):
    1. Shader "Particle Diffuse"
    2. {
    3.     Properties
    4.     {
    5.         _TintColor ("Tint Color", Color) = (.5,.5,.5,.5)
    6.         _MainTex ("Main Texture", 2D) = "white" {}
    7.     }
    8.    
    9.     SubShader
    10.     {
    11.         Tags { "RenderType"="Opaque" "Queue"="Geometry"}
    12.         LOD 100
    13.         ZWrite On
    14.         ZTest On
    15.         Cull Back
    16.         Lighting Off
    17.         ColorMask RGB
    18.        
    19.         Pass
    20.         {
    21.             CGPROGRAM
    22.             #pragma vertex vert
    23.             #pragma fragment frag
    24.             #pragma multi_compile_particles
    25.             #pragma multi_compile_instancing
    26.             #pragma instancing_options procedural:vertInstancingSetup
    27.            
    28.             #include "UnityCG.cginc"
    29.             #include "Lighting.cginc"
    30.             #include "UnityStandardParticleInstancing.cginc"
    31.  
    32.             struct appdata
    33.             {
    34.                 float4 vertex : POSITION;
    35.                 float3 normal : NORMAL0;
    36.                 float4 color : COLOR;
    37.                 float4 uv : TEXCOORD0;
    38.                 UNITY_VERTEX_INPUT_INSTANCE_ID
    39.             };
    40.  
    41.             struct v2f
    42.             {
    43.                 float4 vertex : SV_POSITION;
    44.                 float4 normal : NORMAL0;
    45.                 float4 color : COLOR;
    46.                 float2 uv : TEXCOORD0;
    47.             };
    48.            
    49.             float4 _TintColor;
    50.             sampler2D _MainTex;
    51.             float4 _MainTex_ST;
    52.            
    53.             float3 Diffuse(float3 normal) {
    54.                 float3 worldNormal = normalize(UnityObjectToWorldNormal(normal));
    55.                 return max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz)) * _LightColor0;
    56.             }
    57.            
    58.             v2f vert (appdata v) {
    59.                 v2f o;
    60.                 UNITY_SETUP_INSTANCE_ID(v);
    61.                
    62.                 o.color = v.color * _TintColor * 2;
    63.                 vertInstancingColor(o.color);
    64.                
    65.                 o.vertex = UnityObjectToClipPos(v.vertex);
    66.                
    67.                 //o.color.rgb += Diffuse(v.normal);
    68.                
    69.                 o.uv.xy = v.uv;
    70.                 vertInstancingUVs(v.uv, o.uv.xy);
    71.                
    72.                 o.normal = float4(v.normal,1);
    73.                
    74.                 return o;
    75.             }
    76.            
    77.             float3 frag (v2f i) : SV_Target {
    78.                 float3 Main2D = tex2D(_MainTex, i.uv).rgb;
    79.                 float3 col = i.color.rgb * Main2D;
    80.                
    81.                 col += Diffuse(i.normal.xyz);
    82.                
    83.                 return col;
    84.             }
    85.             ENDCG
    86.         }
    87.     }
    88. }
    The particle system GPU instancing manual doesn't mention anything special needed to be done to normal. Am I missing something important or is it a bug?
     
  2. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    2,285
    I’m away now so can’t give a precise answer, but, it depends what the UnityObjectToWorldNormal macro does.

    The particle instancing only sets up unity_ObjectToWorld and unity_WorldToObject. You can use those to transform the normal, ensuring that normal.w==0.

    I.e.

    float3 n = mul(o2w, float4(in.normal, 0)).xyz;

    Is it a bug that your way doesn’t work? I don’t know until I can look at that macro in our codebase :)