#Handling hundreds of thousands of entities?

1 messages · Page 1 of 1 (latest)

wary drift
#

Hello, I'm in the process of optimising and my game can only handle 10k entities (just a simple moving cube) at 30fps. I'm cpu bottlenecked, and the bottleneck is evidently the entitles graphics system, but there are also my custom system as well (though much less of a bottleneck). I've looked into common tips and best practices for ecs, are there any less well-known performance tips I should follow?

How do I go about entity graphics? Do I make my own instanced graphics system, or is there something I'm missing with entity graphcis? If there is another performant way to do graphics, what is it and how do I implement it?

blazing fable
#

maybe showing a profile would be good to start with

#

are these all dynamic entities?

#

i.e. are any static?

wary drift
#

I did, the biggest things ruining performance are entity graphics, and camera frustum culling (will switching to burst culling fix everything or is it just occlusion culling)

wary drift
blazing fable
#

that's a lot of dynamics to deal with every frame

#

that said i've got plenty of samples with 250k dynamic spheres

#

(and yes at that point rendering is definitely the problem)

wary drift
#

lemme do some mroe tests

blazing fable
#

do they all need to be dynamic?

wary drift
#

moving enemies

blazing fable
wary drift
#

wth

#

something very wrong is going on with minme

wary drift
#

are u using hdrp?

blazing fable
#

yes

wary drift
#

hmm

blazing fable
#

by far the slowest thing in that demo is my path finding update ticks

#

about 4-5ms/frame

#

because i'm doing on the fly optimization/adjustments

wary drift
#

I spawned in 100k enemies (3-5fps), here are the biggest time eaters: Render shadow maps, 100ms (I set max shadows to like, 30, so I dont know why this is); Entity graphics, 90ms;

#

And whatever this is

blazing fable
#

dont look at this view it's useless

#

look at timeline

#

but it looks like you have a nasty hiearchy?

wary drift
#

wtf

#

its just CULLING

blazing fable
#

yeah that isn't even entities

#

wait hmm it seems to be wiating for a job

#

can you show the job threads

#

oh wait its the culling job

wary drift
#

ye

blazing fable
#

what my render part looks like

#

and entities graphics itself is pretty tiny

#

wait hang on

#

do you have your subscene open?

wary drift
#

thats what my other games looks like as well, I have no idea why this project specifically is doing this..

wary drift
blazing fable
#

yeah that's probably not helping

wary drift
#

whaa

blazing fable
#

close your subscene and test it

wary drift
#

so first I turned off the sun to prevent making shadows, that brought me up to 7 fps with 100k

#

closing the scene does nothing

#

do I fully unload it?

#

hmm this might mean something...

#

closing the subscene made that show up on timeline

blazing fable
#

yeah that seem sto be your job

#

it also doesn't look like it's burst compiled

wary drift
#

shit i forgor to enable burst

blazing fable
#

-_-

wary drift
#

whoops

#

now I have an increadible 15 fps

blazing fable
#

what's your profiler showing

#

(just show the whole thing)

#

(jobs included)

wary drift
#

wait why is it only using one thread even if Im using ScheduleParallel

blazing fable
#

it's still not burst compiled

wary drift
#

how do I force a burst compile?

blazing fable
#

post the job

wary drift
#
[BurstCompile] public partial struct EnemyMoveJob : IJobEntity
{
    //COMPILE U FUCKING DIMWIT
    public float DeltaTime;
    public BlobAssetReference<EnemyTargetsBlob> Targets;
    public float2 Offset;

    [BurstCompile] private readonly void Execute(EnemyAspect enemy)
    {        
        enemy.MoveTowardsNextTarget(DeltaTime, Targets, Offset);       
    }
}
blazing fable
#

never seen anyone put their attributes like that ^_^'

#

but you shouldn't have burstcompile on execute

wary drift
#

o

blazing fable
#

(i dont think it will change anything in this case, just pointing out something)

#

are you sure burst has finished compiling?

wary drift
#

ik

blazing fable
#

usually takes a few min after having it off

wary drift
#

normally it says on bottom right if it is compiling

#

but it aint there so it must be done

#

pretty sure it compiled, it might be bad code;

Here is the method being called:

public void MoveTowardsNextTarget(float deltaTime, BlobAssetReference<EnemyTargetsBlob> Targets, float2 RandomFloat2)
    {
        if (TargetOffset.Equals(float3.zero)) _enemy.ValueRW.TargetOffset = new float3(RandomFloat2.x, 0, RandomFloat2.y);

        if (Order >= Targets.Value.Targets.Length) return;
        if (math.distance(Targets.Value.Targets[Order].Location + TargetOffset, _transform.ValueRO.Position) < Speed * deltaTime * 2) 
                _enemy.ValueRW.Order++;

        if (Order >= Targets.Value.Targets.Length) return;

        float3 direction = Targets.Value.Targets[Order].Location + TargetOffset - _transform.ValueRO.Position;

        if (deltaTime > 0.04) _transform.ValueRW.Rotation = quaternion.LookRotation(direction, _transform.ValueRO.Up());
        else _transform.ValueRW.Rotation = 
              math.slerp(_transform.ValueRW.Rotation, quaternion.LookRotation(direction, _transform.ValueRO.Up()), Speed * deltaTime * 2);

        _transform.ValueRW.Position += deltaTime * Speed * _transform.ValueRO.Forward();
    }

