如何将Reality Composer场景加载为ModelEntity而非普通Entity?
解答:从Reality Composer场景直接加载ModelEntity的问题
核心结论
不能直接通过Entity.loadModel(contentsOf:)从Reality Composer生成的.reality文件的场景路径加载得到ModelEntity,原因是Reality Composer的每个场景都会被包装在一个普通根Entity容器中,实际的ModelEntity是这个根容器的子节点。
原因分析
Reality Composer导出的.reality文件里,每个场景的结构固定为:
- 根节点:普通
Entity(作为场景容器) - 子节点:实际的
ModelEntity(你创建或导入的模型对象)
Entity.loadModel要求加载的资源本身就是ModelEntity类型的资源(比如单独的USDZ文件),而场景的根节点是容器Entity,所以调用这个方法会加载失败。
解决方案
方法1:从根Entity中直接获取子ModelEntity
加载场景根Entity后,通过子节点或名称查找并做类型转换,这比遍历层级更简洁:
do { let url = Bundle.main.url(forResource: "Experience", withExtension: "reality")! .appending(path: "Box", directoryHint: .notDirectory) let rootEntity = try Entity.load(contentsOf: url) // 场景仅含一个模型时,直接取第一个子节点并转换 if let modelEntity = rootEntity.children.first as? ModelEntity { // 使用modelEntity(可访问模型、物理属性等) } } catch { print("加载失败:\(error.localizedDescription)") }
方法2:通过模型名称查找并转换
如果在Reality Composer中给模型对象本身(而非场景)设置了名称,可通过findEntity(named:)查找并转换:
do { let url = Bundle.main.url(forResource: "Experience", withExtension: "reality")! .appending(path: "Hexagon", directoryHint: .notDirectory) let rootEntity = try Entity.load(contentsOf: url) // 注意:这里的名称是Reality Composer中模型对象的名称,不是场景名称 if let modelEntity = rootEntity.findEntity(named: "HexagonModel") as? ModelEntity { // 使用modelEntity } } catch { print("加载失败:\(error.localizedDescription)") }
关于findEntity(named:)返回普通Entity的问题
你遇到这个情况,大概率是在Reality Composer中给场景本身命了名,而非给模型对象命名。需要选中模型对象(比如场景里的Box或六边形),在右侧检查器中设置它的名称,这样findEntity(named:)才能定位到对应的ModelEntity。
替代方案(简化你的现有方法)
如果你的场景始终只有一个模型,也可以直接将子ModelEntity的属性复制到根节点,或者直接将子节点作为使用对象,无需复制属性:
do { let url = Bundle.main.url(forResource: "Experience", withExtension: "reality")! .appending(path: "Box", directoryHint: .notDirectory) let rootEntity = try Entity.load(contentsOf: url) guard let modelEntity = rootEntity.children.first as? ModelEntity else { return } // 直接使用modelEntity,或者将其属性复制到根节点 rootEntity.components.set(modelEntity.components[ModelComponent.self]) rootEntity.components.set(modelEntity.components[PhysicsBodyComponent.self]) // 移除原子节点 modelEntity.removeFromParent() } catch { print("加载失败:\(error.localizedDescription)") }
内容的提问来源于stack exchange,提问作者Theo Kallioras
相关产品推荐
相关产品推荐

