Retrieve Normal Vector of Tap location? RayCast from device(head)?

The Location3D that is returned by a SpatialTapGesture does not return normal vector information. This can make it difficult to orient an object that's placed at that location.

Am I misusing this gesture or is this indeed the case?

As an alternative I was thinking I could manually raycast toward the location the user tapped, but to do that, I need two points. One of those points needs to be the location of the device / user's head in world space and I'm not familiar how to get that information.

Has anyone achieved something like this?

Answered by J0hn in 771724022

Alright. Good riddance. This worked for me:

NOTE: There's a BIT of oddness with raycasting to a tap gesture's location. Sometimes it fails, which is confusing to me given the tap succeeded. Maybe I'm not converting the locations correctly? Maybe it works better on device?

In a tap gesture handler, get the tap location on a collision shape with:

let worldPosition: SIMD3<Float> = value.convert(value.location3D, from: .local, to: .scene)

With a running WorldTrackingProvider you can get the current device pose with

worldTracking.queryDeviceAnchor(atTimestamp: CACurrentMediaTime())

Then process it like so to get it world-space:

let transform = Transform(matrix: pose.originFromAnchorTransform)
let locationOfDevice = transform.translation

You can then do a raycast to a tap location in world-coordinate-space like so:

let raycastResult = scene.raycast(from: locationOfDevice, to: worldPosition)

If successful, an entry in the raycast result will have normal information. Here I grab the first one

guard let result = raycastResult.first else {
    print("NO RAYCAST HITS?????")
}

let normal = result.normal

Make a quaternion to rotate from identity to the normal vector's angle:

// Calculate the rotation quaternion to align the forward axis with the normal vector
let rotation = simd_quatf(from: SIMD3<Float>(0, 1, 0), to: normal)

Apply it to an entity:

cylinder.transform.rotation = rotation
Accepted Answer

Alright. Good riddance. This worked for me:

NOTE: There's a BIT of oddness with raycasting to a tap gesture's location. Sometimes it fails, which is confusing to me given the tap succeeded. Maybe I'm not converting the locations correctly? Maybe it works better on device?

In a tap gesture handler, get the tap location on a collision shape with:

let worldPosition: SIMD3<Float> = value.convert(value.location3D, from: .local, to: .scene)

With a running WorldTrackingProvider you can get the current device pose with

worldTracking.queryDeviceAnchor(atTimestamp: CACurrentMediaTime())

Then process it like so to get it world-space:

let transform = Transform(matrix: pose.originFromAnchorTransform)
let locationOfDevice = transform.translation

You can then do a raycast to a tap location in world-coordinate-space like so:

let raycastResult = scene.raycast(from: locationOfDevice, to: worldPosition)

If successful, an entry in the raycast result will have normal information. Here I grab the first one

guard let result = raycastResult.first else {
    print("NO RAYCAST HITS?????")
}

let normal = result.normal

Make a quaternion to rotate from identity to the normal vector's angle:

// Calculate the rotation quaternion to align the forward axis with the normal vector
let rotation = simd_quatf(from: SIMD3<Float>(0, 1, 0), to: normal)

Apply it to an entity:

cylinder.transform.rotation = rotation
Retrieve Normal Vector of Tap location? RayCast from device(head)?
 
 
Q