4

从这个网站:http ://www.toymaker.info/Games/html/vertex_shaders.html

我们有以下代码片段:

// transformations provided by the app, constant Uniform data
float4x4 matWorldViewProj: WORLDVIEWPROJECTION;

// the format of our vertex data
struct VS_OUTPUT
{
  float4 Pos  : POSITION;
};

// Simple Vertex Shader - carry out transformation
VS_OUTPUT VS(float4 Pos  : POSITION)
{
  VS_OUTPUT Out = (VS_OUTPUT)0;
  Out.Pos = mul(Pos,matWorldViewProj);
  return Out;
}

我的问题是:为什么结构 VS_OUTPUT 有一个 4 维向量作为它的位置?位置不只是x,y和z吗?

4

3 回答 3

10

因为您需要 w 坐标进行透视计算。在您从顶点着色器输出之后,DirectX 通过除以 w 来执行透视除法。

本质上,如果您有 32768、-32768、32768、65536 作为输出顶点位置,那么在 w 除之后,您会得到 0.5、-0.5、0.5、1。此时可以丢弃 w,因为不再需要它。然后,此信息通过视口矩阵传递,视口矩阵将其转换为可用的 2D 坐标。

编辑:如果您查看如何使用投影矩阵执行矩阵乘法,您可以看到值如何放置在正确的位置。

采用 D3DXMatrixPerspectiveLH 中指定的投影矩阵

2*zn/w  0       0              0
0       2*zn/h  0              0
0       0       zf/(zf-zn)     1
0       0       zn*zf/(zn-zf)  0

并将其应用于随机 x, y, z, 1(注意顶点位置 w 将始终为 1)顶点输入值,您将得到以下结果

x' = ((2*zn/w) * x) + (0 * y) + (0 * z) + (0 * w)
y' = (0 * x) + ((2*zn/h) * y) + (0 * z) + (0 * w)
z' = (0 * x) + (0 * y) + ((zf/(zf-zn)) * z) + ((zn*zf/(zn-zf)) * w)
w' = (0 * x) + (0 * y) + (1 * z) + (0 * w)

立即您可以看到 w 和 z 是不同的。w 坐标现在只包含传递给投影矩阵的 z 坐标。z 包含更复杂的东西。

所以..假设我们有一个输入位置 (2, 1, 5, 1) 我们有一个 zn (Z-Near) 为 1 和一个 zf (Z-Far 为 10) 和 aw (宽度) 为 1 和 ah (高度)为 1。

传递这些值我们得到

x' = (((2 * 1)/1) * 2
y' = (((2 * 1)/1) * 1
z' = ((10/(10-1)  * 5 + ((10 * 1/(1-10)) * 1)
w' = 5

扩展我们然后得到

x' = 4
y' = 2
z' = 4.4
w' = 5

然后我们执行最终的透视划分,我们得到

x'' = 0.8
y'' = 0.4
z'' = 0.88
w'' = 1

现在我们有了最终的坐标位置。这假设 x 和 y 的范围从 -1 到 1,z 的范围从 0 到 1。如您所见,顶点在屏幕上。

作为一个奇怪的奖励,你可以看到如果 |x'| 或 |y'| 或 |z'| 大于 |w'| 或 z' 小于 0 表示顶点不在屏幕上。此信息用于将三角形剪裁到屏幕上。

无论如何,我认为这是一个非常全面的答案:D

Edit2:请注意,我正在使用 ROW 主要矩阵。列主要矩阵被转置。

于 2009-10-22T08:25:09.833 回答
5

旋转由 3 维矩阵指定,平移由向量指定。您可以通过将它们组合成单个 4 x 3 矩阵,在“单个”操作中执行这两种转换:

rx1 rx2 rx3 tx1
ry1 ry2 ry3 ty1
rz1 rz2 rz3 tz1

但是,由于这不是正方形,因此无法执行各种操作(一个反转)。通过添加一个额外的行(什么都不做):

0   0   0   1

所有这些操作都成为可能(如果不容易的话)。

正如 Goz 在他的回答中解释的那样,将“1”设为非单位值,矩阵变成了透视变换。

于 2009-10-22T08:21:58.667 回答
1

剪裁是此过程的重要组成部分,因为它有助于可视化几何体发生的情况。剪裁阶段基本上丢弃了以原点为中心的 2 单位立方体之外的图元中的任何点(好的,您必须重建部分剪裁的图元,但这无关紧要)。

可以构建一个矩阵,将您的世界空间坐标直接映射到这样的立方体,但从远平面到近平面的逐渐移动将是线性的。也就是说,当距离观看者一英里时移动一英尺(朝向观看者)将导致尺寸增加,这与距离相机几英尺时移动一英尺所导致的尺寸增加相同。

但是,如果我们的向量 (w) 中有另一个坐标,我们可以将向量按分量除以 w,我们的图元不会表现出上述行为,但我们仍然可以让它们最终位于 2 单位立方体内以上。

有关进一步的解释,请参见http://www.opengl.org/resources/faq/technical/depthbuffer.htm#0060http://en.wikipedia.org/wiki/Transformation_matrix#Perspective_projection

一个简单的答案是,如果你不告诉管道 w 是什么,那么你就没有给它足够的关于你的投影的信息。这可以直接验证,而无需了解管道对它的作用......

您可能知道 4x4 矩阵可以根据每个部分的功能拆分为多个部分。当您进行旋转或缩放操作时,左上角的 3x3 矩阵会发生变化。当您进行翻译时,第四列会发生变化。如果您曾经检查过透视矩阵,它会改变矩阵的底行。如果您然后查看矩阵向量乘法是如何完成的,您会看到矩阵的底行仅影响向量的结果 w 分量。所以如果你不告诉管道 w 它不会有你的所有信息。

于 2009-10-22T09:22:00.077 回答