矩阵堆栈 (Direct3D 9)

注意

D3DX 实用工具库已弃用。 建议改用 DirectXMath 以及 GitHub 中的此标头。

D3DX 实用工具库提供 ID3DXMATRIXStack 接口。 它提供一种机制,使矩阵能够推送到矩阵堆栈上并弹出矩阵堆栈。 实现矩阵堆栈是在遍历转换层次结构时跟踪矩阵的有效方法。

D3DX 实用工具库使用矩阵堆栈将转换存储为矩阵。 ID3DXMATRIXStack 接口的各种方法处理当前矩阵或位于堆栈顶部的矩阵。 可以使用 ID3DXMATRIXStack::LoadIdentity 方法清除当前矩阵。 若要显式指定要加载为当前转换矩阵的某个矩阵,请使用 ID3DXMATRIXStack::LoadMatrix 方法。 然后,可以调用 ID3DXMATRIXStack::MultMatrix 方法或 ID3DXMATRIXStack::MultMatrixLocal 方法,以将当前矩阵乘以指定的矩阵。

使用 ID3DXMATRIXStack::P op 方法可返回到上一个转换矩阵,而 ID3DXMATRIXStack::P ush 方法可将转换矩阵添加到堆栈。

矩阵堆栈上的单个矩阵表示为 4x4 同质矩阵,由 D3DX 实用工具库 D3DXMATRIX 结构定义。

D3DX 实用工具库通过组件对象模型 (COM) 对象提供矩阵堆栈。

实现场景层次结构

矩阵堆栈简化了分层模型的构造,其中复杂对象是从一系列更简单的对象构造的。

场景或转换层次结构通常由树数据结构表示。 树数据结构中的每个节点都包含一个矩阵。 特定矩阵表示坐标系从节点的父级到节点的变化。 例如,如果要为人臂建模,则可以实现下图所示的层次结构。

人臂层次结构图

在此层次结构中,Body 矩阵将正文置于世界中。 UpperArm 矩阵包含肩部的旋转,LowerArm 矩阵包含肘部的旋转,手部矩阵包含手腕的旋转。 若要确定手相对于世界的位置,请将从 Body 向下到 Hand 的所有矩阵相乘。

以前的层次结构过于简单,因为每个节点只有一个子节点。 如果开始更详细地为手部建模,可能会添加手指和拇指。 每个数字都可以作为 Hand 的子级添加到层次结构中,如下图所示。

人手层次结构图

如果按深度优先顺序遍历臂的完整图形(在移动到下一个路径之前尽可能沿着一条路径遍历)绘制场景,则执行一系列分段渲染。 例如,若要呈现手部和手指,可以实现以下模式。

  1. 将手部矩阵推送到矩阵堆栈上。
  2. 画手。
  3. 将 Thumb 矩阵推送到矩阵堆栈上。
  4. 画拇指。
  5. 从堆栈中弹出 Thumb 矩阵。
  6. 将手指 1 矩阵推送到矩阵堆栈上。
  7. 绘制第一根手指。
  8. 从堆栈中弹出“手指 1”矩阵。
  9. 将手指 2 矩阵推送到矩阵堆栈上。 以这种方式继续,直到呈现所有手指和拇指。

完成手指的呈现后,将手部矩阵从堆栈中弹出。

可以使用以下示例在代码中遵循此基本过程。 在树数据结构的深度优先搜索过程中遇到节点时,请将矩阵推送到矩阵堆栈的顶部。

MatrixStack->Push();

MatrixStack->MultMatrix(pNode->matrix);

完成节点操作后,将矩阵从矩阵堆栈的顶部弹出。

MatrixStack->Pop();

这样,堆栈顶部的矩阵始终表示当前节点的世界转换。 因此,在绘制每个节点之前,应设置 Direct3D 矩阵。

pD3DDevice->SetTransform(D3DTS_WORLDMATRIX(0), *MatrixStack->GetTop());

有关可以对 D3DX 矩阵堆栈执行的特定方法的详细信息,请参阅 ID3DXMATRIXStack 参考主题。

顶点管道