Improve chunk mesh generation time

Hey, I'm writing a minecraft-like game with OpenGL.
As most of you will know, minecraft is split into chunks which consist of blocks. Because rendering every block itself in every chunk would melt the CPU, I batch all blocks of a chunk into a single mesh (a chunkmesh).

I got a very simple algorythm to calculate the chunkmesh.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
void BlockMesh::regenerate(AABB aabb, std::vector<int> yCoords) {
    if(m_vertices.vboExists()) m_vertices.deleteVBO();
    if(m_normals.vboExists()) m_normals.deleteVBO();
    if(m_colors.vboExists()) m_colors.deleteVBO();

    AM::Mesh<glm::vec3> f_vertices;
    AM::Mesh<glm::vec3> f_normals;
    AM::Mesh<glm::vec4> f_color;

    for(int yi = 0; yi < yCoords.size(); yi++) {
        int y = yCoords.at(yi);
        for(int x = aabb.getFirst().x; x < aabb.getSecond().x; x++){
            for (int z = aabb.getFirst().z; z < aabb.getSecond().z; z++) {
                glm::vec3 currentPosition(x, y, z);
                if(!m_blockSource.blockExists(currentPosition)){
                    continue;
                }
                Block currentBlock = m_blockSource.getBlock(currentPosition);
                if(!currentBlock.exists()){
                    continue;
                }

                //Is true of specified side needs a face
                bool front = true, right = true, back = true, left = true, top = true, bottom = true;

                front = !m_blockSource.blockExists(currentPosition + glm::vec3(0, 0, -1)) || !m_blockSource.getBlock(currentPosition + glm::vec3(0, 0, -1)).isSolid();
                right = !m_blockSource.blockExists(currentPosition + glm::vec3(1, 0, 0)) || !m_blockSource.getBlock(currentPosition + glm::vec3(1, 0, 0)).isSolid();
                back = !m_blockSource.blockExists(currentPosition + glm::vec3(0, 0, 1)) || !m_blockSource.getBlock(currentPosition + glm::vec3(0, 0, 1)).isSolid();
                left = !m_blockSource.blockExists(currentPosition + glm::vec3(-1, 0, 0)) || !m_blockSource.getBlock(currentPosition + glm::vec3(-1, 0, 0)).isSolid();
                top = !m_blockSource.blockExists(currentPosition + glm::vec3(0, 1, 0)) || !m_blockSource.getBlock(currentPosition + glm::vec3(0, 1, 0)).isSolid();
                bottom = !m_blockSource.blockExists(currentPosition + glm::vec3(0, -1, 0)) || !m_blockSource.getBlock(currentPosition + glm::vec3(0, -1, 0)).isSolid();
                
                
                if(front){
                    std::vector<glm::vec3> vertices = translateVertices(AM::standardmodels::model_cube_front, glm::vec3(x, y, z));
                    f_vertices.add(vertices);
                    f_normals.add(AM::standardmodels::model_cube_front_normal);
                    for(int i = 0; i < 6; i++){
                        f_color.add(currentBlock.getVoxel().getColor());
                    }
                }

                if(right){
                    std::vector<glm::vec3> vertices = translateVertices(AM::standardmodels::model_cube_right, glm::vec3(x, y, z));
                    f_vertices.add(vertices);
                    f_normals.add(AM::standardmodels::model_cube_right_normal);
                    for(int i = 0; i < 6; i++){
                        f_color.add(currentBlock.getVoxel().getColor());
                    }
                }

                if(back){
                    std::vector<glm::vec3> vertices = translateVertices(AM::standardmodels::model_cube_back, glm::vec3(x, y, z));
                    f_vertices.add(vertices);
                    f_normals.add(AM::standardmodels::model_cube_back_normal);
                    for(int i = 0; i < 6; i++){
                        f_color.add(currentBlock.getVoxel().getColor());
                    }
                }

                if(left){
                    std::vector<glm::vec3> vertices = translateVertices(AM::standardmodels::model_cube_left, glm::vec3(x, y, z));
                    f_vertices.add(vertices);
                    f_normals.add(AM::standardmodels::model_cube_left_normal);
                    for(int i = 0; i < 6; i++){
                        f_color.add(currentBlock.getVoxel().getColor());
                    }
                }

                if(top){
                    std::vector<glm::vec3> vertices = translateVertices(AM::standardmodels::model_cube_top, glm::vec3(x, y, z));
                    f_vertices.add(vertices);
                    f_normals.add(AM::standardmodels::model_cube_top_normal);
                    for(int i = 0; i < 6; i++){
                        f_color.add(currentBlock.getVoxel().getColor());
                    }
                }

                if(bottom) {
                    std::vector<glm::vec3> vertices = translateVertices(AM::standardmodels::model_cube_bottom, glm::vec3(x, y, z));
                    f_vertices.add(vertices);
                    f_normals.add(AM::standardmodels::model_cube_bottom_normal);
                    for (int i = 0; i < 6; i++) {
                        f_color.add(currentBlock.getVoxel().getColor());
                    }
                }
            }
        }
    }

    m_vertices.upload(f_vertices.get());
    m_normals.upload(f_normals.get());
    m_colors.upload(f_color.get());

    m_verticeAmount = f_vertices.get().size();
}


The stuff at the beginning and the end don't matter that much. The thing that actually matters is the inside of the for-loops!
The algorythm works like that, that every block is checked for its neighbors, and if it has none, a face will be added to the mesh. I think its pretty self explanatory!

With my CPU (AMD FX6300) it takes about 0.51 seconds to generate one mesh consisting of all 16x16x256 blocks.

Is there any room for improvements?

~David
Last edited on
Topic archived. No new replies allowed.