如何在Unity ECS中用1次Draw Call渲染数万个精灵?5分钟认识DOTS渲染包NSprites
【免费下载链接】NSpritesUnity DOTS Sprite Rendering Package项目地址: https://gitcode.com/gh_mirrors/ns/NSprites
NSprites是一款专为 Unity Entities(DOTS/ECS)打造的精灵渲染包:它通过 GPU 实例化(Instancing)+ ComputeBuffer,把所有共享同一材质的精灵实体合并成1 次 Draw Call绘制,让数万个 2D 精灵也能保持满帧运行 ⚡
为什么 ECS 渲染精灵需要专门的包?
在传统 GameObject 工作流里,每个精灵通常对应一个MeshRenderer。当场景里出现几万个小兵、弹丸或粒子精灵时,Draw Call 会直接爆炸,CPU 侧的绘制开销成为性能瓶颈。
而在 DOTS/ECS 世界里情况更"棘手":实体(Entity)本身没有 Renderer 组件,你必须自己搭建一条从实体数据到 GPU 的渲染通路。NSprites 正是解决了这个问题的轻量级渲染框架:
- 🎯 同一材质(Render Archetype)下的所有精灵 → 1 次 Draw Call
- 🔧 任意公开组件都能映射为着色器的实例化属性(位置、颜色、UV 等)
- ⚙️ 三种数据更新策略,避免不必要的 CPU 开销
- 🖥️ 支持编辑器内(SubScene)实时渲染预览
核心原理:NSprites 如何做到 1 次 Draw Call?
核心逻辑集中在Rendering/Systems/SpriteRenderingSystem.cs与Rendering/Common/RenderArchetype.cs:
- 分组:每个精灵实体带一个共享组件
SpriteRenderID(定义于Rendering/Components/SpriteRenderID.cs)。相同 ID 的实体归入同一个Render Archetype(渲染原型 = 网格 + 材质 + 一组实例化属性)。 - 同步:渲染系统通过 Job 系统把各实体的组件数据并行同步到
ComputeBuffer(对应着色器端的StructuredBuffer<T>)。 - 绘制:最后调用一次实例化绘制指令,把该组全部实体画出来——这就是 1 次 Draw Call 的来源。
- 自动扩容:当实体数量超出预分配容量时,ComputeBuffer 会按最小步进自动重新分配,无需手动管理内存。
3 种属性更新模式(PropertyUpdateMode)
NSprites 允许为每个实例化属性指定更新策略(见Rendering/Common/PropertyUpdateMode.cs),这是它省 CPU 的关键:
| 模式 | 更新时机 | 适用场景 |
|---|---|---|
Reactive(默认) | 仅在数据变化/实体增删时 | 最常移动、最常变化的属性(如位置) |
Static | 仅实体创建/销毁时 | 初始化后不再改动的数据 |
EachUpdate | 每帧更新 | 必须每帧刷新的属性 |
数据不动就不上传 GPU——数万个精灵中即使只有几百个在动,CPU 同步成本也非常低 ✅
快速安装:3 步完成
环境要求:Unity 2022.2+,Entities v1.0.0-pre.65+。
打开终端,进入你的 Unity 项目Packages目录,执行:
git clone https://gitcode.com/gh_mirrors/ns/NSprites回到 Unity 等待导入完成即可。包名为com.tonymax.nsprites,当前版本 4.0.2(见项目根目录的 package.json 说明文件)。
5 分钟上手:从零渲染第一万个精灵
第 1 步:声明"组件 → 着色器属性"映射
在任意 .cs 文件顶部用程序集级特性完成绑定(特性定义见Rendering/Common/InstancedPropertyComponentAttribute.cs):
[assembly: InstancedPropertyComponent(typeof(WorldPosition2D), "_pos2D")] [assembly: InstancedPropertyComponent(typeof(SpriteColor), "_color")]第 2 步:注册 Render Archetype
renderArchetypeStorage.RegisterRender( renderID, material, // 材质需开启 [Enable GPU Instancing] bounds, // 精灵可见范围,如 new Bounds(Vector3.zero, Vector3.one * float.MaxValue) 128, 128, // ComputeBuffer 初始容量与扩容步进 "_pos2D", "_color");注册入口在Rendering/Components/RenderArchetypeStorage.cs,整个项目只需注册一次(不要重复注册同一 renderID)。
第 3 步:让实体"可被渲染"
给精灵实体补上渲染组件(扩展方法定义在Rendering/Common/NSprites.cs):
entityManager.AddSpriteRenderComponents(spriteEntity, renderID); entityManager.AddComponentData(spriteEntity, new WorldPosition2D { Value = pos }); entityManager.AddComponentData(spriteEntity, new SpriteColor { Value = Color.white });在 Baker 中也可以用this.AddSpriteComponents(renderID)一键完成。
第 4 步:让着色器支持实例化
着色器中通过StructuredBuffer<T>读取每实例数据,并用内部指针属性_propertyPointers索引(Reactive 模式需要):
StructuredBuffer<int> _propertyPointers; StructuredBuffer<float4> _color; // 顶点着色器内 int propPointer = _propertyPointers[instanceID]; float4 color = _color[propPointer];至此,SpriteRenderingSystem会在每帧 Presentation 阶段自动完成数据同步与绘制,无需额外调用 🎉
兼容性速查表
NSprites 依赖 GPU 实例化与 ComputeBuffer,选型前先看这张表:
| 图形 API | 支持情况 | 平台 | 支持情况 |
|---|---|---|---|
| Direct3D12 | ✅ 支持 | PC | ✅ 支持 |
| Vulkan | ✅ 支持 | WebGL | ❌ 不支持 |
| Direct3D11 | ⚠️ 部分支持 | Android | ⚠️ 未完全验证 |
| OpenGLCore / GLES3 | ⚠️ 部分支持 | iOS | ❓ 未验证 |
项目结构一览
想深入源码?核心目录结构如下(均可在当前仓库中直接找到):
Rendering/Systems/SpriteRenderingSystem.cs—— 渲染系统主入口Rendering/Common/RenderArchetype.cs—— 渲染原型与同步调度Rendering/Components/——SpriteRenderID、属性指针等组件Rendering/Jobs/—— 数据同步 Job(MapChunkJobs / SyncDataJobs)Rendering/Debug/—— 编辑器校验系统,调试数据映射问题NativeContainers/—— 项目自定义的 Native 容器工具package.json—— 包信息与依赖声明
💡 提示:NSprites 只负责"渲染 + 数据管理",排序、剔除、动画等 2D 逻辑需要自行实现,可参考作者的配套示例项目思路。
常见问题
Q:和直接用 SpriteRenderer 有什么区别?SpriteRenderer 面向 GameObject,每个实例通常独立产生 Draw Call;NSprites 面向 ECS 实体,以 Render Archetype 为单位整组实例化绘制,万级精灵下 Draw Call 数量稳定在个位数。
Q:为什么着色器里要用_propertyPointers?Reactive/Static 属性按"块(Chunk)"紧凑排布以节省 GPU 内存,实体在 GPU 缓冲中的位置与实例 ID 不一定一一对应,指针表负责完成这一映射。
Q:如何降低 CPU 开销?把不常变的属性设为Reactive或Static,只有真正每帧变化的数据才用EachUpdate;容量参数按需预留,减少扩容重分配。
总结
NSprites 是 Unity DOTS 生态中非常精炼的精灵渲染方案:注册 → 绑定组件 → 实例化绘制,三步把"数万个精灵"压缩成"个位数 Draw Call"。如果你正在用 ECS 开发大规模 2D 场景(RTS、弹幕、粒子海),这个包值得放进你的工具箱 📦
【免费下载链接】NSpritesUnity DOTS Sprite Rendering Package项目地址: https://gitcode.com/gh_mirrors/ns/NSprites
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考