Fastest way to generate and render cubes

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Maksanty

Hi! I want to create terrain like in game Stonehearth (Link)

I figured out that the map size is 1280 x 1280 blocks (I don’t know what height is, but I guess that it is something about 128-160). This game has visible all of the blocks at once, there is no chunk loading/unloading.

I implemented Chunk System (each chunk 16x16x16 blocks). I was generating world 32x8x32 chunks (512 x 128 x 512 blocks). When I used nodes for it, the performance was terrible. So I switched to VisualServer. The performance increased significantly. So I tried to generate 64 x 8 x 64 world (1024 x 128 x 1024 blocks). And I dropped to ~30 FPS. Then I thought “I need to reduce triangles count”. So I found an algorithm to connect quads into one big quad. It was generating a lot longer, but the vertices count dropped from over 25 000 000 to 400 000. But FPS were still ~30 FPS. When I increased Chunk’s size to 32 x 32 x 32 (and generated 32 x 4 x 32 World, so block’s count was the same), the FPS went to 90 FPS.

Want do I want?
How can I increase render performance? I know, that this is possible (Stoneheart made it).

(Sorry for my english)

:bust_in_silhouette: Reply From: Zylann

Godot 3.1 frustrum culling isn’t the best around, you will easily have a CPU bottleneck if you want to draw a lot of mesh instances. That’s why reducing their amount (by increasing chunk size) improved performance.

I assume the code you used to connect quads also discards quads that are not visible?

You should make sure you are not generating mesh instances for chunks that don’t actually have any quad visible. This will help reducing the amount to cull.
Also, don’t rely in making a mesh instance visible=false because that doesn’t remove it from the culling data structure (octree).

I faced the same issues when making my voxel module and now I think I can render such area at decent performance (without even connecting quads).

I figured out that the map size is 1280 x 1280 blocks (I don’t know what height is, but I guess that it is something about 128-160). This game has visible all of the blocks at once, there is no chunk loading/unloading.

That sounds absurdly large to view all at once if there is no LOD involved. Are you sure? From the screenshots I see on the website, it actually looks like they do stream the map, view distance isn’t that far.

I assume the code you used to connect quads also discards quads that are not visible?

Yes, it is

You should make sure you are not generating mesh instances for chunks that don’t actually have any quad visible

I don’t have any MeshInstances in the scene. I’m generating and drawing meshes like this:

Godot.Collections.Array renderArrays = new Godot.Collections.Array();
    renderArrays.Resize((int)Mesh.ArrayType.Max);

    renderArrays[(int)Mesh.ArrayType.Vertex] = _renderVertices.ToArray();
    renderArrays[(int)Mesh.ArrayType.Normal] = _renderNormals.ToArray();
    renderArrays[(int)Mesh.ArrayType.Color] = _renderColors.ToArray();
    renderArrays[(int)Mesh.ArrayType.Index] = _renderIndicies.ToArray();

    _renderMeshRid = VisualServer.MeshCreate();
    VisualServer.MeshAddSurfaceFromArrays(_renderMeshRid, VisualServer.PrimitiveType.Triangles, renderArrays);

    VisualServer.MeshSurfaceSetMaterial(_renderMeshRid, 0, material.GetRid());

    _instanceRid = VisualServer.InstanceCreate2(_renderMeshRid, Scenario);
    Transform glt = Transform.Identity;
    glt.origin = position;
    VisualServer.InstanceSetTransform(_instanceRid, glt);

Maksanty | 2019-10-02 12:45

I know you are using VisualServer, what I said still stands. That’s how they are called in the renderer as well.
I suppose you also don’t do this every frame?

Zylann | 2019-10-02 17:38

No, I’m not. I only doing it on scene load

Maksanty | 2019-10-02 17:40