Can’t Figure Out How to Get My Earth Entity to Rotate on its Axis

I can‘t Figure Out How to Get My Earth Entity to Rotate on its Axis. This is a follow up post from a previous Apple Developer forum post.

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 want to do this for visionOS 1.2. I realize there are some new animation and possible other capabilities coming up in vision 2.0 but I want to try to address this issue in the current released visionOS version.

Answered by Vision Pro Engineer in 795490022

Hello World uses Entity Component System (ECS) to rotate the Earth. Understanding RealityKit’s modular architecture is a good overview of ECS. It's also covered the WWDC23 session Build spatial experiences with RealityKit.

In this case, you can reuse Hello World's RotationComponent and RotationSystem. This is done in three steps: first copy World/Systems/RotationSystem.swift to your project, next register the component and system, finally add the rotation component to the Earth entity.

Register the component and system in your app's initializer.

init() {
    RotationComponent.registerComponent()
    RotationSystem.registerSystem()
}

Add the component to your Earth entity. Optionally, you can pass speed or axis to the component. This example uses the default values.

earth.components.set(RotationComponent())

That's it! Your Earth should now rotate.

Accepted Answer

Hello World uses Entity Component System (ECS) to rotate the Earth. Understanding RealityKit’s modular architecture is a good overview of ECS. It's also covered the WWDC23 session Build spatial experiences with RealityKit.

In this case, you can reuse Hello World's RotationComponent and RotationSystem. This is done in three steps: first copy World/Systems/RotationSystem.swift to your project, next register the component and system, finally add the rotation component to the Earth entity.

Register the component and system in your app's initializer.

init() {
    RotationComponent.registerComponent()
    RotationSystem.registerSystem()
}

Add the component to your Earth entity. Optionally, you can pass speed or axis to the component. This example uses the default values.

earth.components.set(RotationComponent())

That's it! Your Earth should now rotate.

  1. I’d appreciate if you can provide some more information about systems. I’ve watched the WWDC session that shows a slide trying to relate entities components and systems. However, I still don’t really understand the relationship and when systems are used. Maybe your explanation can help me better understand that, and the relationships with entities and components and also help others.
  2. Also, can you explain what you mean by my app’s initializer code? Can you explain that in terms of my feedback sample test project code in the cross referencedDeveloper forum post that I provided previously and linked you to. I need to understand it in terms of my actual code in my sample test app because I don’t know what you mean by my app’s initializer code. I don’t understand that context.
  3. Finally, can you explain why I need to use a system versus an entity animation like I previously did for an orbit animation. I’m trying to work everything by defining them in Reality Composer Pro as entities with transform components, but I don’t understand why this has to be treated separately as a system and what is the point of registering that system. It seems inconsistent in the use of RealityKit entities and how we animate certain things. For instance, animating an orbit of entities seems was handled differently than doing a rotation of an earth entity. Orbit animation was basically handled through animation with a play animation method. Yet this earth rotation approach that you show here seems not to be an animation, but some other type of method for the Earth to rotate. It doesn’t make sense to me why the orbit of an entity is handled differently than a rotation of an entity. Any further explanation you can give to try to explain why this system is like this would be appreciated.

Hi @aandyzoom01

I’d appreciate if you can provide some more information about systems.

Dive into RealityKit 2 is a WWDC21 talk that covers ECS. The content is a bit dated, but maybe it will help you better understand the architecture. Here are some quick notes on ECS as it relates to your use case.

Entity - In this case it's the Earth entity you create using your model.

Component - You can associate a component with an Entity. A component may or may not have state. In this case the component is RotationComponent and it stores axis and speed. Think of it as a way to say "My earth entity needs to rotate on a given axis at a given speed".

System - This is the code that actually does the rotation; in this case it's RotationSystem. It runs every frame (that's an oversimplification) and is responsible updating the Earth's (and any other entities with the RotationComponent) rotation.

can you explain what you mean by my app’s initializer code

By app initializer I mean the init method of your App struct. So for your app.

struct SampleOrbitAnimationAppApp: App {
    // This is your app initializer 
    init() {
        RotationComponent.registerComponent()
        RotationSystem.registerSystem()
    }

    var body: some Scene {
        ....
    }
}

Finally, can you explain why I need to use a system versus an entity animation like I previously did for an orbit animation

I replied with the ECS code because I had the code on hand and I think it's a good introduction to ECS. ECS is an important architecture to learn if you intend to build more complex games/simulations. That said, you can use an animation for rotation. Specifically you'd use FromToByAnimation<Transform>. It's a bit tricky to make a 360 rotation animation with it, but it's possible. I'll try to find time to put together an example and post it here.

@aandyzoom01 In my comment I said, "you can use a FromToByAnimation to do the rotation". That's true, but today I learned this is also possible using OrbitAnimation. Here's a revised version of the ImmersiveView I provided that uses an animation instead of a system to do the rotation.

struct ImmersiveView: View {
    var body: some View {
        RealityView { content in
            // Create the earth. I put a dot on it so the rotation is easier to see.
            let earth = ModelEntity(mesh: .generateSphere(radius: 0.2), materials: [SimpleMaterial(color: .blue, isMetallic: false)])
            let earthFront = ModelEntity(mesh: .generateSphere(radius: 0.008), materials: [SimpleMaterial(color: .red, isMetallic: true)])
            earth.addChild(earthFront)

            // 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)])
            earth.addChild(starShip)
            let starShipFront = ModelEntity(mesh: .generateSphere(radius: 0.008), materials: [SimpleMaterial(color: .red, isMetallic: true)])
            starShip.addChild(starShipFront)
            
            // Make the starship orbit the Earth.
            let earthWidth = earth.visualBounds(relativeTo: nil).extents.x
            earthFront.position.z = earthWidth / 2
            
            let starshipWidth = starShip.visualBounds(relativeTo: nil).extents.x
            starShipFront.position.z = starshipWidth / 2
           
            let distanceFromEarth:Float = 0.1
            let starshipPosition:SIMD3<Float> = [distanceFromEarth + earthWidth/2 + starshipWidth/2, 0, 0]
            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,
                                       orientToPath: true,
                                       bindTarget: .transform,
                                       repeatMode: .repeat, isAdditive: true)
            
            
            if let animation = try? AnimationResource.generate(with: orbit) {
                starShip.playAnimation(animation)
            }
            
            // New: Make the Earth rotate using OrbitAnimation.
            
            // The rotate animation clears the earth's transform; to work around 
            // this and position the earth we add it to an entity and position that entity.
            let earthParent = Entity()
            earthParent.position = [0, 1.4, -1.2]
            earthParent.addChild(earth)
            content.add(earthParent)
            
            // Do the rotation
            let rotateDefinition = OrbitAnimation(
                spinClockwise: false,
                orientToPath: true,
                bindTarget: .transform,
                speed: 0.25).repeatingForever()
            
            if let rotate = try? AnimationResource.generate(with:rotateDefinition) {
                earth.playAnimation(rotate)
            }
        }
    }
}
Can’t Figure Out How to Get My Earth Entity to Rotate on its Axis
 
 
Q