本文介绍了DirectX:世界观矩阵-我的误解在哪里?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从DirectX(和SharpDX,因此只能在C#/hlsl中编程)开始,并试图构建自己的相机类.它应该是可旋转的,允许向前和向后移动以及向侧面"移动(经典的第一人称移动通常映射为A和D,在我的情况下为上下移动).为了在我的情况下更容易修正错误,模型和世界空间是相同的,因此尚未实现透视投影,就像旋转相机一样,并且我的相机应该沿Z轴正方向(进入屏幕)看.我的错误修正模型是一个简单的四边形,宽度和高度为1.f,z = 0,位于屏幕中央.
为了易于使用,我找到了DirectX的Matrix.LookAtLH(),并使用它来构建我的矩阵以从世界转换为视图坐标,基于我的相机在世界坐标中的定位,一个向上矢量(目前-无需旋转-始终为正值) Y轴)和世界坐标系中的目标点.
我的(顶点)着色器对此矩阵使用了一个简单的乘法:
output.position = mul(position, worldToView);
LookAt-Matrix的计算如下:
Matrix.LookAtLH(vec3(0, 0, -1), vec3(0, 0, 0.5f), vec3(0, 1, 0))
产生此图片:

现在,我想将摄像机向右移动,在这种情况下,将其1.f添加到它的X坐标上. 我的预期结果是与以前相同的四边形,向左移动了一点.
我构造了一个新的LootAt-矩阵,通过相同的向量移动了眼睛坐标和目标坐标:
Matrix.LookAtLH(vec3(1, 0, -1), vec3(1, 0, 0.5f), vec3(0, 1, 0))
结果:

I'm starting with DirectX (and SharpDX, therefore programming only in C#/hlsl) and am trying to build my own camera class. It should be rotatable, allow forward and backward moving and also "sideways" movement (the classical first person movement often mapped to A and D, plus up and down in my case). For easier bugfixing model and world space are the same in my case, perspective projection is not yet implemented, as is rotating the camera, and my camera is supposed to look in the positive Z-axis (into the screen). My bugfixing model is a simple quad with 1.f width and height, z = 0 and being centered on the screen.
For ease of use I found DirectX's Matrix.LookAtLH() and am using it to build my matrix for translation from world to view coordinates, based on positioning of my camera in world coordinates, an up-vector (for now - without rotation - always the positive Y-axis) and a target point in world coordinates.
My (vertex)shader uses a simple multiplication with this matrix:
output.position = mul(position, worldToView);
The LookAt-Matrix is calculated like this:
Matrix.LookAtLH(vec3(0, 0, -1), vec3(0, 0, 0.5f), vec3(0, 1, 0))
resulting in this picture:

Now I want to move my camera to the right, in this case by adding 1.f to it's X-coordinate. My expected result is the same quad as before, having moved a little to the left.
I construct a new LootAt-matrix, moving eye coordinates and target coordinates by the same vector:
Matrix.LookAtLH(vec3(1, 0, -1), vec3(1, 0, 0.5f), vec3(0, 1, 0))
Resulting in this:

我移动相机越多,这种情况越极端,但是屏幕的中心仍然保持四边形的中心.这与我对Matrix.LookAtLH的潜在误解有关吗?

This get's more extreme the more I move the camera, but the center of the screen still holds the center of the quad. Is this related to my potential misconceptions of Matrix.LookAtLH?

推荐答案

使用D3DX函数时,必须先转置矩阵,然后再将其发送到着色器.

When you are using D3DX-functions you have to transpose your matrices before sending them to shaders.

来自此处的更深入的解释:

在线性代数中,使用标准矩阵乘法算法将向量和矩阵相乘.因此,存在一些有关运算顺序和所涉及矩阵的形状"的规则.数学家通常将向量视为包含单列元素的矩阵,并具有类似以下的转换乘法:

In linear algebra, vectors and matrices are multiplied using the standard matrix multiplication algorithm. Thus there are a few rules concerning the order of operations and "shape" of the matrices involved. Mathematicians usually treat vectors as matrices containing a single column of elements, with a translation multiplication looking something like this:

[ 0, 0, 0, tx]  [ x]
[ 0, 0, 0, ty] *[ y]
[ 0, 0, 0, tz]  [ z]
[ 0, 0, 0,  1]  [ 1]

首先请注意,矩阵乘法会根据以下简单规则产生特定行/列配置的结果:

First note that matrix multiplication produces a result of a specific row/column configuration according to this simple rule:

