顶点着色器世界变换,为什么我们使用4维向量?

twe*_*ypi 3 math directx vector hlsl

从这个网站: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;
}
Run Code Online (Sandbox Code Playgroud)

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

Goz*_*Goz 9

因为您需要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
Run Code Online (Sandbox Code Playgroud)

并将其应用于随机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)
Run Code Online (Sandbox Code Playgroud)

您可以立即看到w和z不同.w coord现在只包含传递给投影矩阵的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
Run Code Online (Sandbox Code Playgroud)

扩展我们然后得到

x' = 4
y' = 2
z' = 4.4
w' = 5
Run Code Online (Sandbox Code Playgroud)

然后,我们进行最终的视角分割

x'' = 0.8
y'' = 0.4
z'' = 0.88
w'' = 1
Run Code Online (Sandbox Code Playgroud)

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

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

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

Edit2:警告我正在使用ROW主要矩阵.列主要矩阵被转置.


Chr*_*isF 5

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

rx1 rx2 rx3 tx1
ry1 ry2 ry3 ty1
rz1 rz2 rz3 tz1
Run Code Online (Sandbox Code Playgroud)

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

0   0   0   1
Run Code Online (Sandbox Code Playgroud)

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

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