I’m at a crossroads optimizing performance on mobile VR, specifically draw calls. The choices I see as viable are
ECS
DrawMeshInstanced
Dynamic batching
I don’t want to ECS the whole game though, since I haven’t done it before and know from experience that the first implementation is pretty much always subpar. How usable would this approach be? Is it possible to do transformation and rendering with ECS, but somehow tie the entities to managed classes to produce game logic with them?
Upgrading to Entities 1.0 might also push me away from going this route, no idea yet if there are huge breaking changes coming.
Option 2 would “require” a system to automate generating the draw calls, sounds like a big undertaking. Can skip using MonoBehaviours though.
Option 3 is easiest on the code side obviously since it’s automatic already, but requires the usage of MonoBehaviours which seem to be performance heavy.
You need to check if Hybrid Renderer works for your project, last I checked it was really broken (issue related to SRP Batcher), doesn’t work in some Unity versions, doesn’t work in Mobile.
DrawMeshInstanced is really fast, a lot faster than gameobjects if you’ve got lots of the same model, but you need to do batching and culling by yourself (collecting matrices of visible objects, sorting by renderer, slicing by 1023, copying to temporary buffer -as Unity still doesn’t have Span, NativeSlice or Pointer overload for it in 2022-, I wrote a custom renderer (that uses DrawMeshInstanced) for our games needs and it’s fast.
If you plan to use GameObjects make sure to tick instancing on materials, static on gameObjects as required, but it gets slow on mobile with a lot of objects
This has less to do with ECS (it is plenty easy enough to work with for your use case) and more to do with whether your target hardware supports the specialized rendering technique used by the BatchRendererGroup and the Hybrid Renderer. But it also partly has to do with your project requirements.
If all of these are true, go ECS. Otherwise probably go a different route for now.
Your target is Quest 2 with Vulkan
You are using URP
Your instances only need a single directional light or are unlit
Hybrid renderer seems to work alright on the Quest, so that’s not a blocker.
DrawMeshInstanced is very nice, setting the system up would just be a lot more complicated than letting Unity handle it.
So ECS itself will be usable in a hybrid approach, no technical blockers? It’s possible to get data from entities without jobs and systems? I’d like to architecture most of the game logic outside of ECS which is hard if the entities live in some other dimension.
I guess I’ll try to make a small prototype first to see how it functions, and not start from refactoring the main project
I personally wouldn’t consider anything a “blocker”, but I am also fairly experienced at this point.
World.DefaultGameObjectInjectionWorld.EntityManager gets you full access to ECS state. Be careful though, because driving thousands of entities from a MonoBehaviour can still be slow. You will likely want to generate the minimum amount of unmanaged data required, assign that to an entity or a system, and then let systems update all the entities.
for me, ECS, DrawMeshInstancedIndirect and ComputeShaders are the best choice for my mobile game.
I created my own custom hybrid render by pushing all rendered entity data (matrix…) to the GPU using ECS and Jobs.
I’m using ComputeShader to calculate frustum culling directly on the GPU, this way I don’t have to send data between CPU-GPU every frame except for camera data, which gives me a lot of performance about 3 times faster than the official hybrid renderer.
even better, my custom package supports Vulkan and GLES 3.1+
I hope this isn’t required Initial tests look promising with the official in hybrid renderer, but the scene is still relatively simple.
Anything is a strong word
A system which handles data transfer between the managed and ecs side seems to work nicely! Most things seem fairly easy to build in the data oriented style, so the intermediary system won’t be needed for anything huge. Maybe this is doable.
Sorry. Wasn’t trying to make a blanket statement here. Moreso that the pitfalls with finding references to Entities from GameObjects and other ECS-isms that most people find frustrating and give up on are things I feel comfortable enough to work with or around.
Did you test this? Because if so, and that was your conclusion, then it sounds like you are definitely on the right track.
Yes, but not with my actual systems yet, just a proof of concept. I’m not going to do anything huge though, just use it to do small infrequent events/triggers from the managed side, and sync a little data for the managed side to act on. Maybe I’ll figure out how to do everything in a data driven manner, but things like quests, dialogue, cutscenes, managers and the like seem easier to design in the managed side for now since that’s familiar to me. Might not be that way forever, but it’s good to know it should function this way as well.