Forward and reverse animations with RealityKit on Vision Pro

Hello!

I'm trying to play an animation with a toggle button. When the button is toggled the animation either plays forward from the first frame (.speed = 1) OR plays backward from the last frame (.speed = -1), so if the button is toggled when the animation is only halfway through, it 'jumps' to the first or last frame. The animation is 120 frames, and I want the position in playback to be preserved when the button is toggled - so the animation reverses or continues forward from whatever frame the animation was currently on.

Any tips on implementation? Thanks!

import RealityKit
import RealityKitContent

struct ModelView: View {
    var isPlaying: Bool
    
    @State private var scene: Entity? = nil
    @State private var unboxAnimationResource: AnimationResource? = nil
    
    var body: some View {
        RealityView { content in
            // Specify the name of the Entity you want
            scene = try? await Entity(named: "TestAsset", in: realityKitContentBundle)
            scene!.generateCollisionShapes(recursive: true)
            scene!.components.set(InputTargetComponent())
            content.add(scene!)
        
        } .installGestures()
            .onChange(of: isPlaying) {
                if (isPlaying){
                    var playerDefinition = scene!.availableAnimations[0].definition
                    playerDefinition.speed = 1
                    playerDefinition.repeatMode = .none
                    playerDefinition.trimDuration = 0
                    let playerAnimation = try! AnimationResource.generate(with: playerDefinition)
                    
                    scene!.playAnimation(playerAnimation)
                    
                } else {
                    var playerDefinition = scene!.availableAnimations[0].definition
                    playerDefinition.speed = -1
                    playerDefinition.repeatMode = .none
                    playerDefinition.trimDuration = 0
                    let playerAnimation = try! AnimationResource.generate(with: playerDefinition)
                    
                    scene!.playAnimation(playerAnimation)

                }
                

            }
    }
}

Thanks!

Answered by Vision Pro Engineer in 802559022

Hey @KevinTho,

You're on the right path, but you are playing the full animation each time. Create a @State variable for the AnimationController that is returned from playAnimation. On this controller you can directly change the speed of the animation to reverse it.

if animationController.isPlaying {
    animationController.speed = reverse ? -1.0 : 1.0
}

If you want more customization for which part of the animation you'd like to play, you can read the time property and set the trimStart, trimEnd and offset properties.

Let me know if you have additional questions,
Michael

Hey @KevinTho,

You're on the right path, but you are playing the full animation each time. Create a @State variable for the AnimationController that is returned from playAnimation. On this controller you can directly change the speed of the animation to reverse it.

if animationController.isPlaying {
    animationController.speed = reverse ? -1.0 : 1.0
}

If you want more customization for which part of the animation you'd like to play, you can read the time property and set the trimStart, trimEnd and offset properties.

Let me know if you have additional questions,
Michael

Nice! Getting closer - however now my animation does not start paused when it is loaded, and the animation.speed toggle stops working if I allow the animation to play all the way through. Am I instantiating the AnimationPlaybackController class correctly?

import RealityKit
import RealityKitContent

struct ModelView: View {
    var isPlaying: Bool
    
    @State private var scene: Entity? = nil
    @State private var animationController: AnimationPlaybackController? = nil
    @State private var playerDefinition: AnimationDefinition?
    @State private var playerResource: AnimationResource? = nil
    
    var body: some View {
        RealityView { content in
            // Specify the name of the Entity you want
            scene = try? await Entity(named: "TestAsset", in: realityKitContentBundle)
            scene!.generateCollisionShapes(recursive: true)
            scene!.components.set(InputTargetComponent())
            content.add(scene!)
            
            playerDefinition = scene?.availableAnimations[0].definition
            playerDefinition?.repeatMode = .none
            playerResource = try! AnimationResource.generate(with: playerDefinition!)
            animationController = scene!.playAnimation(playerResource!, startsPaused: true)
            

        } .installGestures()
            .onChange(of: isPlaying) {
                animationController?.speed = isPlaying ? -1.0 : 1.0
            }
    }
}
Forward and reverse animations with RealityKit on Vision Pro
 
 
Q