功能级别 9 硬件上的用户剪裁平面

从 Windows 8 开始,Microsoft 高级着色器语言 (HLSL) 支持一种语法,你可以使用该语法与 Microsoft Direct3D 11 API 一起指定功能级别9_x及更高级别的用户剪辑平面。 可以使用此剪裁平面语法编写着色器,然后将该着色器对象与 Direct3D 11 API 一起使用,以在所有 Direct3D 功能级别上运行。

背景

可以通过 IDirect3DDevice9::SetClipPlane 和 IDirect3DDevice9::GetClipPlane 方法访问 Microsoft Direct3D 9 API 中的用户剪辑平面。 在 Microsoft Direct3D 10 及更高版本中,可以通过 SV_ClipDistance 语义访问用户剪辑平面。 但在Windows 8之前,SV_ClipDistance不适用于 Direct3D 10 或 Direct3D 11 API 中的功能级别9_x硬件。 因此,在Windows 8之前,访问具有功能级别9_x硬件的用户剪辑平面的唯一方法是通过 Direct3D 9 API。 Direct3D Windows 应用商店应用无法使用 Direct3D 9 API。 下面我们介绍可用于在功能级别9_x及更高级别的 Direct3D 11 API 访问用户剪辑平面的语法。

应用使用剪裁平面来定义 3D 世界中的一组不可见平面,这些平面 () 所有绘制的基元中丢弃。 Windows 不会绘制任何剪裁平面的负端的任何像素。 然后,应用可以使用剪裁平面来呈现平面反射。

语法

使用此语法在函数声明中将剪裁平面声明为 函数属性。 例如,此处我们对顶点着色器片段使用 语法:

cbuffer ClipPlaneConstantBuffer 
{
       float4 clipPlane1;
       float4 clipPlane2;
};

[clipplanes(clipPlane1,clipPlane2)]
VertexShaderOutput main(VertexShaderInput input)
{
       // the rest of the vertex shader doesn't refer to the clip plane
 
       …
 
       return output;
}

顶点着色器片段的此示例表示两个剪裁平面。 它表明,需要将新的 剪裁平面 属性放在顶点着色器的返回值之前的方括号内。 在 剪裁平面 属性后的括号内,提供最多 6 个 float4 常量的列表,这些常量定义每个活动剪裁平面的平面系数。 该示例还显示,需要使每个平面的系数驻留在常量缓冲区中。

注意

没有可用于动态禁用剪裁平面的语法。 你必须重新编译一个没有 剪辑平面 属性的相同着色器,或者你的应用可以将常量缓冲区中的系数设置为零,以便平面不再影响任何几何图形。

 

此语法适用于任何 4.0 或更高版本的顶点着色器目标,其中包括vs_4_0_level_9_1和vs_4_0_level_9_3。

在功能级别 9 及更高级别的剪辑空间中创建剪裁平面

下面介绍如何在 功能级别 9_x及更高级别的剪辑空间中创建剪裁平面。

背景阅读

Frank D. Luna 的“DirectX 10 3D 游戏编程简介”介绍了所需的图形数学背景 (第 1 章、第 2 章和第 ) 3 章,以及顶点着色器 (5.6 和 5.8 部分) 发生的各种空间和空间转换。

10Level9 功能级别

在 Direct3D 10 及更高版本中,可以在任何有意义的空间中剪裁,通常在世界空间或视图空间中。 但 Direct3D 9 使用剪辑空间,即预透视分割投影空间。 当顶点着色器将它们传递到 图形管道中的后续阶段时,矢量位于剪辑空间中。

编写 Windows 应用商店应用时,必须使用 10Level9 功能级别 (功能级别 9_x) 以便应用可以在功能级别9_x和更高硬件上运行。 由于应用支持9_x及更高功能级别,因此还必须使用在剪辑空间中应用剪裁平面的常见功能。

使用 vs_4_0_level_9_1 或更高版本编译顶点着色器时,该顶点着色器可以使用 剪裁平面 属性。 Direct3D 10 或更高版本对象具有所发出顶点的点积,该顶点积包含 属性中指定的每个 float4 全局常量。 Direct3D 9 对象有足够的元数据,使 10Level9 运行时发出对 IDirect3DDevice9::SetClipPlane 的适当调用。

剪裁平面数学

剪裁平面由具有 4 个分量的向量定义。 前三个分量定义一个 x、y、z 向量,该矢量源自我们想要剪辑的空间中的原点。 此向量意味着一个平面,垂直于向量并穿过原点。 Windows 将所有像素保留在平面的向量侧,并剪辑平面后面的所有像素。 第四个 w 分量向后推平面,导致 Windows 剪裁较少 (负 w 导致 Windows 沿向量线剪裁更多) 。 如果 x、y、z 分量构成一个单位 (规范化) 向量,则 w 将向后推平面 w 单位。

图形处理单元 (GPU) 执行的用于确定剪裁的数学运算是顶点向量 (x、y、z、1) 与剪裁平面矢量之间的简单点积。 此数学运算在剪裁平面向量上创建投影长度。 负点积显示位于平面剪裁侧的顶点。

在视图空间中剪切

下面是视图空间中的顶点:

视图空间中的顶点

下面是视图空间中的剪裁平面:

视图空间中的剪裁平面

下面是视图空间中顶点和剪裁平面的点积:

ClipDistance = v · C = vCₓ +vyCy + vzCz + Cw

此数学运算适用于 Direct3D 10 或更高版本的对象,但不适用于 Direct3D 9 对象。 对于 Direct3D 9,我们必须首先通过投影转换进入剪辑空间。

投影矩阵

投影矩阵从视图空间转换顶点 (,其中原点为观看者的眼睛,+x 向右,+y 向上,+z 正前方) 为剪辑空间。 投影矩阵读取硬件剪裁和 光栅化阶段的顶点。 下面是一个标准透视矩阵, (其他投影需要不同的数学) :

*r* 窗口宽度/高度 *α* 视角 *f* 从查看器到远平面的距离 *n* 从查看器到近平面的距离
![投影矩阵] (图像/projection-matrix.png)

下一个矩阵是上一个矩阵的简化版本。 我们演示了简化的矩阵,以便稍后在矩阵乘法运算中使用它。

简化的投影矩阵

现在,我们使用矩阵乘法将视图空间顶点转换为剪辑空间:

矩阵乘法

在矩阵乘法运算中,x 和 y 分量只是稍作调整,但 z 和 w 分量却相当复杂。 我们的剪裁平面不会再给我们想要的东西了。

剪裁空间剪裁平面

在这里,我们想要创建一个剪辑空间剪辑平面,其带剪辑空间顶点的点积为我们提供了与 v ·在视图空间中剪裁 ”部分中的 C。

剪裁平面

v · C = v P · CP

vCₓ +vyCy + vzCz + Cw = vPCPₓ +vyPyCPy + vzAyCPz + BCPz + vzCPw

现在,我们可以按顶点分量将前面的数学运算分解为四个单独的公式:

剪裁平面产品的 x 顶点组件

剪裁平面产品的 y 顶点组件

剪裁平面产品的 w 顶点组件

剪裁平面积的 z 顶点组件

我们的视图空间剪辑平面和投影矩阵派生并向我们提供剪辑空间剪辑平面。

剪裁空间剪裁平面

HLSL 编程指南

函数声明语法