Thrive icon indicating copy to clipboard operation
Thrive copied to clipboard

Improve game performance with a lot of entities

Open hhyyrylainen opened this issue 3 years ago • 16 comments

The game performance suffers after playing for roughly an hour (or making a good cell and spamming the editor in freebuild). As a workaround I've reduced and reduced again the total entity cap in the game all the way down to 90. According to Godot engine benchmarks you should be able to have hundreds of physics entities at once, so I'm not sure what's up.

I've done profiling: https://forum.revolutionarygamesstudio.com/t/increasing-game-performance/841

and tried various things including detaching organelles from the scene tree, removing / combining the organelle physics to a single shape group. But nothing seems to give more than 5-10 FPS (when at sub 20 FPS), completely removing the visuals and collisions would technically make the game playable but I think we need to either keep the entity cap low or resolve the performance bottleneck rather than ruin the game visuals for not much gain.

Related issues:

  • https://github.com/Revolutionary-Games/Thrive/issues/2910
  • https://github.com/Revolutionary-Games/Thrive/issues/2909
  • https://github.com/Revolutionary-Games/Thrive/issues/2587 (might need to adjust floating chunks that were spawned from cells dying to also despawn)
  • https://github.com/Revolutionary-Games/Thrive/issues/1551

Here's the PR where I lowered the entity count: https://github.com/Revolutionary-Games/Thrive/pull/3017

hhyyrylainen avatar Jan 14 '22 09:01 hhyyrylainen

TO DO: the collision shapes of our organelles when they are floating chunks are hundreds of vertices, those might be actually what tank the physics system

they should all be basically converted to sphere or other basic shapes instead of being convex polygon shapes with hundreds of vertice A starting point would be to replace all the .shape files with just a radius of 1 spheres

Kemikal1 avatar Jan 14 '22 13:01 Kemikal1

That starting point actually reminds me, I think there's a place in the chunk spawning code or something that sets the shape. Actually looking at this I think I found that perhaps only the environmentally spawned chunks use the convex shapes, and not the microbes. Still that may be related to this if the shapes are used and I don't realize it. I'll open a separate issue about that: https://github.com/Revolutionary-Games/Thrive/issues/3022

hhyyrylainen avatar Jan 14 '22 13:01 hhyyrylainen

Simplifying the collision shapes where possible is the first step I'd make (I had an issue in my own project where an auto generated shape was THOUSANDS of vertices and Godot literally CRASHED if my car ran into that).

Zireael07 avatar Jan 14 '22 14:01 Zireael07

I've tested with one place where I think the convex collision shapes were loaded commented out. That did have some FPS impact (as much as some of the other things I've tried) but it didn't make a save with a huge amount of lag playable.

