Activation des gestes dans RealityKit

Oct 03 2020

J'ai un fichier usdz personnalisé (pas créé par code, mais disons une vraie chaise!). Je sauvegarde ceci dans un fichier Entity.

Une fois que je l'ai, voici mon code:

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)")
        
    }
}

Le problème ici est que `` Le type d'argument 'Entity' n'est pas conforme au type attendu 'HasCollision' ". Donc je ne peux ajouter aucun geste.

Mais je ne trouve aucune ressource utile pour atteindre mon objectif final. Y a-t-il des conseils?

Réponses

2 AndyFedoroff Oct 03 2020 at 23:25

Utilisez la forme forcée de downcasting (type casting) as!avec Entity & HasCollision.

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

ou de cette façon:

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


Une méthode d'instance sourceinstallGestures(_:for:) ressemble à ceci:

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


Paramètres initiaux dans Reality Composer

Avant la compilation, dans Reality Composer set physics = participateset motion type = fixedet accessibility = accessibility enabledpour votre modèle.

Version complète du code

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

Le problème est que vous essayez de donner à ModelEntity une capacité qu'elle ne possède pas (elle n'a pas de gestionnaire de collision).

Vous devez créer vous-même une entité, qui sera conforme à HasCollision.

J'essaierais quelque chose comme ça:

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

J'ai eu une autre situation: j'avais besoin de charger le modèle à partir d'un .usdzfichier et il devrait avoir une animation. Mais aussi j'avais besoin d'avoir des gestes comme la translation et la rotation. La recherche m'a orienté vers le fil avec la bonne réponse. Le code que je vais montrer ci-dessous, l'idée principale est "d'imbriquer l'entité chargée qui contient les animations à l'intérieur d'un ModelEntity, puis de donner à ce ModelEntity un CollisionComponent approprié basé sur les limites du modèle chargé." (c)

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)
           
        }