RealityKit实现点击USDZ模型部位弹出名称及详情的方法
iOS RealityKit 实现USDZ模型特定部位点击识别与弹窗提示
核心实现思路
利用RealityKit的射线检测功能,点击屏幕时获取命中的模型子实体,通过子实体的唯一名称(建模时提前设置)识别具体部位,进而弹出对应描述弹窗。
具体实现步骤
1. 预处理USDZ模型
在Blender、Maya等建模软件中,给牙齿模型的每个需要识别的部位设置唯一且易区分的名称(比如upper_incisor_left、lower_molar_right),导出USDZ时保留这些名称,确保加载到RealityKit后每个子实体都带有对应的name属性。
2. 添加点击手势与射线检测
给ARView添加点击手势识别器,在回调中调用arView.entity(at:)获取点击位置命中的实体,该方法会返回点击路径上最上层的子实体(即你点击的具体牙齿部位)。
3. 匹配部位名称并弹窗
根据命中实体的name,匹配预设的部位描述,用UIAlertController弹出提示。
修改后的完整代码
import ARKit import UIKit import RealityKit class ARViewController_plane: UIViewController { let arView = ARView() var modelEntity: ModelEntity? override func loadView() { super.loadView() view = arView // 加载模型 modelEntity = createModel() guard let model = modelEntity else { return } // 放置模型 placeModel(model: model) // 设置手势(缩放、旋转+新增点击) installGestures(on: model) // 启动AR会话 let configuration = ARWorldTrackingConfiguration() configuration.planeDetection = .horizontal arView.session.run(configuration) } func createModel() -> ModelEntity? { do { return try ModelEntity.loadModel(named: "tsmile1.usdz") } catch { print("模型加载失败: \(error.localizedDescription)") return nil } } func placeModel(model: ModelEntity) { let planeAnchor = AnchorEntity(world: SIMD3(0, 0, 0)) planeAnchor.addChild(model) arView.scene.addAnchor(planeAnchor) } func installGestures(on object: ModelEntity) { // 缩放手势 object.generateCollisionShapes(recursive: true) arView.installGestures([.scale], for: object) // 自定义旋转手势 let rotationGesture = UIPanGestureRecognizer(target: self, action: #selector(handleRotationGesture(_:))) arView.addGestureRecognizer(rotationGesture) // 点击手势(新增) let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleModelTap(_:))) arView.addGestureRecognizer(tapGesture) } @objc func handleRotationGesture(_ gesture: UIPanGestureRecognizer) { guard let model = modelEntity else { return } let translation = gesture.translation(in: arView) let rotationAngle = Float(translation.x) * 0.001 var currentTransform = model.transform let newRotation = simd_quatf(angle: rotationAngle, axis: [0, 0, 1]) currentTransform.rotation = simd_mul(currentTransform.rotation, newRotation) model.transform = currentTransform // 重置手势位移,避免旋转累计过快 if gesture.state == .ended { gesture.setTranslation(.zero, in: arView) } } // 新增:点击模型部位的处理方法 @objc func handleModelTap(_ gesture: UITapGestureRecognizer) { let tapLocation = gesture.location(in: arView) // 射线检测获取命中的实体 guard let hitEntity = arView.entity(at: tapLocation) else { return } // 根据实体名称判断部位,弹出对应描述 var partDescription = "" switch hitEntity.name { case "upper_incisor_left": partDescription = "左上中切牙:负责切割食物,是口腔中最显眼的牙齿之一。" case "lower_molar_right": partDescription = "右下磨牙:承担主要的咀嚼功能,表面有复杂的咬合面。" // 这里添加更多部位的名称与描述匹配 default: partDescription = "未知部位" } // 弹窗展示描述 let alert = UIAlertController(title: "牙齿部位信息", message: partDescription, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "确定", style: .default)) present(alert, animated: true) } }
关键代码说明
arView.entity(at: tapLocation):核心API,通过点击位置发射射线,返回命中的第一个实体(即点击的具体部位)。hitEntity.name:依赖建模时给子部件设置的名称,必须保证USDZ模型导出时保留这些名称。object.generateCollisionShapes(recursive: true):必须设为true,确保射线检测能遍历到所有子实体。
内容的提问来源于stack exchange,提问作者zzhzzh
相关产品推荐
相关产品推荐

