Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm teaching myself 3D maths and in the process building my own rudimentary engine (of sorts). I was wondering what would be the best way to structure my matrix class. There are a few options:

  1. Separate member variables:

    struct Mat4 {
        float
            m11, m12, m13, m14,
            m21, m22, m23, m24,
            m31, m32, m33, m34,
            m41, m42, m43, m44;
    
        // methods
    
    }
    
  2. A multi-dimensional array:

    struct Mat4 {
        float[4][4] m;
    
        // methods
    
    }
    
  3. An array of vectors

    struct Mat4 {
        Vec4[4] m;
    
        // methods
    
    }
    

I'm guessing there would be positives and negatives to each.

From 3D Math Primer for Graphics and Game Development, 2nd Edition p.155:

n-by-m matrix. Source (Wikipedia)

Matrices use 1-based indices, so the first row and column are numbered 1. For example, a12 (read “a one two,” not “a twelve”) is the element in the first row, second column. Notice that this is different from programming languages such as C++ and Java, which use 0-based array indices. A matrix does not have a column 0 or row 0. This difference in indexing can cause some confusion if matrices are stored using an actual array data type. For this reason, it’s common for classes that store small, fixed size matrices of the type used for geometric purposes to give each element its own named member variable, such as float a11, instead of using the language’s native array support with something like float elem[3][3].

So that's one vote for method one.

Is this really the accepted way to do things? It seems rather unwieldy if the only benefit would be sticking with the conventional math notation.

share|improve this question
2  
Think about the interface of your matrix first (the public member functions), for instance you might need an GetRow or GetForwardVector, think about how to implement them most efficiently, then the internal datastructures just fall into place naturally –  Maik Semder Jul 7 '12 at 14:22
2  
In C++ you can use both arrays and member variables at the same time btw, Unions :) –  API-Beast Jul 7 '12 at 14:36
1  
I would definitely go for method one since for a lot of linear algebra you need a few specific cells in your matrix. The arrays are never going to contain just those you need so you will always need to index multiple arrays for simple questions, like the above mentioned forward vector. This is also how Microsoft does it in their XNA framework (but of course one company doing it isn't the best argument) –  Roy T. Jul 7 '12 at 15:45
2  
I would definitely stick with zero-indexed arrays - I do a lot of scientific computing, and it is a lot less confusing to convert the indices when moving between maths and code, than to be inconsistent within your code. If you go with option 2 or 3, it will be easier to make your routines work with any size of matrices, which you might well end up needing for something (for example, I guess you will probably have a matrix multiplication routine, which you might use for matrix*matrix or matrix*vector). –  James Jul 7 '12 at 20:56

1 Answer 1

up vote 10 down vote accepted

Why choose? You can have both. (Without any added complexity to logic and without any additional memory requirement thanks to unions.)

struct Mat4
{
    union
    {
        struct
        {
          float m11, m12, m13, m14,
                m21, m22, m23, m24,
                m31, m32, m33, m34,
                m41, m42, m43, m44;
        };
        float[4][4] m;
    };
// methods
}
share|improve this answer
1  
+1, I normally use float[4][4] m4x4 and float[16] m16 as well as the individual elements, but this is something that you tailor to your own program's requirements. –  Darth Satan Jul 7 '12 at 17:20
    
Note that you often need compiler-specific extensions to make this specific thing work, as ISO C++ does not allow anonymous structures (but in practice it will work on most of the major compilers with extensions). –  Josh Petrie Jul 7 '12 at 17:32
    
I guess you would get away with this approach, but... Is it "allowed" according to ISO c++ to read it as "m", when it was written as "m11, m22, ..."? –  Andre Jul 7 '12 at 17:58
1  
@Andre it is not explicitly allowed by C++ but every major compiler supports it (it’s called type-punning through anonymous unions) as a documented extension. It is also explicitly allowed in C. –  Sam Hocevar Jul 7 '12 at 18:41
1  
You mean I can have my cake and eat it too?! Thanks a bunch mate! (it works in D as well, hehe) –  bjz Jul 8 '12 at 5:10

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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