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

如何在visionOS中通过RealityView动态添加带Attachment的Entity?

在visionOS的RealityView中动态添加带Attachment的实体

实现思路

要动态添加带Attachment的Entity,核心是利用RealityView的update闭包响应ViewModel的状态变化,配合attachments闭包管理附件视图,最终将附件关联到新创建的实体上。

具体实现步骤

  • 在ViewModel中维护待添加的实体配置队列,包含实体的位置、对应附件的标识等信息
  • 在attachments闭包中,基于ViewModel的附件配置动态生成带唯一标识的附件视图
  • 在update闭包中监听ViewModel的新增实体队列,创建实体并将对应附件绑定到实体的AttachmentComponent上,最后添加到根实体

完整代码示例

ViewModel部分

import SwiftUI
import RealityKit

class EntityViewModel: ObservableObject {
    let rootEntity = Entity()
    // 存储待添加的实体配置:UUID作为附件标识,position是实体位置
    @Published var pendingEntities: [(id: UUID, position: SIMD3<Float>)] = []
    // 存储每个附件对应的文本内容
    @Published var attachmentTexts: [UUID: String] = [:]
    
    // 对外提供添加实体的方法
    func addEntity(withText text: String, at position: SIMD3<Float>) {
        let id = UUID()
        pendingEntities.append((id: id, position: position))
        attachmentTexts[id] = text
    }
}

RealityView部分

struct DynamicAttachmentDemoView: View {
    @StateObject private var viewModel = EntityViewModel()
    
    var body: some View {
        RealityView { content, attachments in
            content.add(viewModel.rootEntity)
        } update: { content, attachments in
            // 处理待添加的实体队列
            guard !viewModel.pendingEntities.isEmpty else { return }
            
            for entityConfig in viewModel.pendingEntities {
                // 创建载体实体(示例用立方体)
                let entity = ModelEntity(mesh: .generateBox(size: 0.1))
                entity.position = entityConfig.position
                
                // 通过UUID获取对应的附件实体
                if let attachmentEntity = attachments.entity(for: entityConfig.id) {
                    // 创建AttachmentComponent并绑定到载体实体
                    let attachmentComponent = AttachmentComponent(
                        entity: attachmentEntity,
                        placement: .plane(.front, width: 0.1, height: 0.1)
                    )
                    entity.components.set(attachmentComponent)
                }
                
                // 将实体添加到根实体
                viewModel.rootEntity.addChild(entity)
            }
            
            // 清空待添加队列,避免重复处理
            viewModel.pendingEntities.removeAll()
        } attachments: {
            // 动态生成所有需要的附件视图,用UUID作为唯一标识
            ForEach(Array(viewModel.attachmentTexts.keys), id: \.self) { id in
                Text(viewModel.attachmentTexts[id] ?? "默认文本")
                    .font(.caption)
                    .padding(4)
                    .background(.white)
                    .cornerRadius(4)
                    .tag(id)
            }
        }
        .gesture(addEntityGesture())
    }
    
    // 自定义添加实体的手势(示例:点击屏幕添加)
    private func addEntityGesture() -> some Gesture {
        TapGesture()
            .onEnded {
                // 生成随机位置
                let randomPos = SIMD3<Float>(
                    Float.random(in: -0.5...0.5),
                    Float.random(in: -0.5...0.5),
                    Float.random(in: -0.5...0.5)
                )
                // 调用ViewModel方法添加实体
                viewModel.addEntity(withText: "动态附件 \(UUID().uuidString.prefix(5))", at: randomPos)
            }
    }
}

关键注意点

  • 唯一标识匹配:必须用唯一的值(比如UUID)作为附件的tag,确保实体能准确绑定到对应的附件
  • 状态驱动更新:依赖ViewModel的@Published属性触发RealityView的update闭包,实现动态添加逻辑
  • 附件绑定时机:只能在update闭包中获取附件实体并绑定,因为attachments闭包的内容仅在视图更新时完成初始化

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 18:52:27