Matrix orientation (r,c c,r) conventions?

Started by
6 comments, last by mzeo77 15 years, 9 months ago
I know that according to the mathematical convention the correct orientation of a matrix is [row,column]. However I have seen a lot of games programming resources that put the matrix the other way around. Essentially the transformation matrix becomes 1 0 0 0 0 1 0 0 0 0 1 0 X Y Z 1 instead of 1 0 0 X 0 1 0 Y 0 0 1 Z 0 0 0 1 Is this an accepted convention in games development? If it is does anyone know why? (I'm imagining something along the line of the way arrays are commonly indexed and the need to keep certain data values adjacent for use with SSE). I want to know because I'm writing a C++ 3D maths library for Linux* for use with my final year CS project. It's going to be under a FOSS license and if a convention exists I'd prefer to follow it. *basically a bunch of stuff like vectors, matrices, planes, rays, quaternions, etc. Selecting appropriately optimised implementations (where it makes sense) via function pointers depending on the capabilities of the CPU. I couldn't find such a library for Linux and will need one in a few months.
Advertisement
Some API's like to use a column-vector convention (OpenGL), while others like to use a row-vector convention (DirectX). You're correct in saying that one layout might be chosen over an other depending on how the data will be accessed, but in general there is no functional difference between the two. I personally like column vectors since they're used in every mathematical text I've read, however it comes down to personal preference. Your library should be able to convert between layouts so you can pass it down to a lower-level API anyway.
Quote:Original post by G Morgan
I know that according to the mathematical convention the correct orientation of a matrix is [row,column].
Just to head off any confusion, it's probably worth clarifying that matrices are always indexed as [row][column] (AFAIK, at least). What you're referring to here is the difference between row- and column-vector notation, as Zipster notes above.
Quote:Is this an accepted convention in games development?
Overall, I think row- and column-vector notation are used about equally (in any case, neither convention is superior to the other).
Quote:(I'm imagining something along the line of the way arrays are commonly indexed and the need to keep certain data values adjacent for use with SSE).
As far as I know, SIMD is going to be more concerned with whether the elements of the matrix basis vectors are contiguous than with what notional convention is being used. As such, it should be equally straightforward to optimize a math library regardless of which convention is used (again, AFAIK).
Quote:I want to know because I'm writing a C++ 3D maths library for Linux* for use with my final year CS project. It's going to be under a FOSS license and if a convention exists I'd prefer to follow it.

*basically a bunch of stuff like vectors, matrices, planes, rays, quaternions, etc. Selecting appropriately optimised implementations (where it makes sense) via function pointers depending on the capabilities of the CPU. I couldn't find such a library for Linux and will need one in a few months.
You can probably just pick a convention and go from there. Neither choice is 'right', so just use whatever you're most comfortable with.

Another option would be to support both notational conventions.
I would note that you should probably just pick the convention that matches your graphics library.
with something like
    union    {        f32 m[16];      f32 e[4][4];      struct      {        f32 m11; f32 m12; f32 m13; f32 m14;        f32 m21; f32 m22; f32 m23; f32 m24;        f32 m31; f32 m32; f32 m33; f32 m34;        f32 m41; f32 m42; f32 m43; f32 m44;            };      struct      {        VEC4 left;        VEC4 up;        VEC4 at;        VEC4 pos;      };    };you can just pass off glMultMatrixf( &Matrix.m ) instead of having to convert layouts before passing your matrix to the graphics API
Cheers for the responses. I think I know what I'm doing now. I've got a class

class Matrix {
public:
float r1c1, r2c1, r3c1, r4c1;
float r1c2, r2c2, r3c2, r4c2;
float r1c3, r2c3, r3c3, r4c3;
float r1c4, r2c4, r3c4, r4c4;
};

I'll be using OGL and 'float* m = (float *) myMatrix;' should work as an OGL matrix. Even if the class definition looks a little funny it should work as intended.
Quote:Original post by G Morgan
Cheers for the responses. I think I know what I'm doing now. I've got a class

class Matrix {
public:
float r1c1, r2c1, r3c1, r4c1;
float r1c2, r2c2, r3c2, r4c2;
float r1c3, r2c3, r3c3, r4c3;
float r1c4, r2c4, r3c4, r4c4;
};

I'll be using OGL and 'float* m = (float *) myMatrix;' should work as an OGL matrix. Even if the class definition looks a little funny it should work as intended.
I would recommend instead storing the data internally as an array of 16 floats, and then overloading operator()() for element access, i.e. (not compiled or tested):
class Matrix{    float data[16];public:    float operator()(int r, int c) const {        return data[c * 4 + r];    }    float& operator()(int r, int c) {        return data[c * 4 + r];    }    const float* Data() const {        return data;    }};// ...Matrix m;// ...glMultMatrixf(m.Data()); // This might require a const_cast...
Quote:Original post by jyk
Quote:(I'm imagining something along the line of the way arrays are commonly indexed and the need to keep certain data values adjacent for use with SSE).
As far as I know, SIMD is going to be more concerned with whether the elements of the matrix basis vectors are contiguous than with what notional convention is being used. As such, it should be equally straightforward to optimize a math library regardless of which convention is used (again, AFAIK).


Very flexible SIMD (like the one the SH-4 supports) would have no problem with both conventions.
But SSE & SSE2 found in x86 processors have many limitations. Each convention leaves room for different kind of optimizations. Usually libraries taking advantage of SSE transpose the matrix if needed before doing it's math. (And the suffle instruction from SSE is well suited for transposing)
jyk: In other words, it isn't equally straightforward. (because values are ordered in a different way in memory)

Edit: Oh I see why jyk said that. If we want to optimize the multiplication of two nxn matrices with SSE, there won't be much problem with neither convention. Some other operations don't also have any problem.
But if we want to i.e. optimize specifically the vertex transformations (i.e. multiplying a 1x4 vector with a 4x4 matrix), then the convention does make the difference.

Quote:
Is this an accepted convention in games development? If it is does anyone know why?

Because M$ says so [lol]. Direct3D uses the alternate convention, and D3D is the most used for games. If you look at OGL-only games, you'll find they use the traditional convention.

Also note that D3D has it's Z axis flipped. It uses a left-handed coordinate system, where everything else (OpenGL, Glide, most custom software renderers) use a right-handed one.

Why they do all that? I don't know. But as long as D3D remains as the most used for games, this will be the convention used.

Hope this helps
Dark Sylinc
There are two conventions which you need to sort out for deciding how to you design your engine.

1)
do you want the vector on the right or left of your matrix:
like this: A x (more common in math books)
or
like this: x A (more common in game engines)

Both are equally mathematically correct, its a mater of taste.

2)
How do you store your matrix in memory? Row major or column major? C/c++ uses row major storage.


There are a few considerations when deciding on these two issues:

If you first decide on 1) then you should select 2) so you can send data directly into your 3d API for efficiency without doing a transpose first.

If I remember correctly:
OpenGL documentation are using a notation like A x with a column major storage. D3D uses a x A notation with a row major storage. This means that they have identical memory layouts, only using different notations in their documentation.

When using c/c++ the x A is preferred as it maps directly into c arrays for the memory layout used by both D3D and OpenGL (think float m[4][4]), but this is not a strong argument as you shouldn't use c arrays directly anyway.

Using SSE the memory representation of OpenGL and D3D also simplifies vector matrix multiplication (more efficient).



This topic is closed to new replies.

Advertisement