[d3d11/Instancing] Syntax error when using instancing

Hi,
I need to use hardware instancing to draw a 3D representation of a path. I want each instance of a 3D arrow to be drawn with a given color.
I set up my shader with a gradient texture and each instance is adding a normalized value in a uniform array.

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

Shader "Instanced/UnlitInstanced" {
    Properties {
        _gradient("_gradient", 2D) = "white" {}
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_instancing
            #include "UnityCG.cginc"
            struct appdata
            {
                float4 vertex : POSITION;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            v2f vert(appdata v)
            {
                v2f o;

                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_TRANSFER_INSTANCE_ID(v, o);

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

            sampler2D _gradient;
            float4 _gradient_ST;
            uniform float _colorId[8];

            fixed4 frag(v2f i) : SV_Target
            {
                //UNITY_SETUP_INSTANCE_ID(i);
                float grad = _colorId[UNITY_VERTEX_INPUT_INSTANCE_ID];
                fixed4 col = tex2D(_gradient, float2(grad, 0.0f));
                return col;
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

I get an error on d3d11 at line 47:

  • Why do I get this error?
  • Is the UNITY_SETUP_INSTANCE_ID(i); needed since I use UNITY_TRANSFER_INSTANCE_ID(v, o); in the vertex shader (this does not fix the error btw).

Thanks,
JNQ.

Because UNITY_VERTEX_INPUT_INSTANCE_ID is a macro:
// Used in vertex shader input / output struct.
#define UNITY_VERTEX_INPUT_INSTANCE_ID uint instanceID : SV_InstanceID;

So line 47 is turning into:
float grad = _colorId[uint instancedID : SV_InstanceID;];

And that won’t work at all for multiple reasons. It’s not even actually for the variable you actually want to use either, that’s unity_InstanceID.

Instead you’ll want something like this:

fixed4 frag(v2f i) : SV_Target
{
    // if instancing, this sets up unity_InstanceID, otherwise it does nothing
    UNITY_SETUP_INSTANCE_ID(i);
#if defined(UNITY_INSTANCING_ENABLED)
    // if instancing, use the unity_InstanceID to look up into the color ID array
    float grad = _colorId[unity_InstanceID];
#else
    // if not instancing, just set the value to 0.0 to prevent compiler errors
    float grad = 0.0;
#endif
    ...

edit: Some notes. As of the writing of this Unity’s documentation for 5.5 and 5.6 instancing is still showing 5.4’s information, and they changed a lot of this in 5.5. Also unless you’re drawing the instances manually using Graphics.DrawMeshInstanced() the order of the arrow instances might change on you. You might be better off using per-instanced material properties instead of trying to piggyback off of the instance id, and that part of the documentation is still correct and hasn’t changed for 5.5.

Hey!
Thanks for the answer. I’m using Graphics.DrawMeshInstanced() because I don’t want to have to setup multiple property blocks (and I knew I wanted to keep the order).
One thing that throw me off is the fact that unity is replacing the macro with UNITY_VERTEX_INPUT_INSTANCE_ID…

Thanks,
JNQ

Because Unity changed some of their macro names between Unity 5.4 and 5.5 (and I think again in 5.6). Download the built in shader source for 5.4 and 5.5 and compare the UnityInstancing.cginc (I think that’s the file name).

Unity often tweaks naming conventions in the shaders and auto-upgrades users’ shader files on editor load. They also tend to be 2 or 3 versions late to actually update the documentation to reflect those changes. For example their 5.6 documentation still lists _Object2World as the object to world space matrix, but that changed to unity_ObjectToWorld in 5.4. The shader documentation is a good starting point, but it’s always useful to dig into the shader code itself to double check.