Matrix multiplication order


#1

For some reason, I’m working with gl 3.3 with the methodologie described by the website openGL tutorial, which implies no use of the matrix stack, so I send the transformations as uniform matricies.
I was wondering why were the order of the * operator inverted in OF, It seem to be a choice of usage. Anyway, it’s fustrating to write M * V * P where I usually write P * V * M in my shaders or with glm. I spend a lot of time to understand why my projection matrix was behaving weidly.

Thanks


#2

Yeah, it frustrated me a lot too. It’s because in oF the matrices are defined in row major order instead of column major. I don’t like it much but I’ve learnt to use it.

One trick you could use is to transpose each matrix before the multiplication and then you’ll be able to use it in the M * V * P order but it’s an additional step that’s honestly not worth it.

If you dig in to the source code of ofMatrix4x4 you’ll find this though…

    /// oF uses row-vector style by default, meaning that when transforming a vector
    /// by multiplying with a matrix, you should put the vector on the left side and
    /// the matrix (or matrices) to its right. When multiplying by multiple matrices,
    /// the order of application of the transforms is left-to-right. This means that
    /// the standard order of manipulation operations is 
    /// vector * scale * rotate * translate.
    /// 
    /// Note that in GLSL, this convention is reversed, and column-vector style is
    /// used. oF uploads the matrices to the GL context correctly, but you should
    /// reverse the order of your vertex manipulations to right-to-left style, e.g.
    /// translate * rotate * scale * vector.
    /// 
    /// On the application side, oF has operators which let you do matrix-vector 
    /// multiplication with the vector on the right if that's your preferred style. 
    /// To set up a combined transformation matrix for working in this style, you
    /// should do matrix transformations with the functions like glTranslate,
    /// glRotate, and glScale.
    /// 

And…

/// Although OpenGL uses post-multiplication (vector-on-the-right) with
	/// column-major matrix memory layout, oF uses pre-multiplication
	/// (vector-on-the-left) with row-major matrix memory layout by default.
	/// 
	/// openGL:
	///
	/// |   |   |   |   |
	/// |:-:|:-:|:-:|:-:|
	/// | 0 | 4 | 8 | 12|
	/// | 1 | 5 | 9 | 13|
	/// | 2 | 6 | 10| 14|
	/// | 3 | 7 | 11| 15|
	/// 
	/// ofMatrix4x4:
	/// 
	/// |   |   |   |   |
	/// |:-:|:-:|:-:|:-:|
	/// | 0 | 1 | 2 | 3 |
	/// | 4 | 5 | 6 | 7 |
	/// | 8 | 9 | 10| 11|
	/// | 12| 13| 14| 15|
	///
	/// However, the two memory layouts are compatible because of a funny trick.
	/// 
	/// When the ofMatrix4x4 is uploaded into OpenGL's memory, OpenGL treats it
	/// like a column-major matrix. The rows of the ofMatrix4x4 are loaded as
	/// columns for the GLSL mat4. The result is that the matrix is transposed.
	/// This seems like a bug, but it's in fact exactly what we want, because to
	/// do the transition from pre-multiplication to post-multiplication style,
	/// we need to perform the very same transpose.
	/// 
	/// By using pre-multiplication, oF treats vectors as 1x4 matrices, since 
	/// that provides a valid 1x4 * 4x4 operation. When moving to
	/// post-multiplication, OpenGL is treating vectors like columns, 
	/// providing a similarly valid 4x4 * 4x1 operation. This means that the
	///  resulting vector in OGL-land is the transpose of the result when
	/// done in oF-land.
	/// 
	/// Recall that in matrix multiplication,
	/// 
	/// (V * M * S)^T = (S^T) * (M^T) * (V^T)
	/// 
	/// What this means is that to convert from pre-multiplication to 
	/// post-multiplication, we need to transpose our matrices (and vectors) 
	/// and reverse the order of multiplication. You're already reversing
	/// the order of multiplication by writing your shaders with the vector
	/// on the right, and the implicit transpose that happens when your matrix
	/// is uploaded to GL memory accomplishes the transposition for free!
	/// 
	/// For more information on this subject, check out
	/// [this post](http://seanmiddleditch.com/matrices-handedness-pre-and-post-multiplication-row-vs-column-major-and-notations/).

#3

ok, so to sum up I just have to invert the order of my successive transformations :smiley:
Thanks :slight_smile:


Porting projects to oF0.10, 3d graphic wgoes
#4

also from next version (which is near to be released) the default vector math library will be glm so the order of multiplication will be the same as glsl


#5

How far are we from 0.10.0? I’m working on an addon that relies on a lot of matrix vector stuff (and I actually sent a PR last night due to that) but I might as well go all glm on it if we’re really close to release? If I’m not mistaken, glm already already has the methods implemented that I’ve been having to add in ofMatrix3x3 and ofMatrix4x4 was up next in my list.


#6

it should be ready in march. ofMatrix3x3 has never been very complete and it’s weirdly implemented. For example in you PR you need a switch case to access the different members to set the columns which can be slow. That’s one of the reasons why we moved to glm, i would use glm if i would be doing any addon today


#7

Talking about matricies, with opengl 3.3, ofLoadMatrix(m) or ofLoadIdentity() don’t have any effect, even between push/pop


#8

is that with 0.9.8 or the nightly builds / OF from github? that should be working can you put an example that demos the problem?


#9

with 3.3, VisualStudio2015 Community
myShader.begin();
//(uniform mat4 modelViewProjectionMatrix or any other build in uniform matrix)
ofPushMatrix()
ofLoadMatrix(ofMatrix4x4::makeRotation…)
ofDrawSomething()
ofPopMatrix()