[4.0.1] NSprites - sprite rendering package

8622342--1158279--203323912-3f0aec5a-543d-4145-bf8f-42e07af2d124.gif
NSprites is an open-source sprite rendering package. It uses ComputeBuffers to sync data between your entities and GPU and Graphics.DrawMeshInstancedProcedural to render entities.

Requirements

  • entities v1.0.0-pre.65+
  • unity 2022.2+

When you might want to use it

  • Your project operate with numerous of sprites so you wanna make them native entities. + You want to have your sprites as individual entities.
  • You want to minimize drawcalls, even probably render the most part in the same drawcall.

When you might not want to use it

  • You don’t want to write your own instancing shaders
  • You want more progressive solution with built-in animation / culling / etc systems. (you still can look at NSprites Foundation project or Age of Sprites sample project)

Readme and documentation on GitHub project. Also check Foundation with samples and tools to work with this package.

Notes

This package doesn’t contain any animation / culling / sorting / etc systems. So package provides very core feature - sprite rendering with automatic compute buffer data management. Though such systems can be easily built on top of it. You can inspect samples and use some tools by looking at sample project and foundation (which includes animation / sorting / culling / base rendering).
The main reason of such a pure solution is because developers often want to have unique code architecture and I don’t want to unnecessary limit anyone, because you may have no need in sorting at all, you may want to have simple sorting or nested sprites sorting or implement clever performant sorting algorithm (same with any other high level system).

Changelog

v4.0.1
Temporal fix for chunk components baking issues for unity6 / entities 1.2 compatibility

v4.0.0
Remove RegisterRender overload with no Bounds parameter.
This commit brings breaking changes. To upgrade to this version you need now use overload with explicit bounds parameter.

v3.2.0

  • storage now test if archetype with same id already registered and log an error if it is
  • client code now can clear storage which disposes all render archetypes (for example when you change game level and no more need previous archetypes)

v3.1.7

  • Code refactoring
  • Fix sprites didn’t get rendered until 1st reallocation

v3.1.2
Fix wrong reallocation with min capacity step greater than 1

v3.1.1
Fix invalid data sync for EachUpdate mode properties

v3.1.0
Update to entities 1.0.0-pre.65. Error / obsolete API fixing.

  • Fix asmdefs errors
  • Fix using obsolete API in NSprtiesUtils baker AddSpriteRenderComponents method

v3.0.4
Fix add rendering components methods missed PropertyPointerChunk component

v3.0.3
Add DebugSystem (editor / development build only) which detect missed property-components for sprite renderers and wrong PropertyPointer / PropertyPointerChunk composition (if it somehow was setted wrong)
You can use NSPRITES_DEBUG_SYSTEM_DISABLE to fully disable debug system from compilation if you don’t need it

v3.0.1
Minor internal changes of how PoprertyPointer / PropertyPointerChunk baked to entity

v3.0.0
You can use any blittable component as shader StructuredBuffer<T> property. Previously only 1-filed component could be used. Update details. Using components as properties details.
Upgraid guide: There is no more PropertyFormat so all your
InstancedPropertyComponent should be used without PropertyFormat parameter. So for example [assembly: InstancedPropertyComponent(typeof(SpriteColor), "_color", PropertyFormat.Float4)] becomes [assembly: InstancedPropertyComponent(typeof(SpriteColor), "_color")]

v2.3.0

  • You can now also register Mesh (quad by default as previously) and render bounds per render using new RenderArchetypeStorage methods.
  • Added NSpritesException for better exception analysis

v2.2.4
Bug fixes / improvements

v2.2.0
Add Window → Entities → NSprites window where you can inspect NSprites data. More.

v2.1.0
Add baker extension method for adding sprite render components driven by baking system. From now client code can use this.AddSpriteRenderComponents(int id) from baker code.

v2.0.0
Upgrade codebase to 1.0 API. Details.
Upgrade guide: to register renders you should now use SystemAPI.ManagedAPI.TryGetSingleton<RenderArchetypeStorage>(out var renderArchetypeStorage) instead of accessing directly to system instance like var renderSystem = World.GetSystem<SpriteRenderingSystem>();

v1.1.2
Minor typos / obsolete API / bug fixes + improvements

v1.0.0
Release version. From this point package has documentaton on github wiki and also samples.

alpha-v.2.0.0
Last alpha version when package was in deep developement. This version is hardly differ from next versions. It can be only used with entities v0.17 and has no documentation nor samples.

I highly appreciate any discussions / critique / questions / bug reports / pull requests!
You can join NSprites discord channel to fast contact with author and other package users!

8622342--1158276--204523105-7cabb122-954c-4fb0-97bc-becb27d2d2b9.gif

26 Likes

Looks pretty good?
What is your stress test max number of sprites, that you can render?

1 Like

