You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 19:35:23