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

为何导入Reality Composer场景需手动配置ARReferenceObject才能显示?

问题:RealityComposer导出的.reality文件加载到RealityKit时物体跟踪不生效的原因

我希望将从Reality Composer导出的包含物体锚点和模型的.reality文件加载到RealityKit中。根据我的理解,只需从.reality文件加载根级AnchorEntity并调用view.scene.addAnchor()添加到场景即可(见代码中// 1:处),但这样物体检测无法正确配置,场景无法显示。不过,若我将用于在RealityComposer中创建场景的.arobject文件对应的AR参考对象显式添加到ARWorldTrackingConfiguration.detectionObjects(见代码// 2.处),然后在物体锚点添加到场景的回调事件中,手动将场景内容附加到该锚点,场景就能正常显示(见代码// 3.处)。

请问为何需要这些额外步骤?我在导入RealityComposer场景时,遗漏了哪些能为其中的AnchorEntity正确配置物体跟踪的设置?

注:为简洁起见,本示例中所有文件均采用同步加载方式。

struct RealityKitView: UIViewRepresentable {

    private static let logger = Logger(
        subsystem: Bundle.main.bundleIdentifier!,
        category: String(describing: RealityKitView.self)
    )

    func makeUIView(context: Context) -> ARView {
        let view = ARView()

        let session = view.session
        let config = ARWorldTrackingConfiguration()

        // 1: Try to load the .reality file (nothing appears in the ARView):
        let realityFileSceneURL = Self.createRealityURL(filename: "ImpactHub_Sign", sceneName: "Scene")
        if let realityFileSceneURL {
            do {
                let anchorEntity = try Entity.loadAnchor(contentsOf: realityFileSceneURL)
                view.scene.addAnchor(anchorEntity)
            } catch {
                debugPrint(error.localizedDescription)
            }
        }

        // 2: Add detection reference objects:
        config.detectionObjects = ARReferenceObject.referenceObjects(inGroupNamed: "AR", bundle: Bundle.main)!

        session.run(config, options: [.resetTracking])

        context.coordinator.view = view
        session.delegate = context.coordinator

        return view
    }

    func updateUIView(_ view: ARView, context: Context) {
    }

    static func createRealityURL(filename: String,
                          sceneName:String) -> URL? {
        guard let realityFileURL = Bundle.main.url(forResource: filename, withExtension: "reality")
 else {
            print("Error finding Reality file \(filename)")
            return nil
        }
        let realityFileSceneURL = realityFileURL.appendingPathComponent(sceneName,
                                                                    isDirectory: false)
        return realityFileSceneURL
    }

    func makeCoordinator() -> Coordinator {
        Coordinator()
    }

    class Coordinator: NSObject, ARSessionDelegate {

        private static let logger = Logger(
            subsystem: Bundle.main.bundleIdentifier!,
            category: String(describing: Coordinator.self)
        )

        weak var view: ARView?

        func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {
            guard let view = self.view else { return }

            debugPrint("Anchors added to the scene: ", anchors)

            anchors.compactMap { $0 as? ARObjectAnchor }.forEach { anchor in
                debugPrint("Object anchor added")

                // 3: Load .reality file and manually create an AnchorEntity bound to the object
                // anchor that has just been detected. This way, the scene appears.
                let realityFileSceneURL = RealityKitView.createRealityURL(filename: "ImpactHub_Sign", sceneName: "Scene")
                if let realityFileSceneURL {
                    do {
                        let anchorEntity = try Entity.loadAnchor(contentsOf: realityFileSceneURL)

                        anchorEntity.children.forEach { childEntity in
                            let anchorEntity = AnchorEntity(anchor: anchor)
                            anchorEntity.addChild(childEntity)
                            view.scene.addAnchor(anchorEntity)
                        }
                    } catch {
                        print(error)
                    }
                }
            }
        }
    }

}

解答

1. 直接加载.reality文件不生效的核心原因

从RealityComposer导出的.reality文件里的AnchorEntity,只是绑定了物体锚点的逻辑结构,但它不会自动触发ARKit的物体检测功能——ARKit的物体跟踪必须显式在会话配置中启用,RealityComposer导出的资源不会自动修改你的AR会话参数。

另外,直接加载的AnchorEntity并没有和ARKit实时检测到的ARObjectAnchor建立绑定:它只是一个“等待匹配”的锚点模板,但ARKit不知道要去检测对应的物体,自然不会激活这个锚点,模型也就不会显示。

2. 你遗漏的关键设置

  • 未显式启用物体检测会话配置:ARKit不会自动扫描.reality文件里的参考对象信息来开启检测,必须手动将对应的.arobject参考对象添加到config.detectionObjects,这是启动物体跟踪的必要前提。
  • 未将场景锚点与实时检测结果绑定:直接加载的AnchorEntity处于“未激活”状态,只有当ARKit检测到目标物体并生成真实空间中的ARObjectAnchor后,把场景内容绑定到这个实时锚点上,才能让模型和检测到的物体位置对齐。

3. 为何手动步骤能生效?

  • 步骤2中添加config.detectionObjects,相当于告诉ARKit:“我要检测这些物体,找到后生成对应的空间锚点”。
  • 步骤3中在didAdd anchors回调里绑定场景,是因为此时ARKit已经定位到目标物体并生成了真实的空间锚点,把模型挂到这个锚点上,才能让模型随物体位置变化实时更新。

优化建议

可以简化流程,不需要重复加载.reality文件,提前保存场景内容,等到检测到锚点时直接复用:

// 在RealityKitView中添加属性保存场景内容
private var sceneContents: [Entity]?

// 在makeUIView的步骤1中修改:
if let realityFileSceneURL {
    do {
        let anchorEntity = try Entity.loadAnchor(contentsOf: realityFileSceneURL)
        // 克隆并保存子实体,不直接添加锚点到场景
        sceneContents = anchorEntity.children.map { $0.clone(recursive: true) }
    } catch {
        debugPrint(error.localizedDescription)
    }
}

// 修改Coordinator,让它能访问sceneContents(可通过给Coordinator添加parent属性实现)
class Coordinator: NSObject, ARSessionDelegate {
    weak var view: ARView?
    weak var parent: RealityKitView? // 添加这个属性
    
    func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {
        guard let view = view, let sceneContents = parent?.sceneContents else { return }
        
        anchors.compactMap { $0 as? ARObjectAnchor }.forEach { anchor in
            let anchorEntity = AnchorEntity(anchor: anchor)
            sceneContents.forEach { anchorEntity.addChild($0) }
            view.scene.addAnchor(anchorEntity)
        }
    }
}

// 在makeCoordinator中传递parent
func makeCoordinator() -> Coordinator {
    let coordinator = Coordinator()
    coordinator.parent = self
    return coordinator
}

内容的提问来源于stack exchange,提问作者Peter

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 19:50:58