Understanding ARKit World Transform Matrices
EDIT: The original question is best addressed by just adding 0.05 to the y component of the node's position
. However, the original answer below does address a bit about composing transformation matrices, if that is something you are interested in.
======================================================================
If you want to apply an operation to a matrix, the most immediately simple way is to make a matrix that does that operation, and then multiply your original matrix by that new matrix.
For a translation, assuming you want to translate by x
, y
, z
, you can do this:
let translation = simd_float4x4(
float4(1, 0, 0, 0),
float4(0, 1, 0, 0),
float4(0, 0, 1, 0),
float4(x, y, z, 1)
)
Note that this is just an identity matrix (1 down the diagonal) with the last column (!!!important, the float4s above are COLUMNS, not ROWS, as they would visually seem) set to contain the x/y/z values. You can research further into homogeneous coordinates, but think of this as just how a translation is represented.
Then, in simd, just do this: let newWorldTransform = translation * oldWorldTransform
and you will have the old world transform translated by your x/y/z translation values (in your example, [x, y, z] = [0, 0.05, 0]).
However, it may be worth exploring why you want to edit your hit test results. I cannot think of a practical use case for that, so maybe if you explain a bit more about what you are trying to do I could suggest a more intuitive way to do it.
ARKIt and RealityKit – Why in Camera matrix last line always zero?
simd_float4x4
structure represents four columns with the following indices: 0
, 1
, 2
, and 3
. The last column with index 3 holds translation values for x
, y
and z
. The fourth element in the last column is not like w
in quaternions, it stands for homogeneous coordinates. Three diagonal 1
values are scale for x
, y
, and z
axis.
┌ ┐
| 1 0 0 tx |
| 0 1 0 ty |
| 0 0 1 tz |
| 0 0 0 1 |
└ ┘
If you need a more detailed info on 4x4 matrices, read this post.
First three values in the lowest row are for projection purposes.
What are the first two columns in SCNMatrix4
SCNMatrix4 is the 3d transformation matrix. In short:
M = T * R * S
Translation by (tx, ty, tz):
┌ ┐
T = | 1 0 0 tx |
| 0 1 0 ty |
| 0 0 1 tz |
| 0 0 0 1 |
└ ┘
Scale by (sx, sy, sz):
┌ ┐
S = | sx 0 0 0 |
| 0 sy 0 0 |
| 0 0 sz 0 |
| 0 0 0 1 |
└ ┘
Rotation by (rx, ry, rz):
R = ZYX
┌ ┐
X = | 1 0 0 0 |
| 0 cos(rx) -sin(rx) 0 |
| 0 sin(rx) cos(rx) 0 |
| 0 0 0 1 |
└ ┘
┌ ┐
Y = | cos(ry) 0 sin(ry) 0 |
| 0 1 0 0 |
| -sin(ry) 0 cos(ry) 0 |
| 0 0 0 1 |
└ ┘
┌ ┐
Z = | cos(rz) -sin(rz) 0 0 |
| sin(rz) cos(rz) 0 0 |
| 0 0 1 0 |
| 0 0 0 1 |
└ ┘
By the way, it's simple to decompose the SCNMatrix4 using SceneKit framework:
let n = SCNNode()
n.transform = YOUR_MATRIX
let position = n.position
let orientation = n.orientation
let scale = n.scale
How do I extract rotation values from a simdTransform in ARKit?
The 3D rotation is expressed as a quaternion, which is made of a 3D vector, describing the axis that you are rotating around, and an angle, which describes the angle of rotation about that axis.
To get a quaternion from a 4x4 simd matrix, you can initialise simd_quatf
from the matrix:
let m = simd_float4x4([
[0.9482585, 0.0065377234, 0.31743154, 0.0],
[-0.07080679, 0.9789629, 0.1913578, 0.0],
[-0.3095027, -0.20393308, 0.9287729, 0.0],
[0.13866597, 0.20701922, -0.57620335, 1.0]
])
let q = simd_quatf(m)
The rotation
property of SCNNode
is expressed as SCNVector4
, which has x, y, and z properties describing the axis, and w describing the rotation. simd_quatf
has axis
(Float
) and angle
(SIMD3<Float>
) properties, so to get your vector:
let sq = SCNVector4(q.axis.x, q.axis.y, q.axis.z, q.angle)
You can see here that the results are the same:
ARKit – eulerAngles of Transform Matrix 4x4
Assuming mij is matrix element in the i-th row and j-th column.
R=atan2(m12, m22)
c2 = sqrt(m00^2 + m01^2)
P = atan2(-m02, c2)
s1 = sin(R), c1 = cos(R)
Y = atan2(s1*m20 - c1*m10, c1*m11-s1*m21)
Source:
The math is described in this document really well: https://pdfs.semanticscholar.org/6681/37fa4b875d890f446e689eea1e334bcf6bf6.pdf
As opposed to going to quaternion, there are some corner cases (gimbal lock) you have to worry about that the above solution handles pretty well.
Related Topics
Why Can't I Pass a Protocol.Type to a Generic T.Type Parameter
Multiple Functions With the Same Name
Access Firebase Variable Outside Closure
Checking If an Object Is a Given Type in Swift
How to Detect If an Skspritenode Has Been Touched
How to Create a Segue That Can Be Called from a Button That Is Created Programmatically
Programmatically Detect Tab Bar or Tabview Height in Swiftui
Forced to Cast, Even If Protocol Requires Given Type
Why Are Emoji Characters Like 👩👩👧👦 Treated So Strangely in Swift Strings
How to Set Layer Cornerradius For Only Bottom-Left, Bottom-Right, and Top-Left Corner
Getting Keyboard Size from Userinfo in Swift
How to Compare Two Dictionaries in Swift
How to Create Array of Unique Object List in Swift
Nsuserdefaults Not Working on Xcode Beta With Watch Os2
Binary Operator * Cannot Be Applied to Operands of Type Int and Double