Search code examples
swiftswiftuiaugmented-realityarkitrealitykit

RealityKit – How to add motion to a loaded ModelEntity from USDZ file?


I have successfully loaded an USDZ file to my scene. Now I want to add motion the ModelEntity. I have added PhysicsMotionComponent but it is not working. After Loading model it is static as usual. No movement. How to give an entity motion in RealityKit?

When I see the components I see that components are added. But The entity in not moving. What am I doing wrong?

My codes:

import SwiftUI
import RealityKit
import ARKit
import Combine

struct ARViewContainer: UIViewRepresentable {
    
    
    func makeUIView(context: Context) -> ARView {
        let arVIew = ARView(frame: .zero)
        context.coordinator.arVIew = arVIew
        arVIew.session.delegate = context.coordinator
        let config = ARWorldTrackingConfiguration()
        arVIew.session.run(config, options: [.resetTracking,.removeExistingAnchors])
        
        
        let anchorEntity = AnchorEntity()
 
        
        loadASingleModel(name:"toy_biplane") { entity in
            if let entity = entity {

             let kinematics: PhysicsBodyComponent = .init(massProperties: .default,
                                                                           material: nil,
                                                                               mode: .kinematic)

                        let motion: PhysicsMotionComponent = .init(linearVelocity: [0.1 ,0, 0],
                                                                  angularVelocity: [3, 3, 3])

                        entity.components.set(kinematics)
                        entity.components.set(motion)
                anchorEntity.addChild(entity)
                //anchorEntity.transform.matrix.columns.3.z = -1.0
                arVIew.scene.anchors.append(anchorEntity)
                print("Model Added: ",entity.name)

            }else{
                print("No entity avaible")
            }
        }

        return arVIew
    }
    

    // MARK: - AsychLoading working
    func loadASingleModel(name:String,completion:@escaping (_ model:ModelEntity?)->Void){
        
        var cancellable:AnyCancellable?
        cancellable = Entity.loadModelAsync(named:name)
                    .sink(receiveCompletion: { handler in
                        if case let .failure(error) = handler {
                            print("Unable to load a model due to error \(error)")
                        }
                        cancellable?.cancel()
                        completion(nil)

                    }, receiveValue: { [self] (model: ModelEntity?) in
                        if let model = model  {
                            cancellable?.cancel()
                            print("Congrats! Model is successfully loaded!")
                            completion(model)
                        }
                    })
    }
    
    func updateUIView(_ uiView: ARView, context: Context) {
        
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(arViewContainer: self)
    }
    
    class Coordinator:NSObject{
        var parent:ARViewContainer
        var arVIew:ARView?
        init(arViewContainer:ARViewContainer){
            parent = arViewContainer
        }
    }
}

extension ARViewContainer.Coordinator:ARSessionDelegate{
    
    func session(_ session: ARSession, didUpdate frame: ARFrame) {
        
    }
    
    
    
}

Solution

  • Add to your code .generateCollisionShapes(recursive:) instance method for every participant (entity) that not only creates collision's shapes but also allows you to simulate physics.

    enter image description here

    import SwiftUI
    import RealityKit
    
    struct ARViewContainer: UIViewRepresentable {
        
        let boxx = ModelEntity(mesh: .generateBox(size: 0.5))
        let ball = ModelEntity(mesh: .generateSphere(radius: 0.25))
        let anchor = AnchorEntity()
        
        func makeUIView(context: Context) -> ARView {
            let arView = ARView(frame: .zero)
            // BALL
            ball.physicsBody = .init()
            ball.physicsMotion = .init()
            ball.physicsMotion?.linearVelocity = [10,0,0]
            ball.position.x = -3
            ball.generateCollisionShapes(recursive: true)
            anchor.addChild(ball)
            // BOX
            boxx.physicsBody = .init()
            boxx.physicsMotion = .init()
            boxx.physicsMotion?.linearVelocity = [0,2,0]
            boxx.generateCollisionShapes(recursive: true)
            anchor.addChild(boxx)
            // Anchor
            anchor.position.z = -3
            arView.scene.addAnchor(anchor)
            return arView
        }
        func updateUIView(_ uiView: ARView, context: Context) { }
    }
    

    struct ContentView : View {
        var body: some View {
            return ARViewContainer().edgesIgnoringSafeArea(.all)
        }
    }
    

    For more details, read THIS post.