# Computing pixel's screen position in a vertex shader: right or wrong?

I am building a deferred rendering engine and I have a question. The article I took the sample code from suggested computing screen position of the pixel as follows:

VertexShaderFunction()
{
...
output.Position = mul(worldViewProj, input.Position);
output.ScreenPosition = output.Position;
}

{
input.ScreenPosition.xy /= input.ScreenPosition.w;
float2 TexCoord = 0.5f * (float2(input.ScreenPosition.x,-input.ScreenPosition.y) + 1);
...
}


The question is what if I compute the position in the vertex shader (which should optimize the performance as VSF is launched significantly less number of times than PSF) would I get the per-vertex lighting insted. Here is how I want to do this:

VertexShaderFunction()
{
...
output.Position = mul(worldViewProj, input.Position);
output.ScreenPosition.xy = output.Position / output.Position.w;
}

{
float2 TexCoord = 0.5f * (float2(input.ScreenPosition.x,-input.ScreenPosition.y) + 1);
...
}


What exactly happens with the data I pass from VS to PS? How exactly is it interpolated? Will it give me the right per-pixel result in this case? I tried launching the game both ways and saw no visual difference. Is my assumption right?

Thanks.

P.S. I am optimizing the point light shader, so I actually pass a sphere geometry into the VS.

Solution:

struct PSInput
{
float2 vPos : VPOS;
};

{
float2 ScrPos = input.vPos*halfPixel*2;

//The correct Screen Space Texture Coordinates.
float2 TexCoord = ScrPos + halfPixel;

//Bonus: getting the world position.
ScrPos = ScrPos*2 - 1;
ScrPos = float2(ScrPos.x, -ScrPos.y);

float4 position;
position.xy = ScrPos;
position.z = depthVal; // Read from the depth map.
position.w = 1.0f;

position = mul(position, InvertViewProjection);
position /= position.w;
}


As you are using hlsl I presume you use DirectX. You can use the input semantic VPOS (DX9) or SV_Position (DX>=10): MSDN - VPOS & SV_POSITION semantics

When you pass the render target resolution reciprocal one mad is sufficient to construct the screen space uv for every type of geometry.

You can not simply do what you proposed as the interpolation does a perspective correction. In SM4 you can deactivate this for a single fragment shader input by setting the interpolation modifier to noperspective: MSDN - InterpolationModifier

I did not use this method but it should work. Using the semantic is the easier and probably equally performant way.

A simple optimization for your code is replacing

float2 TexCoord = 0.5f * (float2(input.ScreenPosition.x,-input.ScreenPosition.y) + 1);


by

float2 TexCoord = 0.5f * float2(input.ScreenPosition.x,-input.ScreenPosition.y) + 0.5f;


this should ensure that a mad instruction is used instead of two seperate instructions.

• I have just read about vPos in another article. Yes this is exactly what I need. I am using XNA -> SM 3.0, so I cannot employ your second suggestion :(. Oct 22, 2013 at 16:53
• Thanks for the non-perspective hint "noperspective". It solved my issue... Feb 1, 2019 at 8:35

I doubt it you will get a optimized gain from this. But to answer your question, that looks a bit funky. rather do it like this :

Setup a quad with the vertex positions from -1 to 1 in xy. In the pixelshader just simply pass the input position as the SV_Position. no need for projection multiplications.

And for uvs, do the following equation.
texCoord = ( input.pos + 1.0f ) * 0.5f;
-1 + 1 -> 0 -> 0 * 0.5 = 0
1 + 1 -> 2 -> 2 * 0.5 = 1
And from there you have the basic 0->1 uvset.

This is super simple and should be super fast to.

• I did not mention that I was optimizing for a point light. I actually pass a sphere geometry to the shader. The directional light shader that does use the quad computes uvs even better than you propose - it set's the quad vertices to 0,1. Oct 22, 2013 at 13:31
• well, it´s depending how you map it i guess. Well, you mention Defferd rendering engine, so i assumed you where asking about the defferd rendering pass. Oct 22, 2013 at 13:35