I'm trying to understand better how to 'navigate' around a large USD scene inside a RealityView in SwiftUI (itself in a volume on VisionOS).
With a little trial and error I have been able to understand scale and translate transforms, and I can have the USD zoom to 'presets' of different scale and translation transforms.
Separately I can also rotate an unscaled and untranslated USD, and have it rotate in place 90 degrees at a time to return to a rotation of 0 degrees.
But if I try to combine the two activities, the rotation occurs around the center of the USD, not my zoomed location.
Is there a session or sample code available that combines these activities? I think I would understand relatively quickly if I saw it in action.
Thanks for any pointers available!
The solution may be:
- Create a new entity. Let’s refer to it as the parent entity.
- Add the entity (from the USDZ) to the parent. Let’s refer to it as the child entity.
- Perform the rotations on the parent entity.
- Perform the translations and scaling on the child entity.
If that doesn’t work the following explanation and snippet will help you understand rotating with pivot entities which should help you accomplish your goal. Otherwise please reply with a focused code snippet that recreates the issue.
A rotation’s pivot point is relative to its entity’s origin. It sounds like the origin of your entity (USDZ) is the center of its content. What you’re observing is expected. A common way to rotate at a different pivot point is to create a pivot entity, position it at the desired pivot point, make it the parent of the entity you wish to rotate, then rotate the pivot entity. Below is a small snippet that demonstrates this. Tap the robot and notice its rotation pivots where you tap.
var body: some View {
RealityView { content in
// Robot is available in Reality Composer Pro's content library
if let robot = try? await ModelEntity(named: "Robot"),
let mesh = robot.model?.mesh,
let shape:ShapeResource = try? await .generateConvex(from: mesh) {
robot.scale = .init(repeating: 1.5)
robot.components.set(CollisionComponent(shapes: [shape]))
robot.components.set(InputTargetComponent())
content.add(robot)
}
}
.gesture(SpatialTapGesture()
.targetedToAnyEntity()
.onEnded { event in
let robot = event.entity
let location3D = event.convert(event.location3D, from: .local, to: .scene)
let previousParent = robot.parent
// create a new invisible entity and position it where the tap occurred
let pivot = Entity()
pivot.position = location3D
// add the robot to the pivot
pivot.addChild(robot, preservingWorldTransform: true)
// rotate the pivot to rotate the robot 90 degrees on its z-axis
let angle = Float(Angle(degrees: 90).radians)
pivot.transform.rotation *= simd_quatf(angle: angle, axis: [0, 0, 1])
// reparent the robot to its previous parent
previousParent?.addChild(robot, preservingWorldTransform: true)
// remove the pivot
pivot.removeFromParent()
}
)
}