3

The source of my confusion is the documentation on SCNMatrix4 from Apple:

SceneKit uses matrices to represent coordinate space transformations, which in turn can represent the combined position, rotation or orientation, and scale of an object in three-dimensional space. SceneKit matrix structures are in row-major order, so they are suitable for passing to shader programs or OpenGL APIs that accept matrix parameters.

This seems contradictory since OpenGL uses column-major transformation matrices!

In general the documentation of Apple on this topic is poor:

  • GLKMatrix4 does not talk about column vs. row major at all, but I am certain from all discussions online that GLKMatrix is plain and simple column-major.
  • simd_float4x4 does not talk about the topic, but at least the variable names make it clear that it is stored as columns:

From simd/float.h:

typedef struct { simd_float4 columns[4]; } simd_float4x4;

Some discussion online about SCNMatrix4 talk as if SCNMatrix4 is different from GLKMatrix4, but looking at the code for SCNMatrix4 give some hints that it might just be column-order as expected:

/* Returns a transform that translates by '(tx, ty, tz)':
 * m' =  [1 0 0 0; 0 1 0 0; 0 0 1 0; tx ty tz 1]. */
NS_INLINE SCNMatrix4 SCNMatrix4MakeTranslation(float tx, float ty, float tz) {
    SCNMatrix4 m = SCNMatrix4Identity;
    m.m41 = tx;
    m.m42 = ty;
    m.m43 = tz;
    return m;
}

So is SCNMatrix4 row-major (storing translations in m14, m24, m34) or column-major (storing translations in m41, m42, m43)?

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Christopher Oezbek
  • 23,994
  • 6
  • 61
  • 85
  • Also very important that causes significant confusion as well https://stackoverflow.com/questions/53435756/xcode-simd-issue-with-translation-and-rotation-matrix-example – oneiros Nov 24 '18 at 15:01

1 Answers1

3

SCNMatrix4 stores the translation in m41, m42 and m43, as is GLKMatrix4. This little Playground confirms it as well as its definition.

import SceneKit

let translation = SCNMatrix4MakeTranslation(1, 2, 3)

translation.m41
// 1
translation.m42
// 2
translation.m43
// 3

I have no idea why this is wrong in the documentation though, probably just a mistake.

Christopher Oezbek
  • 23,994
  • 6
  • 61
  • 85
jlsiewert
  • 3,494
  • 18
  • 41