One more thing I found when looking into this was that currently the amount of cell chunks to spawn is HexCount / CORPSE_CHUNK_DIVISOR which means that larger cells have linearly scaling more corpse chunks spawned when they die. I think we could have a max cap of 10 there and a power formula for quickly diminishing how many chunks a larger cell drops when it dies. Also a global cap for the number of cell chunks might be good (and as I mentioned in the issue description it seems that the cell chunks are not despawned when you get far away from them, seems like they maybe aren't added to the spawned group).

hhyyrylainen avatar Jan 14 '22 14:01 hhyyrylainen

I can confirm that after a cell death the FPS drops by 5-6 with the appearance of the free floating organelles. Simplifying the collision shapes and reducing the overall number of spawned chunks seems like a good approach.

RacerBG avatar Jan 14 '22 20:01 RacerBG

I also noticed that every microbe has its own organelle models, maybe they can be replaced by an image and only spawned upon death.

Ghurir avatar Jun 14 '22 12:06 Ghurir

Despite what people think, the microbe stage is rendered in 3D, using bilboarding would be very obvious. Using something like Godot multimesh to reduce the required draw calls and number of Godot nodes to update might be doable, though that doesn't fully work as each multimesh can only have a single mesh type so we'd need one multimesh for each organelle type and render order (because the organelle models are all slightly transparent) would be difficult.

hhyyrylainen avatar Jun 14 '22 13:06 hhyyrylainen

because the organelle models are all slightly transparent

Do they really need that transparency? That's likely the root of the problems here, many models that are in the transparent pipeline... maybe they could just be opaque OR use a dithering shader trick (examples here and here

Zireael07 avatar Jun 14 '22 14:06 Zireael07

Many organelles have internal structure that would not be visible at all if the "shell" of the organelle was not transparent.

hhyyrylainen avatar Jun 14 '22 14:06 hhyyrylainen

Then I believe the fake transparency shader should help you achieve better performance. I've used a variation of said shader on my semi-transparent sci-fish road barriers and got a clear performance boost along with them showing up when doing screen texture grab. Godot 4.x will have some sort of alpha dither built-in, I believe, too

Zireael07 avatar Jun 14 '22 15:06 Zireael07

Using Godot's "Show collision shapes", one thing that strikes me as relevant is how many shapes there end up being way inside larger cells. Are they necessary (for digestion perhaps)? If not, couldn't we figure out a way to delete shapes that are blocked by the outermost ones? Even if they never collide with anything, the engine still has to check them for every physics tick.

image

Kiloku avatar Aug 04 '22 15:08 Kiloku

Each organelle has it's own shape it adds to the cell. My hope is that Godot is smart enough to have an overall AABB for the cell so that the collision shapes are not checked when unnecessary. If we made the cells hollow that would make it more likely that cells can get permanently stuck in each other. One other thing I've been considering is to just create a mesh collision shape for the cell.

Monitoring the physics processing time it doesn't actually seem like it goes up any significant amount even when the game is lagging.

hhyyrylainen avatar Aug 04 '22 15:08 hhyyrylainen

I'm not sure about this but it feels like entities are being rendered off-screen for whatever reason. It also seems like calculations are lowering performance. Total ATP seems to stutter and dip below maximum, while ATP production is net positive this only happens when entities get complex enough, so I figure this has to do with some inefficient math that's real-time being applied to every cell.

deadhitter1 avatar Aug 26 '22 11:08 deadhitter1

I'm not sure about this but it feels like entities are being rendered off-screen for whatever reason.

https://github.com/Revolutionary-Games/Thrive/issues/3646

Total ATP seems to stutter and dip below maximum, while ATP production is net positive

When the game lags with lag spikes, the game logic runs a bigger update. The ATP generation cannot generate more than what the storage can hold, but the ATP draining parts can scale infinitely high as the delta time goes up.

hhyyrylainen avatar Aug 26 '22 12:08 hhyyrylainen

A solution to the collision problem could be to write a custom type RigidBody2d that can move 3d objects. We would have to override all its functions to accept 3d parameters, so that rewriting al physics code isn't necessary.

I think that the upsides and downsides of this are obvious, +fps gain. +2d collision should be less laggy.

-not extendible to 3d physics -no rotation on 3d axis -could be hard to maintain -feasibility questionable

Ghurir avatar Sep 02 '22 10:09 Ghurir

That's a pretty interesting idea. I didn't really consider doing that mainly for two reasons: later stages will have to have 3D physics anyway so the solution would only work for microbe stage and on the small chance that at some point some 3D elements are added to the microbe stage that need 3D physics, it's not a really futureproof solution. Even now the chunks like iron etc. can rotate due to physics forces and I think that looks better / more realistic than if they only simulated 2D physics.

Overall I think while it would likely be quite a bit harder to write our own physics engine integration (to bypass Godot), I think that approach would be much more maintainable and give full control to us.

hhyyrylainen avatar Sep 02 '22 10:09 hhyyrylainen

I think that decreasing the distance of object rendering and spawning could also increase the preformance,

Gameboy555r avatar Feb 02 '23 16:02 Gameboy555r

Object rendering already works correctly, if you use the debug panel in the game (you can find the keybinding in the options menu) you can view how many draw calls the game does and compare that to the entity count. From that at least my conclusion is that frustrum culling is working correctly.

Entity limit is already in the options menu and I recommend (and everyone else should as well) that if someone has bad performance they set the entity limit to the smallest possible value.

hhyyrylainen avatar Feb 02 '23 18:02 hhyyrylainen