Search Unity

Question Rendering parts of a Render Texture depending on screen position in 2021.3 URP Single Pass Instanced

Discussion in 'Shaders' started by kampmann_rwth, Sep 17, 2022.

  1. kampmann_rwth

    kampmann_rwth

    Joined:
    Mar 19, 2022
    Posts:
    4
    Hey together,

    I am currently trying to implement portals for VR in the URP Editor Version 2021.3.5 with Single Pass Instanced as the Render Mode.
    Oriented on non-VR and former VR implementations I was trying to use Render Textures of the destination Portal view to be displayed on the "source" portal. On the source portal its however necessary to not show the whole Render Texture but only the part of it where the portal is visible on the users screen.
    To achieve this the screen position is calculated in the vertex shader by
    o.screenPos = ComputeScreenPos(o.vertex);
    and this projected (?) by dividing xy by w in the fragment shader.
    The resulting xy position is then simply used to read the corresponding texture position.

    That worked perfectly fine in non-VR and former (I guess) Multi Pass rendering VR versions. For me both eyes however get a weird offset each and don't match at all.
    In an Single Pass rendering without instancing I have seen the usage of
    ComputeNonStereoScreenPos()
    but that had no effect for me and the function is not mentioned in the Instanced documentation anyway.
    I have also tried around with UNITY_DECLARE_SCREENSPACE_TEXTURE() with no effect either.

    Due to the Single Pass documentation I suspect that each eye does not get the full texture, which my supervisor guessed as well. Is there a way in Single Pass Instanced to read from the full texture similar to ComputeNonStereoScreenPos()?
    Or has someone a different idea what the problem might be?

    Thanks upfront!
     
  2. kampmann_rwth

    kampmann_rwth

    Joined:
    Mar 19, 2022
    Posts:
    4
    The problem is solved and the screen position part was not the problem. I used wrong projection matrices for the portal cameras.
     
  3. dexhort

    dexhort

    Joined:
    Dec 18, 2021
    Posts:
    10
    Hi, can you explain what you have done exactly, cause I'm having the exacte same trouble and can't find any solution online.
     
  4. kampmann_rwth

    kampmann_rwth

    Joined:
    Mar 19, 2022
    Posts:
    4
    Hey, as written I have used wrong projection matrices. Unity provides a way to obtain the stereo projection matrices by https://docs.unity3d.com/ScriptReference/Camera.GetStereoProjectionMatrix.html
    Here you can get the corresponding matrices for the left and the right eye, which the portal cameras have to use as well. As example for the left eye camera:
    leftRenderCam.projectionMatrix = Camera.main.GetStereoProjectionMatrix(Camera.StereoscopicEye.Left);


    If I am not wrong, this solved the described problem.
    I actually stoped finalising this approach, but if it does not solve the problem or you have more questions I can try to help nevertheless.
     
  5. dexhort

    dexhort

    Joined:
    Dec 18, 2021
    Posts:
    10
    Thank you for this, I understand a little bit more, but I have another question.

    In your scene, your player eyes are rendered in separate camera ? Or you used a single camera like the default XR origin in Unity 2021.3 ?
    Did you enable stereo rendering ? How ?

    I have already setup the Render mode to single, in both OpenXR and Oculus, but my
    Code (CSharp):
    1. Camera.main.StereoEnabled
    display only false.

    Do I need to setup something more ? (I have already read like 10 times the page about the single Pass stereo rendering, and nothing talk about anything else than the render mode).
     
  6. kampmann_rwth

    kampmann_rwth

    Joined:
    Mar 19, 2022
    Posts:
    4
    So I was using the default XROrigin. The leftRenderCam in my code example stands for the camera that captures the image for portal. To create the depth impression one would expect by a portal I used two cameras that mimic the respective eye. The camera setup worked as follows:


    Code (CSharp):
    1.  
    2. public Material portalMaterial;
    3.  
    4. private bool renderTexturesInitialized = false;
    5.  
    6. private Camera leftRenderCam;
    7. private Camera rightRenderCam;
    8. private RenderTexture leftRenderTexture;
    9. private RenderTexture rightRenderTexture;
    10.  
    11. void Update()
    12.         {
    13.             if (!renderTexturesInitialized && XRSettings.eyeTextureWidth > 0)
    14.             {
    15.                 Debug.Log(XRSettings.eyeTextureWidth + " + " + XRSettings.eyeTextureHeight);
    16.                 leftRenderTexture = new RenderTexture(XRSettings.eyeTextureWidth, XRSettings.eyeTextureHeight, 16);
    17.                 rightRenderTexture = new RenderTexture(XRSettings.eyeTextureWidth, XRSettings.eyeTextureHeight, 16);
    18.  
    19.                 leftRenderCam = new GameObject(gameObject.name + " left render camera", typeof(Camera), typeof(Skybox)).GetComponent<Camera>();
    20.                 leftRenderCam.name = gameObject.name + " left render camera";
    21.                 leftRenderCam.tag = "Untagged";
    22.                 leftRenderCam.targetTexture = leftRenderTexture;
    23.                 leftRenderCam.projectionMatrix = Camera.main.GetStereoProjectionMatrix(Camera.StereoscopicEye.Left);
    24.  
    25.  
    26.                 rightRenderCam = new GameObject(gameObject.name + " right render camera", typeof(Camera), typeof(Skybox)).GetComponent<Camera>();
    27.                 rightRenderCam.name = gameObject.name + " right render camera";
    28.                 rightRenderCam.tag = "Untagged";
    29.                 rightRenderCam.targetTexture = rightRenderTexture;
    30.                 rightRenderCam.projectionMatrix = Camera.main.GetStereoProjectionMatrix(Camera.StereoscopicEye.Right);
    31.  
    32.                 portalMaterial.SetTexture("_LeftEyeTexture", leftRenderTexture);
    33.                 portalMaterial.SetTexture("_RightEyeTexture", rightRenderTexture);
    34.  
    35.                 renderTexturesInitialized = true;
    36.                 Debug.Log("RenderTexture Initialized");
    37.             }
    38.         }
    Note that it is located in the Update function because the XROrigin main camera is not entirely set up in the Start function yet. All portal camera position calculations have to be done in the LateUpdate afterwards to reduce lag, just that you know.
    If I remember correctly
    XRSettings.eyeTextureWidth > 0
    was a hack to determine if the main camera is finally fully initialized.

    The portal material was given from the outside and expected two different textures. It then selected the corresponding texture, depending on the currently rendered eye.
     
  7. dexhort

    dexhort

    Joined:
    Dec 18, 2021
    Posts:
    10
    Thank you so much ! It works perfectly now !
     
    kampmann_rwth likes this.