换句话说,将A行和B列大小的矩阵乘以B行和C列的矩阵将产生A行和C列的矩阵.同样,为了适当地相乘,B必须两者相等.在这种情况下,我们有4x4 * 4x1,它产生一个4x1或另一个列向量.如果我们更改乘法顺序,则为4x1 * 4x4,这是非法的.

In other words, a matrix of size A rows and B columns multiplied by a matrix of B rows and C columns will produce a matrix of A rows and C columns. Also, in order to be properly multiplied, B must be equal for both. In this case, we have 4x4 * 4x1, which produces a 4x1, or another column vector. If we changed the order of multiplication, it would be 4x1 * 4x4, which would be illegal.

但是,计算机科学家经常将向量视为单行的矩阵.这样做有多种原因,但通常是因为单行代表单个线性内存块或一维数组,因为数组通常被寻址为array [row] [column].为了避免在代码中使用二维数组,人们简单地使用行向量"来代替.因此,为了使用矩阵乘法获得所需的结果,我们将顺序交换为1x4 * 4x4 = 1x4或向量*矩阵:

However, computer scientists often treat vectors as a matrix with a single row. There are several reasons for this, but often because a single row represents a single linear chunk of memory, or a single dimensional array, since arrays are typically addressed as array[row][column]. In order to avoid using 2 dimensional arrays in code, people simple use "row vectors" instead. Thus, in order to achieve the desired result using matrix multiplication, we swap the order to be 1x4 * 4x4 = 1x4, or vector * matrix:

[ x, y, z, 1] * [ 0, 0, 0, 0]
                [ 0, 0, 0, 0]
            [ 0, 0, 0, 0]
            [ x, y, z, 1]

请注意必须移动平移矩阵的x,y,z元素以保持正确的乘法结果(在这种情况下为转置).

Notice how the x, y, z, elements of the translation matrix had to be moved in order to preserve the proper result for multiplication (in this case, it is transposed).

使用列向量时,操作的典型变换顺序为P * V * W * v,因为列向量必须排在最后才能产生正确的结果.请记住,矩阵乘法是关联的,而不是可交换的,因此,为了获得适当的矢量结果,该矢量已被世界转换,转换为视图空间,转换为同构屏幕空间,我们必须按该顺序进行乘法.这给我们(使用关联性)P *(V *(W * v)),因此从内部到外部,首先进行世界变换,然后查看,然后进行投影.

When using column vectors, the typical transform order of operations are P* V * W * v, because the column vector must come last to produce the proper result. Remember, matrix multiplications are associated, not commutative, so in order to achieve the appropriate result of vector transformed by world, transformed into view space, transformed into homogenous screen space, we must multiply in that order. This gives us (using associativity) P * (V * (W * v)), thus working from inner parens to outer parens, world transformation first, view next, projection next.

如果我们使用行向量,则乘法如下:v * W * V *P.使用关联性,我们意识到它的操作顺序完全相同:(((v * W)* V)*P.或世界第一,然后是视图,然后是投影.

If we use row vectors, then the multiplication is as follows: v * W * V * P. Using associativity, we realize it is simply the same order of operations: ((v * W) * V) * P. Or world first, then view, then projection.

这两种乘法都同样有效,并且DX库选择使用后者,因为它与内存布局模式匹配,并且允许您从左到右读取转换顺序.

Both forms of multiplication are equally valid, and the DX library chooses to use the latter because it matches memory layout patterns, and it allows you to read your transformation order from left to right.

HLSL支持两种操作顺序. "*"运算符按元素缩放执行简单的元素,而不执行矩阵乘法.这是使用"mul()"固有操作执行的.如果将4元素向量作为第一个参数传递给mul()内在函数,则假定您希望将其视为行向量".因此,您必须提供以正确顺序相乘的矩阵,并以正确的行/列格式提供矩阵.当使用DX效果参数从DX库传递矩阵时,这是默认行为.如果您将4元素向量作为mul()内在函数的第二个参数提供,则它将其视为列向量,并且必须为列向量提供正确形成和相乘的矩阵.

HLSL supports BOTH orders of operations. The "*" operator performs a simple element by element scaling, it does not perform matrix multiplication. That is performed using the "mul()" intrinsic operation. If you pass a 4 element vector as the first parameter to the mul() intrinsic function, it assumes you wish to treat it as a "row vector." Thus, you must supply matrices that have been multiplied in the proper order, and supplied using the proper row/column format. This is the default behavior when passing in matrices from the DX libraries using the DX effect parameters. If you supply the 4 element vector as the second parameter to the mul() intrinsic, it treats it as a column vector, and you must provide properly formed and multiplied matrices for column vectors.

这篇关于DirectX:世界观矩阵-我的误解在哪里?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-04 23:57