RealityKit中如何给绑定骨骼的实体增删子实体并实现部件切换?
骨骼绑定角色部件切换的RealityKit最佳实践
我在SwiftUI应用里用RealityKit的Perspective Camera渲染可定制角色,角色的服饰、发型等部件都完成了骨骼绑定。Blender中模型分为可切换对象组(比如鞋子组)和骨架,导出USDC时会激活所有对象。之前未添加Armature Modifier导出时,直接存储Model实体就能实现部件切换;但为了导出动画添加该Modifier后,ModelComponent被合并到骨架中,导致无法简单交换实体或修改材质。
我准备了包含动画骨骼的Blend文件与USDC导出文件,用于测试立方体与球体的切换显示。
测试代码
import SwiftUI import RealityKit struct SwapDemoView: View { var body: some View { RealityView { content in let camera = PerspectiveCamera() camera.transform.translation = SIMD3(x: 0, y: 0.1, z: 3) guard let root = try? await Entity(named: "simpleSwapDemo") else { fatalError("simpleSwapDemo.usdc is not present") } print(root) // 获取初始层级 guard let cube = root.findEntity(named: "Cube") else { fatalError("Cube实体不存在") } cube.removeFromParent() // <-- 移除后Cube仍然可见,实际场景中会保存实体以便切换回来,这里仅测试移除功能 print(root) // 确认Cube已从层级中移除 let resource = root.availableAnimations[0] root.playAnimation(resource.repeat()) content.add(root) content.add(camera) } .background(.white) } }
实体层级变化
移除Cube前的层级
▿ 'root' : Entity, children: 1 ⟐ SynchronizationComponent ⟐ AnimationLibraryComponent ⟐ Transform ▿ 'Armature' : ModelEntity, children: 2 ⟐ SynchronizationComponent ⟐ ModelComponent ⟐ SkeletalPosesComponent ⟐ AnimationLibraryComponent ⟐ Transform ▿ 'Armature' : Entity ⟐ SynchronizationComponent ⟐ Transform ▿ 'Primitives' : Entity, children: 2 ⟐ SynchronizationComponent ⟐ Transform ▿ 'Sphere' : Entity, children: 1 ⟐ SynchronizationComponent ⟐ Transform ▿ 'Sphere' : Entity ⟐ SynchronizationComponent ⟐ Transform ▿ 'Cube' : Entity, children: 1 ⟐ SynchronizationComponent ⟐ Transform ▿ 'Cube' : Entity ⟐ SynchronizationComponent ⟐ Transform
移除Cube后的层级
▿ 'root' : Entity, children: 1 ⟐ SynchronizationComponent ⟐ AnimationLibraryComponent ⟐ Transform ▿ 'Armature' : ModelEntity, children: 2 ⟐ SynchronizationComponent ⟐ ModelComponent ⟐ SkeletalPosesComponent ⟐ AnimationLibraryComponent ⟐ Transform ▿ 'Armature' : Entity ⟐ SynchronizationComponent ⟐ Transform ▿ 'Primitives' : Entity, children: 1 ⟐ SynchronizationComponent ⟐ Transform ▿ 'Sphere' : Entity, children: 1 ⟐ SynchronizationComponent ⟐ Transform ▿ 'Sphere' : Entity ⟐ SynchronizationComponent ⟐ Transform
层级显示Cube已被移除,但渲染时Cube仍可见。现询问此类场景的最佳实践,是否需单独导出动画再应用到骨架及具体实现方法。
最佳实践与解决方案
1. 避免导出时合并ModelComponent
在Blender中导出USDC时,不要给所有可切换部件应用Armature Modifier并合并到骨架:
- 仅给骨架保留必要的动画数据
- 每个可切换部件(服饰、发型)单独保留ModelComponent,且保持与骨架的骨骼绑定关系(不应用Armature Modifier到网格,仅保留绑定数据)
- 导出时确保每个部件作为独立的ModelEntity存在,而非合并到骨架的ModelComponent中
2. 单独导出动画并绑定到骨架
如果必须合并网格导出动画,可采用“骨架+独立部件+单独动画”的流程:
- 第一步:导出仅包含骨架和动画的USDC文件(不含任何可切换部件)
- 第二步:导出每个可切换部件的USDC文件(已完成骨骼绑定,但不包含动画)
- 在RealityKit中操作:
- 加载骨架动画实体
- 逐个加载可切换部件实体,将其绑定到骨架的对应骨骼上
- 通过控制部件实体的
isEnabled属性或添加/移除父节点实现切换
3. 修改现有合并模型的部件切换方法
如果已经导出了合并后的模型,可通过操作ModelComponent的mesh实现部件隐藏/替换:
if let armatureModel = root.findEntity(named: "Armature") as? ModelEntity { guard var mesh = armatureModel.model?.mesh else { return } // 遍历子几何体,找到Cube对应的部分并隐藏 mesh.submeshes.enumerated().forEach { index, submesh in if submesh.name == "Cube" { var modifiedSubmesh = submesh modifiedSubmesh.isVisible = false mesh.submeshes[index] = modifiedSubmesh } } armatureModel.model?.mesh = mesh }
关键注意事项
- Blender中每个可切换部件的网格需设置唯一名称,方便在RealityKit中识别
- 骨骼绑定后,部件的变换应完全由骨骼控制,避免手动修改部件的Transform
- 切换部件时优先使用
isEnabled属性而非移除实体,性能更优且能保留绑定关系
内容的提问来源于stack exchange,提问作者Reality-User
相关产品推荐
相关产品推荐

