How can I reverse USDZ animation in realityKit

How can i play a USDZ entity animation in reverse? I have tried to put a negative value to the speed as I was doing in SceneKit to make the animation reverse play but it did not work. here is my code:

import SwiftUI
import RealityKit

struct ImmersiveView: View {
    @State var entity = Entity()
    @State var openDoor: Bool = true
    
    var body: some View {
        RealityView { content in
            if let mainDoor = try? await Entity(named: "Door.usdz") {
                
                if let frame = mainDoor.findEntity(named: "DoorFrame")
                {

                    frame.position = [0, 0, -8]

                    frame.orientation = simd_quatf(angle: (270 * (.pi / 180)), axis: SIMD3(x: 1, y: 0, z: 0))
                    
                    content.add(frame)
                    
                    entity = frame.findEntity(named: "Door")!
                    
                    entity.components.set(InputTargetComponent(allowedInputTypes: .indirect))
                    
                    entity.components.set(HoverEffectComponent())
                    
                    let entityModel = entity.children[0]
                    
                    entityModel.generateCollisionShapes(recursive: true)
                }
            }
        }
        .gesture(
            SpatialTapGesture()
                .targetedToEntity(entity)
                .onEnded { value in
                    print(value)
                    if openDoor == true
                    {
                        let animController = entity.playAnimation(entity.availableAnimations[0], transitionDuration: 0 , startsPaused: true)

                        animController.speed = 1.0
                        animController.resume()
                        
                        openDoor = false
                    }
                    else
                    {
                        let animController = entity.playAnimation(entity.availableAnimations[0], transitionDuration: 0 , startsPaused: true)
                        
                        animController.speed = -1.0 // it does not work to reverse
                        animController.resume()
                        
                        openDoor = true
                    }
                }
            )
    }
}

The Door should open with first click which is already happening and close with second click which is not happening as it does not reverse play the animation

Answered by Vision Pro Engineer in 782007022

Setting an AnimationDefinition's speed property to a negative value will cause its associated animation to play in reverse. For example:

var reversedDefinition = animationResource.definition
reversedDefinition.speed = -1
let reversedAnimation = try AnimationResource.generate(with: reversedDefinition)
entity.playAnimation(reversedAnimation)

Also here is the link for the USDZ file for the door if you want to check https://www.worldhotelity.com/stack/Door.usdz

Accepted Answer

As I expected In visionOS 1.1, the AnimationPlaybackController object is still not able to play back a reverse asset animation, as it was in iOS RealityKit. in iOS RealityKit you could reverse the animation by simply give speed negative value like -1 but if you try it in visionOS RealityKit it would stop the animation totally as you give a speed = 0 , the workaround so far is a bi complicated by making 2 animations one forward and the other reverse and apply each when needed. Hopefully Apply would resolve this issue in the next version of visionOS.

When using the AnimationController, you can move forwards and backwards using the .time property. You could create a lerp function that has a from and to value, and pass a lerpTime. In my case, lerpTime is elapsedTime remapped to 0-1. Which would originally be 0 to animation duration if I wanted to play forwards or animation duration to 0 if I wanted to play backwards.

Example:

let currentValue = lerp(a: from, b: to, t: lerpTime)
animationController.time = TimeInterval(currentValue)

Setting an AnimationDefinition's speed property to a negative value will cause its associated animation to play in reverse. For example:

var reversedDefinition = animationResource.definition
reversedDefinition.speed = -1
let reversedAnimation = try AnimationResource.generate(with: reversedDefinition)
entity.playAnimation(reversedAnimation)

Thanks to @helpingtiger I could edit my code and make it possible to reverse the animation , and here is the edited working code

import SwiftUI
import RealityKit

struct ImmersiveView: View {
    @State var entity = Entity()
    @State var openDoor: Bool = true
    
    var body: some View {
        RealityView { content in
            if let mainDoor = try? await Entity(named: "Door.usdz") {
                
                if let frame = mainDoor.findEntity(named: "DoorFrame")
                {

                    frame.position = [0, 0, -8]

                    frame.orientation = simd_quatf(angle: (270 * (.pi / 180)), axis: SIMD3(x: 1, y: 0, z: 0))
                    
                    content.add(frame)
                    
                    entity = frame.findEntity(named: "Door")!
                    
                    entity.components.set(InputTargetComponent(allowedInputTypes: .indirect))
                    
                    entity.components.set(HoverEffectComponent())
                    
                    let entityModel = entity.children[0]
                    
                    entityModel.generateCollisionShapes(recursive: true)
                }
            }
        }
        
        .gesture(
            SpatialTapGesture()
                .targetedToEntity(entity)
                .onEnded { value in
                    print(value)
                    if openDoor == true
                    {
                        var playerDefinition = entity.availableAnimations[0].definition
                        playerDefinition.speed = 1
                        playerDefinition.repeatMode = .none
                        playerDefinition.trimDuration = 0
                        
                        let playerAnimation = try! AnimationResource.generate(with: playerDefinition)

                        entity.playAnimation(playerAnimation)

                        openDoor = false
                    }
                    else
                    {
                        var playerDefinition = entity.availableAnimations[0].definition
                        playerDefinition.speed = -1
                        playerDefinition.repeatMode = .none
                        playerDefinition.trimDuration = 0
                        
                        let playerAnimation = try! AnimationResource.generate(with: playerDefinition)

                        entity.playAnimation(playerAnimation)
                        
                        openDoor = true
                    }
                }
            )
    }    
}
How can I reverse USDZ animation in realityKit
 
 
Q