15

In ARKit, when I perform a hit-test, I get back an instance of ARHitTestResult. One of the properties of this is worldTransform, which I understand contains a 4x4 transformation matrix of the position of the object – simd_float4x4.

As someone who is very unfamiliar with linear algebra and 3D graphics, how would I edit this matrix to, say, increase its y coordinate by 0.05?

If there is a blog post or something I could look at that would help me wrap my head around this, please let me know. I am not sure what terms I should be googling.

Sorry if my question is full of misunderstandings! As you can probably tell, I am not too familiar with these concepts.

Thank you to anyone who helps.

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
Zack
  • 1,585
  • 1
  • 18
  • 29
  • 1
    You should go through https://github.com/olucurious/Awesome-ARKit this. it has many examples. you can get clear idea by this examples – Prashant Tukadiya Sep 08 '18 at 04:16

2 Answers2

14

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.

Dennis L
  • 1,713
  • 14
  • 21
  • The reason I want to do this is: I have a plane that I have detected and when the users taps on the plane, I want an object to appear there. If I use the hit test result directly, the object appears in the middle of the plane instead of sitting in top of it, so I want to shift it up. – Zack Sep 09 '18 at 06:43
  • 1
    Oh, in that case it seems like the simplest thing might be to just add 0.05 to the y component of the node's `position` value after you create it in the plane. Would that work? – Dennis L Sep 11 '18 at 06:16
  • Oh yes, I didn’t think of that. I’ll get back to you on whether or not it works, thanks. – Zack Sep 11 '18 at 06:44
  • 1
    Thank you, that has worked! I have marked your answer as accepted and I think it would be a good idea to edit your answer to refer to the comments as well. Thank you! – Zack Sep 15 '18 at 02:05
  • Thanks @Zack, glad to hear it worked. I went ahead and updated my answer to reflect that. – Dennis L Sep 18 '18 at 04:24
  • @Dennis L In my case i want to transform worldtransform to view coordinates. i used projectpoint of scenekit to do this. But it gives me inaccurate results. Is there any extra processing to be done to the input of ""projectpoint" – Roshan Bade Aug 19 '19 at 04:00
  • Hey @Dennis, thank you so much for your detailed answers! I and my team stuck on an issue for days ah :/ I posted an interesting question: https://stackoverflow.com/questions/63662318/arkit-apply-filter-cifilter-to-a-specific-part-vertex-of-an-arfaceanchor Would love your suggestions! – Roi Mulia Aug 31 '20 at 07:32
  • Thank you for the edit, `.points` is what I needed. I don't understand, why are these properties not in the documentation for [`worldTransform`](https://developer.apple.com/documentation/arkit/arraycastresult/3132062-worldtransform) or [`simd_float4x4`](https://developer.apple.com/documentation/accelerate/simd_float4x4)? – Boris Verkhovskiy Nov 04 '21 at 19:47
5

Matrices in 3D graphics is a regular way to translate, rotate, scale and shear 3D objects. In ARKit, RealityKit and SceneKit for consistent linear transformations you need to use simd_float4x4-like matrices:

var myMatrix: simd_float4x4


Translation 4x4 Matrix has 16 elements inside – 4 elements (float4) by 4 columns. Columns indices are 0, 1, 2 and 3. Translation matrix uses the fourth column with index 3.

enter image description here

SceneKit example

Use the following code to place your model 25 cm above its default position SCNVector3(0,0,0):

let sphereNode = SCNNode()
sphereNode.geometry = SCNSphere(radius: 1.0)
sphereNode.geometry?.firstMaterial?.diffuse.contents = UIColor.red
scene.rootNode.addChildNode(sphereNode)
    

var translation = matrix_identity_float4x4
translation.columns.3.y = 0.25
sphereNode.simdWorldTransform = translation

RealityKit example

let model = ModelEntity(mesh: .generateBox(size: 0.3))
let anchor = AnchorEntity()
anchor.addChild(model)

let currentMatrix = anchor.transform.matrix
var positionMatrix = simd_float4x4()
positionMatrix.columns.3.y = 0.25
let transform = simd_mul(currentMatrix, positionMatrix)
anchor.move(to: transform, relativeTo: model, duration: 1.0)
Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
  • I am wondering why 4*4 matrices usages last column values for translation instead of the last row? As shown in apple documentation example for 3*3 matrix, The last row is used for translation values. https://developer.apple.com/documentation/accelerate/simd/working_with_matrices – kidsid49 Nov 05 '19 at 17:09
  • In `matrix_identity_float4x4` – last row is for projection. – Andy Jazz Nov 05 '19 at 17:23