Can't Get OrbitAnimation() to work on my project

DESCRIPTION OF PROBLEM I have an Apple Vision Pro App Store app called Starship SE Corps. I'm trying to add an animation for my app so that the starship entity orbits the Earth entity. I'm trying to use OrbitAnimation as discussed in the WWDC23 session "Build Spatial Experiences with RealityKit" (https://developer.apple.com/wwdc23/10080). However, I can't get the animation to work.

STEPS TO REPRODUCE I created a sample test app called "SampleOrbitAnimationApp" to focus in on the code I'm having trouble with.

When I build and run my sample test app, the app runs on both the visionOS 1.2 simulator and on my real Apple Vision Pro device running visionOS 1.2. However, my starship entity is static and is not animating/orbiting around my Earth entity.

  1. I tried putting my OrbitAnimation code in the RealityView update: closure. Doing that, however causes some property scope errors because the entity I refer to in the OrbitAnimation code is my entity that I create in the RealityView code block...so the update: closure code block can't see the entity property.
  2. Trying to make the entity reference more global at the top of the ImmersiveView (so update: closure sees the entity property) causes other parameter issues in the .app file call to the ImmersiveView and in the #Preview call to the ImmersiveView. Maybe that should be expected and I would need to workaround that (but I couldn't find a sensible way to do so). If this is the right approach, I need help on how to resolve this across the project files.
  3. I did find some example code online where a developer put the OrbitAnimation code directly in the RealityView code block without having an update: or attachments: closure at all. I tried that approach but also couldn't get that to work.

The test sample app tries to target the OrbitAnimation and ImmersiveView code I'm struggling with (i.e. I can't get the starship to move and orbit around the Earth). It uses my same production app Package for Starship and Earth entities, built in Reality Composer Pro. Those entities, included in my sample test app, work fine on my latest production App Store release, so I think they are fine. The issue is how to do the OrbitAnimation code for those entities. I realize new capabilities are coming in visionOS 2, but I would like to make OrbitAnimation work now in my visionOS 1.2 app.

Answered by aandyzoom01 in 794299022

I figured out what I was doing wrong. I needed to make a new scene in RCP where the starship is a child to the Earth. The OrbitAnimation struct causes a child entity to orbit around a parent entity. It now works, but I have a lot to fix to make the starship rotate its orientation so the same side always faces the earth and I need to adjust the angle of the orbit and other parameters.

The behavior you're describing usually happens when the OrbitAnimation's transform's translation is set to [0, 0, 0]. Here's a code snippet that creates an orbiting a sphere. Note the comment. I hope this unblocks you!

struct ImmersiveView: View {

    var body: some View {
        RealityView { content in
            
            let sphere = ModelEntity(mesh: .generateSphere(radius: 0.2), materials: [SimpleMaterial(color: .green, isMetallic: false)])
            let yAxis: SIMD3<Float> = [0, 1, 0]
            
            let orbit = OrbitAnimation(
                name: "orbit",
                duration: 10,
                axis: yAxis,

                // set to something other than [0, 0, 0]
                startTransform: Transform(translation: [0, 1.4, -1]),

                spinClockwise: false,
                orientToPath: true,
                rotationCount: 3,
                bindTarget: .transform
            )
            
            if let animation = try? AnimationResource.generate(with: orbit) {
                sphere.playAnimation(animation)
            }
            
            content.add(sphere)
        }
    }
}

I've added some of my sample test app code below.

From what I understand, I already have the OrbitAnimation startTransform parameter for my starshipEntity setup correctly based on my Reality Composer Pro (RCP) package that includes the transform component definition for my starship entity (see attached screenshot below for the transform component from RCP). Since I already have my starship and Earth entity defined in my RCP package that I import (i.e. import Starship), I don't believe I need to define the sphere or yAxis property, and my startTransform parameter can just be starshipEntity.transform. I took this code approach based on the WWDC23 session "Build Spatial Experiences with RealityKit" (https://developer.apple.com/wwdc23/10080). In your example code, you show a translation parameter to the Transform struct. Are you saying there is a translation that needs to be set that is beyond what I already have in the RCP Transform component for my starship entity? If so, I don't understand why and I didn't see something like that needed for the moon entity in the WWDC23 session I reference above. A translation parameter is not mentioned in the above referenced WWDC23 session.

Also, can you confirm that I can do the OrbitAnimation directly in the RealityView content closure and that I don't have to put OrbitAnimation in an update: closure?

import SwiftUI
import RealityKit
import Starship

struct ImmersiveView: View {
    
    @Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace
    @Environment(\.dismissWindow) var dismissWindow
    @Environment(\.openWindow) var openWindow
    
