Search Unity

Graphics.DrawMeshNow + VR Single Pass Stereo

Discussion in 'General Graphics' started by SunnySunshine, Jul 18, 2019.

  1. SunnySunshine

    SunnySunshine

    Joined:
    May 18, 2009
    Posts:
    671
    I want to draw a mesh from the viewpoint of a specific camera into a render texture using Graphics.DrawMeshNow(). I've managed to get this working when rendering to regular render texture (non-VR). However, when targeting VR render texture using Single Pass Stereo, I can't seem to figure out how to set it up properly for the mesh to be rendered into the render texture correctly.

    Same goes when rendering using CommandBuffers. They work fine if using some event like AfterForwardOpaque, but when using events like AfterDepthNormalsTexture, stereo will not be set up and the render texture will be incorrectly written.

    Does anyone have any experience of this?
     
  2. richardkettlewell

    richardkettlewell

    Unity Technologies

    Joined:
    Sep 9, 2015
    Posts:
    1,145
    What shader are you using?

    I suspect it’s a path we’ve never used/tested in unity..
     
  3. robinb-u3d

    robinb-u3d

    Unity Technologies

    Joined:
    Jul 13, 2015
    Posts:
    18
    So for that exact case the AfterDepthNormalsTexture event I can see that it looks like we exit single pass stereo just before we trigger the command buffer call. I'm not sure if this would be regarded as a bug or not, the XR team would probably need to look into it. You could file a bug report if you want them to investigate this issue.

    In the meantime it looks like in Unity 2019.1 we added https://docs.unity3d.com/ScriptReference/Rendering.CommandBuffer.SetSinglePassStereo.html which sounds like it should allow you to enable single pass stereo in those callbacks where it doesn't work. You may also need to enable the correct shader pass as well. You would then need to turn it off yourself if you enable it and you would only want to do this in callbacks where it doesn't currently work for you to avoid accidentally turning off Stereo when you do want it enabled.

    For SRP land there is https://docs.unity3d.com/ScriptReference/Rendering.ScriptableRenderContext.StartMultiEye.html that provides a neater way of dropping in and out of stereo.
     
    richardkettlewell likes this.
  4. SunnySunshine

    SunnySunshine

    Joined:
    May 18, 2009
    Posts:
    671
    I'm using custom shaders in forward rendering in built-in pipeline. There's two problems these shaders solve:

    1. I'm using Graphics.DrawMeshNow() to render a custom depth texture. This depth texture is then used together with a GrabPass by an opaque object to fake transparency, while still retaining shadow support (receiving). This works fine in non-VR.

    I just discovered yesterday though that it somehow seemed to work sampling a depth texture while writing into it at the same time when using forward rendering, so maybe this whole step is unnecessary. Will have to have another look at that. Regardless, it would be nice to know how to use Graphics.DrawMeshNow() with single pass stereo. :)

    2. I'm offseting vertices in my shader, which means the internal DepthNormals shader ("Hidden/Internal-DepthNormalsTexture") will not match up with my shader. Therefore I made my own which uses command buffers. This works fine in non-VR.

    That seems exactly what I'm looking for! I'll have a look at that later today.
     
    Last edited: Jul 19, 2019
    richardkettlewell likes this.
  5. SunnySunshine

    SunnySunshine

    Joined:
    May 18, 2009
    Posts:
    671
    Nevermind. It seems like what I did here was use an unlit (fragment) shader, that doesn't write into the depth texture since it doesn't have a shadow caster pass. As soon as I added "Diffuse" fallback, this would not work anymore. So I still need to have a way to draw a custom depth texture for VR using Graphics.DrawMeshNow().
     
  6. SunnySunshine

    SunnySunshine

    Joined:
    May 18, 2009
    Posts:
    671
    I can confirm using commandBuffer.SetSinglePassStereo(SinglePassStereoMode.SideBySide) works perfectly! Object is now rendered on both sides. :)

    So my only problem left is how to make Graphics.DrawMeshNow() do something similar to CommadBuffer.SetSinglePassStereo. Or, if not possible, how to make two invocations to Graphics.DrawMeshNow() with the correct parameters.

    BTW. I had a lot of trouble setting up drawing mesh from a specific camrea, but I discovered this undocumented function which seems to work really well for this. Doesn't work with VR though!

    Code (CSharp):
    1. //Just an example...
    2. var mat = new Material(Shader.Find("Standard"));
    3. mat.SetPass(0);
    4. Camera.SetupCurrent(Camera.main); // This function is undocumented, but using it will properly set up matrices for mesh to be rendered from the viewpoint of the camera.
    5. Graphics.SetRenderTarget(someRenderTexture);
    6. GL.Clear(true, true, Color.black);
    7. Graphics.DrawMeshNow(someMesh, Matrix4x4.identity);
     
    Last edited: Jul 19, 2019
    richardkettlewell likes this.
  7. SunnySunshine

    SunnySunshine

    Joined:
    May 18, 2009
    Posts:
    671
    Ah, naturally I can use a command buffer for this instead. No need for Graphics.DrawMeshNow(). Just tested this and it works fine. :)

    Would still be cool if Graphics.DrawMeshNow() was able to render in stereo, but as far as my problems are concerned, I'm all good using command buffers!