Custom shader doesn't support GPU Instancing for XR app

I have a shader that I’m using in a Hololens 2 project, but I’m realising now that it’s only rendered on one side because it doesn’t support GPU instancing. I have no experience with shaders, but I tried to adjust it as described in the fragment shader example from this page:

This didn’t work though, the objects are still only visible on one eye, but twice with a slight offset.
Can someone help me with that?
Here’s the shader with the adjustments:

Shader "MyShader"
{
    Properties
    {
        ....
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" "Queue"="Transparent"}
        LOD 100
     
        Pass
        {
            zwrite off
            blend one one
            cull off
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #pragma multi_compile SCAN2_OFF SCAN2_ON
            ...
         
            struct appdata
            {
                float4 vertex : POSITION;
                float4 normal : NORMAL;
                float4 color : COLOR;
                float2 uv_main : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
            };
            struct v2f
            {
                float4 vertex : SV_POSITION;
                float4 color : COLOR;
                float2 uv_main : TEXCOORD0;
                float2 scanlines_uv : TEXCOORD1;
                float2 scan2_uv : TEXCOORD2;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };
UNITY_INSTANCING_BUFFER_START(Props)
                UNITY_DEFINE_INSTANCED_PROP(float4, _Color)
                UNITY_DEFINE_INSTANCED_PROP(float4, _RimColor)
                UNITY_DEFINE_INSTANCED_PROP(float4, _MainTex_ST)
                UNITY_DEFINE_INSTANCED_PROP(float4, _Scanlines_ST)
                UNITY_DEFINE_INSTANCED_PROP(float4, _Scan2_ST)
            UNITY_INSTANCING_BUFFER_END(Props)

            v2f vert (appdata v)
            {
                v2f o;
                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_TRANSFER_INSTANCE_ID(v, o);
                ...
                return o;
            }
            fixed4 frag (v2f i) : SV_Target
            {
    UNITY_SETUP_INSTANCE_ID(i);
                fixed4 main = tex2D(_MainTex, i.uv_main) * _Brightness;
                ...
              return UNITY_ACCESS_INSTANCED_PROP(Props, main * max(pri,msk) * rim * fixed4(0.5,0.5,0.5,0.5));
            }
            ENDCG
        }
    }
    CustomEditor "MyShaderGUI"
}

I am guessing you use single pass instanced for VR (best performance for VR rendering)?
If so, add support for that: Unity - Manual: Single-pass instanced rendering and custom shaders

I’m using unity 2022.1, that option isn’t available there.
Edit: In the OpenXR settings I can switch between Single Pass Instanced and Multi Pass, but it doesn’t seem to work. I think it’s a shader problem.

Then it will still use single pass instancing. It’s the standard for all modern VR apps

So it’s a problem with the shader as I assumed. When I use built-in materials, they get rendered correctly on both eyes.

Yep, you can add support according to the guide

I already tried that as you can see in the code above, but it only makes the objects appear twice on one eye with a slight offset.

I never see UNITY_VERTEX_OUTPUT_STEREO mentioned in it. Am I overlooking something?

1 Like