Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice
  3. Dismiss Notice

DrawMeshInstancedIndirect in VR draws every other mesh in different eyes

Discussion in 'Shaders' started by rasmusreplay, Mar 25, 2022.

  1. rasmusreplay

    rasmusreplay

    Joined:
    Apr 8, 2021
    Posts:
    3
    Hi

    We have recently changed from Unity 2019.3 to 2020.3 at work. This of course required quite a big overhaul of the VR backend to change to OpenXR from using only SteamVR previously. We are only targeting Oculus Quest 2 atm though. As the migration was pretty much done, we realized a problem with the graphics.

    Specifically, we are rendering audience as colored meshes by using Graphics.DrawMeshInstanceIndirect through the Single Pass Instanced renderer mode, and every other audience member is ONLY rendered in the left or right eye respectively. We have run through all of the Single Pass Instanced preps unity advices, but it doesn't help. I posted the shader below, be aware that it also holds some MatCap world space stuff. Also, it works in the MultiPass renderer.


    Code (CSharp):
    1. // Shader is adjusted version of Unity example at: https://docs.unity3d.com/ScriptReference/Graphics.DrawMeshInstancedIndirect.html
    2.  
    3. Shader "Instanced/InstancedShader"
    4. {
    5.     Properties
    6.     {
    7.         _MainTex("Albedo (RGB)", 2D) = "white" {}
    8.         _MatCap("MatCap (RGB)",2D) = "white" {}
    9.         _MovementScalar("Movement Scalar", Range(0.001, 1.0)) = 0.5
    10.     }
    11.         SubShader
    12.         {
    13.             Pass
    14.             {
    15.                 //Tags {"LightMode" = "ForwardBase"}
    16.                 Lighting Off
    17.                 CGPROGRAM
    18.                 #pragma vertex vert
    19.                 #pragma fragment frag
    20.                 #pragma fragmentoption ARB_precision_hint_fastest
    21.                 #pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap novertexlight
    22.                 #pragma target 4.5
    23.  
    24.             #include "UnityCG.cginc"
    25.             #include "UnityLightingCommon.cginc"
    26.  
    27.             sampler2D _MainTex;
    28.             sampler2D _MatCap;
    29.  
    30.         #if SHADER_TARGET >= 45
    31.             StructuredBuffer<float4> positionBuffer;
    32.             StructuredBuffer<int> rotationIndexBuffer;
    33.             StructuredBuffer<float2> sampleIndexBuffer;
    34.             StructuredBuffer<float> newIDBuffer;
    35.         #endif
    36.  
    37.             int mod(int x, int y);
    38.  
    39.             uniform float _MovementScalar;
    40.             float4x4 _RotationMatrices[8];
    41.             float yOffset = 0;
    42.  
    43.             struct appdata
    44.             {
    45.                 float4 vertex : POSITION;
    46.                 float2 texcoord : TEXCOORD0;
    47.                 float3 normal : NORMAL;
    48.                 float3 color : COLOR;
    49.                 UNITY_VERTEX_INPUT_INSTANCE_ID // SinglePassInstancing requirement
    50.             };
    51.  
    52.             struct v2f
    53.             {
    54.                 float4 pos : SV_POSITION;
    55.                 float2 uv : TEXCOORD0;
    56.                 float2 cap : TEXCOORD1;
    57.                 float3 diffuse : TEXCOORD2;
    58.                 float3 color : TEXCOORD3;
    59.                 UNITY_VERTEX_OUTPUT_STEREO // SinglePassInstancing requirement
    60.             };
    61.  
    62.             v2f vert(appdata v, uint instanceID : SV_InstanceID)
    63.             {
    64.                 // Create output variable
    65.                 v2f o;
    66.  
    67.                 UNITY_SETUP_INSTANCE_ID(v); // SinglePassInstancing requirement
    68.                 UNITY_INITIALIZE_OUTPUT(v2f, o); // SinglePassInstancing requirement
    69.                 UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); // SinglePassInstancing requirement
    70.  
    71.                 #if !defined(unity_InstanceID)
    72.                 uint unity_InstanceID = 0;
    73.                 #endif
    74.  
    75.  
    76.                 // Assign positions and rotation matrix from buffer to each individual instance
    77.                 #if SHADER_TARGET >= 45
    78.                     //float newID = newIDBuffer[unity_InstanceID];
    79.                     float4 data = positionBuffer[instanceID];
    80.                     int index = rotationIndexBuffer[instanceID];
    81.                     float4x4 rotationMatrix = _RotationMatrices[index];
    82.                     float2 sampleIndex = sampleIndexBuffer[instanceID];
    83.                 #else
    84.                     float4 data = 0;
    85.                     int index = 0;
    86.                     float4x4 rotationMatrix = 0;
    87.                     float2 sampleIndex = 0;
    88.                 #endif
    89.  
    90.                     // Up and down movement
    91.                     float3 movementVector = float3(0, yOffset + sin(_Time.y) * _MovementScalar, 0);
    92.  
    93.                     // Get localposition for instance
    94.                     float3 localPosition = v.vertex.xyz * data.w;
    95.  
    96.                     // Up and down movement for localposition
    97.                     localPosition += movementVector;
    98.  
    99.                     // Rotate instance
    100.                     localPosition = mul(rotationMatrix, float4(localPosition.xyz,1));
    101.  
    102.                     // Transform position to world space
    103.                     float3 worldPosition = data.xyz + localPosition;
    104.  
    105.  
    106.                     //Transform from world to clip space
    107.                     o.pos = UnityWorldToClipPos(float4(worldPosition, 1.0f));
    108.  
    109.                     //Sample from UVs
    110.                     o.uv = float2(v.texcoord.x + sampleIndex.x, v.texcoord.y + sampleIndex.y) / 2;
    111.  
    112.                     // MatCap vertex calculations
    113.                     float3 worldNorm = mul((float3x3)unity_ObjectToWorld, v.normal);
    114.                     worldNorm = mul(rotationMatrix,float4(worldNorm,1));
    115.  
    116.                     o.cap.xy = worldNorm.xy * 0.5 + 0.5;
    117.  
    118.                     o.color = v.color;
    119.  
    120.                     return o;
    121.                 }
    122.  
    123.             fixed4 frag(v2f i) : SV_Target
    124.             {
    125.                     UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);
    126.  
    127.                     fixed4 tex = tex2D(_MainTex, i.uv);
    128.                     fixed4 output = tex2D(_MatCap, i.cap) * tex * unity_ColorSpaceDouble;
    129.  
    130.                     return output;
    131.                 }
    132.  
    133.             ENDCG
    134.             }
    135.         }
    136. }
    137.  
    Our current theory is that the Single Pass Instance renderer does not communicate with the meshes drawn from DMII and copy them over, as they are ping pong rendered. At least the instanceID are relative to the unity_StereoEyeIndex we found out by downloading the cginc libraries. Hope someone can help <3
     
  2. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Did you ever solve this? We're about to try something similar.
     
  3. thebarryman

    thebarryman

    Joined:
    Nov 22, 2012
    Posts:
    130
    I am not aware of any clean fix to this. What I do is after UNITY_VERTEX_INPUT_INSTANCE_ID in your vertex input struct, put something like

    uint rawInstanceID : SV_InstanceID;

    You will need to double your draw counts and then just divide rawInstanceID by 2 to index into whatever data you are using to render.