在 RealityKit 中,如何在单击模型特定部分时显示带有该部分名称的弹出窗口?
我正在开发一个iOS AR应用程序,并且我导入了牙齿的USDZ模型。我想实现一个功能,当用户点击牙齿模型的特定部分时,会出现一个小弹出窗口,其中包含有关该部分的一些描述性文本。
我面临的主要挑战是确定模型的哪一部分已被单击。我怎样才能实现这个目标?您能否指导我完成实现此功能所需的步骤和接口?非常感谢您的帮助!
现在这是我的代码:
import ARKit
import UIKit
import RealityKit
class ARViewController_plane: UIViewController {
let arView = ARView()
var modelEntity: ModelEntity?
override func loadView() {
super.loadView()
view = arView
// create model
modelEntity = createModel()
// 放置模型
placeModel(model: modelEntity!)
// 设置手势
installestures(on: modelEntity!)
// 配置
let configuration = ARWorldTrackingConfiguration()
configuration.planeDetection = .horizontal
// 运行
arView.session.run(configuration)
}
func createModel() -> ModelEntity {
let modelEntity = try! ModelEntity.loadModel(named: "tsmile1.usdz")
return modelEntity
}
func placeModel(model:ModelEntity) {
let planeAnchor = AnchorEntity(world: SIMD3(0, 0, 0))//(.plane(.horizontal, classification: .any, minimumBounds: SIMD2<Float>(0.02, 0.02)))
planeAnchor.addChild(modelEntity!)
arView.scene.addAnchor(planeAnchor)
}
func installestures(on object: ModelEntity) {
// scale
object.generateCollisionShapes(recursive: true)
arView.installGestures([.scale], for: object)
// my rotation
let rotationGesture = UIPanGestureRecognizer(target: self, action: #selector(handleRotationGesture(_:)))
arView.addGestureRecognizer(rotationGesture)
}
@objc func handleRotationGesture(_ gesture: UIPanGestureRecognizer) {
let translation = gesture.translation(in: arView)
// 控制旋转速度
let rotationAngle = Float(translation.x) * 0.001
// 获取当前模型的变换
var currentTransform = modelEntity!.transform
// 创建新的四元数旋转(围绕模型的Z轴旋转)
let newRotation = simd_quatf(angle: rotationAngle, axis: [0, 0, 1])
// 将新的旋转与现有的旋转叠加
currentTransform.rotation = simd_mul(currentTransform.rotation, newRotation)
// 应用新的变换
modelEntity!.transform = currentTransform
}
}
如果您的牙齿模型实际上由几个单独的部分组成,并且不是所谓的组合网格(其中所有可见部分都只是纹理),那么您需要做的就是分配一个
CollisionComponent
牙齿模型的每个单独部分(牙釉质、牙本质、牙髓等)。这种想法的明显缺点是collision shapes
可能会相互重叠,这将不可避免地导致我们做出错误的反应。为了制作一个由不同部分组成的牙齿的简单测试模型,我使用了 Maya。
这种场景的魔杖就是
generateConvex(from:)
方法。
这是一个代码:
import SwiftUI
import RealityKit
struct ContentView : View {
let arView = ARView(frame: .zero)
var body: some View {
ARToothView(arView: arView)
.ignoresSafeArea()
.onTapGesture {
let name = (arView.entity(at: $0) as? ModelEntity)?.name ?? ""
print(name)
}
}
}
struct ARToothView : UIViewRepresentable {
let arView: ARView
let parts = ["enamel", "pulp", "dentine"]
let anchor = AnchorEntity()
// load tooth as Entity to preserve Maya's separate parts
let tooth = try! Entity.load(named: "tooth")
func makeUIView(context: Context) -> ARView {
tooth.scale *= 9
tooth.position.z = -1.0
tooth.orientation = .init(angle: .pi/2, axis: [1,0,0])
anchor.addChild(tooth)
for i in 0 ..< parts.count {
let model = tooth.findEntity(named: parts[i]) as! ModelEntity
let mesh = model.model?.mesh
let shape = ShapeResource.generateConvex(from: mesh!) // convex shape
let collision = CollisionComponent(shapes: [shape])
model.components.set(collision)
arView.installGestures([.translation], for: model)
}
print(tooth) // full hierarchy with CollisionComponents
arView.scene.anchors.append(anchor)
return arView
}
func updateUIView(_ view: ARView, context: Context) { }
}
控制台:
牙齿的 3D 横截面模型可能如下所示。