I am trying to achieve a naturally feeling movement of an entity, but the drag gesture always gives me movement perpendicular the view. That means if I restrict y to the stay the same I can only move the model left and right. A movement (of the mouse) upwards would result exclusive into a movement up/down.
My model has many sub entities and I found that I need to create a box as collision shape so that I can move the entire model. Previously if I generated collision shapes it would only move the individual part.
This code is not working mostly, except the restriction for y which feels very much like a hack.
Is there a facility by the system that would rotate the movement vector along the x axis such that y becomes zero?
Or am I approaching this wrong? how would you move objects in immersive space usually?
import SwiftUI
import RealityKit
import RealityKitContent
struct ImmersiveView: View {
@State private var initialDragOffset: SIMD3<Float> = .zero
var body: some View {
RealityView { content in
async let model = Entity(named: "01-TFKmono2-Normal-PremiumGrey", in: realityKitContentBundle)
if let model = try? await model
{
// Set the model's position to the world origin
model.position = [0, 0, 0]
// Offset the model in the y direction by half its height
let boundingBox = model.visualBounds(relativeTo: nil)
let boxSize = boundingBox.extents
// Create the collision box and set it to the model
let collision = CollisionComponent(shapes: [.generateBox(size: [boxSize.x, boxSize.y, boxSize.z]).offsetBy(translation: .init(x: 0, y: boxSize.y / 2, z: 0))], isStatic: false)
model.components.set(collision)
// Set the InputTargetComponent and add the model to the content
model.components.set(InputTargetComponent())
content.add(model)
// move the mode 2 meters in front of viewer
model.position.z = -2
}
}
.gesture(DragGesture()
.targetedToAnyEntity()
.onChanged { value in
if initialDragOffset == .zero {
// Calculate the initial drag offset at the beginning of the drag
let startLocation = value.convert(value.startLocation3D, from: .local, to: value.entity.parent!)
initialDragOffset = value.entity.position - SIMD3<Float>(startLocation.x, startLocation.y, startLocation.z)
}
// Convert the 3D location of the drag gesture to the entity's parent coordinate space
let dragLocation = value.convert(value.location3D, from: .local, to: value.entity.parent!)
var newPosition = SIMD3<Float>(dragLocation.x, dragLocation.y, dragLocation.z) + initialDragOffset
// don't modify y coordinate so that model remains standing on ground
newPosition.y = value.entity.position.y
// Set the entity's position to the new position
value.entity.position = newPosition
}.onEnded({ value in
initialDragOffset = .zero
}))
}
}
#Preview {
ImmersiveView()
.previewLayout(.sizeThatFits)
}