如何在RealityKit中实现USDZ实体动画的反向播放?
如何在RealityKit中反向播放USDZ实体动画?
我尝试了如同在SceneKit中设置负速度的方式来实现动画反向播放,但并未生效。当前点击实体可正常触发第一次开门动画,但第二次点击无法通过反向动画实现关门效果。
以下是我的实现代码:
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 // 此设置无法实现反向播放 animController.resume() openDoor = true } } ) } }
解决方案
RealityKit的AnimationController.speed属性不支持负值(这是和SceneKit的核心差异),所以直接设置speed = -1不会生效。你可以通过以下两种方式实现动画反向播放:
方式一:使用ReversedAnimation包装原动画
直接创建原动画的反向版本进行播放,代码修改如下:
.gesture( SpatialTapGesture() .targetedToEntity(entity) .onEnded { value in // 先停止当前动画,避免叠加冲突 entity.stopAllAnimations() if openDoor { // 播放正向动画 let forwardAnim = entity.availableAnimations[0] entity.playAnimation(forwardAnim, transitionDuration: 0) openDoor = false } else { // 创建并播放反向动画 let reversedAnim = entity.availableAnimations[0].reversed() entity.playAnimation(reversedAnim, transitionDuration: 0) openDoor = true } } )
方式二:通过playbackRange控制播放区间
设置动画的播放范围从结束点到起始点,配合正向速度实现反向效果:
.gesture( SpatialTapGesture() .targetedToEntity(entity) .onEnded { value in // 停止当前动画 entity.stopAllAnimations() if openDoor { let controller = entity.playAnimation(entity.availableAnimations[0], transitionDuration: 0, startsPaused: true) controller.playbackRange = 0...1 // 正向区间:从开始到结束 controller.speed = 1 controller.resume() openDoor = false } else { let controller = entity.playAnimation(entity.availableAnimations[0], transitionDuration: 0, startsPaused: true) controller.playbackRange = 1...0 // 反向区间:从结束到开始 controller.speed = 1 controller.resume() openDoor = true } } )
两种方式都能实现关门的反向动画效果,推荐第一种方式,代码更简洁直观。
内容的提问来源于stack exchange,提问作者Ostoura
相关产品推荐
相关产品推荐

