Włączanie gestów w RealityKit

Oct 03 2020

Mam niestandardowy plik usdz (nie tworzę za pomocą kodu, ale powiedzmy, że prawdziwe krzesło!). Zapisuję to w pliku Entity.

Kiedy już to mam, to jest mój kod:

func updateUIView(_ uiView: ARView, context: Context) {
            
    if let modelEntity = model.modelEntity {
        
        print("\(model.modelName)")
        
        let anchorEntity = AnchorEntity(plane: .horizontal)
        
        anchorEntity.addChild(modelEntity.clone(recursive: true))
        
        uiView.scene.addAnchor(anchorEntity)
        
        // modelEntity.generateCollisionShapes(recursive: true) 
        // If we have multiple object, recursive true help to generate collision for all of them
        
        uiView.installGestures(.rotation, for: modelEntity as! Entity & HasCollision)
        
        uiView.debugOptions = .showPhysics
        
    } else {
        
        print("Unable to load modelEntity for \(model.modelName)")
        
    }
}

Problem polega na tym, że „„ Typ argumentu 'Entity' nie jest zgodny z oczekiwanym typem 'HasCollision' ”. Więc nie mogę dodać żadnego gestu.

Ale nie mogę znaleźć żadnego użytecznego źródła, aby osiągnąć mój ostateczny cel. Czy jest jakaś rada?

Odpowiedzi

2 AndyFedoroff Oct 03 2020 at 23:25

Użyj wymuszonej formy downcastingu (odlewania typu) as!z Entity & HasCollision.

arView.installGestures([.rotation], for: modelEntity as! Entity & HasCollision)

lub w ten sposób:

let entity = modelEntity as? Entity & HasCollision
arView.installGestures([.all], for: entity!)


Źródło metoda instancji installGestures(_:for:)wygląda następująco:

@discardableResult func installGestures(_ gestures: ARView.EntityGestures = .all,
                           for entity: HasCollision) -> [EntityGestureRecognizer]


Ustawienia początkowe w programie Reality Composer

Przed kompilacją, to w rzeczywistości zbiór Kompozytor physics = participatesi motion type = fixedi accessibility = accessibility enableddla danego modelu.

Pełna wersja kodu

import SwiftUI
import RealityKit

struct ARViewContainer: UIViewRepresentable {
    
    let boxAnchor = try! Experience.loadBox()
    
    func makeUIView(context: Context) -> ARView {
        
        let arView = ARView(frame: .zero)   
        arView.scene.anchors.append(boxAnchor)
        return arView
    }
    
    func updateUIView(_ uiView: ARView, context: Context) {
        
        if let modelEntity: Entity = boxAnchor.steelBox {    
            let anchorEntity = AnchorEntity(.plane(.vertical, 
                                             classification: .wall, 
                                             minimumBounds: [0.2, 0.2]))  
            anchorEntity.addChild(modelEntity.clone(recursive: true))    
            uiView.scene.addAnchor(anchorEntity)    
            modelEntity.generateCollisionShapes(recursive: true)    
            uiView.installGestures([.all], 
                               for: modelEntity as! Entity & HasCollision)    
            uiView.debugOptions = [.showPhysics]
        }
    }
}
1 YanivH Oct 04 2020 at 17:30

Problem polega na tym, że próbujesz nadać ModelEntity zdolność, której nie posiada (nie ma ona obsługi kolizji).

Musisz samodzielnie stworzyć jednostkę, która będzie zgodna z HasCollision.

Spróbowałbym czegoś takiego:

import RealityKit

class MyEntity: Entity, HasAnchoring, HasModel, HasCollision {

}

func updateUIView(_ uiView: ARView, context: Context) {
    // This is simply to create a dummy modelEntity
    let plane = MeshResource.generatePlane(width: 0.1, depth: 0.1)
    let texture = MaterialColorParameter.color(UIColor.red)
    var material = SimpleMaterial()
    material.baseColor = texture
    let modelEntity = ModelEntity(mesh: plane, materials: [material])
      
    // This is the class we have wrapping the model
    let myEntity = MyEntity()
    myEntity.addChild(modelEntity)
    
    // Now, we add the collision component
    let boxShape = ShapeResource.generateBox(width: 0.1, height: 0.1, depth: 0.1)
    let boxShapeCollisionComponent = CollisionComponent (
      shapes: [boxShape],
      mode: .trigger,
      filter: .default
    )
    myEntity.collision = boxShapeCollisionComponent
    // Or, you could of called myEntity.generateCollisionShapes(recursive: true)
    
    // Last thing, lets put this plane, with a box collision component,
    // right in front of us
    myEntity.transform = Transform.identity
    myEntity.transform.translation.z = myEntity.transform.translation.z - 0.3
    uiView.scene.addAnchor(myEntity)
    
    uiView.installGestures(.rotation, for: myEntity)
    
    uiView.debugOptions = .showPhysics
}
АлександрГрабовский Oct 30 2020 at 00:07

Mam inną sytuację: musiałem wczytać model z .usdzpliku i powinien mieć animację. Ale potrzebowałem też gestów, takich jak tłumaczenie i rotacja. Badania skierowały mnie do wątku z właściwą odpowiedzią. Jego kod, który pokażę poniżej, głównym pomysłem jest „zagnieżdżenie załadowanej jednostki, która ma animacje wewnątrz elementu ModelEntity, a następnie nadanie temu ModelEntity odpowiedniego składnika CollisionComponent w oparciu o granice załadowanego modelu”. (do)

loadRequest = Entity.loadAsync(contentsOf: url).sink(receiveCompletion: { status in
            print(status)
        }) { entity in
           
            // Scaling entity to a reasonable size
            entity.setScale(SIMD3(repeating: 0.01), relativeTo: nil)
           
            // Creating parent ModelEntity
            let parentEntity = ModelEntity()
            parentEntity.addChild(entity)
           
            // Anchoring the entity and adding it to the scene
            let anchor = AnchorEntity(.plane(.horizontal, classification: .any, minimumBounds: .zero))
            anchor.addChild(parentEntity)
            self.arView.scene.addAnchor(anchor)
           
            // Playing availableAnimations on repeat
            entity.availableAnimations.forEach { entity.playAnimation($0.repeat()) }
           
            // Add a collision component to the parentEntity with a rough shape and appropriate offset for the model that it contains
            let entityBounds = entity.visualBounds(relativeTo: parentEntity)
            parentEntity.collision = CollisionComponent(shapes: [ShapeResource.generateBox(size: entityBounds.extents).offsetBy(translation: entityBounds.center)])
                       
            // installing gestures for the parentEntity
            self.arView.installGestures(for: parentEntity)
           
        }