• Create Account

### #ActualHodgman

Posted 29 May 2013 - 09:02 PM

Why would oDepth be divided by oPos.w automatically?  It uses the TEXCOORD0 semantic, not SV_Position.

The position semantic is special -- it's used by the rasterizer to figure out how all the other values should be interpolated.

i.e. oDepth is divided by oPos.w automatically in-between the vertex and pixel shader, during rasterization/interpolation.
So if in the vertex shader you write "oDepth = oPos.z/oPos.w", then in the pixel shader, oDepth will equal oPos.z/oPos.w/oPos.w.

I had this slightly wrong; what happens in normal usage is that the PS receives:
PS.input.oDepth = interpolate(oPos.z/oPos.w)*interpolate(oPos.w)

if in the vertex shader you write "oDepth = oPos.z/oPos.w", then in the pixel shader you get:
PS.input.oDepth = interpolate(oPos.z/oPos.w/oPos.w)*interpolate(oPos.w)

Say you've got some regular code like this:
VS:
output.pos = mul(...);
output.texcoord = ...
PS:
float color = tex2D( input.texcoord );
The hardware will perform perspective correct interpolation of all your PS-inputs/VS-outputs.
It does this by:
1) At the end of the vertex shader, every interpolant is divided by w.
2) An extra hidden interpolant is created, which holds the value of 1/w.
3) At the start of the pixel shader, every interpolant is divided by the interpolated value of 1/w.

Thanks to the GPU doing this behind the scenes, you get results like in Image A here, otherwise if the GPU didn't do this, you'd get results like in Image B, which looks like PS1 games did...

If you want to disable perspective-correction and see the PS1-esque results for yourself, then at the end of your vertex shader, perform the perspective division yourself (which also sets w to 1, which disables the above 3 steps)
output.position /= output.position.w;//disable hardware perspective correction
If you want to verify that the above 3 steps are what actually happens, then create the hidden "1/w" interpolant yourself and use it in the PS:
VS:
output.texcoord /= output.position.w; // step 1
output.hidden = 1/output.position.w; // step 2
output.position /= output.position.w;//disable hardware perspective correction
PS:
input.texcood /= input.hidden; // step 3
This code should give you the same results as the regular, built-in hardware version... except that doing "output.position /= output.position.w" in the VS can cause the GPU to cause some clipping problems, etc...

However, none of this is necessary. Just use a depth-stencil target instead of a colour target, and don't do anything special to output depth besides just rasterizing triangles as usual and have the hardware write them to the depth buffer.

^This is worth repeating though. If you simply want to output z/w to a texture, then use a depth-stencil target and just let the rasterizer do it all automatically.

### #2Hodgman

Posted 29 May 2013 - 09:00 PM

Why would oDepth be divided by oPos.w automatically?  It uses the TEXCOORD0 semantic, not SV_Position.

The position semantic is special -- it's used by the rasterizer to figure out how all the other values should be interpolated.

i.e. oDepth is divided by oPos.w automatically in-between the vertex and pixel shader, during rasterization/interpolation.
So if in the vertex shader you write "oDepth = oPos.z/oPos.w", then in the pixel shader, oDepth will equal oPos.z/oPos.w/oPos.w.

I had this slightly wrong; what happens in normal usage is that the PS receives:
PS.input.oDepth = interpolate(oPos.z/oPos.w)*interpolate(oPos.w)

if in the vertex shader you write "oDepth = oPos.z/oPos.w", then in the pixel shader you get:
PS.input.oDepth = interpolate(oPos.z/oPos.w/oPos.w)*interpolate(oPos.w)

Say you've got some regular code like this:
VS:
output.pos = mul(...);
output.texcoord = ...
PS:
float color = tex2D( input.tex );
The hardware will perform perspective correct interpolation of all your PS-inputs/VS-outputs.
It does this by:
1) At the end of the vertex shader, every interpolant is divided by w.
2) An extra hidden interpolant is created, which holds the value of 1/w.
3) At the start of the pixel shader, every interpolant is divided by the interpolated value of 1/w.

