linearizing the depth in vertex shader

please refer to http://www.mvps.org/directx/articles/linear_z/linearz.htm

When using a programmable vertex shader, we have direct control of the transformation process, and can implement our own.  Vertex position can be read from the input registers, manipulated however we like, then output as a 4D homogenous coordinate to the output position register.  However, there is one apparent problem at handling our linearity issue: the output from the shader is still homogenous, and will be divided in the same manner as the output from the fixed pipeline transformation would be.  So how do we handle this, if we can't eliminate the division operation? 

The answer is actually pretty simple - just multiply Z by W prior to returning the result from the vertex shader.  The net effect is that Z*W/W = Z!  If we first divide Z by the far distance, to scale it to the range of 0.0 -> 1.0, we've got a linear result that will survive perspective division.  A simple HLSL implementation might look (in part) something like this:

float4 vPos = mul(Input.Pos,worldViewProj);
vPos.z = vPos.z * vPos.w / Far;
Output.Pos = vPos;

To simplify this, instead of needing to divide by the far plane distance to scale Z, we could instead scale the values in the Z column of the projection matrix we use:

D3DXMATRIX mProj;
D3DXMatrixPerspectiveFovLH(&mProj,fFov,fNear,fFar);
mProj._33/=fFar;
mProj._43/=fFar;
//...set to shader constant register or concatenate
//...with world and view matrices first as needed

This reduces the vertex shader transformation to:

float4 vPos = mul(Input.Pos,worldViewProj);
vPos.z = vPos.z * vPos.w;
Output.Pos = vPos;

posted on 2013-07-11 13:07  不吃鱼的猫  阅读(343)  评论(0编辑  收藏  举报