Adding Instancing Support to Mobile/VertexLit Shader?

Hi,

I tried adding instancing support to the Mobile/VertexLit (Directional Lights Only) by adding this pragma/code:

#pragma multi_compile_instancing

...

UNITY_TRANSFER_INSTANCE_ID (v, o);

and while it has improved the batch count, the improvement is still less than the Standard shader.

STATS (120 GameObjects):
Standard Shader (Instancing Enabled): 10 Batches
Custom Mobile/Vertex-Lit Shader (Instancing Enabled): ~84 Batches
Simplest Instanced Shader (Instancing Enabled): 10 Batches
No instancing enabled: ~157 batches

I’ve tried copying the relevant parts from the example instanced shader with no effect. I have also striped down that example shader as much as possible, to see what parts might be responsible for the lesser batch count.

Is the fog/lightmap settings somehow interferring with my custom mobile/vertexlit variant? I’m guessing not, since the Standard shader has those features yet handles the instancing as well as the simple shader.

Any help would be greatly appreciated!

Here is my Mobile/VertexLit (Directional Lights Only) with instancing added:

Shader "Custom/Mobile/Instanced/VertexLit (Only Directional Lights)" {
    Properties {
        _MainTex ("Base (RGB)", 2D) = "white" {}
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 80

    Pass {
        Name "FORWARD"
        Tags { "LightMode" = "ForwardBase" }

        CGPROGRAM
        #pragma vertex vert_surf
        #pragma fragment frag_surf
        #pragma multi_compile_fwdbase
        #pragma multi_compile_fog
        #pragma multi_compile_instancing
        #include "HLSLSupport.cginc"
        #include "UnityCG.cginc"
        #include "Lighting.cginc"
        #include "AutoLight.cginc"

        inline float3 LightingLambertVS (float3 normal, float3 lightDir)
        {
            fixed diff = max (0, dot (normal, lightDir));           
            return _LightColor0.rgb * diff;
        }

        sampler2D _MainTex;

        struct Input {
            float2 uv_MainTex;
        };

        void surf (Input IN, inout SurfaceOutput o) {
            half4 c = tex2D (_MainTex, IN.uv_MainTex);
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }
        struct v2f_surf {
          float4 pos : SV_POSITION;
          float2 pack0 : TEXCOORD0;
          #ifndef LIGHTMAP_ON
          fixed3 normal : TEXCOORD1;
          #endif
          #ifdef LIGHTMAP_ON
          float2 lmap : TEXCOORD2;
          #endif
          #ifndef LIGHTMAP_ON
          fixed3 vlight : TEXCOORD2;
          #endif
          LIGHTING_COORDS(3,4)
          UNITY_FOG_COORDS(5)
          UNITY_VERTEX_OUTPUT_STEREO
          UNITY_VERTEX_INPUT_INSTANCE_ID
        };
        float4 _MainTex_ST;

        v2f_surf vert_surf (appdata_full v)
        {
            v2f_surf o;
            UNITY_SETUP_INSTANCE_ID(v);
            UNITY_TRANSFER_INSTANCE_ID (v, o);
            UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
            o.pos = UnityObjectToClipPos(v.vertex);
            o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
            #ifdef LIGHTMAP_ON
            o.lmap.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
            #endif
            float3 worldN = UnityObjectToWorldNormal(v.normal);
            #ifndef LIGHTMAP_ON
            o.normal = worldN;
            #endif
            #ifndef LIGHTMAP_ON

            o.vlight = ShadeSH9 (float4(worldN,1.0));
            o.vlight += LightingLambertVS (worldN, _WorldSpaceLightPos0.xyz);

            #endif
            TRANSFER_VERTEX_TO_FRAGMENT(o);
            UNITY_TRANSFER_FOG(o,o.pos);
            return o;
        }

        fixed4 frag_surf (v2f_surf IN) : SV_Target
        {
            Input surfIN;
            surfIN.uv_MainTex = IN.pack0.xy;
            SurfaceOutput o;
            o.Albedo = 0.0;
            o.Emission = 0.0;
            o.Specular = 0.0;
            o.Alpha = 0.0;
            o.Gloss = 0.0;
            #ifndef LIGHTMAP_ON
            o.Normal = IN.normal;
            #else
            o.Normal = 0;
            #endif
            surf (surfIN, o);
            fixed atten = LIGHT_ATTENUATION(IN);
            fixed4 c = 0;
            #ifndef LIGHTMAP_ON
            c.rgb = o.Albedo * IN.vlight * atten;
            #endif
            #ifdef LIGHTMAP_ON
            fixed3 lm = DecodeLightmap (UNITY_SAMPLE_TEX2D(unity_Lightmap, IN.lmap.xy));
            #ifdef SHADOWS_SCREEN
            c.rgb += o.Albedo * min(lm, atten*2);
            #else
            c.rgb += o.Albedo * lm;
            #endif
            c.a = o.Alpha;
            #endif
            UNITY_APPLY_FOG(IN.fogCoord, c);
            UNITY_OPAQUE_ALPHA(c.a);
            return c;
        }

        ENDCG
        }
    }

FallBack "Mobile/VertexLit"
}

Here is the striped-down example instancing shader I am comparing it to:

// Upgrade NOTE: replaced 'UNITY_INSTANCE_ID' with 'UNITY_VERTEX_INPUT_INSTANCE_ID'

Shader "Custom/SimplestInstancedShader"
{
    Properties
    {
        _Color ("Color", Color) = (1, 1, 1, 1)
    }

    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_instancing
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;

                o.vertex = UnityObjectToClipPos (v.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                return (0, 0, 0, 1);
            }
            ENDCG
        }
    }
}

Thank you!

1 Like

Have you fixed it?

1 Like