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?
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