Lab 035 – Teleport to viewpoints
We can adjust the users orientation in the scene by rotating a pivot entity. This will let us take on the viewpoint of a target entity.
Overview
Building on the concepts from Lab 034, we can use the tapped entity orientation in our calculations. We’re going to need a new pivot entity. We’ll make our scene content a child of the pivot. Then we will move the scene content relative to the pivot. We will also rotate the pivot to the inverse rotation of the target.
// Create a new pivot entity. We'll add our scene root as a child to this.
@State var scenePivot: Entity = Entity()
@State var sceneContent: Entity? // set with the root of our RCP scene
...
// Get the root from the RCP scene
if let sceneContent = scene.findEntity(named: "Root") {
// Add the root level scene content as a child of the scene pivot
self.scenePivot.addChild(sceneContent)
self.sceneContent = sceneContent
}When we tap on the gesture, we’ll move the scene content relative to the target, just like in Lab 034. Review that lab for details on the math. The difference here is that we’ll set the position relative to the new scene pivot entity.
sceneContent.setPosition([newPosition.x, 0, newPosition.z], relativeTo: scenePivot)Now that we’ve moved, let’s adjust the orientation. We’ll rotate the pivot entity to the inverse of the orientation for the tapped target.
// Get the orientation of the tapped entity
let entityOrientation = value.entity.orientation
// To make the use face the same direction as the entity we need to rotate the pivot in the opposite direction
let inverseOrientation = entityOrientation.inverse
// set the orientation on the pivot entity to handle scene rotation
scenePivot.orientation = inverseOrientationThis works well, but there is an issue. We are only using TapGesture for this, which does not give us access to the input device pose. In other words, we don’t know if the user has physically turned to face another direction, so we can’t take that into account. In a future lab we will get the device pose and use it as part of these calculations.
Video Demo
Full Lab Code
struct Lab035: View {
// Create a new pivot entity. We'll add our scene root as a child to this.
@State var scenePivot: Entity = Entity()
@State var sceneContent: Entity?
var body: some View {
RealityView { content in
if let scene = try? await Entity(named: "TeleportLabs", in: realityKitContentBundle) {
content.add(scene)
content.add(self.scenePivot)
// Get the scene content and stash it in state
if let sceneContent = scene.findEntity(named: "Root") {
// Add the root level scene content as a child of the scene pivot
self.scenePivot.addChild(sceneContent)
self.sceneContent = sceneContent
}
}
}
.gesture(teleportTapViewpoint)
}
var teleportTapViewpoint: some Gesture {
TapGesture()
.targetedToAnyEntity()
.onEnded { value in
guard let sceneContent = self.sceneContent else { return }
// Calculate the vector from the origin to the tapped position
let vectorToTap = value.entity.position
// Normalize the vector to get a direction from the origin to the tapped position
let direction = normalize(vectorToTap)
// Calculate the distance (or magnitude) between the origin and the tapped position
let distance = length(vectorToTap)
// Calculate the new position by inverting the direction multiplied by the distance
let newPosition = -direction * distance
// Move the sceneContent relative to the scenePivot
// Update sceneOffset's X and Z components, leave Y as it is
sceneContent.setPosition([newPosition.x, 0, newPosition.z], relativeTo: scenePivot)
// Get the orientation of the tapped entity
let entityOrientation = value.entity.orientation
// To make the use face the same direction as the entity we need to rotate the world in the opposite direction
let inverseOrientation = entityOrientation.inverse
// set the orientation on the pivot entity to handle scene rotation
scenePivot.orientation = inverseOrientation
}
}
}Support our work so we can continue to bring you new examples and articles.
Download the Xcode project with this and many more labs from Step Into Vision.

Follow Step Into Vision