For a world like Minecraft where the large majority of cubes are static, in the few tests I’ve done, batched cubes will beat multimeshes… IF their hidden faces are culled, and even more if greedy meshing is applied to merge common faces.
Having many Multimeshes on screen will have trouble hiding occluded faces and cause overdraw. Vertex count will also be higher.
The advantage of Multimesh however, is being able to modify or move every cube much faster, because on the other hand, a batched mesh will need to be entirely rebuilt (at least in Godot). It’s also easier to modify with a script, while a batched mesh will require a fast language like C++ or a compute shader.
In both cases, it’s also a good idea to chunk the world at least by 32x32x32 to take advantage of frustum culling.
One thing I didnt try however: using multimesh, but exploiting the
Color component to store which side to occlude. Then in the vertex shader, discard vertices belonging to a side of the mesh. Sort of a hybrid approach. Random thought tho
How would you occlude a face of a Mesh that is a part of a MultiMesh? From what I know (and very little at that), a MultiMesh will only show one variant of a single Mesh in various positions depending on how you configure the MultiMesh. So if the Mesh being shown by the MultiMesh is a cube, it will render all six sides of the cube. Is there some way to change that, so only some cubes in the MultiMesh will have all six sides, while others have a different number of faces shown?
Bean_of_all_Beans | 2021-01-27 01:15
Honestly I have no idea if this is a good approach. But if you want to try that, read about shaders (here: Shaders — Godot Engine (stable) documentation in English, or here https://thebookofshaders.com/, or any good tutorial).
The way you can hide cube faces with a shader is by exploiting the fact each side of a cube uses independent vertices. They are not actually shared, because each face has different normals. So if all 4 vertices of a face are discarded, that specific face will disappear.
“Discarding” a vertex can be done by either giving it a NaN position (which is a hack). But it can also be done by forcing it to a position of zero, which will make all triangles of the face degenerate. Their edges will be all in one place, so they won’t produce any pixel to draw.
In multimeshes, each instance can have extra data, not just a transform. You can add custom data per instance, as a ““Color”” (MultiMesh — Godot Engine (stable) documentation in English). This custom data is of course not necessarily color. It can be exploited to hold the information about which sides should be discarded. So somehow, in the vertex shader, you can check
INSTANCE_CUSTOM, check the vertex normal, and do the discarding based on that (I dont have code for that cuz I’m litterally imagining the technique as I write, and it’s late xD).
Of course, the vertex shader cannot know by itself its neighbor cubes. So in this approach you still need to figure out on the CPU which sides of each cube should be occluded. The point is that instead of generating a mesh vertex by vertex using GDScript, you generate instances and simply tell them how they should look like.
It all depends on what you really want to do though. For minecraft terrain, batched greedy cubes would do the job really well.
Zylann | 2021-01-27 02:03