Direct3D 转换管道
本文为 Direct3D 应用程序开发人员提供了有关如何通过直接操作 Direct3D 矩阵设置 Direct3D 转换管道参数的技术说明。
概述
Direct3D 使用三个转换来将 3D 模型坐标更改为像素坐标(屏幕空间)。 这些转换是世界转换、视图转换和投影转换。
世界转换控制如何将模型坐标转换为世界坐标。 世界转换可以包括平移、旋转和缩放,但它不适用于灯光。 有关使用世界转换的详细信息,请参阅 世界转换。
视图转换控制从世界坐标到“相机空间”的转换,确定相机在世界中的位置。 有关使用视图转换的示例,请参阅 视图转换。
投影转换将几何图形从相机空间更改为“剪辑空间”,并应用透视失真。 术语“剪辑空间”是指在此转换期间如何将几何图形剪裁到视图体积。 有关使用投影转换的示例,请参阅 投影转换。
最后,剪辑空间中的几何图形将转换为像素坐标, (屏幕空间) 。 此转换由视区设置控制。
简单地说,剪裁和转换顶点必须在同源空间中发生 (坐标系统包含第四个元素) 的空间,但大多数应用程序的最终结果必须是“屏幕空间”中定义的非同质三维 (三维) 坐标。这意味着输入顶点和剪裁量都必须转换为同质空间才能执行剪裁,然后再转换回要显示的非同源空间。
三个 Direct3D 转换(世界转换、视图转换和投影转换)由 Direct3D 矩阵定义。 Direct3D 矩阵是由 D3DMATRIX 结构定义的 4x4 同构矩阵。 尽管 Direct3D 矩阵不是标准对象(它们不由 COM 接口表示),但可以像创建和设置任何其他 Direct3D 对象一样创建和设置它们。 有关 Direct3D 矩阵的详细信息,请参阅 转换。
转换管道
如果模型坐标中的顶点由 Pm = (Xm、Ym、Zm、1) 给出,则下图中显示的转换将应用于计算屏幕坐标 Ps = (Xs、Ys、Zs、Ws) 。
下面是上图中所示阶段的说明:
世界矩阵 Mworld 将顶点从模型空间转换为世界空间。 此矩阵按以下方式设置:
d3dDevice->SetTransform (D3DTRANSFORMSTATE_WORLD, matrix address)
Direct3D 实现假定此矩阵的最后一列 (0、0、0、1) 。 如果用户指定具有不同最后一列的矩阵,但照明和雾将不正确,则不会返回错误。
视图矩阵 Mview 将顶点从世界空间转换为相机空间。 此矩阵按以下方式设置:
d3dDevice->SetTransform (D3DTRANSFORMSTATE_VIEW, matrix address)
Direct3D 实现假定此矩阵的最后一列 (0、0、0、1) 。 如果用户指定具有不同最后一列的矩阵,但照明和雾将不正确,则不会返回错误。
投影矩阵 Mproj 将顶点从相机空间转换为投影空间。 此矩阵按以下方式设置:
d3dDevice->SetTransform (D3DTRANSFORMSTATE_PROJECTION, matrix address)
投影矩阵的最后一列应 (0、0、1、0) 或 (0、0、a、0) ,以便获得正确的雾和照明效果;首选 (0、0、1、0) 形式。
投影空间中所有点 Xp = (Xp、Yp、Zp、Wp) 的剪辑音量定义为:
-Wp < Xp <= Wp -Wp < Yp <= Wp 0 < Zp <= Wp
不满足这些公式的所有点将被剪裁。
如果视图卷定义为:
- 近剪裁平面中相机空间中的屏幕窗口宽度
- 近剪裁平面中相机空间中的 Sh 屏幕窗口高度
- 相机空间中沿 Z 轴到近剪裁平面的 Zn 距离
- 相机空间中沿 Z 轴的远距剪裁平面的 Zf 距离
然后,可以编写透视投影矩阵,如下所示:
其中 Mij 是 Mproj 的成员。
对于正交投影,我们有:
Direct3D 假定透视投影矩阵采用以下形式:
如果透视投影矩阵不具有此形式,则会出现一些项目。 例如,表雾将不起作用。
Direct3D 允许用户更改剪辑音量,如下所示:
这可以重写为:
其中:
Cx, Cy - dvClipX, dvClipY from D3DVIEWPORT9 Cw, Ch - dvClipWidth, dvClipHeight from D3DVIEWPORT9 Zmin, Zmax - dvMinZ, dvMaxZ from D3DVIEWPORT9
此转换可以提供更高的精度,相当于缩放和移动剪裁量。
相应的 Mclip 矩阵为:
顶点的转换方式为:
dvClipWidth = 2 dvClipHeight = 2 dvClipX = -1 dvClipY = 1 dvMinZ = 0 dvMaxZ = 1
如果不想缩放剪辑音量,可以将视区参数设置为默认值:
(Xc, Yc, Zc, Wc) = (Xp, Yp, Zp, Wp) * Mclip
如果用户在 DrawPrimitive 调用中指定D3DDP_DONOTCLIP标志,则剪辑阶段是可选的。 在这种情况下,可以组合所有矩阵 (包括 Mvs) 。
视区比例矩阵 Mvs 将坐标缩放为在视区窗口中,并将 Y 轴从上翻转为向下翻转:
其中:
dwX, dwY - viewport offsets in pixels from D3DVIEWPORT9 dwWidth, dwHeight - viewport width and height in pixels from D3DVIEWPORT9
最后,计算屏幕坐标并将其传递给光栅器:
使用技巧
下面是有关如何使用 Direct3D 转换管道的一些提示:
世界和视图矩阵的最后一列应 (0、0、0、1) ,否则照明不正确。
设置视区参数以生成标识 Mclip 矩阵,除非你确切地了解它的用途。
dvClipWidth = 2 dvClipHeight = 2 dvClipX = -1 dvClipY = 1 dvMinZ = 0 dvMaxZ = 1