I’m making a 3D sandbox game with an unusual modelling and creation system. Things were going great until someone decided to make beautiful maps using the game editor and now I’m out of ideas for how can I optimize draw calls on complex scenes.
Let me give some context behind how the system works:
There are Models, which contains N chunks, with 16^3 Blocks. The Blocks are made of a shape and a type.
The mesher create a new Mesh Instance for each chunk, and assigns a new surface for each unique Block type.
The textures are dynamic, 512x512, made by users. There is no viable way of making an Atlas for UV tricks, but I’m looking for generating multiple Atlases and try to use that.
In this scene, there is a lot of models.
Everything is procedurally generated, no occlusion culling for you!
tl;dr it is a voxel system with custom shapes on voxels, and you can create models that can be transformed and are not stuck in the main/terrain voxel grid.
Now, I need help and wisdom from the optimization wizards of Godot to solve the optimization flaws of the system.
“Optimize” in this context could mean any of a variety of things. What behavior is the game exhibiting that you want to improve? Whatever you do is likely to be a tradeoff, so you need to understand what you want to improve and what you’re willing to sacrifice for it.
For example, you might (perhaps, depending on what you already have…) be able to make this run at a higher frame rate by baking meshes and textures, but then you potentially have to deal with a request to edit baked things, not to mention questions of when and how things get baked. And whether you unbake them or whether you keep the raw data around for editing as well.
I sympathize with your position, but your question is open-ended and high-level enough that I think people will struggle to give useful suggestions. We’re probably going to need details on what you’re currently doing and how that’s not meeting your needs.
Right, I forgot to specify the intention. The objective is to reduce draw calls in this scene and improve FPS in complex scenes without having to rely on baking entire scenes or regions. Right now, the game performs poorly when there is a lot of objects with multiple materials on screen.
Since everything is dynamic, and players can edit any model, baking would make editing less smooth overall. So, I’m looking for anything that can make rendering faster in this case. Reducing draw calls is the most obvious thing I can think of, but I’m not sure if this would improve FPS in this case.
Do you care if the behavior is different in the editor?
You could potentially do things like make “edit” vs. “view” mode, and dial the draw distance way back on edit mode so all the distant geometry is culled.
You could make that slightly less jarring by baking low level of detail grouped placeholders. Maybe cut the world up in a grid, and only draw full detail for the grid cell you’re in and maybe adjacent cells, depending on grid size. You could bake a low poly placeholder for each grid.
You could potentially see if doing LOD with materials helps; that is, if something is far enough away, use a single (hopefully simple) material.
Ultimately, if you have an arbitrary amount of complex geometry and you want to display it without simplifying it, there’s going to be a base time/compute cost you can’t eliminate. There may be some tweaks you can do for your mesh representation (though Godot is probably already doing what it can there), but I wouldn’t bet on there being a cost-free “go faster” button that gets you where you want to be. This is the kind of problem LOD was made to address.
What you’re doing looks like it’s specialized enough that you might want to consider whether you should be building your own engine.
you can enable frustum culling. you need to set it up, but this will hide the nodes that are not visible on the screen.
512x512 is too much. by the quality displayed here, 64x64 or smaller would work.
you mean meshinstance3D.
you mean meshinstance3D?
do not use more nodes than you need to. if you dragged these from a file there’s going to be a Node3D root and that does nothing other than apply scale and rotation, something that should’ve been done in blender.
it’s an option in project settings.
it’s disabled by default because it can hinder performance if there aren’t enough things on screen, it also needs certain situations, it works better for interiors or if there’s a mountain on your side.
for this it could work maybe, but this is a hack for voxel and it would be better to create a mesh using godot’s mesh tools, but it’s more advanced.
In this specific case, everything is clumped together in a small region. LOD isn’t going to improve the performance for the cathedral, but it will in larger, open scenes.
You are right, there isn’t so much we can do without simplification of the mesh and the entire way of plotting things on the scene. It is indeed very specialized.
I think of building an custom engine at some point but, right now, I have to use the existing tools due to lack of financial resources and time, and I was really hoping for Godot to have a “go faster” button lol, or at least something that could make complex and heavy scenes faster with specific drawbacks, but if this button exists it would be probably enabled by default.
As far as I am aware, Occlusion Culling needs baking and this can’t be done in realtime. It could be an option for read-only scenes, that is the “Play Mode” on Blokoto after publishing the map.
Well, remember you have source to Godot; you don’t have to rebuild everything, but you might find that diving into Godot’s guts and adding direct support for your style of geometry at a lower level unlocks some options.
you problem is you are clampping too many features into it.
I was going to recommend that if you need voxels, to use the voxel version of godot:
but it takes an atlas, which you don’t want to use. I don’t know of any voxel game that uses individual materials for each mesh.
most everything in the godot editor can be done in real time, like navmesh baking. and baking tends to be pretty fast, but you would have to test it.
in a game like this there could be dozens of players placing blocks constantly.
That is an option too, but sadly I’m not a C++ programmer yet. GDExtension could probably improve some aspects of it and I’m looking forward to recreate some hot parts of the codebase in it
There is one relatively simple thing you could try; use LOD with the meshes. When editing a mesh, you could also edit a low-detail version of that mesh and include it via Godot’s standard LOD system. The low-detail mesh could have a simplified material, maybe even just flat shaded and untextured.
You might need to configure the LOD system; I haven’t used it, so I’m not sure how it chooses the range at which to swap detail levels.
Adding low detail models ought to be relatively quick, and even if it looks a bit crunchy it will at least tell you whether there are performance gains to be had there.
well, for better performance you need to combine all the blocks and pass the entire map as a single (or a bunch of) mesh, which would require using the mesh tools:
your game is never going to perform well as a billion blocks with different materials. in game dev you have to make sacrifices, you can’t have the cake and eat it too. and you are starting to see with this project where these limitations are.
of course combining everything could bring it’s own set of limitations. if you use an actual Voxel (a 3D dimensional array of int), it would be possible to add and remove blocks and then rebuild the mesh, all with one click.
but this takes some work.
I think greedy meshing (or a better meshing algorithm overall) will already have a better impact similar to how LODs work. As far as I am aware, Godot LOD have to be baked too, when importing models.
Yeah we are probably hitting the ceiling on optimization tricks that does not affect the simple nature of the game. What I can do is making the Atlas trick to reduce draw calls on the GPU. Every other optimization trick is probably going to require some form of batching with MultiMesh or baking meshes together
There used to be an LOD node, but I think that went away in 4.x. I’d suspect there’s still a way to manually make LOD meshes, but it might be more of a research subject than I though.
Occlusion culling doesn’t require baking; the baking process is for generating the occluder mesh. However, you can manually create the occluder mesh using a convex shape. When you create the model, implement a function to generate the occluder mesh using a convex mesh. I did this for my procedural terrain generator. My terrain, which consists of 2 million polygons across 100 chunks, is rendered with only 12 chunks at most due to occlusion culling and distance fading—averaging 30,000 polygons rendered.
Additionally, you can obtain the ArrayMesh of the models and combine them into a larger model. This can be done before the ‘play mode,’ similar to a baking process. All games that include level editing typically feature an edit mode, a play mode, and a baking process. However, if you want players to edit the level while playing (without a ‘play’ button), there’s not much you can do to optimize the level because a baking process is always necessary.