使用Raycasting射线检测时如何为整个Reality模型所有部件统一改色
RealityKit点击子实体时让整个关联模型组统一变灰的解决方案
核心思路是:射线检测命中任意子实体后,向上遍历找到模型的根节点,再给根节点下所有带ModelComponent的子实体统一添加灰度效果,同时提前给所有子模型添加碰撞体保证射线检测可以命中任意部分。
步骤1:加载模型时初始化配置
- 存储模型根实体的全局引用,同时给所有子ModelEntity自动生成碰撞体,保证点击旗帜、星星等部件都能触发射线检测:
// 声明全局变量存储模型根实体 var fanfareRoot: Entity! // 加载模型时的处理 Task { do { fanfareRoot = try await Entity.loadAsync(named: "fanfare").get() arView.scene.addAnchor(fanfareRoot) // 遍历所有子节点,给带模型组件的实体生成碰撞体 fanfareRoot.children.forEach { child in guard let modelChild = child as? ModelEntity else { return } // 若子实体存在嵌套模型,可将recursive参数设为true modelChild.generateCollisionShapes(recursive: false) } } catch { print("模型加载失败: \(error)") } }
步骤2:点击事件处理逻辑
- 射线检测命中实体后,向上遍历找到模型根节点,再给根节点下所有模型实体统一添加灰度效果:
@objc func handleTap(_ gesture: UITapGestureRecognizer) { let tapLocation = gesture.location(in: arView) // 射线检测获取命中的子实体 guard let hitEntity = arView.entity(at: tapLocation) else { return } // 向上遍历找到模型的根实体 var currentEntity = hitEntity while currentEntity.parent != nil && currentEntity != fanfareRoot { currentEntity = currentEntity.parent! } // 校验找到的是目标根实体后,统一添加灰度效果 guard currentEntity == fanfareRoot else { return } currentEntity.children.forEach { child in guard var modelChild = child as? ModelEntity else { return } modelChild.components.set(ModelDebugOptionsComponent(visualizationMode: .lightingDiffuse)) } }
优化方案(可选)
如果场景中存在多个同类型模型,可自定义空的标识组件挂载到根实体上,避免根节点匹配错误:
// 自定义标识组件 struct FanfareRootComponent: Component {} // 加载模型时给根实体添加标识 fanfareRoot.components.set(FanfareRootComponent()) // 遍历找根时的判断逻辑 while currentEntity.parent != nil && !currentEntity.components.has(FanfareRootComponent.self) { currentEntity = currentEntity.parent! }
内容的提问来源于stack exchange,提问作者Bob
相关产品推荐
相关产品推荐

