顶点着色器世界变换,为什么我们使用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;
}
我的问题是:为什么 struct VS_OUTPUT 有一个 4 维向量作为其位置?位置不就是x、y、z吗?
From this site: http://www.toymaker.info/Games/html/vertex_shaders.html
We have the following code snippet:
// 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;
}
My question is: why does the struct VS_OUTPUT have a 4 dimensional vector as its position? Isn't position just x, y and z?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
因为透视计算需要w坐标。从顶点着色器输出后,DirectX 通过除以 w 来执行透视除法。
本质上,如果您将 32768、-32768、32768、65536 作为输出顶点位置,那么在 w 除之后,您将得到 0.5、-0.5、0.5、1。此时可以丢弃 w,因为不再需要它。然后,该信息通过视口矩阵传递,视口矩阵将其转换为可用的 2D 坐标。
编辑:如果您查看如何使用投影矩阵执行矩阵乘法,您可以看到如何将值放置在正确的位置。
采用 D3DXMatrixPerspectiveLH 中指定的投影矩阵
并将其应用到随机 x, y, z, 1(注意顶点位置 w 始终为 1)顶点输入值,您将得到以下结果
您可以立即看到 w 和 z 是不同的。 w 坐标现在仅包含传递给投影矩阵的 z 坐标。 z 包含更复杂的东西。
所以..假设我们有一个输入位置(2,1,5,1),我们的zn(Z-Near)为1,zf(Z-Far为10)和aw(宽度)为1,ah(高度)为 1。
传递这些值我们得到
扩展,然后得到
我们然后执行最终的透视除法,我们得到
现在我们有了最终的坐标位置。假设 x 和 y 的范围从 -1 到 1,z 的范围从 0 到 1。正如您所看到的,顶点在屏幕上。
作为一个奇怪的奖励,你可以看到 if |x'|或 |y'|或 |z'|大于 |w'|或者 z' 小于 0,表示顶点在屏幕外。此信息用于将三角形剪切到屏幕上。
无论如何,我认为这是一个非常全面的答案:D
Edit2:请注意,我正在使用 ROW 主要矩阵。列主矩阵被转置。
Because you need the w coordinate for perspective calculation. After you output from the vertex shader than DirectX performs a perspective divide by dividing by w.
Essentially if you have 32768, -32768, 32768, 65536 as your output vertex position then after w divide you get 0.5, -0.5, 0.5, 1. At this point the w can be discarded as it is no longer needed. This information is then passed through the viewport matrix which transforms it to usable 2D coordinates.
Edit: If you look at how a matrix multiplication is performed using the projection matrix you can see how the values get placed in the correct places.
Taking the projection matrix specified in D3DXMatrixPerspectiveLH
And applying it to a random x, y, z, 1 (Note for a vertex position w will always be 1) vertex input value you get the following
Instantly you can see that w and z are different. The w coord now just contains the z coordinate passed to the projection matrix. z contains something far more complicated.
So .. assume we have an input position of (2, 1, 5, 1) we have a zn (Z-Near) of 1 and a zf (Z-Far of 10) and a w (width) of 1 and a h (height) of 1.
Passing these values through we get
expanding that we then get
We then perform final perspective divide and we get
And now we have our final coordinate position. This assumes that x and y ranges from -1 to 1 and z ranges from 0 to 1. As you can see the vertex is on-screen.
As a bizarre bonus you can see that if |x'| or |y'| or |z'| is larger than |w'| or z' is less than 0 that the vertex is offscreen. This info is used for clipping the triangle to the screen.
Anyway I think thats a pretty comprehensive answer :D
Edit2: Be warned i am using ROW major matrices. Column major matrices are transposed.
旋转由 3 维矩阵指定,平移由向量指定。您可以通过将它们组合成一个 4 x 3 矩阵,在“单个”操作中执行这两种变换:
但是,由于这不是方形的,因此无法执行各种操作(其中之一是求逆)。通过添加额外的行(不执行任何操作):
所有这些操作都变得可能(如果不容易的话)。
正如 Goz 在 他的答案中解释的那样 通过使“1”成为非恒等值,矩阵变成了透视变换。
Rotation is specified by a 3 dimensional matrix and translation by a vector. You can perform both transforms in a "single" operation by combining them into a single 4 x 3 matrix:
However as this isn't square there are various operations that can't be performed (inversion for one). By adding an extra row (that does nothing):
all these operations become possible (if not easy).
As Goz explains in his answer by making the "1" a non identity value the matrix becomes a perspective transformation.
剪裁是此过程的重要组成部分,因为它有助于可视化几何体发生的情况。裁剪阶段本质上会丢弃基元中位于以原点为中心的 2 单位立方体之外的任何点(好吧,您必须重建部分裁剪的基元,但这在这里并不重要)。
可以构造一个矩阵,将世界空间坐标直接映射到这样的立方体,但从远平面到近平面的逐渐移动将是线性的。也就是说,距离观看者一英里时移动一只脚(朝向观看者)将导致与距离相机几英尺时移动一只脚相同的尺寸增加。
然而,如果我们的向量 (w) 中有另一个坐标,我们可以将向量按分量除以 w,并且我们的基元不会表现出上述行为,但我们仍然可以使它们最终位于 2 单位立方体内多于。
有关详细说明,请参阅 http://www.opengl.org/resources/ faq/technical/depthbuffer.htm#0060 和 http://en.wikipedia。 org/wiki/Transformation_matrix#Perspective_projection。
一个简单的答案是,如果您不告诉管道 w 是什么,那么您就没有向其提供有关投影的足够信息。这可以直接验证,而无需了解管道的作用...
您可能知道,4x4 矩阵可以根据每个部分的作用分为多个部分。当您进行旋转或缩放操作时,左上角的 3x3 矩阵会发生变化。当您进行翻译时,第四列会发生更改。如果您检查透视矩阵,它会改变矩阵的底行。如果您随后查看矩阵向量乘法是如何完成的,您会发现矩阵的底行仅影响向量的结果 w 分量。因此,如果您不告诉管道有关 w 的信息,它就不会拥有您的所有信息。
Clipping is an important part of this process, as it helps to visualize what happens to the geometry. The clipping stage essentially discards any point in a primitive that is outside of a 2-unit cube centered around the origin (OK, you have to reconstruct primitives that are partially clipped but that doesn't matter here).
It would be possible to construct a matrix that directly mapped your world space coordinates to such a cube, but gradual movement from the far plane to the near plane would be linear. That is to say that a move of one foot (towards the viewer) when one mile away from the viewer would cause the same increase in size as a move of one foot when several feet from the camera.
However, if we have another coordinate in our vector (w), we can divide the vector component-wise by w, and our primitives won't exhibit the above behavior, but we can still make them end up inside the 2-unit cube above.
For further explanations see http://www.opengl.org/resources/faq/technical/depthbuffer.htm#0060 and http://en.wikipedia.org/wiki/Transformation_matrix#Perspective_projection.
A simple answer would be to say that if you don't tell the pipeline what w is then you haven't given it enough information about your projection. This can be verified directly without understanding what the pipeline does with it...
As you probably know the 4x4 matrix can be split into parts based on what each part does. The 3x3 matrix at the top left is altered when you do rotation or scale operations. The fourth column is altered when you do a translation. If you ever inspect a perspective matrix, it alters the bottom row of the matrix. If you then look at how a Matrix-Vector multiplication is done, you see that the bottom row of the matrix ONLY affects the resultant w component of the vector. So if you don't tell the pipeline about w it won't have all your information.