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

如何在RealityKit中高效渲染大量实体并独立控制其动画参数?

在RealityKit中高效渲染10000个可独立动画的立方体

RealityKit默认不会像SceneKit那样自动对共享几何的实体进行实例化批处理——即使多个ModelEntity使用完全相同的ModelComponent,每个实体依然会触发独立的绘制调用,数量上万时会严重拖慢性能。以下是两种兼顾渲染效率与独立动画/物理需求的解决方案:

方案一:启用自动批处理(适合需要独立实体、物理效果的场景)

从iOS 15、macOS 12开始,RealityKit为ModelComponent提供了batchMode属性,设置为.shared后,所有使用同一ModelComponent且batchMode为.shared的实体将被自动批处理,合并为少量绘制调用,同时保留每个实体的独立变换、动画和物理组件。

实现代码

let material = UnlitMaterial(color: .red)
// 创建共享ModelComponent并开启批处理模式
var modelComponent = ModelComponent(
  mesh: .generateBox(size: 0.1),
  materials: [material]
)
modelComponent.batchMode = .shared

let containerEntity = Entity()

for i in 0..<10000 {
  let modelEntity = ModelEntity()
  modelEntity.model = modelComponent
  // 设置独立位置
  modelEntity.transform.translation = [
    -7.5 + Float(i % 100) * 0.15,
    -7.5 + floor(Float(i) / 100.0) * 0.15,
    0
  ]
  // 直接添加物理组件实现独立物理效果
  modelEntity.components[PhysicsComponent.self] = PhysicsComponent(
    mass: 0.1,
    shape: .generateBox(size: 0.1)
  )
  containerEntity.addChild(modelEntity)
}

let anchor = AnchorEntity()
anchor.addChild(containerEntity)
scene.addAnchor(anchor)

注意事项

  • 所有要批处理的实体必须使用完全相同的ModelComponent(包括网格、材质、渲染参数),修改任意实体的材质或网格都会打破批处理。
  • 该特性仅支持iOS 15+、macOS 12+、visionOS等新版本系统。

方案二:使用InstancedMesh(极致性能,适合仅需独立变换动画的场景)

如果不需要每个立方体拥有独立物理组件,仅需独立的平移/缩放/旋转动画,使用InstancedMesh可实现真正的GPU实例化,仅产生1次绘制调用,性能达到最优。

实现代码

let material = UnlitMaterial(color: .red)
let baseMesh = MeshResource.generateBox(size: 0.1)

// 预存所有实例的变换数据
var instanceTransforms: [Transform] = []
for i in 0..<10000 {
  let translation = SIMD3<Float>(
    -7.5 + Float(i % 100) * 0.15,
    -7.5 + floor(Float(i) / 100.0) * 0.15,
    0
  )
  instanceTransforms.append(Transform(translation: translation))
}

// 创建实例化网格
let instancedMesh = InstancedMesh(
  mesh: baseMesh,
  instances: instanceTransforms
)

// 用单个ModelEntity承载所有实例
let instancedEntity = ModelEntity(
  model: ModelComponent(
    mesh: .instanced(instancedMesh),
    materials: [material]
  )
)

// 更新单个实例变换的方法
func updateInstanceTransform(at index: Int, newTransform: Transform) {
  guard var instancedMesh = instancedEntity.model?.mesh as? InstancedMesh else { return }
  instancedMesh.instances[index] = newTransform
  instancedEntity.model?.mesh = .instanced(instancedMesh)
}

let anchor = AnchorEntity()
anchor.addChild(instancedEntity)
scene.addAnchor(anchor)

注意事项

  • 所有实例共享同一材质和网格,无法单独修改某个实例的材质。
  • 实例没有独立实体,无法直接添加PhysicsComponent等组件,若需物理效果建议选用方案一。
  • 更新实例变换时,需重新将InstancedMesh赋值给ModelComponent,RealityKit会自动处理GPU数据同步。

为何默认代码无批处理效果?

RealityKit的Entity-Component模型更侧重灵活性,默认每个实体都是独立渲染单元,以支持更自由的组件组合(如不同的物理、动画配置)。自动批处理需要明确启用batchMode,让框架知晓你愿意以部分灵活性换取性能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 07:23:17