iOS ARKit 动画
动画是增强虛拟元素真实感和生动性的重要方面,RealityKit 支持变換动面(Transform Animation)和骨骼动画(Skeletal Animation)两种动面模式。变换动画一般程序化地执行,支持基本的平移、旋转、缩放,更复杂的动画通常由第三方模型制作软件采用骨骼绑定的方式生成,独立或者内置于模型文件中。USDZ和 Reality 文件格式都支持动画,在使用时,可以直接由该类文件将动画导人场景中。
- 变换动画 TransForm
变换动画可以实现对虚拟元素常见的基本操作,如平移、旋转、缩放,在执行时,通常使用实体类的move(to: relativeTo:duration:)方法,该方法参数 duration 用于指定动画时间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | import SwiftUI import RealityKit import ARKit struct TransformView : View { var body : some View { return ARViewContainer14 (). edgesIgnoringSafeArea (. all ) } } struct ARViewContainer14 : UIViewRepresentable { func makeUIView ( context : Context ) - > ARView { let arView = ARView ( frame : . zero ) let config = ARWorldTrackingConfiguration () config . planeDetection = . horizontal arView . session . run ( config , options :[ ]) arView . session . delegate = arView arView . createPlane14 () return arView } func updateUIView ( _ uiView : ARView , context : Context ) { } } var cubeEntity : ModelEntity ? var gestureStartLocation : SIMD3 < Float > ? extension ARView { func createPlane14 (){ let planeAnchor = AnchorEntity ( plane :. horizontal ) do { let cubeMesh = MeshResource . generateBox ( size : 0.1 ) var cubeMaterial = SimpleMaterial ( color :. white , isMetallic : false ) cubeMaterial . color = try SimpleMaterial . BaseColor ( tint : UIColor . yellow . withAlphaComponent ( 0.9999 ), texture : MaterialParameters . Texture ( TextureResource . load ( named : "Box_Texture.jpg" ))) cubeEntity = ModelEntity ( mesh : cubeMesh , materials :[ cubeMaterial ]) cubeEntity !. generateCollisionShapes ( recursive : false ) cubeEntity ?. name = "this is a cube" planeAnchor . addChild ( cubeEntity !) self . scene . addAnchor ( planeAnchor ) self . installGestures (. all , for : cubeEntity !). forEach { $ 0 . addTarget ( self , action : # selector ( handleModelGesture )) } } catch { print ( "找不到文件" ) } } @objc func handleModelGesture ( _ sender : Any ) { switch sender { case let rotation as EntityRotationGestureRecognizer : rotation . isEnabled = false var transform = rotation . entity !. transform transform . rotation = simd_quatf ( angle : . pi * 1.5 , axis : [ 0 , 1 , 0 ]) rotation . entity !. move ( to : transform , relativeTo : nil , duration : 5.0 ) rotation . isEnabled = true case let translation as EntityTranslationGestureRecognizer : translation . isEnabled = false var transform = translation . entity !. transform transform . translation = SIMD3 < Float > ( x : 0.8 , y : 0 , z : 0 ) translation . entity !. move ( to : transform , relativeTo : nil , duration : 5.0 ) translation . isEnabled = true case let Scale as EntityScaleGestureRecognizer : Scale . isEnabled = false var scaleTransform = Scale . entity !. transform scaleTransform . scale = SIMD3 < Float > ( x : 2 , y : 2 , z : 2 ) Scale . entity !. move ( to : scaleTransform , relativeTo : nil , duration : 5.0 ) Scale . isEnabled = true default : break } } @objc func handleScaleGesture ( _ sender : EntityScaleGestureRecognizer ){ print ( "in scale" ) } } # if DEBUG struct TransformView_Previews : PreviewProvider { static var previews : some View { ARViewContainer14 () } } # endif |
在使用 move()方法进行变换动画之前,应当先设置需要达到的目标,利用duration 参数控制动画时长。move()方法另一个重载 move(to:relativeTo:duration:timingFunction:)版本,其参数 timingFunction为 Animation TimingFunction 类型,通过它可以指定动画效果,如线性(linear)、缓入(easeln)、缓出(easeOut)、缓入缓出(easelnOut)、三次贝赛尔曲线(cubicBezier),通过使用该方法可以改善动画体验。
- 骨骼动画
变换动画只适合于执行相对简单的动画操作,如控制灯光沿圆形轨道移动、用户单击模型时出现弹跳效果等,对于复杂的动画,一般使用第三方软件(Maya、3ds MAX 等)预先制作好骨骼动画,然后导出为USDZ 或Reality 格式文件供 ARKit 使用。在RealityKit 中,使用骨骼动画的典型代码如代码下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | import SwiftUI import RealityKit import ARKit struct BoneAnimationView : View { var body: some View { return ARViewContainer9().edgesIgnoringSafeArea(.all) } } struct ARViewContainer9: UIViewRepresentable { func makeUIView(context: Context) -> ARView { let arView = ARView(frame: .zero) let config = ARWorldTrackingConfiguration() config.planeDetection = .horizontal arView.session.run(config, options:[ ]) arView.session.delegate = arView arView.CreateRobot() return arView } func updateUIView(_ uiView: ARView, context: Context) { } } extension ARView{ func CreateRobot(){ let planeAnchor = AnchorEntity(plane:.horizontal) do { let robot = try ModelEntity.load(named: "toy_drummer" ) planeAnchor.addChild(robot) robot.scale = [0.01,0.01,0.01] self.scene.addAnchor(planeAnchor) print( "Total animation count : \(robot.availableAnimations.count)" ) robot.playAnimation(robot.availableAnimations[0].repeat()) } catch { print( "找不到USDZ文件" ) } } } #if DEBUG struct BoneAnimationView_Previews : PreviewProvider { static var previews: some View { BoneAnimationView() } } #endif |
具体代码地址:https://github.com/duzhaoquan/ARkitDemo.git
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理