7

In my previous question I already found how to put a rotation transform over only one axis on an object, now I want this to be animated.

Is there a way to do this in RealityKit?

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
Robbe Verhoest
  • 401
  • 4
  • 9

2 Answers2

13

1. Transform Animation

You can move, rotate and scale a model in RealityKit using .move(...) instance method. For a faster compiling I used SwiftUI macOS app – although, you can use this code in iOS app as well.

import SwiftUI
import RealityKit

struct ContentView: View {
    var body: some View {
        ARInterface().ignoresSafeArea()
    }
}

struct ARInterface: NSViewRepresentable {

    let arView = ARView(frame: .zero)
    
    func makeNSView(context: Context) -> ARView {
        
        let scene = try! Experience.loadBox()
        scene.steelBox?.scale = [10, 10, 10]

        let transform = Transform(pitch: 0, yaw: 0, roll: .pi)
        scene.steelBox?.orientation = transform.rotation

        arView.scene.anchors.append(scene)
            
        scene.steelBox?.move(to: transform,
                     relativeTo: scene.steelBox,
                       duration: 5.0,
                 timingFunction: .linear)
        
        return arView
    }
    
    func updateNSView(_ uiView: ARView, context: Context) { }
}

Read this post to find out how to overcome the 180 degree rotation barrier.

enter image description here


2. Transform Animation using Matrices

For those who prefer to use a matrix math, I recommend reading this post:

Change a rotation of AnchorEntity in RealityKit


3. Transform Animation using Physics

For those who like to use dynamics, I give a link to this post:

How to move a model and generate its collision shape at the same time?


4. Asset Animation

To play an asset animation (whether it's a skeletal character animation or a set of transform animations, including a rotation about mesh's pivot point) made in 3D apps, like Maya or Houdini, use an animationPlaybackController:

import Cocoa
import RealityKit

class ViewController: NSViewController {
    
    @IBOutlet var arView: ARView!
    
    override func awakeFromNib() {

        do {
            let robot = try ModelEntity.load(named: "drummer")

            let anchor = AnchorEntity(world: [0, -0.7, 0])

            anchor.transform.rotation = simd_quatf(angle: .pi/4, 
                                                    axis: [0, 1, 0])
            arView.scene.anchors.append(anchor)
            
            robot.scale = [1, 1, 1] * 0.1

            anchor.children.append(robot)
            
            robot.playAnimation(robot.availableAnimations[0].repeat(), 
                                transitionDuration: 0.5, 
                                      startsPaused: false)
        } catch {
            fatalError("Cannot load USDZ asset.")
        }
    }
}

To be able to play multiple animations, try this technique or this one.

enter image description here


5. Transform Animation in Reality Composer

For those who prefer UI, there's a "perpetual" spin behavior in Reality Composer:

Reality Composer - How to rotate an object forever?


6. Transform Animation using Python bindings for USDZ

USDZ schemas become more and more popular in everyday Python scripting for Pixar's format.

Augmented Reality 911 — USDZ Schemas

float xformOp:rotateY:spin.timeSamples = { 1: 0, 300: 1800 }
uniform token[] xformOpOrder = ["xformOp:rotateY:spin"]


7. Eternal Orbiting using Trigonometry

Trigonometric functions sin() and cos(), Timer and counter objects will allow you to orbit a model around any axis.

Hovering an entity in front of ARCamera


8. Orbiting animation

Using OrbitAnimation struct you can revolve an entity around its origin. Here's a code snippet for visionOS app.

import SwiftUI
import RealityKit

struct ContentView: View {
    var body: some View {
        RealityView { content in
            async let car = ModelEntity(named: "car.usdz")
            
            let entity = Entity()
            entity.position.y = 0.1
            
            if let car = try? await car {
                car.scale /= 5
                entity.addChild(car)
                
                let orbit = OrbitAnimation(duration: 5.0,
                                               axis: [1,0,0],
                                     startTransform: entity.transform,
                                         bindTarget: .transform,
                                         repeatMode: .repeat)
                
                if let animation = try? AnimationResource.generate(with: orbit) {
                    entity.playAnimation(animation)
                }
                content.add(entity)
            }
        }
    }
}
#Preview {
    ContentView()
}

enter image description here

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
  • 2
    Hello @Andy Can You please answer this: https://stackoverflow.com/questions/70890755/how-to-add-motion-to-a-loaded-modelentity-from-usdz-file-realitykit : You are a great help for the community. – Tanvirgeek Jan 28 '22 at 13:22
  • 1
    Hi @Tanvirgeek, I'll try to answer your question as soon as I have free time today. – Andy Jazz Jan 28 '22 at 13:25
  • Hi Andy. Thank you for the answer. Why don't you use Playgrounds for 3D demos? It's much faster and UI technology agnostic. – Darkwonder Mar 20 '23 at 04:40
  • 1
    Why not, @Darkwonder?! I definitely use Swift Playgrounds on iPad. – https://medium.com/geekculture/realitykit-911-swift-playgrounds-or-how-to-create-and-debug-ar-apps-on-ipad-pro-190a6d2e03bb – Andy Jazz Mar 20 '23 at 06:10
  • I am asking because your answer often helps me, but I can't use it out of the box because I work with SwiftUI. Another reason is that I need more examples to play around where Playgrounds let me do it instantly. If you want, I can share two Playground macOS examples that can be copied. – Darkwonder Mar 20 '23 at 07:09
  • 1
    Thanks a lot but there is no need to do this as 99% developers use Xcode to debug the RealityKit app. – Andy Jazz Mar 20 '23 at 07:13
8

Rotation with animation:

copy the box's current transform

var rotationTransform = boxAnchor.steelBox?.transform

set the box to rotate 90 degrees over z-axis

rotationTransform?.rotation = simd_quatf(angle: .pi/2, axis: [0,0,1])

move the box to the new transform over 10s

boxAnchor.steelBox?.move(to: rotationTransform!, relativeTo: boxAnchor.steelBox?.parent, duration: 10, timingFunction: .easeInOut)

Translation with animation:

var translationTransform = boxAnchor.steelBox?.transform

translationTransform?.translation = SIMD3<Float>(x: 5, y: 0, z: 0)

boxAnchor.steelBox?.move(to: translationTransform!, relativeTo: boxAnchor.steelBox?.parent, duration: 10, timingFunction: .easeInOut)

Scale with animation:

var scaleTransform = boxAnchor.steelBox?.transform

scaleTransform?.scale = SIMD3<Float>(x: 1, y: 1, z: 1)

boxAnchor.steelBox?.move(to: scaleTransform!, relativeTo: boxAnchor.steelBox?.parent, duration: 10, timingFunction: .easeInOut)
Robbe Verhoest
  • 401
  • 4
  • 9