    var body: some View {
        RealityView { content, attachments  in
            //Get Earth model from createEarthModel() function
            let earthEntity = await createEarthModel()
            
            //Get Starship model from createStarshipModel() function
            let starshipEntity = await createStarshipModel()
            
            //Add to RealityView
            content.add(starshipEntity)
            content.add(earthEntity)
           
            //Playing an orbit transform animation
            let orbit = OrbitAnimation(name: "Orbit",
                                       duration: 30,
                                       axis: [0, 1, 0],
                                       startTransform: starshipEntity.transform,
                                       bindTarget: .transform,
                                       repeatMode: .repeat)
            
            if let animation = try? AnimationResource.generate(with: orbit) {
                starshipEntity.playAnimation(animation)
            }

        } 
        
    }
}

Accepted Answer

I figured out what I was doing wrong. I needed to make a new scene in RCP where the starship is a child to the Earth. The OrbitAnimation struct causes a child entity to orbit around a parent entity. It now works, but I have a lot to fix to make the starship rotate its orientation so the same side always faces the earth and I need to adjust the angle of the orbit and other parameters.

I have some progress but still need help. I needed to make a new scene in RCP where the starship is a child to the Earth. The OrbitAnimation struct causes a child entity to orbit around a parent entity. It now works, but I have a lot to fix to make the starship rotate its orientation so the same side always faces the earth and I need to adjust the angle of the orbit and other parameters. So help is still needed.

Here's example code that orbits a starship around earth while ensuring the starship faces earth. There are 2 important parts.

RealityView { content in
    let earth = ModelEntity(mesh: .generateSphere(radius: 0.2), materials: [SimpleMaterial(color: .blue, isMetallic: false)])
    earth.position = [0, 1, -1]
    
    // Creating a starship out of 2 spheres. The red sphere is the front of the starship and should face earth.
    let starShip = ModelEntity(mesh: .generateSphere(radius: 0.05), materials: [SimpleMaterial(color: .green, isMetallic: false)])
    
    let starShipFront = ModelEntity(mesh: .generateSphere(radius: 0.008), materials: [SimpleMaterial(color: .red, isMetallic: true)])
    
    let earthWidth = earth.visualBounds(relativeTo: nil).extents.x
    let starshipWidth = starShip.visualBounds(relativeTo: nil).extents.x
    
    starShipFront.position.z = starshipWidth / 2
    starShip.addChild(starShipFront)

    let distanceFromEarth:Float = 0.1
    
    let starshipPosition:SIMD3<Float> = [distanceFromEarth + earthWidth/2 + starshipWidth/2, 0, 0]
    
    // Important - rotate the starship to face the earth
    let starshipRotation = simd_quatf(angle: -.pi/2, axis: [0, 1, 0])
    
    let animationTransform = Transform(rotation: starshipRotation, translation: starshipPosition)
    
    let orbit = OrbitAnimation(name: "Orbit",
               duration: 5,
               axis: [0, 1, 0],
               startTransform: animationTransform,
               
               // Important - update the starship's orientation during the animation to orient itself along the rotation path
               orientToPath: true,
               bindTarget: .transform,
               repeatMode: .repeat, isAdditive: true)
    
    
    if let animation = try? AnimationResource.generate(with: orbit) {
        starShip.playAnimation(animation)
    }
    
    earth.addChild(starShip)
    content.add(earth)
}

I forgot to mention. This is also possible via the new animations timeline in Reality Composer Pro 2.0. See Compose interactive 3D content in Reality Composer Pro for more detail.

Thanks for the advice. In my code I actually didn't need to create the starship or earth entities because I already had them fully defined in Reality Composer Pro. I just added the orientToPath: true parameter and that kept the starship at the same orientation throughout the orbit path.

Also, I fixed the orbit plane problem by resetting the Earth (parent) transform component, rotation z value to 0, instead of 23. Now the starship orbits the earth on a level tilt around the earth.

Once last thing (I hope, :)) how would I have the earth (parent) entity rotate CCW underneath the orbiting starship child?

I tried adding the following code block to the RealityView but it is not working:

if let rotatingEarth = starshipEntity.findEntity(named: "Earth") {
                rotatingEarth.transform.rotation = simd_quatf.init(angle: 360, axis: SIMD3(x: 0, y: 1, z: 0))
                
                if let animation = try? AnimationResource.generate(with: rotatingEarth as! AnimationDefinition) {
                    rotatingEarth.playAnimation(animation)
                }

            }

Any advice on getting the earth to rotate?

I tried reviewing the Hello World WWDC23 project code, but I was unable to understand the complexity and how that sample project got the earth to rotate.

I'm happy to help you make the Earth rotate, but ask that you create a new forum post with the question since it's a separate question. Once you've done that, reply with a link to the post and I'll take a look.

Can't Get OrbitAnimation() to work on my project
 
 
Q