I want to extract the three components of a simd_float4x4
transform matrix without engine-specific helpers (such as RealityKit's Transform
).
I already found the way to extract translation
and scale
, but I'm missing rotation
.
The closest I found is simd_quatf(matrix)
, but it doesn't work when the transform matrix has a scale
.
let transform = Transform(
scale: simd_float3(1, 2, 3),
rotation: simd_quatf(angle: 0.5, axis: .init(0, 1, 0)),
translation: simd_float3(10, 20, 30)
)
let matrix = transform.matrix
// Translation: OK
let translation = simd_float3(
matrix.columns.3.x,
matrix.columns.3.y,
matrix.columns.3.z
)
print("Expected: \( transform.translation )")
print("Actual: \( translation )")
// Expected: SIMD3<Float>(10.0, 20.0, 30.0)
// Actual: SIMD3<Float>(10.0, 20.0, 30.0)
// Scale: OK
let scale = simd_float3(
simd_length(simd_float3(matrix.columns.0.x, matrix.columns.0.y, matrix.columns.0.z)),
simd_length(simd_float3(matrix.columns.1.x, matrix.columns.1.y, matrix.columns.1.z)),
simd_length(simd_float3(matrix.columns.2.x, matrix.columns.2.y, matrix.columns.2.z))
)
print("Expected: \( transform.scale )")
print("Actual: \( scale )")
// Expected: SIMD3<Float>(1.0, 2.0, 3.0)
// Actual: SIMD3<Float>(1.0, 2.0, 3.0)
// Rotation: doesn't match
let rotation = simd_quatf(matrix)
print("Expected: \( transform.rotation )")
print("Actual: \( rotation )")
// Expected: simd_quatf(real: 0.9689124, imag: SIMD3<Float>(0.0, 0.24740396, 0.0))
// Actual: simd_quatf(real: 1.2757674, imag: SIMD3<Float>(0.0, 0.37579384, 0.0))
Update
I know it's possible to extract a rotation value because Transform
is able to do it, I merely don't know how it's calculated internally.
In this example, both Transform
extract the same rotation value despite the second Transform only has the matrix:
// Initialize from components
let transform1 = Transform(
scale: simd_float3(10, 20, 30),
rotation: simd_quatf(angle: 0.5, axis: .init(0, 1, 0)),
translation: simd_float3(1, 2, 3)
)
// Initialize from composed matrix
let matrix = simd_float4x4([
[8.7758255, 0.0, -4.7942553, 0.0],
[0.0, 20.0, 0.0, 0.0],
[14.382767, 0.0, 26.327477, 0.0],
[1.0, 2.0, 3.0, 1.0]
])
let transform2 = Transform(matrix: matrix)
// Both extract the same value:
// simd_quatf(real: 0.9689124, imag: SIMD3<Float>(0.0, 0.24740396, 0.0))
print( transform1.rotation )
print( transform2.rotation )
// This doesn't extract the same value:
// simd_quatf(real: 3.745107, imag: SIMD3<Float>(0.0, 1.2801384, 0.0))
print( simd_quatf(matrix) )
// They don't match visually either
anchor1.orientation = transform1.rotation
anchor2.orientation = transform2.rotation // same as anchor 1
anchor3.orientation = simd_quatf(matrix) // different from anchor 1 & 2