Mad Dog Cadogen
Mad Dog Cadogen

Reputation: 667

VisionOS - Set entity position with an anchor

I'm working on a VisionOS app but I'm a bit stuck on placing entities within an immersive space.

What I want:

  1. User enters an ImmersiveSpace
  2. A sphere appears before them (in their view, at head height)
  3. They can then move the sphere around using DragGesture()

The issue I'm having is gesture and position don't seem to play well with each other. I can position the sphere correctly, but when it's dragged it jumps up in the view. It's as if the original position is added again making it jump.

Here's my code so far:

//  ImmersiveView.swift

import SwiftUI
import RealityKit
import RealityKitContent

struct ImmersiveView: View {
    
    @State private var entity = Entity()
    
    var body: some View {
                
        RealityView {
            content in
            do {
                entity = try await Entity(named: "Sphere", in: realityKitContentBundle)
                                
                let anchor = AnchorEntity(.head)
                anchor.anchoring.trackingMode = .once
                entity.setParent(anchor)
                content.add(anchor)
                
                entity.position = SIMD3<Float>(0, 0, -1)
                entity.name = "Head Anchor"
                
            } catch {
                print("Error loading Sphere model: \(error.localizedDescription)")
            }
        }
        .gesture(
            DragGesture()
                .targetedToEntity(entity)
                .onChanged { value in
                    (entity).position = value.convert(
                        value.location3D,
                        from: .local,
                        to: (entity).parent!
                    )
                }
        )
    }
}

Upvotes: 1

Views: 1058

Answers (1)

Andy Jazz
Andy Jazz

Reputation: 58113

You need an intermediate property to store model's translation value in 3D space.

import SwiftUI
import RealityKit
import RealityKitContent

struct ContentView: View {
    @State var sphere = Entity()
    @State var translation: Vector3D = .zero
    let anchor = AnchorEntity(.head, trackingMode: .once)
    
    var gesture: some Gesture {
        DragGesture()
            .targetedToEntity(sphere)
            .onChanged {
                $0.entity.position = $0.convert(
                                             $0.translation3D + translation,
                                           from: .local,
                                             to: sphere)
            }
            .onEnded {
                translation += $0.translation3D
            }
    }    
    var body: some View {
        RealityView { content in
            // rkcb is realityKitContentBundle
            sphere = try! await Entity(named: "Scene", in: rkcb)
            sphere.scale *= 5
            sphere.position = [0, 1,-4]
            anchor.addChild(sphere)
            content.add(anchor)
        }
        .gesture(gesture)
    }
}

Upvotes: 1

Related Questions