Bug in RealityKit Transform

The same rotation produces different rotation matrices. For example this:

let R1 = Transform(rotation: simd_quatf(from: [1, 0, 0], to: [0, 1, 0]))
let R2 = Transform(rotation: simd_quatf(from: [2, 0, 0], to: [0, 2, 0]))
print(R1.matrix)
print(R2.matrix)

outputs

simd_float4x4([[-1.1920929e-07, 1.0000001, 0.0, 0.0], [-1.0000001, -1.1920929e-07, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]])
simd_float4x4([[-3.0000005, 4.0000005, 0.0, 0.0], [-4.0000005, -3.0000005, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]])

With some cleaning up the matrices look like this

// R1
[0, -1, 0, 0]
[1,  0, 0, 0] 
[0,  0, 1, 0]
[0,  0, 0, 1]

// R2
[-3, -4, 0, 0]
[ 4, -3, 0, 0] 
[ 0,  0, 1, 0]
[ 0,  0, 0, 1]

We see that R2 actually scales its input. A pure rotation should have a scale of 1.

Another disagreement occurs when evaluating the Transform's scale. For example this

print(R2.scale)
print(Transform(matrix: R2).scale)

outputs this

SIMD3<Float>(1.0, 1.0, 1.0)
SIMD3<Float>(5.000001, 5.000001, 1.0)

Why are the scales different for the same exact transform?

Also, the rotation angles do not agree. This

print(R2.rotation.angle * 180 / .pi)
print(Transform(matrix: R2.matrix).rotation.angle * 180 / .pi)

produces

90.00001
126.8699

90 degrees is the correct rotation angle. Where does 126.87 degrees come from?

The Transform API specifies that rotation should be a unit quaternion. The quaternion you used for R2 is not normalized.

I see that it says that. But the fact still remains that it is possible to create a Transform that disagrees with itself.

This test should never fail:

func testTransform(A: Transform) {
    assert(A.rotation.angle == Transform(matrix: A.matrix).rotation.angle)
}

Something strange is going on internally with RealityKit's Transform. There must be redundancy in Transform's state that leads it to disagree with itself when passed an unnormalized quaternion.

Bug in RealityKit Transform
 
 
Q