What Are the First Two Columns in Scnmatrix4

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

Is SceneKit's SCNMatrix4 stored as column or row-major?

SCNMatrix4 stores the translation in m41, m42 and m43, as is GLKMatrix4. This little Playground confirms it as well as its definition.

import SceneKit

let translation = SCNMatrix4MakeTranslation(1, 2, 3)

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

I have no idea why this is wrong in the documentation though, probably just a mistake.

SceneKit – What is the lowest row of elements in SCNMatrix4 for?

I could be wrong but I think m41, m42, and m43 can be used to get positional data and is essentially the same as using result.worldTransform.columns.3when performing a hitTest.

As such when placing an SCNNode via performing an ARSCNHitTest you could use either:

let hitTestTransform = SCNMatrix4(result.worldTransform)
let positionFromMatrix4 = SCNVector3(hitTestTransform.m41, hitTestTransform.m42, hitTestTransform.m43)
let positionFromColumns = SCNVector3(result.worldTransform.columns.3.x, result.worldTransform.columns.3.y, result.worldTransform.columns.3.z)

The below example should help clarify things:

/// Places Our Model At The Position Of An Existining ARPlaneAnchor
///
/// - Parameter gesture: UITapGestureRecognizer
@IBAction func placeModel(_ gesture: UITapGestureRecognizer){

//1. Get The Touch Location
let touchLocation = gesture.location(in: self.augmentedRealityView)

//2. Perform An ARSCNHitTest For Any Existing Planes
guard let result = self.augmentedRealityView.hitTest(touchLocation, types: [.existingPlane, .existingPlaneUsingExtent]).first else { return }

//3. Get The World Transform
let hitTestTransform = SCNMatrix4(result.worldTransform)

//4. Initialize Our Position Either From .m41, .m42, .m43 Or From Columns.3
let positionFromMatrix4 = SCNVector3(hitTestTransform.m41, hitTestTransform.m42, hitTestTransform.m43)
let positionFromColumns = SCNVector3(result.worldTransform.columns.3.x, result.worldTransform.columns.3.y, result.worldTransform.columns.3.z)

//5. Log Them To Check I'm Not Being A Moron
print(
"""
Position From Matrix 4 == \(positionFromMatrix4)
Position From Columns == \(positionFromColumns)
""")

/*
Position From Matrix 4 == SCNVector3(x: -0.39050543, y: -0.004766479, z: 0.08107365)
Position From Columns == SCNVector3(x: -0.39050543, y: -0.004766479, z: 0.08107365)
*/

//6. Add A Node At The Position & Add It To The Hierachy
let boxNode = SCNNode(geometry: SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0))
boxNode.geometry?.firstMaterial?.diffuse.contents = UIColor.cyan
boxNode.position = positionFromMatrix4
self.augmentedRealityView.scene.rootNode.addChildNode(boxNode)
}

Hope it helps...

SceneKit Transformation ScnMatrix4

the Core Animation programming guide explains this briefly:

https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreAnimation_guide/CoreAnimationBasics/CoreAnimationBasics.html#//apple_ref/doc/uid/TP40004514-CH2-SW18

In the case of complex transforms it's not always possible to extract the position/rotation/scale information directly from the coefficients though.

simd_float4x4, SCNMatrix columns not documented

A "transformation matrix" in 3D graphics doesn't store translation, rotation, scale, and perspective per column (or row). Instead these are all stored mixed so that multiplying a 4-element vector with the transformation matrix will "apply" the transformation (that is, the result of the multiplication is the transformed vector) and so that multiplying two transformation matrices produce a new transformation matrix that combines the two.

Because of this it's not very meaningful to describe the columns, rows, or even most cells in the matrix (the diagonal is used for scaling but those same cells are also used for some rotation values).

You can read more about transformation matrices on Wikipedia and the Wikipedia page for "affine" transforms has some good illustrations of 2D transforms.

ARKit nodes dissapear after sceneView.session.setWorldOrigin transformation

After resolving the scaling issues, I reduced the size of the world (scale) and put the objects a little further apart from each other (to fix the flickering/"z-fighting") - wikipedia's page was very helpful, I'm pretty sure all I needed to do was reduce the world size.

Xcode simd - issue with Translation and Rotation Matrix Example

This can be confusing, yes.

The documentation you mentions makes the following computation:

let translatedVector = positionVector * translationMatrix

Note that the matrix is on the right side of the multiplication.
You are probably used to the notation b = M * a but if you take the transpose you get b' = a' * M' which is what the sample does.

In SIMD there's no way to differentiate a vector from its transpose (b from b') and the library allows you to make the multiplication in both ways:

static simd_float3 SIMD_CFUNC simd_mul(simd_float3x3 __x, simd_float3 __y);
static simd_float3 SIMD_CFUNC simd_mul(simd_float3 __x, simd_float3x3 __y) { return simd_mul(simd_transpose(__y), __x); }


Related Topics



Leave a reply



Submit