discoverthreejs-site icon indicating copy to clipboard operation
discoverthreejs-site copied to clipboard

The book uses column-major order for matrices, while three.js docs use row-order

Open w2xi opened this issue 4 years ago • 4 comments

Describe the bug When i was reading about transformation matrices topic in this book, i found that the description of formula of X-Rotation has a little difference with the makeRotationX method of Matrix4 class in official docs. I didn't know which one was correct. So, i report a issue here now.

Screenshots Transformation Matrices screenshot-discoverthreejs com-2021 08 27-10_08_02

makeRotationX method of Matrix4 class screenshot-threejs org-2021 08 27-12_58_56

w2xi avatar Aug 27 '21 02:08 w2xi

Hey, good catch. Actually neither is incorrect - the difference is because there are two conventions for writing matrices called row-major and column-major ordering.

Internally, three.js matrices are stored in column-major order. However, for some reason the matrix.set method takes the elements in row-major order and internally converts them to column-major (I'm sure there's a good reason for that but I don't know it 😅).

If the 4x4 matrix is made up of four vectors:

X = (a,b,c,d)
Y = (e,f,g,h)
Z = (i,j,k,l)
W = (m,n,o,p)

Then we can write the matrix in row major order (each vector makes up a row):

Mr = (
    a, b, c, d,
    e, f, g, h, 
    i, j, k, l,
    m,n,o,p
)

Or column-major order (each vector makes up a column):

Mc = (
    a, e, i, m,   
    b, f, j, n, 
    c, g, k, o, 
    d, h, l, p
)

Then a transformation matrix representing an X rotation around θ can be written either in row major order:

ROTXr = (
    1, 0, 0, 0,
    0, cos(θ), -sin(θ), 0,
    0, sin(θ), cos(θ), 0,
    0, 0, 0, 1
)

or in column major order:

ROTXc = (
    1, 0, 0, 0,
    0, cos(θ), sin(θ), 0,
    0, -sin(θ), cos(θ), 0,
    0, 0, 0, 1
)

The docs follow the Matrix4.set method and everything is written in row-major order. However, in the book I've written things in column-major to match the way they are stored internally, and also because all of the reference books I checked (and wikipedia) write matrices in column major order.

So there's two choices here:

A. Current situation: write matrices to match the literature (e.g. realtime rendering book, wikipedia, several game math books that I checked) B. Switch over the write matrices the way the three.js docs do even though it's less common

Neither one of these is correct so I'm open to suggestions.

looeee avatar Aug 27 '21 09:08 looeee

I tracked down the original reasoning here, way back in 2013.

https://github.com/mrdoob/three.js/issues/3814#issuecomment-23323800

Originally three.js stored matrices internally in row-major (I guess from pre-WebGL days) but then switched (in r49) to column-major for efficiency and to match other WebGL/OpenGL libraries. To help with backwards compatibility they kept the .set method as row-major.

looeee avatar Aug 28 '21 02:08 looeee

Thanks your reply. I just found out It seems to be explained that the reason why it does with this in docs. screenshot-threejs org-2021 08 28-12_44_53

w2xi avatar Aug 28 '21 04:08 w2xi

Thanks to the work you have done. I am new to threejs. This book covers everything as I need to get started. Great! it helped me a lot so far, thanks.

w2xi avatar Aug 28 '21 05:08 w2xi