ARKit/SceneKit 中矩阵的理解

2020-04-27
摘要: 本文简单介绍了 ARKit 和 SceneKit 中 transform 矩阵的含义。

概览#

一般在苹果的 ARKit 和 SceneKit 中,用到的矩阵有 SCNMatrix4simd_float4x4GLKMatrix4

GLKMatrix4是从 OpenGL 框架 GLKit 中带过来的,各种函数很全面。

SCNMatrix4 最初是给 SceneKit 使用的,后来扩展到 ARKit 中,矩阵操作函数不够全面,比如没有转置函数 transpose。

simd_float4x4 看名字就知道是 simd 类型的,是后来为了取代 SCNMatrix4 来推出的,各种函数也很全面。

探究#

其相互转换我们就不作探究了。

Column Major#

我们需要注意的是,在 Apple 的框架中(绝大部分图形引擎/游戏引擎中),矩阵都是 Column-Major 的,也就是说,是按列存储的。因为矩阵运算更适合按列存储。

[^Column-Major or Row-Major?]: https://stackoverflow.com/questions/44897619/is-scenekits-scnmatrix4-stored-as-column-or-row-major, https://stackoverflow.com/questions/53471099/scnmatrix4-vs-simd-column-major-or-row-major

import SceneKit

let translation = SCNMatrix4MakeTranslation(1, 2, 3)

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

所以在 ARKit by Tutorials 3rd 书中 Chapter 6 - Force 一节中:

Note: Transform is an SCNMatrix4 which is a 4x4 mathematical matrix. When you see a reference, like m41, for example, it’s referring to row 4, column 1 of the matrix. Each row in the matrix relates to a specific transform value, like its translation, rotation and scale.

下划线部分描述是错误的。m41 代表着矩阵的第 4 列,第 1 个元素。

Matrix Content#

$$\left[\begin{array}{llll}x_x & y_x & z_x & t_x \\ x_y & y_y & z_y & t_y \\ x_z & y_z & z_z & t_z \\ 0 & 0 & 0 & 1\end{array}\right]$$

如图所示,是一个 $\mathrm{transform}$ 矩阵的典型示意。最后一列中,$m41, m42, m43$ 分别表示其 $x,y,z$ 坐标。前三列的前三个元素用于表示其 $\mathrm{orientation}$,分别表示其 $x,y,z$ 轴的方向向量。经过实验探究,在 camera.transform 中,其为单位向量,即它的 $\mathrm{magnitude}$ 为 $1$,对于其他 $\mathrm{transform}$ 矩阵,不确定是否具有该性质。

let distance = simd_distance(focusNode.simdPosition,
                             simd_make_float3(transform.m41,
                                              transform.m42,
                                              transform.m43))
let direction = SCNVector3(-(distance * 2.5) * transform.m31,
                           -(distance * 2.5) * (transform.m32 - Float.pi / 4),
                           -(distance * 2.5) * transform.m33)

以上是利用 camera.transform 计算到某一节点的距离(第四列)和方向(利用相机的 $z$ 轴,即第三列)的应用。为什么用 $z$ 轴,而且还需要乘以负号?因为在 SceneKit 中,坐标系为如图所示的右手系。Z 轴正方向指向”背后”。

另外,值得一提的是,对于 camera 来说,其坐标轴的定义如下:

This transform creates a local coordinate space for the camera that is constant with respect to device orientation. In camera space, the x-axis points to the right when the device is in UIDeviceOrientation.landscapeRight orientation—that is, the x-axis always points along the long axis of the device, from the front-facing camera toward the Home button. The y-axis points upward (with respect to UIDeviceOrientation.landscapeRight orientation), and the z-axis points away from the device on the screen side.

若竖屏握持手机,$z$ 轴的方向依旧是指向”背后”,即平行于垂直于屏幕向上的向量;$x$ 轴的方向平行于从前置摄像头指向 Home 键的向量;$y$ 轴的方向则是水平向右。如图所示: