unit coordinates are not in -1 and +1 range

In my vertex shader I obtain clip space coordinates of vertexes and pass it to the fragment shader. However if I store clip space coordinates in SV_POSITION, in fragment shader, division by w doesn’t result coordinates in the range of +1,-1. While if I keep them as TEXCOORD1, they are in the range. What is the explanation of this?

    struct v2f
    {
        float2 uv : TEXCOORD0; // texture coordinate
        float4 vertexInClipSpaceTEXCOORD1:TEXCOORD1; // clip space position
        float4 vertexInClipSpace :  SV_POSITION;
    }
//Vertex shader
    v2f vert(appdata v)
    {
        v2f o;
        float4 vertexPositionInWorldSpace = mul(unity_ObjectToWorld, float4(v.vertex.xyz, 1));
        o.vertexInClipSpace = mul(UNITY_MATRIX_VP, vertexPositionInWorldSpace);
        o.vertexInClipSpaceTEXCOORD1= o.vertexInClipSpace;
    }
//Fragment shader
fixed4 frag(v2f i) : SV_Target
{

    float2 signedUV = i.vertexInClipSpace.xy / i.vertexInClipSpace.w;
    if ((signedUV.x) > 1.0 || (signedUV.y) > 1.0 || (signedUV.x) < -1.0 || (signedUV.y) < -1.0)
    {
        return fixed4(0.3, 0.0, 0.0, 1.0);
    }
    else
    {
        return fixed4(0.0, 0.0, 0.3, 1.0);

    }
}

Clip space is in -w to w range, but the value stored in the variable using the SV_POSITION semantic isn’t still in clip space by the time it reaches the fragment shader!

struct v2f { float4 pos : SV_POSITION; }

v2f vert(appdata v) {
v2f o;
// clip space position, this value has xy be in -w to w range
o.pos = UnityObjectToClipPos(v.vertex);
return o;
}

… rasterization occurs, which converts the clip pos into pixel positions …

fixed4 frag(v2f i) : SV_Target {
float2 pos = i.pos.xy / i.pos.w; // gets you something completely weird, because the xy values are now pixel positions! I’m not even sure what w is anymore, might be 1, making the divide useless.
…

The value you get in the fragment shader is actually now what’s referred to as the VPOS. For some platforms accessing the SV_POSITION in the fragment shader will actually cause a compiler error rather than getting the VPOS. This is why you need to pass the clip pos to the fragment shader via a TEXCOORD semantic.

1 Like