And here is the method calling the Job:

[BurstCompile] public void OnUpdate(ref SystemState state)
    {
        Entity gameEntity = SystemAPI.GetSingletonEntity<GameProperties>();
        GameAspect game = SystemAPI.GetAspect<GameAspect>(gameEntity);

        int entityCount = new EntityQueryBuilder(Allocator.Temp).Build(state.EntityManager).CalculateEntityCountWithoutFiltering();
        int recommendedCores = math.clamp((int)math.floor(math.log10(entityCount) - 6), 1, JobsUtility.JobWorkerMaximumCount);
        if (JobsUtility.JobWorkerCount != recommendedCores) JobsUtility.JobWorkerCount = recommendedCores;

        new EnemyMoveJob 
        { 
            DeltaTime = SystemAPI.Time.DeltaTime, 
            Targets = game.EnemyTargets, 
            Offset = game.RandomFloat2(1f) 
         }.ScheduleParallel();
    } 
blazing fable
#

if (JobsUtility.JobWorkerCount != recommendedCores) JobsUtility.JobWorkerCount = recommendedCores;
i suspect this is becoming 1 or 0 or something

wary drift
#

me too, Ill go check it out, but for now i have a burst error

blazing fable
#

also this is very weird to do btw

wary drift
#

no wonder it aint compiling

#

Boxing a valuetype EnemyType to a managed object is not supported

#

shit

#

lemme fix that

wary drift
#

its a temporary thing until I can find a good balance

#

how would others handle it?

#

would they just put an arbituary number that should get most cases?

blazing fable
#

the cost of calculating this is going to be more than the cost of scheduling on all threads

#

also doesn't this just break every system that runs after it?

#

the normal way to handle this is to not doing anything

#

entity jobs are already split per chunk across threads

#

not per entity

wary drift
#

I don't want to have too many handled near the beggining of the game for lower end devices as I think 4 threads is still overkill for 2 enemies, alas Ill just leave it for now

#

update on burst: 30 fps

#

its absolutely beuriifful

blazing fable
#

it will be 1 thread

wary drift
#

does it choose itself automagically?

blazing fable
#

jobs just create work that the threads can steal

#

when you create a parallel ijobentity it creates work per chunk

#

each chunk has up to 128 entities

#

if you have 30 enttities in 1 chunk, thats' 1 piece of work

#

so it's not going to run on more than 1 thread

wary drift
#

Im so used to manally multithreading

#

jobs is so kewl

#

now I'm finally gpu limmited

#

now would be the time to look for graphics solutions right?

#

some form of gpu instancing perhaps?

#

what would you suggset

#

The game can comfortably run 10 million moving entites (without meshes, just transforms), I need to figure out a way to display them performantly

blazing fable
#

if you want 10mill dynamics you're probably going to need a very custom solution

wary drift
#

probs not that

#

like 100k - 1m

#

realistically its never gonna get to 10k, but Im future proofing, + if I can get 1mil at 60fps

#

then 5k will run way better as wekk

#

well*

wary drift
blazing fable
#

you probably don't need a grpahics engine

#

it's all about how you pass your data to the engine

#

i can easily throw 1 mill particles onto the gpu and it'll be fine

wary drift
#

what, like manually telling gpu to read an array of stucts (structs containing position of all triangles and verticies) and draw something based on that? I imagine that would still run better than normal because it doesn't contain unnessasary data. I think something easier would be to implement very aggressive culling; my ideas are, of course trying out the burst occlusion culling, and also my own custom stuff, like perhaps culling of individual faces, and if there is a group of many entities inside eachother, only render a few of them. I could try out LODs but that'd be tough to get right, as cubes are already very simple (maybe go from cube, to tetrahedron, to a plane).

blazing fable
#

i mean like, directly calling Graphics.DrawMeshInstanced

#

and organizing your meshes to optimize this

#

entities.graphics is general purpose to handle all use cases

#

you can always write a data setup that is more optimal to your sepcific requirements

#

i would definitely not start with a custom solution though

wary drift
#

I'll look into short term optimisations, like I said this is completely overkill, where im at now

#

if I really require more graphical power, Ill look into instancing

#

Thanks for answering my many ecs posts the past few days; im only recently going into data oriented design

#

and im really loving it so far

#

it forces me to make optimised code

#

and the design is so much easier to read and it is so much easier to refactor with its modular design

blazing fable
wary drift
#

ah