Instantiating thousands of blocks gives big performance drop

Godot Version

4.1.3

Question

I’m pretty new at Godot and game development in general. I made a for loop that instances thousands of scenes of a cube mesh, creating a sort of 3d floating island.

Takes about 30 seconds to generate, and drops the fps tremendously when it loads. So I’m sure I am going about this the wrong way. What’s the best approach for generating lots of objects?

My goal is to make a pseudo-Minecraft type of game that uses beveled blocks instead of cubes, so it’s important that players be able to remove these blocks. Is there anything I should look into to better inform myself?

my thought would be, because it’s instantiated and added child, it’s always rendered per draw call, so anything inside that not much important and cant be seen could just be set to visible=false

Even setting the visibility to false on all instanced blocks isn’t improving performance by much. Getting the same low fps. Thanks for the suggestion though. Really curious why it’s still so laggy…

i read about using MultiMeshInstance3d able to generate lots of stuff without fps drop, then i found this Visibility ranges (HLOD) — Godot Engine (stable) documentation in English

and this

I wish there was more information on this. Really clueless as to where to begin.

Have you read the official docs about 3D optimization? I think that’s a good place to start.
If you want to make a Minecraft-style game, you probably have to approach it in a Minecraft-style manner. Minecraft support worlds of unlimited sizes. That doesn’t mean that Minecraft create unlimited amounts of blocks at the same time. You have to “fake” the user experience. Create as much as the user sees, and skip the blocks that are affected by culling. And if you want a beveled look, those kind of blocks only are necessary to render close to the player. And perhaps a shader could create the beveled look, rather than using extra meshes to each cube?

Cheesy as it may, but watch some “I recreated Minecraft in X!” videos. They tend to explain the basics.

Basically what they, and Minecraft do is they split the world into chunks like 8x8x8 blocks and generate one mesh for each chunk, with faces that are never visible removed. And then display chunks only in a fixed range around the player. Should work with beveled edges too

Note: Minecraft uses infinitely tall chunks, which is a weird choice imo, but can make sense

Still confused about the performance drop. I did the math, and I have about 100k blocks instantiated. So the mesh should be 6 total sides, so 12 total triangles per cube. Is this an unreasonable amount of polygons?

Technically, yes. The game is still taking into account the polygons that are not visible (eg behind other blocks). Like stated above, the way to optimize this would be to use one mesh that only displays the blocks that the player can see.

So I watched this video of someone building Minecraft in godot from scratch:

It was very helpful. In this tutorial, he essentially creates a multi-mesh for all the visible surfaces in a chunk. However, I’m realizing the way it handles block placement and removal with the mesh it essentially needs to redraw the entire chunk. This isn’t a big deal if the chunk only has a few faces exposed, but I’m starting to question if this is how Minecraft actually handles this. Am I to believe that if an entire chunk is exposed, it would have to redraw the entire mesh from top to bottom if I update one block?

What about situations with complex cave systems? I can see a scenario where a chunk has a lot of exposed surfaces, and therefore a larger mesh surface area where re-creating the entire chunk would be cumbersome.

I already created something similar, and am experiencing stuttering every time I need to place or remove a block. Am I doing something wrong maybe?

This is how voxels are usually rendered in games (when they aren’t raytraced). :smile:
No matter what, everything you see on screen has to redrawn every frame anyway. If you were to create a node, or even just a mesh for each individual voxel, the rendering pipeline will be sending each one (that isn’t determined by a culling mechanism that it doesn’t need to be rendered to the screen this frame) over to the gpu as a separate draw call. Draw calls have a cost to them, so being able to have fewer unique meshes that need their own draw call saves you processing time every frame, and allow you to draw far more voxels on screen at once.

The tradeoff for this is exactly as you’ve noticed, now whenever one block inside a chunk is modified, the mesh for the entire chunk needs to be recalculated. This would be a really good time to start learning about how to use Godot’s profiler, so you can see where exactly the majority of your cpu time is being spent. When dealing with issues of performance always measure. You may be very surprised by what exactly is eating all your cpu time. Once you’ve measured, you can consider what strategies you might take to deal with your problem. Maybe something about your surface extraction algorithm is much slower than it should be. Maybe your chunk size is too large and you are doing too much work in a single frame for your target hardware. A game like minecraft is going to offload most of the work it does on chunks onto other threads, the player won’t notice if it took 3 frames for the chunk to be remeshed so long as the rendering and character controller stay smooth.