[EDIT] Sorry, somehow the title was cut off. This question is about Procedural Drawing on single-pass (multi-instance) stereo Hello! I'm trying to use purely procedural rendering (without a mesh, generating triangles in a geom shader on-the-fly based on a data buffer) in single-pass stereo with Direct3D. However, the rendering only works on the left eye. The right eye is empty. In the shader, use the UNITY_SETUP_INSTANCE_ID / UNITY_TRANSFER_INSTANCE_ID / UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO macros [1,2]. If I change the shader to render a mesh instead, then it works on both eyes. Also, in multi-pass stereo, both eyes are rendered correctly. So I believe that the problem is in the way the draw call is made. I tried using CommandBuffer.DrawProcedural() and CommandBuffer.DrawProceduralIndirect(), and for both functions I tried setting the instance count to either 1 or 2. I also tried CommandBuffer.SetInstanceMultiplier() to double the number of instances. But it always only renders on the left eye, never on the right. This is both in the Editor (with MockHMD) and on the Hololens, and happens in both Unity 2020.1 and Unity2020.2. Is there something I'm missing? Is there a working example on how to use procedural drawing in single-pass stereo? Thanks in advance for any hint. [1] https://docs.unity3d.com/2020.2/Documentation/Manual/SinglePassStereoRenderingHoloLens.html [2] https://forum.unity.com/threads/is-...ing-with-geometry-shader.898070/#post-5928629
UPDATE: After downgrading to Unity 2019.4 the shader renders on both eyes in the Unity Editor, so it might be a bug in Unity2020. But on the Hololens it still only renders on the left eye. I've tested this even with a sample project ( https://github.com/keijiro/NoiseBall3 ) and this too renders fine in the Editor in Unity2019, but on the Hololens and in Unity2020 Editor only renders on the left eye. Interestingly, there are shadow rendering artifacts visible on the right eye as well (if I remove the shadow rendering in Graphics.DrawProcedural(), the artifacts disappear), so it seems the shader is rendered but the fragment color does not end up in the image. I could not find any difference in graphics settings.
I managed to get Graphics.DrawProceduralIndirect() to work in 2019.4 with single pass instancing by setting the number of instances in the args buffer to 2, and then in the shader something like this: Code (CSharp): struct Attributes { uint vertexID : SV_VertexID; UNITY_VERTEX_INPUT_INSTANCE_ID }; // The order that triangles are defined in my compute shader struct Triangle { float3 vertices[3]; float3 normals[3]; }; // Append buffer containing output of compute shader StructuredBuffer<Triangle> _Triangles; // This structure for vertex output struct VertexOutput { float3 positionWS : TEXCOORD0; // Position in world space float3 normalWS : TEXCOORD1; // Normal vector in world space float4 positionCS : SV_POSITION; // Position in clip space UNITY_VERTEX_OUTPUT_STEREO }; VertexOutput Vert(Attributes input) { VertexOutput output = (VertexOutput)0; UNITY_SETUP_INSTANCE_ID(input); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); Triangle tri = _Triangles[input.vertexID / 3]; float3 vert = tri.vertices[input.vertexID % 3]; float3 norm = tri.normals[input.vertexID % 3]; output.positionWS = vert; output.normalWS = norm; // Apply shadow caster logic to the CS position output.positionCS = TransformWorldToHClip(vert, norm); return output;
Hello, I am quite happy to have found this post, I have almost exactly the same problem. Trying to use DrawProceduralIndirect with VR in single-stereo-instanced mode, on an Oculus Rift S. I can confirm that it only renders in the left eye within the Oculus and the Unity Mock HMD, in Unity 2020.2.1f1 (HDRP 10.2.2). I tried all the macros about instancing and stereo -> no change. I tried to double the number of instanceCount in the indirect args buffer, but all it did was to render my geometry two times in the left eye... After seeing this post, I tried Unity 2020.3.0f1, with HDRP 10.3.2. Now I have SHADOWS in the right eye, and all the rendering in the left. That is some progress I will try other HDRP versions in this version of Unity and the alpha/beta of the next versions. I will post any findings. FYI, in my shaders, I only do a simple vertex shader that extracts the input vertex data from the compute buffers I filled previously, and pass it all the VertMesh() functions of every pass. In this case, all I should have to do is give the AttributeMesh struct the instance_ID of my vertex shader, and the rest of the HDRP pipeline calls all the stereo/instance macros.
I tried with 2 other version of Unity/HDRP: 2021.1.0b12, HDRP 11.0.0 2021.2.0a9, HDRP 12.0.0 In both cases, Multi Draw is working, but Single Pass Instanced is not (only left eye). I would really like to know if I am doing something wrong, or if it is a bug and we just have to wait. On top of that, the viewport and the left eye are flickering (alternate render and black screen). I guess that may be coming from my shaders. Indirect rendering can mess things up UPDATE: Tested the 2019.4.22f1, HDRP 7.5.3. Same problem in the Oculus in Single Pass Instanced. Multi ok. And no flickering in scene view. That's way too many versions in which it does not work for it to be a Unity bug. Something must be missing in our meddling with HDRP.
Hi again. I managed to make it work!! FYI, this is what I had to add in order for it to work. This is my vertex shader, sourcing vertices from the compute buffer, and calling HDRP VertMesh for a number of passes (shadowcaster, depth_only, gbuffer and forward): Code (CSharp): PackedVaryingsMeshToPS GrassVert(VertexShaderInput input) { // 1) EXTRACT info from the ComputeBuffer. DrawTriangle tri = _DrawTriangles[input.vertexID / 3]; DrawVertex vertex = tri.vertices[input.vertexID % 3]; float3 positionRWS = GetCameraRelativePositionWS(vertex.positionWS); // 2) CALL the HDRP vertex shader with the extracted info. AttributesMesh inputMesh = (AttributesMesh)0; inputMesh.positionOS = TransformWorldToObject(positionRWS); #if defined(ATTRIBUTES_NEED_NORMAL) inputMesh.normalOS = ...; #endif #if defined(ATTRIBUTES_NEED_TANGENT) inputMesh.tangentOS = ...; #endif #if defined(ATTRIBUTES_NEED_TEXCOORD0) inputMesh.uv0 = float4(vertex.uv, 0, 0); #endif UNITY_TRANSFER_INSTANCE_ID(input, inputMesh); // copy .instanceID from input to output VaryingsMeshToPS varyingsType = VertMesh(inputMesh); // VertMesh already does: //UNITY_SETUP_INSTANCE_ID(input); // setup "unity_InstanceID" and "unity_StereoIndex" from input.instanceID //UNITY_TRANSFER_INSTANCE_ID(input, output); // copy .instanceID from input(AttributeMesh) to output(VaryingsMeshToPS) // THIS IS WHAT I HAD TO ADD, HERE. UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(varyingsType); // output.stereoTargetEyeIndexAsRTArrayIdx = unity_StereoEyeIndex // 3) PACK the result for the rest of the HDRP Pipeline. PackedVaryingsMeshToPS packed = PackVaryingsMeshToPS(varyingsType); // Fragment shader does this: // UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(packedInput); // unity_StereoEyeIndex = input.stereoTargetEyeIndexAsRTArrayIdx; return packed; } So I had to add that macro, and add the missing struct variable to every input/output struct (and call a macro inside the Pack/Unpack generated functions), like this: Code (CSharp): struct VaryingsMeshToPS { float4 positionCS : SV_POSITION; #if UNITY_ANY_INSTANCING_ENABLED uint instanceID : CUSTOM_INSTANCE_ID; UNITY_VERTEX_OUTPUT_STEREO // <--- THIS #endif }; struct PackedVaryingsMeshToPS { float4 positionCS : SV_POSITION; #if UNITY_ANY_INSTANCING_ENABLED uint instanceID : CUSTOM_INSTANCE_ID; UNITY_VERTEX_OUTPUT_STEREO // <--- THIS #endif }; PackedVaryingsMeshToPS PackVaryingsMeshToPS (VaryingsMeshToPS input) { PackedVaryingsMeshToPS output; output.positionCS = input.positionCS; #if UNITY_ANY_INSTANCING_ENABLED output.instanceID = input.instanceID; UNITY_TRANSFER_VERTEX_OUTPUT_STEREO(input, output); // <--- THIS #endif return output; } VaryingsMeshToPS UnpackVaryingsMeshToPS (PackedVaryingsMeshToPS input) { VaryingsMeshToPS output; output.positionCS = input.positionCS; #if UNITY_ANY_INSTANCING_ENABLED output.instanceID = input.instanceID; UNITY_TRANSFER_VERTEX_OUTPUT_STEREO(input, output); // <--- THIS #endif return output; } For some reasons, I thought that the struct were good, and the original Vert/Frag shaders did all the required plumbing. After all, when you directly use a generated shader from a shadergraph, it works in VR. So this is my solution, it requires more editing of the generated shader, but it works in 2020.2. I hope this helps.
Hello! I tried your solution, but it doesn't work. And I'm using URP, do you think it cause this? Code (CSharp): struct Attributes { uint vertexID : SV_VERTEXID; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct v2f { float4 pos : SV_POSITION; float4 worldPos : TEXCOORD0; float4 normal : TEXCOORD1; float4 shadowCoord : TEXCOORD2; float fogCoord : TEXCOORD3; float2 uv : TEXCOORD4; half1 color : TEXCOORD5; #ifdef LIGHTMAP_ON half4 texcoord1 : TEXCOORD6; #endif UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO }; struct DrawVertex{ //info in world space float3 objpos; float color; float4 positionWS; float4 normalOS; float4 normalWS; float2 uv; }; struct DrawTriangle{ DrawVertex vertices[3]; }; StructuredBuffer<DrawTriangle> drawTriangles; v2f vert(Attributes input) { UNITY_SETUP_INSTANCE_ID(input); v2f o; DrawTriangle tri = drawTriangles[input.vertexID / 3]; DrawVertex i = tri.vertices[input.vertexID % 3]; VertexPositionInputs vertexInput = GetVertexPositionInputs(i.objpos); o.worldPos = i.positionWS; o.color = i.color; o.normal = i.normalWS; o.pos = TransformWorldToHClip(o.worldPos); o.uv = i.uv; o.shadowCoord = GetShadowCoord(vertexInput); o.fogCoord = ComputeFogFactor(o.pos.z); UNITY_TRANSFER_INSTANCE_ID(input,o); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); return o; }