我已阅读多篇关于前/后乘法,列/行专业,DirectX与OpenGL的文章和帖子,我可能比开头时更困惑。
所以,假设我们在OpenGL中编写这些指令(伪代码):
旋转(...) 翻译(...)
据我所知,OpenGL会做v'= R * T * v,有效地转换向量的局部坐标系。
但是在DirectX中,如果我们以相同的顺序进行转换(伪代码),
旋转(...) 翻译(...)
结果会不一样吧?由于DirectX预乘,结果将是v'= v * R * T,因此使用全局坐标变换矢量。
所以,当我说OpenGL是后乘法并且DirectX是预乘时就像是说OpenGL在局部坐标中移动而DirectX在全局坐标中移动时,我是否正确?
谢谢。
答案 0 :(得分:1)
最好的办法是阅读Matrices, Handedness, Pre and Post Multiplication, Row vs Column Major, and Notations。
OpenGL代码通常使用右手坐标系,列主矩阵,列向量和后乘法。
Direct3D代码通常使用左手坐标系,行主矩阵,行向量和预乘。
XNA Game Studio的数学库(以及Monogame,Unity等)使用右手坐标系,行主矩阵,行向量和预乘。
DirectXMath库使用行主矩阵,行向量和预乘,但您可以选择使用左手或右手坐标系统。对于年龄较大的deprecated D3DXMath来说,情况确实如此。
在任一系统中,您仍在使用相同的对象坐标 - >世界坐标 - >眼坐标 - >剪辑坐标转换。
因此,您可以使用OpenGL GLM:
using namespace glm;
mat4 myTranslationMatrix = translate(10.0f, 0.0f, 0.0f);
mat4 myRotationMatrix = rotate( 90.f, vec3( 0, 1, 0 ) );
mat4 myScaleMatrix = scale(2.0f, 2.0f, 2.0f);
mat4 myModelMatrix = myTranslationMatrix * myRotationMatrix * myScaleMatrix;
vec4 myTransformedVector = myModelMatrix * myOriginalVector;
在DirectXMath中你会做:
using namespace DirectX;
XMMATRIX myTranslationMatrix = XMMatrixTranslation(10.0f, 0.0f, 0.0f);
XMMATRIX myRotationMatrix = XMMatrixRotationY(XMConvertToRadians(90.f));
XMMATRIX myScaleMatrix = XMMatrixScaling(2.0f, 2.0f, 2.0f)
XMMATRIX myModelMatrix = myScaleMatrix * myRotationMatrix * myTranslationMatrix;
XMVECTOR myTransformedVector = XMVector4Transform( myOriginalVector, myModelMatrix );
结果你会得到同样的转变。
如果您不熟悉DirectXMath,那么您应该查看SimpleMath中的DirectX Tool Kit包装器,该包装器隐藏了一些与C ++构造函数和运算符一致的严格SIMD友好对齐要求。因为SimpleMath基于XNA Game Studio C#数学设计,所以它采用右手视图坐标,但您可以轻松地将其与“本机”DirectXMath混合,以便在需要时使用左手视图坐标。
这些决定中的大多数是任意的,但确实有合理的设计推理。 OpenGL的数学库试图匹配后乘法的正常数学约定,这导致它们采用列主矩阵。在Direct3D的早期阶段,团队认为连接顺序的逆转令人困惑,因此它们颠覆了所有惯例。
许多年后,XNA游戏工作室团队认为传统的Direct3D连接顺序很直观,但是“向前”是负面的z令人困惑,所以他们切换到右手坐标。因此,许多更现代的Direct3D样本都使用右手视图系统,但你仍会看到Direct3D样本的左手和右手观看设置的混合。所以在这一点上,我们真的有“OpenGL风格”,“经典的Direct3D风格“和”现代Direct3D风格“。请注意,当使用固定功能硬件完成任务时,这些约定确实很重要,但使用可编程着色器管道,重要的是您保持一致。事实上,HLSL着色器默认为期望矩阵为列主格式,因此您经常会看到DirectXMath矩阵在复制到常量缓冲区时进行转置。
答案 1 :(得分:0)
在OpenGL中没有预乘这样的东西。
你认为OpenGL反转乘法的原因是它将矩阵存储在列主要布局中:
a c
b d
乘以转置矩阵的数学规则是:
A^T * B^T = (B*A)^T
因此,如果你想计算v' = v * R * T
(所有行主矩阵),你将不得不写
(v')^T = v * R * T
或在您的伪代码中:
translate(...) rotate(...) translate(...)
另外您也可以存储旋转和翻译矩阵专栏。