|
Writing OpenGL-compatible Matrix Code by Morgan Aldridge This document isn't intended to to teach you how to use matrices or how to use matrices for translations and/or rotations, it is merely intended to quickly discuss some of the issues that you will encounter when trying to write matrix code that will be compatible with OpenGL's matrix code. First, you may be wondering why would you want to write matrix code that is compatible with OpenGL's matrix code. If you've ever needed to do complex transformations, rotations, and/or scaling on data that, then you already understand how important matrices are, but imagine that you could re-use some of your matrices for your OpenGL rotations, translations, and scaling, that's where it comes in handy. Now, one thing that you should note is that most of the newer graphics cards are starting to have hardware accelerated T&L (transform and lighting), so they can process matrices much faster than you can write your own, so if you write your own matrix code you will lose the possibility of gaining the extra T&L speed from the graphics accellerator. But, many things still need to be done in software with matrices, so it's always a good idea to have some matrix code, it's just an added plus if those matrices can also be used with OpenGL. So, how does OpenGL handle matrices differently? Well, it's mostly just a matter of storage, so that's what I'll describe now. OpenGL uses 4x4 matrices, the standard for use with 3D translations and rotations, but what differs from the standard is the way that the matrices are stored and how the elements of the matrix are accessed (basically still a storage issue, but a different type of storage issue). Matrices, when implemented in computer software, are stored as either a two dimensional array (Figure 1) or as a single array (Figure 2). Now, with OpenGL you can define your arrays as either floats or doubles, there are functions for handling matrices of either type.
OpenGL uses arrays defined as a single dimension array, so you would use a method such as shown in Figure 2. The other issue with the storage of the matrices is how the data is organised in the array to represent a matrix, there are also basically two different methods, the standard method is to store each element in the matrix by row & column (Figure 3), but OpenGL does everything (yes even matrix storage) as if you were looking at a set of axes so it stores elements by x & y (Figure 4).
So, you can see by Figure 2 & 3 how the elements are ordered in the array (from index 0 to 16). Now, accessing the elements so that data is stored correctly for respective formats is really the hardest thing you'll need to do. To access data stored in 2D arrays for matrices (not the method that OpenGL uses) you would normally access it by row & column. For example, the following is how you'd access an element in row 1, column 3 (Figure 5):
To access the same element in a single dimension array using the normal ordering method of row & column (also not OpenGL's method), you would do the following (Figure 6):
Now, to access the same element by x & y (OpenGL's method), you need to actually access it by column & row as follows (Figure 7):
I prefer to access to access the elements by row & column starting at indices of 1 (instead of indices of 0 as you do with arrays), because it makes it much more like true mathematical matrices as drawn on paper, so what I usually do is create a macro. Now, for accessing a single dimension array using row & column I would create a macro as follows (Figure 7):
If I were going to create a macro to access matrix elements by x & y, OpenGL's method, I would simply reverse the r & c in the code of the macro (not in the name) as follows (Figure 9):
With that macro (Figure 9) I can continue to access the elements by the familiar row & column method but will actually be accessing it by x & y. A very handy macro to have indeed! To use the macro I would simply define it (as shown in Figure 8 or 9), then I would make a call similar to the following (Figure 10):
Hopefully this is all making pretty good sense so far. Now that you see the differences between OpenGL's methods of storing matrices the only left to do is learn how to give OpenGL one of your matrices. This is probably the easiest thing to do since OpenGL has predefined functions which you can use and there are really only two of them! glLoadMatrixf() and glMultMatrixf() (there are also the equivalent functions glLoadMatrixd() and glMultMatrixf() which do the same thing only they take a matrix of doubles instead of a matrix of floats) allow you to load a matrix as the current OpenGL matrix, and to multiply the current OpenGL matrix by a matrix, respectively. Each takes one argument, a matrix such as those this article has discussed as stored with the method OpenGL uses, they're fairly easy to use. Well, I hope this has helped you create matrix code that is compatible with OpenGL's matrix code. Additional Information: Need some more information on how matrices work and how to write code to use them? Check out Matrix Math by Jeff Weeks and Codex Software, it includes code for multiplying matrices, multiplying a vertex by a matrix, and shows the various transformation, rotation, and scaling matrices. Want to learn more about the OpenGL matrix commands mentioned here? Check out the OpenGL Reference Manual.
|