Is Single Pass Stereo rendering supported for RenderTextures?

I’m trying to manually render a VR camera into a double-wide RenderTexture the same way that the main camera would render with VR enabled. I don’t see any documentation stating that this isn’t supported, but it doesn’t appear to work. I upgraded to Unity 2017.1.03f because RenderTextureDescriptor.vrUsage seemed promising, but it doesn’t seem to do anything. The camera always renders just one eye. Here’s a snippet I’m using to test this:

using UnityEngine;
using UnityEngine.VR;

public class StereoTest : MonoBehaviour {
    private Camera m_Camera;

    void Awake() {
        m_Camera = GetComponent<Camera>();

        RenderTextureDescriptor desc = new RenderTextureDescriptor(
            VRSettings.eyeTextureWidth * 2,
            VRSettings.eyeTextureHeight,
            RenderTextureFormat.Default,
            24);
        desc.vrUsage = VRTextureUsage.TwoEyes;
        RenderTexture texture = new RenderTexture(desc);
        texture.name = "Stereo RenderTexture";
        texture.Create();
        m_Camera.targetTexture = texture;
    }

    void LateUpdate() {
        // Tested enabling UNITY_SINGLE_PASS_STEREO because it wasn't being set by the camera.
        // Shader.EnableKeyword("UNITY_SINGLE_PASS_STEREO");
        m_Camera.Render();
        // Shader.DisableKeyword("UNITY_SINGLE_PASS_STEREO");
    }
}

I’ve still not been able to find an answer to this. Not sure what else I can try here.

I was also unable to find an answer to this problem.

My solution was to create a left and right render textures seperately and combine them together into one large render texture using Graphics.Blit. The texture you blit onto must be twice the width as your left and right texture.

C# Code

//Merge Left Right Texture into Stereo Texture
RenderTexture lastActive = RenderTexture.active;
Graphics.Blit(m_TextureLeft, m_Texture, material, 0);
Graphics.Blit(m_TextureRight, m_Texture, material, 1);
RenderTexture.active = lastActive;

Blit Shader

Shader "Nekativ/StereoAppend" {
    Properties {
        _MainTex ("", 2D) = "white" {}
    }
    CGINCLUDE
    #include "UnityCG.cginc"
 
    sampler2D _MainTex;

    struct v2f
    {
        float4 vertex : SV_POSITION;
        float2 uv : TEXCOORD0;
    };
 
    v2f vert (appdata_base v)
    {
        v2f o;
        o.vertex = UnityObjectToClipPos(v.vertex);
        o.uv = v.texcoord;
        return o;
    }
 
    ENDCG
    SubShader {
        ZTest Always Cull Off ZWrite Off
   
        //Blit Left
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
       
            fixed4 frag (v2f i) : SV_Target
            {
                clip(0.5 - i.uv.x);
                fixed4 c = tex2D(_MainTex, float2(i.uv.x*2, i.uv.y));
                return c;
            }
            ENDCG
        }
   
        //Blit Right
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
       
            fixed4 frag (v2f i) : SV_Target
            {
                clip(i.uv.x-0.5);
                fixed4 c = tex2D(_MainTex, float2(i.uv.x*2-1, i.uv.y));
                return c;
            }
            ENDCG
        }

    }
    FallBack "Diffuse"
}

Thank you for the response Nekative!

I will likely go a similar route to what you have done, but I was also hoping to harness the performance benefits of single pass stereo. If one of the Unity devs could chime in on whether or not this is supposed to be supported, that would be lovely. And if it’s not meant to be supported, what is the purpose of RenderTextureDescriptor.vrUsage?

2 Likes

This is a bug / limitation in Unity currently. Only cameras that render without Camera.Render support single pass stereo. Seems odd, but it is what it is.

I’m experiencing this same issue, trying to render a mask with a separate camera but no matter how I try and wrangle it, it doesn’t work. Hopefully it’s fixed soon

