Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RealityKit – Animate a transform on a loop

I can't figure out how to have the move function below repeat in order to create a constant rotation on a simple meshResource. Any suggestions?

var transform = sphereEntity.transform
transform.rotation =  simd_quatf(angle: .pi, axis: [0,1,0])
let anim = sphereEntity.move(to: transform, relativeTo: sphereEntity.parent, duration: 5.0)
like image 462
lostcoder Avatar asked May 20 '26 20:05

lostcoder


2 Answers

Looping an animation is possible by subscribing to the AnimationEvents.PlaybackCompleted event.

You'll have to move your animation logic into a separate function which you call once. Inside this function you subscribe to the PlaybackCompleted event. When this event is fired you call the same animation function.

You can subscribe to AnimationEvents by using the Scene.subscribe() method:

func subscribe<E>(to event: E.Type, 
                  on sourceObject: EventSource? = nil, 
                  _ handler: @escaping (E) -> Void) -> Cancellable where E : Event

Please note that you'll have to import the Combine framework to be able to use this:

import Combine

The animation function then looks like this:

// This needs to be an instance variable, otherwise it'll
// get deallocated immediately and the animation won't start.
var animUpdateSubscription: Cancellable?

func animate(entity: HasTransform,
             angle: Float,
             axis: SIMD3<Float>,
             duration: TimeInterval,
             loop: Bool)
{
    var transform = entity.transform
    // We'll add the rotation to the current rotation
    transform.rotation *= simd_quatf(angle: angle, axis: axis)
    entity.move(to: transform, relativeTo: entity.parent, duration: duration)
    
    // Checks if we should loop and if we have already subscribed
    // to the AnimationEvent. We only need to do this once. 
    guard loop,
          animUpdateSubscription == nil
    else { return }
    
    animUpdateSubscription = scene.subscribe(to: AnimationEvents.PlaybackCompleted.self, 
                                             on: entity, 
    { _ in
        self.animate(entity: entity, 
                     angle: angle, 
                     axis: axis, 
                     duration: duration, 
                     loop: loop)
    })
}

Now you can call this function once to trigger a looped animation:

animate(entity: entity, 
        angle: angle, 
        axis: axis, 
        duration: duration, 
        loop: loop)
like image 132
MasDennis Avatar answered May 23 '26 13:05

MasDennis


.move() instance method starts working when it's placed after the line entity added to a scene.

let boxEntity = ModelEntity(mesh: .generateBox(size: 1.0), 
                       materials: [SimpleMaterial()])

var transform = boxEntity.transform

transform.rotation =  simd_quatf(angle: .pi, axis: [0, 1, 0])
    
let boxAnchor = AnchorEntity()
boxAnchor.children.append(boxEntity)
arView.scene.anchors.append(boxAnchor)
    
boxEntity.move(to: transform, relativeTo: nil, duration: 5.0)

At the moment (December 23, 2022) all RealityKit's .move() methods still can't loop.

like image 43
Andy Jazz Avatar answered May 23 '26 11:05

Andy Jazz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!