目前在 simd.framework、Metal 或 MetalKit 中没有用于创建此类矩阵的实用程序函数。但是,您可以使用 GLKit 的矩阵函数并将生成的 GLKMatrix4s 转换为 float4x4s,然后再将它们复制到 Metal 缓冲区中以便在着色器中使用。
GLKMatrix4 只是一个包含 16 个浮点数组的联合,存储在 column-major order 中。
因此,我们可以在float4x4 上编写一个扩展,允许使用 GLKit 矩阵初始化一个 simd 矩阵:
extension float4x4 {
init(matrix: GLKMatrix4) {
self.init(columns: (float4(x: matrix.m00, y: matrix.m01, z: matrix.m02, w: matrix.m03),
float4(x: matrix.m10, y: matrix.m11, z: matrix.m12, w: matrix.m13),
float4(x: matrix.m20, y: matrix.m21, z: matrix.m22, w: matrix.m23),
float4(x: matrix.m30, y: matrix.m31, z: matrix.m32, w: matrix.m33)))
}
}
我通过创建一个表示围绕 +Z 轴逆时针旋转 45 度的 GLKit 矩阵来验证生成的矩阵符合我的期望,并确保它确实将单位向量 <1, 0, 0> 旋转到单位上矢量<sqrt(2)/2, sqrt(2)/2, 0>:
let rotation = GLKMatrix4MakeZRotation(.pi / 4)
let simdRotation = float4x4(matrix: rotation)
let v = float4(1, 0, 0, 0)
let vp = simdRotation * v
print("\(vp)")
> float4(0.707107, 0.707107, 0.0, 0.0)
请注意,我在这里遵守惯例,即矩阵-矢量乘法将矢量视为列矢量并将矩阵放在左侧,这是当前使用中最常见的惯例。
关于 GLKit 和 Metal 的剪辑空间,您应该注意一个警告。您可以阅读有关该问题以及如何纠正它的信息,here。