visionOS – Anchoring particle system to hand also anchors spawned particles

Dear Apple Developer Forums,

I am just starting out developing in Swift, using RealityKit and Reality Composer Pro, as a project I'm working on is transitioning from using Unity to native only. I am trying to attach a particle system to the user's right hand, emitting from a single point, showing a 'spatial trail' of sorts, basically acting as a visualizer of the hand's spatial history. However, in Reality Composer Pro, when I anchor my particle emitter's parent entity using an Anchor component, even though the "Particles Inherit Transform" option is unticked (false), all of the spawned particles will also be anchored to the specified anchor position, as opposed to the expected behavior, which is that the emitter itself is anchored, but the spawned particles retain their spawn position in worldspace. Am I missing something, or does anchoring simply behave this way in relation to particle systems?

Thank you!

RCP 1.0, Xcode 15.4, visionOS 1.2

Answered by Vision Pro Engineer in 801385022

Hi @ztnyngy

The effect you're after is possible using an ARKitSession with a HandTrackingProvider to position the particle emitter at the position of the user's right hand.

To do this, start by adding an entity with a particle emitter to the default "Immersive" scene in Reality Composer Pro, naming it "ParticleEmitter". Then, load that entity in your reality view and add it as the child to your rightHandRoot entity. Finally, start an ARKit hand tracking session and update your rightHandRoot entity to the anchor position of the tracked right hand, which in turn updates the particle emitter's position.

struct ImmersiveView: View {

    var rightHandRoot = Entity()
    
    let arkitSession = ARKitSession()
    let handTrackingProvider = HandTrackingProvider()
    
    var body: some View {
        RealityView { content in
            // Load the particle emitter entity from the Reality Composer Pro scene.
            if let immersiveContentEntity = try? await Entity(named: "Immersive", in: realityKitContentBundle),
               let particleEmitter = immersiveContentEntity.findEntity(named: "ParticleEmitter") {
                // Add the particle emitter to the scene as a child of the particle root entity.
                rightHandRoot.addChild(particleEmitter)
                content.add(rightHandRoot)
            }
        }.task {
            do {
                // Start hand tracking.
                try await arkitSession.run([handTrackingProvider])
                
                // Wait for hand tracking updates.
                for await update in handTrackingProvider.anchorUpdates {
                    // Get the anchor.
                    let anchor = update.anchor
                    
                    // Update the particle root transform to match the right hand anchor.
                    if anchor.chirality == .right {
                        rightHandRoot.setTransformMatrix(anchor.originFromAnchorTransform, relativeTo: nil)
                    }
                }
            } catch {
                print("Failed to start hand tracking session. \(error)")
            }
        }
    }
}

Finally, don't forget to add an NSHandsTrackingUsageDescription to your app's information property list.

Hope this does the trick!

Accepted Answer

Hi @ztnyngy

The effect you're after is possible using an ARKitSession with a HandTrackingProvider to position the particle emitter at the position of the user's right hand.

To do this, start by adding an entity with a particle emitter to the default "Immersive" scene in Reality Composer Pro, naming it "ParticleEmitter". Then, load that entity in your reality view and add it as the child to your rightHandRoot entity. Finally, start an ARKit hand tracking session and update your rightHandRoot entity to the anchor position of the tracked right hand, which in turn updates the particle emitter's position.

struct ImmersiveView: View {

    var rightHandRoot = Entity()
    
    let arkitSession = ARKitSession()
    let handTrackingProvider = HandTrackingProvider()
    
    var body: some View {
        RealityView { content in
            // Load the particle emitter entity from the Reality Composer Pro scene.
            if let immersiveContentEntity = try? await Entity(named: "Immersive", in: realityKitContentBundle),
               let particleEmitter = immersiveContentEntity.findEntity(named: "ParticleEmitter") {
                // Add the particle emitter to the scene as a child of the particle root entity.
                rightHandRoot.addChild(particleEmitter)
                content.add(rightHandRoot)
            }
        }.task {
            do {
                // Start hand tracking.
                try await arkitSession.run([handTrackingProvider])
                
                // Wait for hand tracking updates.
                for await update in handTrackingProvider.anchorUpdates {
                    // Get the anchor.
                    let anchor = update.anchor
                    
                    // Update the particle root transform to match the right hand anchor.
                    if anchor.chirality == .right {
                        rightHandRoot.setTransformMatrix(anchor.originFromAnchorTransform, relativeTo: nil)
                    }
                }
            } catch {
                print("Failed to start hand tracking session. \(error)")
            }
        }
    }
}

Finally, don't forget to add an NSHandsTrackingUsageDescription to your app's information property list.

Hope this does the trick!

visionOS – Anchoring particle system to hand also anchors spawned particles
 
 
Q