Direct3D 转换管道

本文为 Direct3D 应用程序开发人员提供了有关如何通过直接操作 Direct3D 矩阵来设置 Direct3D 转换管道参数的技术说明。

概述

Direct3D 使用三个转换来将 3D 模型坐标更改为像素坐标(屏幕空间)。 这些转换是世界转换、视图转换和投影转换。

"世界转换" 控制模型坐标如何转换为世界坐标。 世界变换可以包括平移、旋转和 scalings,但不适用于光源。 有关使用世界转换的详细信息,请参阅 世界转换

视图转换控制从世界坐标到 "相机空间" 的转换,确定世界上的照相机位置。 有关使用视图转换的示例,请参阅 查看转换

投影转换将几何从相机空间更改为 "剪裁空间",并应用透视扭曲。 术语 "剪裁空间" 是指在此转换过程中如何将几何图形裁剪到视图卷。 有关使用投影转换的示例,请参阅 投影转换

最后,剪辑空间中的几何转换为像素坐标 (屏幕空间) 。 此转换由视区设置控制。

剪切和转换顶点必须发生在同构空间中 (只需 put,其中坐标系统包含第四个元素的空间) ,但是大多数应用程序的最终结果需要是在 "屏幕空间" 中定义的非同源三维 (3D) 坐标。 这意味着必须将输入顶点和剪切卷都转换为同源空间,才能执行剪辑,然后将其重新转换回非同源空间以显示。

这三个 Direct3D 转换(世界、视图和投影转换)由 Direct3D 矩阵定义。 Direct3D matrix 是由 D3DMATRIX 结构定义的4x4 同源矩阵。 尽管 Direct3D 矩阵不是标准对象,但它们不是由 COM 接口表示的,但你可以创建并设置它们,就像对任何其他 Direct3D 对象一样。 有关 Direct3D 矩阵的详细信息,请参阅 转换

转换管道

如果模型坐标中的顶点由 Pm = (Xm、Ym、Zm、1) ,则下图所示的转换将应用于计算屏幕坐标 Ps = (Xs,Y) ,Zs,Ws) 。

将空间模型转换为屏幕空间转换

下面是上图中显示的阶段的说明:

  1. World matrix Mworld 将顶点从模型空间转换为世界空间。 此矩阵的设置方式如下:

        d3dDevice->SetTransform (D3DTRANSFORMSTATE_WORLD, matrix address) 
    

    Direct3D 实现假定此矩阵的最后一列 (0,0,0,1) 。 如果用户指定的矩阵具有不同的最后一列,则不会返回任何错误,但光照和雾化将不正确。

  2. 视图矩阵 Mview 将顶点从世界空间转换为相机空间。 此矩阵的设置方式如下:

        d3dDevice->SetTransform (D3DTRANSFORMSTATE_VIEW, matrix address) 
    

    Direct3D 实现假定此矩阵的最后一列 (0,0,0,1) 。 如果用户指定的矩阵具有不同的最后一列,则不会返回任何错误,但光照和雾化将不正确。

  3. 投影矩阵 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-近剪裁平面中相机空间的屏幕窗口高度
    • Zn-相机空间中沿 Z 轴的近剪裁平面的距离
    • Zf-相机空间中沿 Z 轴的远距离修剪平面

    然后,可以按如下所示编写透视投影矩阵:

    显示透视投影矩阵。

    其中,Mij 是 Mproj 的成员。

    对于正交投影,我们拥有:

    正交投影

    Direct3D 假设透视投影矩阵采用以下格式:

    透视投影矩阵

    如果透视投影矩阵没有此窗体,则将有一些项目。 例如,表雾化将不起作用。

  4. Direct3D 允许用户更改剪辑卷,如下所示:

    更改剪辑音量

    这可以重新编写为:

    更改剪辑音量

    其中:

        Cx, Cy - dvClipX, dvClipY from D3DVIEWPORT9  
        Cw, Ch - dvClipWidth, dvClipHeight from D3DVIEWPORT9  
        Zmin, Zmax - dvMinZ, dvMaxZ from D3DVIEWPORT9  
    

    此转换可提供更高的精度,并等效于缩放和移动剪辑量。

    相应的 Mclip 矩阵为:

    mclip 矩阵

    顶点由以下内容转换:

        dvClipWidth = 2   
        dvClipHeight = 2   
        dvClipX = -1   
        dvClipY = 1   
        dvMinZ = 0   
        dvMaxZ = 1   
    

    如果你不想缩放剪辑卷,则可以将视区参数设置为默认值:

        (Xc, Yc, Zc, Wc) = (Xp, Yp, Zp, Wp) * Mclip   
    
  5. 如果用户 _ 在 DrawPrimitive 调用中指定 D3DDP DONOTCLIP 标志,则剪辑阶段是可选的。 在这种情况下,可以将所有矩阵 (包括 Mvs) 组合在一起。

  6. 视区缩放矩阵 Mvs 在视区窗口内缩放坐标,并将 Y 轴向上翻转:

    视区缩放矩阵 mvs

    其中:

        dwX, dwY - viewport offsets in pixels from D3DVIEWPORT9 
        dwWidth, dwHeight - viewport width and height in pixels from D3DVIEWPORT9    
    
  7. 最后,计算屏幕坐标并将其传递给光栅化:

    屏幕坐标,计算并传递到光栅化

使用提示

下面是有关如何使用 Direct3D 转换管道的一些提示:

  • 世界上的最后一列和视图矩阵应为 (0,0,0,1) ,否则光照将不正确。

  • 设置视区参数以生成标识 Mclip 矩阵,除非你清楚地了解所需的内容。

        dvClipWidth = 2 
        dvClipHeight = 2
        dvClipX = -1
        dvClipY = 1
        dvMinZ = 0 
        dvMaxZ = 1