With just pure package installed and just entities with properties it was near to 1kk sprites at screen with stable 60fps. It was 7 properties (1 of those writes whole 1kk capacity buffer each frame) for each entity-sprite. But it is hard to break performance for such things, because most of the time system just asks chunks do they have any component / order changes. But in real world for 2D rendering there is often sorting problems which usually bottleneck.

4 Likes

Out of curiosity, how are you handling sprite animations? Are you shifting the UVs in your ComputeBuffer per frame?

Exactly. I know how much frames I have, theirs distribution and durations and then just calculate current UVs

2 Likes

when i build android wiith il2cpp, has a error message

1 Like

Yep, I’ve fixed it. Obviously it was _camera which somehow gets null ref in runtime but in editor all goes well. So for now I’ve added lazy initialize during OnUpdate.

Btw, what the preferred way in 0.51 and in 1.0 to work with hybrid objects like camera? Should I put it to subscene and assume that all will ok in build?

Also one another issue I see in android build is soldier’s idle animation gets wrong UVs. Algorithm is very primitive, so I believe it is rendered texture, maybe unity’s sprite atlas is to advanced and perform some different magic for different build targets, so maybe I should try another atlas solution, cause that isn’t 1st issue with sprite atlas (if it is of course).

1 Like

Following with profound interest. I’d be looking for 1.0 (upon release) support. Some of our animations are rather complex and sprite rendering is one of those tasks that we definitely don’t want to do ourselves so we haven’t completely committed to building our game with ECS and this sound like the incentive. Great job!

1 Like

Rapidly answering I think there is not so much things in 1.0 which NSprites should integrate/update, so probably it can already be used with 1.0. Though I will update project soon.

UPD: 1.0 has changes in IJobChunk, so there is no more firstEntityIndex parameter. Though it is simple to get per-chunk index offsets with EntityQuery.CalculateBaseEntityIndexArrayAsync().
I use this parameter to write data Chunk → ComputeBuffer in parallel for each-update properties.

2 Likes

Waiting for this project update to 1.0

1 Like

Hi. How is the update progressing? Btw, thanks for your work!

1 Like

I was close to publish minimal compatible with entities 1.0 version, but stacked a little with this . Today will try to restore assets, check all working as expected and publish update.

1 Like

I’m definitely interested in something like this for my 2D top down RPG maker esque game.
Can I do tilemaps with this? As in, can I batch together 16x16 sprite tiles into one entity?

Since this package doesn’t limit you what shader to use (it just require shader to be instanced compatible), you can built whatever you want.

What you mean batching 16x16 sprites in one entity? (I mean what should it be? shared texture? solid renderer?) How would you organize data for tilemaps in ECS? And how you expect render will perform?

I think what I mean is more of a feature request connected to a larger workflow I want to achieve.

Essentially I want to have Tile Chunks in my 2d, top down, networked multiplayer game. Tile data is stored in a Dynamic Buffer on each chunk entity and the data stored in each element is just a simple byte defining the index to be used in a texture atlas lookup.

public struct VisualTile : IBufferElementData
{
    public byte Index;
}

16x16 is a rough estimate of how many tiles I want to store in each chunk. So each chunk is roughly 256 bytes.

Whenever the dynamic buffer is changed the data is copied into a compute buffer which is then sent to the shader responsible of rendering a single plane of 16x16 tiles using a texture atlas. I don’t know much more than this but it’s an API that I would really love to have in a package like this.

That looks quite problematic. I guess for the meantime I’ll stick with the hybrid approach.

I’d rather try to split such workflow to 2 parts - editor authoring and runtime.

  • Let runtime be just single sprites, because they are already updated per chunk changes any data you declared as sprite’s property. You still would use atlas and have all rendering as solid drawcall. One really downside I see about rendering tilemap as bunch of individual sprites is probably a lot of overdraw, because it is still bunch of quads.
    As baking result sprite entities would have just differ TexST on atlas depending on byte index, which can be even cut of in the end of baking process.
  • Editor authoring should mimic unity’s palette drawer (at best) or just have the same structure. Like map object, grid , etc. Then just implement a little bit of bakers which will create sprite entities.
2 Likes

It was some kind of unity buggy dark magic but after project recreation all works fine. From now package supports latest entities update.

2 Likes

hello, Age-of-Sprites project is supported WebGL?

Few things we can worry about WebGL compatibility in this project are

  • GPU instancing, which isn’t supported by WebGL v1.0, but now unity uses v2.0+, so should be fine. Though not all browsers supports v2.0 WebGL.
  • URP package provide support for WebGL without further details
  • Input System package supports WebGL with some not related for this project details
  • DOTS (entities) supports WebGL with many issues I’ve seen on this forum. For example people find incompatibility with using Hybrid Renderer (not used in this project of course). So from this point it requires testing

So theoretically it can be built as is for WebGL