Jump to content
  • Advertisement
Sign in to follow this  
Ashkan

Matrix Ordering in Shaders

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

If you intended to correct an error in the post then please contact us.

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 this post


Link to post
Share on other sites
Advertisement
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 this post


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

I'll go ahead and give your color-encoding approach a shot.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!