0
\$\begingroup\$

I have the following function:

void AnimatedModelShaderClass::PrepareToDraw(ID3D11DeviceContext* deviceContext, XMMATRIX worldMatrix, XMMATRIX viewMatrix,
XMMATRIX projectionMatrix, ID3D11ShaderResourceView* mesh) {

WVP = worldMatrix * viewMatrix * projectionMatrix;
cbPerObj.WVP = XMMatrixTranspose(WVP);
cbPerObj.World = XMMatrixTranspose(worldMatrix);
[...]

}

WVP is defined in the AnimatedModelShaderClass class as

XMMATRIX WVP;

The world, view and projection matrices are correctly received by the function, but as soon as the first line is executed, i can see that WVP contains some very weird values.

If i substitute the first line with the (supposedly) equivalent:

WVP = XMMatrixMultiply( XMMatrixMultiply(worldMatrix,viewMatrix), projectionMatrix);

then WVP is evaluated correctly and the numbers inside make sense.

Aren't the two ways equivalent? What am i missing?

Thanks in advance.

UPDATE:

It doesn't seem to have anything to do with the multiplications order, it works correctly if i replace the faulty line with:

XMMATRIX temp1 = projectionMatrix;
XMMATRIX temp2 = viewMatrix;
XMMATRIX temp3 = worldMatrix;

WVP = temp3 * temp2 * temp1;

What's the difference? I don't get it...

\$\endgroup\$
1
\$\begingroup\$

This has to do with the order of multiplication. While in regular Maths the multiplication goes from left to right, C++ and to my knowledge other programming languages do it the other way around. With scalar math, this is no problem but with matrix multiplication being noncommutative you should switch up the order to make it work with the standard * operator while XMMultiply uses an order that from left to right and thus is not suffering from this issue. This means that calculating the MVP/WVP correctly using the * operator the calculation should be

WVP = projectionMatrix * viewMatrix * worldMatrix ;

Yet this does not mean that XMMatrixMultiply() is the preferred method as this depends on the style used in your project so feel free to use either the function or the * operator as both are equally right.

\$\endgroup\$
2
  • \$\begingroup\$ matrix multiplication is associative. \$\endgroup\$
    – tkausl
    Mar 29 '19 at 18:26
  • \$\begingroup\$ @tkausl Oops, you're right thanks for the heads-up! This logic should no longer be faulty if I'm correct! \$\endgroup\$ Mar 29 '19 at 18:58
0
\$\begingroup\$

Matrix transformations are non-communicative i.e. A * B != B * A.

Consider what you are doing with the matrices:

You are taking something in what is called model space, and applying the model, or "world" transform to it:

VertexWorld = WorldTransform * Vertex;

The result of this is to change the vertex to a new coordinate basis, or change it's frame of reference.

Next you would, for the purposes of graphics, put it into a frame of reference dependant on the camera, or eye (we call this "view space"):

VertexEye = ViewTransform * VertexWorld;

Now, you want the vertex in screen, or "clip space":

VertexScreen = ProjectionTransform * VertexEye;

Note the order of multiplication: in computers, statements are evaluated right to left, so the vertex is multiplied by the matrix, then assigned to the new variable.

So if you want to condense this down into a single line of code, you can concatenate the transformations into a single matrix:

WVPTransform = ProjectionTransform * ViewTransform * WorldTransform;
VertexScreen = WVPTransform * Vertex;

Or:

VertexScreen = ProjectionTransform * ViewTransform * WorldTransform * Vertex;

Hope that helps you understand.

\$\endgroup\$
0
\$\begingroup\$

Ok, i have a solution to my problem, even if i still need time to understand what it does exactly. The fix is to use the XM_CALLCONV annotation to make sure the function uses the appropriate calling convention, like so:

void XM_CALLCONV AnimatedModelShaderClass::PrepareToDraw(ID3D11DeviceContext* deviceContext, XMMATRIX worldMatrix, XMMATRIX viewMatrix, XMMATRIX projectionMatrix, ID3D11ShaderResourceView* mesh)

This solves my problem, WVP is instantiated correctly. I won't go into details explaining why it works because i don't know it myself. For reference, this is where i got the answer, hope it helps!

thanks

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.