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

VisionOS ARKit:追踪图像上放置网格球体失败,求简便实现方法

问题分析与解决方案

你的代码追踪功能正常但球体不显示,核心问题有两个:

  • ViewModel中的rootEntity没有关联到ARView的渲染场景,导致所有子实体都不在可视层级内
  • updateImage方法每次收到锚点更新都会重复创建新实体,既浪费资源也可能引发显示异常

修复步骤

1. 关联rootEntity到ARView场景

把ViewModel里的rootEntity改为@Published属性,让SwiftUI的ARView能绑定它作为场景根实体:

@MainActor
class ImageTrackingViewModel: ObservableObject {
    private let session = ARKitSession()
    @Published var rootEntity = Entity() // 改为@Published对外暴露
    private let imageInfo = ImageTrackingProvider(
        referenceImages: ReferenceImage.loadReferenceImages(inGroupNamed: "albumCovers")
    )
    // ... 其他代码不变
}

然后在SwiftUI视图中,将ARView的场景根锚点设置为ViewModel的rootEntity:

struct ARViewContainer: UIViewRepresentable {
    @ObservedObject var vm: ImageTrackingViewModel
    
    func makeUIView(context: Context) -> ARView {
        let arView = ARView(frame: .zero)
        // 将ViewModel的rootEntity加入AR场景
        arView.scene.addAnchor(vm.rootEntity)
        return arView
    }
    
    func updateUIView(_ uiView: ARView, context: Context) {}
}

2. 避免重复创建实体

修改updateImage方法,先检查entityMap中是否已有对应锚点的实体,仅在不存在时创建添加:

func updateImage(_ anchor: ImageAnchor, rootEntity: Entity) {
    // 仅当实体不存在时才创建
    if entityMap[anchor.id] == nil {
        let entity = ModelEntity(mesh: .generateSphere(radius: 0.1), materials: [SimpleMaterial(color: .systemBlue, isMetallic: false)])
        entityMap[anchor.id] = entity
        rootEntity.addChild(entity)
    }
    
    if anchor.isTracked {
        // 使用anchorFromOriginTransform作为实体相对父节点的变换
        entityMap[anchor.id]?.transform = Transform(matrix: anchor.anchorFromOriginTransform)
    }
}

3. 更简便的锚点绑定方式

可以直接将实体挂载到AnchorEntity上,无需手动维护transform,ARKit会自动同步锚点位置:

func updateImage(_ anchor: ImageAnchor, rootEntity: Entity) {
    if entityMap[anchor.id] == nil {
        let entity = ModelEntity(mesh: .generateSphere(radius: 0.1), materials: [SimpleMaterial(color: .systemBlue, isMetallic: false)])
        entityMap[anchor.id] = entity
        // 用AnchorEntity绑定ImageAnchor,自动同步位置
        let anchorEntity = AnchorEntity(anchor: anchor)
        anchorEntity.addChild(entity)
        rootEntity.addChild(anchorEntity)
    }
}

这种方式无需手动更新变换,代码更简洁可靠。

额外注意事项

  • 确保albumCovers资源组已勾选"Target Membership",且参考图片的物理尺寸设置准确
  • 补充相机权限请求逻辑,否则会话可能无法正常启动:
func start() async {
    do {
        // 请求相机权限
        let status = await AVCaptureDevice.requestAccess(for: .video)
        guard status else {
            print("相机权限被拒绝")
            return
        }
        
        if ImageTrackingProvider.isSupported {
            print("ARKitSession starting.")
            try await session.run([imageInfo])
            for await update in imageInfo.anchorUpdates {
                updateImage(update.anchor, rootEntity: rootEntity)
            }
        }
    } catch {
        print("会话启动失败:\(error)")
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 17:37:32