Search Unity

Screen space vertex coordinates not quite right in VR

Discussion in 'Shaders' started by JoePatrick, Jun 11, 2019.

  1. JoePatrick

    JoePatrick

    Joined:
    Nov 3, 2013
    Posts:
    121
    Hi

    So I am working on updating my seamless portals for VR and I'm coming across an issue where the shader is not quite right and I think it has something to do with converting vertex positions into screen space - probably because of the multiple cameras or something.

    This is what it looks like (left eye)


    And here is what the preview looks like - this is how it's supposed to look



    And here's my shader (note that there is some stuff for masking out the image but that isn't relevent to the issue so just ignore that stuff)

    Code (CSharp):
    1. Shader "Custom/Seamless Portal" {
    2.     Properties{
    3.          _MainTex("Render Texture", 2D) = "white" {}
    4.         _MaskTex("Portal Mask", 2D) = "white" {}
    5.         _BGTex("Masked Background Texture", 2D) = "white" {}
    6.         _TexLight("Enable Mask Background Lighting", Int) = 0
    7.     }
    8.  
    9.     SubShader{
    10.         LOD 250
    11.         Pass{
    12.             Tags {"LightMode"="ForwardBase"}
    13.             CGPROGRAM
    14.  
    15.                 #pragma vertex vert
    16.                 #pragma fragment frag
    17.  
    18.                 #include "unitycg.cginc"
    19.                 #include "UnityLightingCommon.cginc"
    20.  
    21.                 sampler2D _MainTex;
    22.  
    23.                 sampler2D _MaskTex;
    24.                 float4 _MaskTex_ST;
    25.  
    26.                 sampler2D _BGTex;
    27.                 float4 _BGTex_ST;
    28.  
    29.                 int _TexLight;
    30.  
    31.                 struct VertInput {
    32.                     float4 vertex : POSITION;
    33.                     float3 normal : NORMAL;
    34.                     float2 uvM : TEXCOORD0;
    35.                     float2 uvBG : TEXCOORD1;
    36.                 };
    37.  
    38.                 struct VertOutput {
    39.                     float4 vertex : SV_POSITION;
    40.                     fixed4 diff : COLOR0;
    41.                     float2 uvM : TEXCOORD0;
    42.                     float2 uvBG : TEXCOORD1;
    43.                     Vector screenPos : TEXCOORD2;
    44.                 };
    45.  
    46.                 VertOutput vert(VertInput i) {
    47.                     VertOutput o;
    48.                     o.vertex = UnityObjectToClipPos(i.vertex);
    49.                     o.uvM = TRANSFORM_TEX(i.uvM,_MaskTex);
    50.                     o.uvBG = TRANSFORM_TEX(i.uvBG,_BGTex);
    51.                     o.screenPos = ComputeScreenPos(o.vertex);
    52.  
    53.                     half3 worldNormal = UnityObjectToWorldNormal(i.normal.xyz);
    54.                     half nl = max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz));
    55.                     o.diff = nl * _LightColor0;
    56.                     o.diff.rgb += ShadeSH9(half4(worldNormal,1));
    57.  
    58.                     return o;
    59.                 }
    60.  
    61.                 half4 frag(VertOutput i) : SV_Target{
    62.                     i.screenPos /= i.screenPos.w;
    63.  
    64.                     //IGNORE THE MULTIPLICATION BY THE MASK TEX
    65.                     float4 tex = tex2D(_MaskTex, i.uvM) * tex2D(_MainTex, float2(i.screenPos.x, i.screenPos.y));
    66.                  
    67.                     ///THIS STUFF IS NOT RELEVENT
    68.                     if(_TexLight == 1)
    69.                         tex += (1-tex2D(_MaskTex, i.uvM)) * tex2D(_BGTex, i.uvBG) * i.diff;
    70.                     else
    71.                         tex += (1-tex2D(_MaskTex, i.uvM)) * tex2D(_BGTex, i.uvBG);
    72.              
    73.                     return tex;
    74.                 }
    75.  
    76.             ENDCG
    77.         }
    78.     }
    79.  
    80. }
    81.  
    Thanks :)
     
  2. mgear

    mgear

    Joined:
    Aug 3, 2010
    Posts:
    9,442
  3. JoePatrick

    JoePatrick

    Joined:
    Nov 3, 2013
    Posts:
    121
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Is the portal camera rendering in stereo? Use the frame debugger and step through rendering. You should be rendering separate views from each eye for the portal. If it’s only rendering one view then it won’t be correct because it’s either rendering from the position of one eye, in which case the other eye will be wrong, or it’s rendering from the original camera position with out eye offsets.
     
  5. JoePatrick

    JoePatrick

    Joined:
    Nov 3, 2013
    Posts:
    121
    Its definitely rendering both eyes and the camera is in the correct positon (see the preview screenshot) its just the shader thays getting the UVs wrong :/
     
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    The preview is showing it as a monoscopic non-vr view, not in stereo. It's not even from the position of an eye offset. It working in the preview window has no bearing on if it works in stereo or not.
     
  7. JoePatrick

    JoePatrick

    Joined:
    Nov 3, 2013
    Posts:
    121
    Yes but that is the left eye camera selected. Both cameras are in the scene, they are both rendering as I can switch between them in the game view, and they are offset as they should be
     
  8. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Again, the camera preview does not take into account any XR specific rendering settings. The left and right eye camera game objects should be placed in the same location, and will use custom projection matrices and offset view positions when rendering to the headset (or the game view, if it’s set to show an eye). The camera preview is showing the view from that camera using the camera’s default projection matrix and position. My guess is however you’re rendering the portal render texture, it’s rendering not using the XR settings, and rendering using the default projection matrix.
     
  9. JoePatrick

    JoePatrick

    Joined:
    Nov 3, 2013
    Posts:
    121
    Sp you're saying the projection matrix for the camera that renders the portal texture is wrong? How would I go about fixing that if you know?
    Thanks
     
  10. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    That depends on how you've set things up. My guess is you have your eye cameras, and either a single additional "portal" camera, or one for each eye, but they're not using the same XR settings as their "parent" camera. If you're following along a non-XR tutorial for doing portals, it's a common technique to make your portal camera a child of the parent camera as it ensures they line up without needed to have additional code to update the portal camera. The problem with this for XR is if you have a camera as a child of another camera and set it to have an eye target, some systems will treat the parent gameobject as the XR root for that camera, meaning that it'll be offset from the "parent".

    Instead, my prefered method is to reuse the actual eye cameras, swapping the cullingMask, setting a targetTexture, and calling Render() on the camera from script during one of the rendering events (like OnRenderImage or OnPreRender), then undo the changes.
     
  11. JoePatrick

    JoePatrick

    Joined:
    Nov 3, 2013
    Posts:
    121
    So I actually wrote this script like 2 years ago and just updating for vr now but I actually don't parent it, I have a script that calculates the position so that it can account for different rotations etc and I am using the actual eye cameras as the reference but I will try doing what you said about reusing the eye camera, that sounds like a good idea.
     
  12. niki_kyl

    niki_kyl

    Joined:
    Dec 15, 2016
    Posts:
    5
    Were you able to solve it? We were running into the same problem as well!
     
  13. JoePatrick

    JoePatrick

    Joined:
    Nov 3, 2013
    Posts:
    121
    Been very busy recently so haven't been able to try it yet so not sure if it works or not
     
  14. matt6pup

    matt6pup

    Joined:
    Sep 14, 2018
    Posts:
    1
    I've also been having this same problem so help would be appreciated.
     
  15. battou

    battou

    Joined:
    Jan 25, 2011
    Posts:
    222
    Also having problem with getting correct screen space position in shader in VR. Any solution?
     
    matt6pup likes this.
  16. battou

    battou

    Joined:
    Jan 25, 2011
    Posts:
    222
    I belive its due to Asymmeric FOV. But I dont know how to compensate for it
     
  17. bruceweir1

    bruceweir1

    Joined:
    Nov 29, 2017
    Posts:
    15
    If it is the same problem that I have been having with screen-space textures in VR, then you need to adjust the screen coordinates.

    This example will create a material with a yellow dot in the centre of the screen which looks correct in VR:


    Shader "Custom/ExperimentalScreenShaderVR"
    {
    Properties
    {
    _MainTex ("Texture", 2D) = "white" {}

    }
    SubShader
    {
    Tags { "RenderType"="Opaque" }
    LOD 100

    Pass
    {
    CGPROGRAM
    #pragma vertex vert
    #pragma fragment frag


    #include "UnityCG.cginc"

    struct appdata
    {
    float4 vertex : POSITION;
    float2 uv : TEXCOORD0;
    };

    struct v2f
    {
    float2 uv : TEXCOORD0;

    float4 vertex : SV_POSITION;
    float4 scrPos : TEXCOORD1;
    };

    sampler2D _MainTex;
    float4 _MainTex_ST;

    v2f vert (appdata v)
    {
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex);

    o.uv = v.uv;

    o.scrPos = UnityObjectToClipPos(v.vertex);
    o.scrPos = ComputeScreenPos(o.scrPos);

    return o;
    }

    fixed4 frag (v2f i) : SV_Target
    {
    float2 screenPosition = i.scrPos.xy/i.scrPos.w;

    //This is the important bit
    if(unity_StereoEyeIndex == 0)
    {
    screenPosition.x -= 0.0275;
    }
    else
    {
    screenPosition.x += 0.0275;
    }


    float2 clipCoords;

    clipCoords.x = (screenPosition.x * 2) - 1;
    clipCoords.y = (screenPosition.y * 2) - 1;


    if(length(clipCoords) < .1)
    {
    return float4(1, 1, 0, 1);
    }
    else
    {
    return float4(0, 0, 0, 1);
    }
    }
    ENDCG
    }
    }
    }

     
    Last edited: Oct 19, 2021
  18. Arclite83

    Arclite83

    Joined:
    Feb 6, 2018
    Posts:
    4
    I tried this but with no luck. I can get a matching camera but when I try to render, it distorts. I have the same thing as the original screen, each eye is offset "in" a bit.

    Any help would be appreciated!
     
  19. Arclite83

    Arclite83

    Joined:
    Feb 6, 2018
    Posts:
    4
    I have it working, the camera alters the aspect and projection matrix multiple times. I'm using a quest 2. For now I simply logged all the camera properties, and experimented with which gave me the eyes I need. It appears the camera changes multiple times in different steps in the life cycle, probably getting overwritten by the hardware.

    Hopefully this helps someone else narrow down their issues. Once I stopped copying the portal camera and made my own, I was able to walk it back to those properties.
     
    Tom-Goethals likes this.