Habilitando gestos no RealityKit
Eu tenho um arquivo usdz personalizado (não cria por meio de código, mas digamos uma cadeira real!). Eu salvo isso em um Entity.
Assim que o tiver, este é o meu 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)")
}
}
O problema aqui é que `" O tipo de argumento 'Entidade' não está em conformidade com o tipo esperado 'HasCollision' ". Então eu não posso adicionar nenhum gesto.
Mas não consigo encontrar nenhum recurso útil para atingir meu objetivo final. Existe algum conselho?
Respostas
Use a forma forçada de downcasting (fundição de tipo) as!com Entity & HasCollision.
arView.installGestures([.rotation], for: modelEntity as! Entity & HasCollision)
ou desta forma:
let entity = modelEntity as? Entity & HasCollision
arView.installGestures([.all], for: entity!)
Um método de instância de origem seinstallGestures(_:for:) parece com isto:
@discardableResult func installGestures(_ gestures: ARView.EntityGestures = .all,
for entity: HasCollision) -> [EntityGestureRecognizer]
Configurações iniciais no Reality Composer
Antes de compilar, na realidade set Compositor physics = participatese motion type = fixede accessibility = accessibility enabledpara o seu modelo.
Versão 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]
}
}
}
O problema é que você está tentando dar ao ModelEntity uma habilidade que ele não possui (ele não possui um manipulador de colisão).
Você precisa criar uma entidade por conta própria, que estará em conformidade com HasCollision.
Eu tentaria algo assim:
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
}
Eu tenho outra situação: eu precisava carregar o modelo do .usdzarquivo e deveria ter uma animação. Mas também precisava ter gestos como translação e rotação. A pesquisa me direcionou para o tópico com a resposta certa. O código que mostrarei abaixo, a ideia principal é "aninhar a entidade carregada que tem as animações dentro de um ModelEntity e, em seguida, dar a esse ModelEntity um CollisionComponent apropriado com base nos limites do modelo carregado." (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)
}