Position From Depth(3)一点补充

现在对第二篇文章最后的算法进行更详尽描述,涉及到D3D的不同坐标空间切换,前面说到:

 

 

一块硬件深度缓冲存储的是Post-Projection后的Z值除以Post-Projection后的W值,W等于视图空间表面position的Z分量,不明白看如下链接:

http://www.sjbaker.org/steve/omniv/love_your_z_buffer.html(可能需要墙一下)

     一块硬件深度缓冲存储的是Post-Projection后的Z值除以Post-Projection后的W值,W等于视图空间表面position的Z分量。这个值不怎么适合我们用,但幸运的是,我们可以从这个使用perspective projection(透视投影)的参数中重建view-space的Z。如果我们这样做,并且想要它是规范化的,可以将它转换成一个规范化的深度值,但这并不是必要的。我们可以计算出View ray到远裁剪平面,如果我们不是clamp它到的Z = 1的平面,就可以缩放视点空间的Z轴,而不需要一开始就操纵它。请看以下代码:// Light vertex shader #if PointLight || SpotLight // Calculate the view space vertex position output.PositionVS = mul(input.PositionOS, WorldViewMatrix); #elif DirectionalLight // 方向光在VS里面clamp, 因为我们是在XY方向上进行插值的 float3 positionVS = mul(input.PositionOS, InvProjMatrix); output.ViewRay = float3(positionVS.xy / positionVS.z, 1.0f); #endif // Light Pixel shader #if PointLight || SpotLight // Clamp the view space position to the plane at Z = 1 float3 viewRay = float3(input.PositionVS.xy / input.PositionVS.z, 1.0f); #elif DirectionalLight // For a directional light we already clamped in the vertex shader float3 viewRay = input.ViewRay.xyz; #endif // Calculate our projection constants (you should of course do this in the app code, I'm just showing how to do it) ProjectionA = FarClipDistance / (FarClipDistance - NearClipDistance); ProjectionB = (-FarClipDistance * NearClipDistance) / (FarClipDistance - NearClipDistance); // Sample the depth and convert to linear view space Z (assume it gets sampled as // a floating point value of the range [0,1]) float depth = DepthTexture.Sample(PointSampler, texCoord).x; float linearDepth = ProjectionB / (depth - ProjectionA); float3 positionVS = viewRay * linearDepth;  

 

我们先说说视图变换:

D3DXMATRIX *WINAPI D3DXMatrixLookAtLH(          D3DXMATRIX *pOut,
    CONST D3DXVECTOR3 *pEye,
    CONST D3DXVECTOR3 *pAt,
    CONST D3DXVECTOR3 *pUp
);
这个函数用来控制摄影机,用来控制视图矩阵的。
pEye眼睛的位置,观察的方向。
pAt是摄影机的前进和后退,向左或向右。向上或向下。

pUp是向上的方向。公式如下:

zaxis = normal(At - Eye) :Direction
xaxis = normal(cross(Up, zaxis)) :Right
yaxis = cross(zaxis, xaxis) : Up
 xaxis.x           yaxis.x           zaxis.x          0
 xaxis.y           yaxis.y           zaxis.y          0
 xaxis.z           yaxis.z           zaxis.z          0
-dot(xaxis, eye) -dot(yaxis, eye) -dot(zaxis, eye) 1
因此WorldMat * ViewMat 后的点P(x,y,z,1)的Z = X * zaxis.x + Y * zaxis.y  + zaxis.z  * Z - dot(zaxis, eye)
我们再看看Post-Projection的过程:

用下面的方法来计算左手坐标系透视投影矩阵:

xScale     0          0               0
0        yScale       0               0
0          0       zf/(zf-zn)         1
0          0       -zn*zf/(zf-zn)     0
其中:
yScale = cot(fovY/2)
xScale = aspect ratio * yScale

此时WorldMat * ViewMat *ProjectMat  此时的W = WorldMat * ViewMat 的Z

 

这个方法只是做解释,其实我们用的是:

The Resolution of Z.

z_buffer_value 为深度缓冲的值
  z_buffer_value = (1<<N) * ( a + b / z )

  Where:

     N = number of bits of Z precision
     a = zFar / ( zFar - zNear )
     b = zFar * zNear / ( zNear - zFar )
     z = distance from the eye to the object (视图空间的Z值)
  ...and z_buffer_value is an integer.
于是有 b/ (Z >> N  - a)大家动了吧。


你可能感兴趣的:(Position From Depth(3)一点补充)