Habilitar gestos en RealityKit

Oct 03 2020

Tengo un archivo usdz personalizado (no se crea a través del código, ¡pero digamos una silla real!). Guardo esto en un Entity.

Una vez que lo tengo, este es mi código:

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

El problema aquí es que "el tipo de argumento 'Entidad' no se ajusta al tipo esperado 'HasCollision'". Entonces no puedo agregar ningún gesto.

Pero no encuentro ningún recurso útil para lograr mi objetivo final. ¿Algún consejo?

Respuestas

2 AndyFedoroff Oct 03 2020 at 23:25

Utilice la forma forzada de downcasting (tipo casting) as!con Entity & HasCollision.

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

o de esta manera:

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


Un método de instancia de origen se installGestures(_:for:)ve así:

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


Configuración inicial en Reality Composer

Antes de compilar, en realidad se impuso Compositor physics = participatese motion type = fixedy accessibility = accessibility enabledpara su modelo.

Versión de código completo

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

El problema es que está intentando darle a ModelEntity una habilidad que no posee (no tiene un manejador de colisiones).

Debe crear una entidad usted mismo, que se ajustará a HasCollision.

Intentaría algo como esto:

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

Tuve otra situación: necesitaba cargar el modelo desde el .usdzarchivo y debería tener una animación. Pero también necesitaba tener gestos como traducción y rotación. La investigación me dirigió al hilo con la respuesta correcta. El código que mostraré a continuación, la idea principal es "anidar la entidad cargada que tiene las animaciones dentro de una ModelEntity, y luego darle a esa ModelEntity un CollisionComponent apropiado basado en los límites del modelo cargado". (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)
           
        }