【问题标题】:Enabling gestures in RealityKit在 RealityKit 中启用手势
【发布时间】:2021-01-18 19:01:44
【问题描述】:

我有一个自定义的 usdz 文件(不是通过代码创建的,但假设是一把真正的椅子!)。我将其保存在 Entity 中。

一旦我有了它,这就是我的代码:

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

这里的问题是`“参数类型'Entity'不符合预期的类型'HasCollision'”。所以我不能添加任何手势。

但我找不到任何有用的资源来实现我的最终目标。有什么建议吗?

【问题讨论】:

    标签: swift swiftui augmented-reality arkit realitykit


    【解决方案1】:

    我遇到了一些其他情况:我需要从.usdz 文件加载模型,并且它应该有一个动画。但我也需要像平移和旋转这样的手势。该研究将我引导至thread,并给出了正确答案。我将在下面展示其中的代码,主要思想是“将具有动画的加载实体嵌套在 ModelEntity 中,然后根据加载模型的边界为该 ModelEntity 提供适当的 CollisionComponent。” (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)
               
            }
    

    【讨论】:

    • 您的回答正好为实体添加了所需的手势,但您知道如何在实体和现实世界对象(如墙壁或沙发)之间添加碰撞吗?
    • @KeyhanKamangar 很好的问题,但现在我没有任何建议。我认为最好为此提出一个单独的问题
    • 我为它提出了一个单独的问题:stackoverflow.com/questions/68857977/…
    【解决方案2】:

    使用强制形式的向下转换(类型转换)as!Entity & HasCollision

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

    或者这样:

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


    source 实例方法installGestures(_:for:) 如下所示:

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


    Reality Composer 中的初始设置

    在编译之前,在 Reality Composer 中为您的模型设置 physics = participatesmotion type = fixedaccessibility = accessibility enabled

    完整代码版

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

    【讨论】:

    • 非常感谢您的回答。但目前,此代码因“在展开可选值时意外发现 nil”而崩溃。我的模型格式是usdz,这样对吗? (我是否必须在我的模型中打勾 realConverter 中的一些选项?)
    • 请发布更多代码。并且,首先,检查您的 usdz 模型的名称。
    • 更新了我的问题。我的模型来自后端,我确定名称和格式是正确的。没有手势,放置工作正常。另外:我正在 updateUIView 内部工作,因为该项目是使用 SwiftUI 制作的。这会是个问题吗?
    • 我也没有...请问您是否有其他解决方案? (modelEntity 是 Entity 类型)
    • 这个问题100%来自Reality Composer。简单的原始立方体适用于 Xcode 12 中的手势。起初,您应该无法在 Reality Composer 中为您的模型进行物理处理。
    【解决方案3】:

    问题在于您试图赋予 ModelEntity 一种它不具备的能力(它没有碰撞处理程序)。

    您需要自己创建一个符合 HasCollision 的实体。

    我会尝试这样的:

    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
    }
    

    【讨论】:

    • 感谢您的回答!您对必须实现它有什么建议吗?或者任何资源?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多