• What is your GameDev Story?

This topic is 3834 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

Matrix ordering in HLSL and Cg shaders has been always confusing to me. For some reason, I have yet to reach that aha-moment when everything falls in place so I usually turn to brute-forcing by giving all possible permutations a shot in case things don't work right out of the box. What a horrible approach! Today, after several failed attempts, I finally settled down to solve this problem once and forever. So I started approaching the problem the scientific way: by gathering facts and using my powers of deduction to arrive at a logical conclusion. I'm confused by the shear amount of contradictory statements I've come by. This is really driving me crazy. Enlighten me and I would be in your depth forever! 1) DirectX SDK documentation states that:
Quote:
 Matrix packing order for uniform parameters is set to column-major by default. This means each column of the matrix is stored in a single constant register. On the other hand, a row-major matrix packs each row of the matrix in a single constant register.
Clearly, column-major matrices has been chosen by a long-time follower of row-major syntax for performance reasons, mainly because it allows vector-matrix multiplications to be performed using a series of dot-products, which should have been otherwise performed by a series of MAD instructions. OK, everything is fine up to this point. 2) A couple of paragraphs down, I encountered this example:
Quote:
 Overloaded versions of the multiply intrinsic function handle cases where one operand is a vector and the other operand is a matrix. Such as: vector * vector, vector * matrix, matrix * vector, and matrix * matrix. For instance: float4x3 World; float4 main(float4 pos : SV_POSITION) : SV_POSITION { float4 val; val.xyz = mul(pos,World); val.w = 0; return val; }  produces the same result as: float4x3 World; float4 main(float4 pos : SV_POSITION) : SV_POSITION { float4 val; val.xyz = (float3) mul((float1x4)pos,World); val.w = 0; return val; }  This example casts the pos vector to a column vector using the (float1x4) cast. Changing a vector by casting, or swapping the order of the arguments supplied to multiply is equivalent to transposing the matrix.
a) If "World" is a column matrix, why is it post-multiplied by pos?! Shouldn't the correct ordering have been mul( World, pos )? b) Seriously, since when a 1x4 vector is considered column-major? Adding to this mess is the fact that Cg totally uses a different ordering. Cg claims to be using row-major matrices, but the multiplication order is mul( World, pos ). If they're using row-major matrices, why isn't it the other way around? Besides, they're using the row major getters and setters to set column major matrices. As it turns out, when they refer to row-major matrices, they're pointing to the order in which those matrices are laid out in memory (C/C++ way as opposed to Fortran for instance), rather than as a method of indicating the order in which those matrices are to be multiplied. This is really crazy. I can't make sense out of all that. Any help is greatly appreciated.

Share on other sites
I usually run into similar issues when I am working on any tangent space calculations - for some reason it always seem non-intuitive. What I do in these cases is sit down with my trusty graphing calculator and do the vector/matrix calculations by hand while drawing the resulting images on paper. It takes forever, but you will be able see if something is incorrect and it actually will help you understand why the matrices are multiplied in a particular order.

As for the SDK documentation, it could just be a typo. In all of my shaders, the vertex is on the left and the matrix is on the right side. However, if the matrix is transposed prior to uploading it to the shader then the opposite order works fine.

Another trick that I have used to understand what is going on is to set each row of the matrix to a constant color, then use that row as the output color to see what row is where. Make sure you use colors that are identifiable in both the row order and the column order and you should be able to figure out which row came from where in your original matrix.

Hope this helps!

Share on other sites
Many thanks Jason! I appreciate the help :)

• What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.

• 10
• 11
• 13
• 9
• 11
• Forum Statistics

• Total Topics
634087
• Total Posts
3015446
×

Important Information

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!