Thursday, September 29, 2016

physics - How do I convert matrices intended for OpenGL to be compatible for DirectX?


I have finished working through the book "Game Physics Engine Development 2nd Ed" by Millington, and have got it working, but I want to adapt it to work with DirectX.


I understand that D3D9+ has the option to use either left handed, or right handed convention, but I am unsure about how to return my matrices to be usable by D3D. The source code gives returning OpenGL column major matrices (the transpose of the working transform matrix shown below), but DirectX is row major.


For those unfamiliar for the organization of the matrices used in the book:


[r11 r12 r13 t1]
[r21 r22 r23 t2]
[r31 r32 r33 t3]

[ 0 0 0 1]

r## meaning the value of that element in the rotation matrix, and t# meaning the translation value.


So the question in short is: How do I convert the matrix above to be easily usable by D3D? All of the documentation that I have found simply states that D3D is row major, but not where to put what elements so that it is usable by D3D in terms of rotation, and translation elements.



Answer



First, a point of clarification: row-major means something different than row vector. OpenGL uses column vectors, which abstractly means that you consider a vector as a 4x1 matrix, and transform a vector v by a matrix M with v' = M · v. DirectX uses row vectors, which means that you consider a vector as a 1x4 matrix, and transform a vector w by a matrix N with w' = w · N. Notice that the two vectors are simply the transpose of each other: if you have an OpenGL vector v, then the DirectX vector is vT. And thanks to the linear algebra rule (A · B)T = BT · AT, you can see that the DirectX transformed vector (v')T = (M · v)T = vT · MT. That is, the DirectX matrix is simply the transpose of the OpenGL matrix.


And unrelated: OpenGL expects column-major storage, which means that the in-memory representation of a matrix keeps columns contiguous. So your example matrix would be stored as {r11, r21, r31, 0, r12, r22, r32, 0, r13, r23, r33, 0, t1, t2, t3, 1}. DirectX expects row-major storage, which means that the in-memory representation of a matrix keeps rows contiguous. So your example matrix would be stored as {r11, r12, r13, t1, r21, r22, r23, t2, r31, r32, r33, t3, 0, 0, 0, 1}. (Incidentally, in C and C++ two-dimensional arrays use row-major storage.)


And the fun part: it's easy to conflate these because they have "similar" effects. That is, if you take a matrix that's intended to be used with column vectors, and store it in column-major format, you get exactly the same thing as the transpose of that matrix (i.e. a matrix that represents the same transformation, but on row vectors) stored in row-major format. In a sense, the two operations cancel each other out. So OpenGL matrices and DirectX matrices look the same in raw memory. (And, of course, both of these are different than right-handedness vs left-handedness).


To summarize: If you're working in DirectX and looking at references that present OpenGL matrices, just transpose them to get matrices that you can use with DirectX.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...