Question

I'm working on a Voxel Engine and I'm using VBO. My problem is that I don't know how to generate Vertices.

I need to generate vertices for a chunk, So create a Chunk of cubes (With one VBO) from X,Y,Z coords.

How Can I do this?

Was it helpful?

Solution

First you will need to create/load the data for the voxels. Something like the following could be used to generate a 10x10x10 field of binary voxels:

Note: All code is untested and probably not optimal.

class Field {
    bool data[10*10*10];
public:
    bool& at(int i, int j, int k) { return data[i*10*10 + j*10 + k]; }
};


Field aField;
for (int i = 0; i < 10; ++i) {
    for (int j = 0; j < 10; ++j) {
        for (int k = 0; k < 10; ++k) {
            aField.at(i, j, k) = !(rand() % 2);
        }
    }
}

I'm assuming you are after Minecraft style voxels, otherwise you probably want to use something like Marching Cubes to process the binary voxel field and pass the result to the vertex buffer code.

The next step is for each occupied voxel in the field, draw the faces associated with the cube. For this we need to create a list of all vertices and (in this case) triangle indices.

std::vector< std::array<GLfloat, 3> > vecVerts;
std::vector< std::array<GLuint, 3> > vecTris;
for (int i,j,k from 0 to 10) {
    if (aField.at(i,j,k)) {
        // Add vertices for eight corners of cube
        vecVerts.emplace_back(dWidth*(i  ), dWidth*(j  ), dWidth*(k  ));
        vecVerts.emplace_back(dWidth*(i+1), dWidth*(j  ), dWidth*(k  ));
        vecVerts.emplace_back(dWidth*(i  ), dWidth*(j+1), dWidth*(k  ));
        vecVerts.emplace_back(dWidth*(i+1), dWidth*(j+1), dWidth*(k  ));
        vecVerts.emplace_back(dWidth*(i  ), dWidth*(j  ), dWidth*(k+1));
        vecVerts.emplace_back(dWidth*(i+1), dWidth*(j  ), dWidth*(k+1));
        vecVerts.emplace_back(dWidth*(i  ), dWidth*(j+1), dWidth*(k+1));
        vecVerts.emplace_back(dWidth*(i+1), dWidth*(j+1), dWidth*(k+1));

        // Add triangle coordinates for each triangle
        vecTris.emplace_back(0, 1, 3); vecTris.emplace_back(0, 2, 3);
        vecTris.emplace_back(4, 5, 7); vecTris.emplace_back(4, 6, 7);
        /* todo: add remaining triangles, should be 8 more */
    }
}

The above code will create two arrays in memory storing your vertex locations and the indices for the triangles. You'll notice that the code always draws 12 triangles for each voxel, it would be better to do a check if there is an adjacent occupied voxel and remove faces between such voxels, but I'll leave that for you. I also recommend you consider using glm::vec3 for storing vertex data rather then just a array.

We can now pass our arrays to OpenGL:

GLuint unVertexArray;
glGenVertexArrays(1, &unVertexArray);
glBindVertexArray(unVertexArray);

GLuint unVertexBuffer;
glGenBuffers(1, &unVertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, unVertexBuffer);
glBufferData(GL_ARRAY_BUFFER, 3*vecVerts.size()*sizeof(GLfloat),
    &vecVerts[0][0], GL_STATIC_DRAW);

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

GLuint unIndiciesBuffer;
glGenBuffers(1, &unIndicesBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, unIndicesBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3*vecTris.size()*sizeof(GLuint),
    &vecTris[0][0], GL_STATIC_DRAW);

glBindVertexArray(0);

Then finally, to draw our arrays:

glBindVertexArray(unVertexArray);
glDrawElements(GL_TRIANGLES, 3*vecTris.size(), GL_UNSIGNED_INT, NULL);
glBindVertexArray(0);

I might (am almost certain I) have forgotten a few things here, but this should give you a general outline of what you will need to do. For a proper explanation of most of the gl calls used above there are many online references, such as http://arcsynthesis.org/gltut/index.html

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top