投影转换 (Direct3D 9)

可以将投影转换视为控制相机的内部;这类似于为相机选择镜头。 这是三种转换类型中最复杂的。 投影转换的这一讨论组织为以下主题。

投影矩阵通常是缩放和透视投影。 投影转换将查看 frustum 转换为立方体形状。 由于视锥的近端小于远端,因此它具有扩展靠近相机的对象的效果:这是如何将透视应用于场景。

观看 frustum中,相机与观看转换空间的原点之间的距离任意定义为 D,因此投影矩阵如下图所示。

投影矩阵插图

查看矩阵通过向 z 方向翻译 -D 将相机转换为原点。翻译矩阵如下图所示。

翻译矩阵插图

将转换矩阵乘以投影矩阵(T*P),可提供复合投影矩阵,如下图所示。

复合投影矩阵插图

透视转换将查看 frustum 转换为新的坐标空间。 请注意,frustum 变为小熊体,并且原点从场景右上角移动到中心,如下图所示。

关系图,说明透视如何将视锥转换为新的坐标空间

在透视转换中,x 方向和 y 方向的限制 -1 和 1。 z 方向的限制是前平面的 0,后平面为 1。

此矩阵基于从相机到接近剪裁平面的指定距离转换和缩放对象,但它不考虑视场(fov),并且它为距离中的对象生成的 z 值可能几乎相同,使得深度比较变得困难。 以下矩阵解决了这些问题,并调整顶点以考虑视区纵横比,使其成为透视投影的一个不错的选择。

透视投影插图

在此矩阵中,Zn 是接近剪裁平面的 z 值。 变量 w、h 和 Q 具有以下含义。 请注意,fovw 和 fovk 以弧度表示视区的水平和垂直视图字段。

变量的 公式的含义

对于应用程序,使用视场角度定义 x 和 y 缩放系数可能不如使用视口的水平和垂直尺寸(在相机空间中)那么方便。 随着数学的计算结果,w 和 h 的以下两个公式使用视区的尺寸,并且等效于前面的公式。

w 和 h 变量的 公式的含义

在这些公式中,Zn 表示接近剪裁平面的位置,Vw 和 Vh 变量表示视区的宽度和高度(以相机空间为单位)。

对于C++应用程序,这两个维度直接对应于 D3DVIEWPORT9 结构的 Width 和 Height 成员。

无论你决定使用哪种公式,请务必将 Zn 设置为尽可能大的一个值,因为与相机非常接近的 z 值不会变化很大。 这使得使用 16 位 z 缓冲区进行深度比较有点复杂。

与世界和视图转换一样,调用 IDirect3DDevice9::SetTransform 方法来设置投影转换。

设置投影矩阵

以下 ProjectionMatrix 示例函数设置前后剪裁平面以及视图角度的水平和垂直字段。 视图字段应小于 pi 弧度。

D3DXMATRIX 
ProjectionMatrix(const float near_plane, // Distance to near clipping 
                                         // plane
                 const float far_plane,  // Distance to far clipping 
                                         // plane
                 const float fov_horiz,  // Horizontal field of view 
                                         // angle, in radians
                 const float fov_vert)   // Vertical field of view 
                                         // angle, in radians
{
    float    h, w, Q;

    w = (float)1/tan(fov_horiz*0.5);  // 1/tan(x) == cot(x)
    h = (float)1/tan(fov_vert*0.5);   // 1/tan(x) == cot(x)
    Q = far_plane/(far_plane - near_plane);

    D3DXMATRIX ret;
    ZeroMemory(&ret, sizeof(ret));

    ret(0, 0) = w;
    ret(1, 1) = h;
    ret(2, 2) = Q;
    ret(3, 2) = -Q*near_plane;
    ret(2, 3) = 1;
    return ret;
}   // End of ProjectionMatrix

创建矩阵后,使用 IDirect3DDevice9::SetTransform 指定D3DTS_PROJECTION对其进行设置。

D3DX 实用工具库提供以下函数来帮助设置投影矩阵。

W 友好投影矩阵

Direct3D 可以使用由世界、视图和投影矩阵转换的顶点的 w 分量来执行深度缓冲区或雾效果的基于深度的计算。 此类计算要求投影矩阵规范化 w 等效于 world-space z。 简言之,如果投影矩阵包含非 1 的 (3,4) 系数,则必须按 (3,4) 系数的反转来缩放所有系数,才能生成正确的矩阵。 如果未提供兼容的矩阵,则无法正确应用雾效果和深度缓冲。

下图显示了一个不相容的投影矩阵,并缩放了相同的矩阵,以便启用眼睛相对雾。

不相容投影矩阵和具有眼睛相对雾的矩阵的插图

在前面的矩阵中,所有变量都假定为非零。 有关眼睛相对雾的详细信息,请参阅 Eye-Relative 与基于 Z 的深度。 有关基于 w 的深度缓冲的信息,请参阅 深度缓冲区(Direct3D 9)

Direct3D 在其基于 w 的深度计算中使用当前设置的投影矩阵。 因此,应用程序必须设置合规的投影矩阵才能接收所需的基于 w 的功能,即使它们不使用 Direct3D 进行转换也是如此。

转换