Thanks to the GPU doing this behind the scenes, you get results like in Image A here, otherwise if the GPU didn't do this, you'd get results like in Image B, which looks like PS1 games did...

If you want to disable perspective-correction and see the PS1-esque results for yourself, then at the end of your vertex shader, perform the perspective division yourself (which also sets w to 1, which disables the above 3 steps)
output.position /= output.position.w;//disable hardware perspective correction
If you want to verify that the above 3 steps are what actually happens, then create the hidden "1/w" interpolant yourself and use it in the PS:
VS:
output.texcoord /= output.position.w; // step 1
output.hidden = 1/output.position.w; // step 2
output.position /= output.position.w;//disable hardware perspective correction
PS:
input.texcood /= input.hidden; // step 3
This code should give you the same results as the regular, built-in hardware version... except that doing "output.position /= output.position.w" in the VS can cause the GPU to cause some clipping problems, etc...

However, none of this is necessary. Just use a depth-stencil target instead of a colour target, and don't do anything special to output depth besides just rasterizing triangles as usual and have the hardware write them to the depth buffer.

^This is worth repeating though. If you simply want to output z/w to a texture, then use a depth-stencil target and just let the rasterizer do it all automatically.

### #1Hodgman

Posted 29 May 2013 - 08:57 PM

Why would oDepth be divided by oPos.w automatically?  It uses the TEXCOORD0 semantic, not SV_Position.

The position semantic is special -- it's used by the rasterizer to figure out how all the other values should be interpolated.

i.e. oDepth is divided by oPos.w automatically in-between the vertex and pixel shader, during rasterization/interpolation.
So if in the vertex shader you write "oDepth = oPos.z/oPos.w", then in the pixel shader, oDepth will equal oPos.z/oPos.w/oPos.w.

I had this slightly wrong; what happens in normal usage is that the PS receives:
PS.input.oDepth = interpolate(oPos.z/oPos.w)*interpolate(oPos.w)

if in the vertex shader you write "oDepth = oPos.z/oPos.w", then in the pixel shader you get:
PS.input.oDepth = interpolate(oPos.z/oPos.w/oPos.w)*interpolate(oPos.w)

Say you've got some regular code like this:

VS:
output.pos = mul(...);
output.texcoord = ...
PS:
float color = tex2D( input.tex );

The hardware will perform perspective correct interpolation of all your PS-inputs/VS-outputs.
It does this by:
* At the end of the vertex shader, every interpolant is divided by w.
* An extra hidden interpolant is created, which holds the value of 1/w.
* At the start of the pixel shader, every interpolant is divided by the interpolated value of 1/w.

Thanks to the GPU doing this behind the scenes, you get results like in Image A here, otherwise if the GPU didn't do this, you'd get results like in Image B, which looks like PS1 games did...

If you want to disable perspective-correction and see the PS1-esque results for yourself, then at the end of your vertex shader, perform the perspective division yourself (which also sets w to 1, which disables the above 3 steps), create the hidden "1/w" interpolant yourself and use it in the PS.

output.position /= output.position.w;//disable hardware perspective correction

If you want to verify that the above 3 steps are what actually happens, then add:

VS:
output.hidden = 1/output.position.w;
output.texcoord /= output.position.w;

output.position /= output.position.w;//disable hardware perspective correction
PS:
input.texcood /= input.hidden;

This code should give you the same results as the regular, built-in hardware version... except that doing "output.position /= output.position.w" in the VS can cause the GPU to cause some clipping problems, etc...

However, none of this is necessary. Just use a depth-stencil target instead of a colour target, and don't do anything special to output depth besides just rasterizing triangles as usual and have the hardware write them to the depth buffer.

^This is worth repeating though. If you simply want to output z/w to a texture, then use a depth-stencil target and just let the rasterizer do it all automatically.

PARTNERS