如何将SCNScene正确加载到ARView场景中
问题根因
ARView是RealityKit框架的渲染组件,它的scene属性是RealityKit独有的Scene类型,和SceneKit体系下的SCNScene完全不兼容,直接赋值必然失败。
另外你直接替换整个view.scene的逻辑本身就有问题:全量替换场景会清空当前AR会话已经检测到的平面、已添加的锚点,甚至你初始化的FocusEntity实例也会被清除,完全不符合往现有AR场景里放置物体的需求。
正确实现方案
你不需要替换整个AR场景,只需要把.scn格式的模型转换成RealityKit可识别的Entity实例,挂载到对应位置的锚点上,再把锚点添加到现有场景即可,具体步骤如下:
- 从.scn资源中读取目标SCNNode
- 将SCNNode转换为RealityKit支持的实体对象
- 以FocusEntity当前命中平面的世界坐标创建锚点,把转换后的模型实体挂载到锚点
- 将锚点添加到ARView现有场景中
修正后的放置逻辑代码如下:
import SwiftUI import RealityKit import SceneKit import ARKit class ARCoordinator: NSObject, ARSessionDelegate { weak var view: ARView? var focusEntity: FocusEntity? func session(_ session: ARSession, didAdd anchors: [ARAnchor]) { guard let view = self.view else { return } debugPrint("Anchors added to the scene: ", anchors) // 避免重复初始化FocusEntity guard self.focusEntity == nil else { return } self.focusEntity = FocusEntity(on: view, style: .classic(color: .yellow)) } @objc func handleTap() { guard let view = self.view, let focusEntity = self.focusEntity, // 确保焦点实体已经在检测到的平面上,避免放置到空位置 focusEntity.isOnPlane else { return } // 读取scn资源和目标节点 guard let scnScene = SCNScene(named: "art.scnassets/object.scn"), let scnNode = scnScene.rootNode.childNodes.first else { print("模型资源读取失败") return } do { // iOS15+ 系统提供SCNNode直接转RealityKit Entity的API let modelEntity = try Entity(scnNode: scnNode) // 根据模型实际尺寸调整缩放比例,避免模型过大/过小 modelEntity.scale = [0.05, 0.05, 0.05] // 创建和焦点位置对齐的世界锚点 let placementAnchor = AnchorEntity(world: focusEntity.position) placementAnchor.addChild(modelEntity) // 将锚点添加到现有场景,不要全量替换scene view.scene.addAnchor(placementAnchor) } catch { print("SCN节点转换失败:\(error.localizedDescription)") } } }
补充说明
- 如果你的App部署目标低于iOS15,无法使用系统自带的SCNNode转Entity能力,最稳妥的方案是直接把模型转成USDZ格式:你可以把.scn文件中的模型导出为.dae格式,拖入Xcode的资源目录,Xcode会自动完成格式转换生成可用的USDZ资源,之后直接调用
try? Entity.load(named: "object")即可加载,不需要依赖第三方转换工具。 - 不要随意修改ARView的
scene属性,ARView初始化时会自动创建适配AR会话的场景实例,自定义场景会破坏世界追踪、平面检测的基础能力。
内容的提问来源于stack exchange,提问作者Mc.Lover
相关产品推荐
相关产品推荐