It seems that this is still not fixed. What is the point of the RenderTextureDescriptor.vrUsage flag if it doesn’t do anything? Whenever a camera’s targetTexture is set to a RenderTexture, it will return stereoEnabled false, regardless of the vrUsage flag on the RenderTexture. This basically makes it impossible to implement single-pass stereo reflections and other effects.

1 Like

Still no fix.

Anyone trying to reproduce this bug:

public class cam_test : MonoBehaviour {

    RenderTexture clientRenderTexture;
    private Camera CAM;

    // Use this for initialization
    void Start () {
        CAM = this.GetComponent<Camera>();
        clientRenderTexture = new RenderTexture(XRSettings.eyeTextureDesc);
        Debug.Log("XR loaded sdk - " + XRSettings.loadedDeviceName + " -- " + XRSettings.isDeviceActive);
        clientRenderTexture.vrUsage = VRTextureUsage.TwoEyes;
        //CAM.targetTexture = clientRenderTexture;
    }
  
    // Update is called once per frame
    void Update () {
        // To capture Render Texture
        if (Input.GetKeyDown("x")) {
            Texture2D s = toTexture2D(clientRenderTexture);
            File.WriteAllBytes(Application.dataPath + "/SavedScreen.png", s.EncodeToPNG());
        }
    }
    Texture2D toTexture2D(RenderTexture rTex)
    {
        Texture2D tex = new Texture2D(clientRenderTexture.width*2, clientRenderTexture.height, TextureFormat.RGB24, false);
        RenderTexture.active = rTex;
        tex.ReadPixels(new Rect(0, 0, rTex.width, rTex.height), 0, 0);
        tex.Apply();
        return tex;
    }
  
    private void OnPreRender()
    {
        Debug.Log("eye - " + CAM.stereoActiveEye);

    }
}

The above code should keep logging “eye - left” in single pass stereo.
eye - left” followed by “eye - right” in multi pass stereo.

uncommenting the following line:

 //CAM.targetTexture = clientRenderTexture;

will start logging “eye - mono”.

Clearly the rendertexture breaks the stereo render mode of the camera.

Interestingly, if you enable HDR on the camera it renders two of the same mono output side by side… idk whats that about…

Tested on Unity 2018.1 and 2018.3

Hope this helps!

Figured I’d bump this as I’m having the same problem. Would love to have this implemented!

I to have this problem while working on a custom bloom effect, any image effect with multiple passes dosnt seam to work and the documentation Unity - Manual: Single-pass stereo rendering for Android dosnt cover it at all.

[push]
Problem still exist. That sucks @ :frowning:

The problem still exist…

Still the case… almost 3 years after…

1 Like

Was attempting to migrate form multi-pass to single-pass since the WMR plugin now only supports single-pass, same problem. Camera.Render() should use the same rendering properties (single-pass stereo) but will only render the left eye, no matter the “targetEye”

I’ve been trying to get my reflections in VR to render in a single-pass too. Then I found this thread.
It’s so dissapointing that this doesn’t work.
Is there anything we can do to encourage this to be possible?

Also having this issue. Anyone figured out how to set target texture and have our camera render both eyes to this texture?

Same issue here! Where do we vote to get this finally fixed? I multi-view render-textures so we can finally implement portals on quest without reverting to slow multi-pass rendering

3 Likes

Issuetracker is now listing the bugreport I had submitted a while ago.

Feel free to vote.

This is not an issue anymore. I don’t have time now to write complete guides but you can definitely do postprocessing effects in single pass stere on quest 1 and 2. It differs based on unity version if you are using universal render pipeline as Unity is deprecating command buffer blit. The way you define render textures is fine, you probably have not used
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
in your shader codes. Just keep reading the documentation and or pull some of unity made postprocessing effects for guidelines.

2 Likes

And don’t follow old tutorials on this stuff as a lot has changed in the last 3 years.