Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question Converting clip-space positions to camera texture uv coordinates?

Discussion in 'Shaders' started by Sinterklaas, May 14, 2021.

  1. Sinterklaas

    Sinterklaas

    Joined:
    Jun 6, 2018
    Posts:
    93
    So I'm trying to sample a camera texture in a shader, but I think I'm misunderstanding how clip-space works. From what I've read, clip space goes from -1 to 1 on the xy plane, so it seems to me that converting positions to camera texture uvs is a simple matter of converting to a 0 to 1 range. However, this does not appear to be the case?

    If my assumption is correct, I'd expect the following shader to output correct camera texture uvs:

    Code (CSharp):
    1. Shader "Unlit/ScreenUVs"
    2. {
    3.     SubShader
    4.     {
    5.         Tags { "RenderType" = "Opaque" }
    6.  
    7.         Pass
    8.         {
    9.             CGPROGRAM
    10.             #pragma vertex vert
    11.             #pragma fragment frag
    12.  
    13.             struct VertexData
    14.             {
    15.                 float4 vertex : POSITION;
    16.             };
    17.  
    18.             struct Interpolators
    19.             {
    20.                 float4 pos : SV_POSITION;
    21.                 float3 worldPos : TEXCOORD0;
    22.                 float2 screenUVs : TEXCOORD1;
    23.             };
    24.  
    25.             Interpolators vert(VertexData v)
    26.             {
    27.                 Interpolators i;
    28.                 i.worldPos = mul(unity_ObjectToWorld, v.vertex);
    29.                 i.pos = mul(unity_MatrixVP, float4(i.worldPos, 1));
    30.                 i.screenUVs = i.pos.xy * 0.5 + 0.5;
    31.                 return i;
    32.             }
    33.  
    34.             float4 frag(Interpolators i) : SV_TARGET
    35.             {
    36.                 return float4(i.screenUVs.x, i.screenUVs.y, 0, 1);
    37.             }
    38.             ENDCG
    39.         }
    40.     }
    41. }
    42.  
    Drawing a screen-sized quad results in the picture below. As you can see, the 0 to 1 uv gradient does not extent to the boundaries of the screen, but only exists near the center of the x and y axes.

    So it seems to me that clip space does not exist between -1 and 1 in Unity, but instead extends much further. If this is correct, how could I convert my clip-space positions to camera texture uvs? Or was my initial assumption about clip space correct, and is my math simply off?

     
  2. Sinterklaas

    Sinterklaas

    Joined:
    Jun 6, 2018
    Posts:
    93
    Ok, so I've discovered the solution by complete accident, though I do not understand why this works at all. If I change my vertex shader to:
    Code (CSharp):
    1. Interpolators vert(VertexData v)
    2. {
    3.     Interpolators i;
    4.     i.worldPos = mul(unity_ObjectToWorld, v.vertex);
    5.     i.pos = mul(unity_MatrixVP, float4(i.worldPos, 1));
    6.     i.screenUVs = i.pos.xy / i.pos.w * 0.5 + 0.5;
    7.     return i;
    8. }
    Then the uvs are correct (apart from being y-inverted). Could anyone explain to me what exactly this does and why this is correct? I've noticed that the division is unnecessary when the camera is set to ortographic projection mode, so I'm guessing it has something to do with perspective projections?
     
    Lunastras and eclipse130300 like this.