Vbos with Std::Vector

VBOs with std::vector

If you have a std::vector<T> v, you may obtain a T* pointing to the start of the contiguous data (which is what OpenGL is after) with the expression &v[0].


In your case, this means passing a Vertex* to glBufferData:

glBufferData(
GL_ARRAY_BUFFER,
vertices.size() * sizeof(Vertex),
&vertices[0],
GL_STATIC_DRAW
);

Or like this, which is the same:

glBufferData(
GL_ARRAY_BUFFER,
vertices.size() * sizeof(Vertex),
&vertices.front(),
GL_STATIC_DRAW
);

You can rely on implicit conversion from Vertex* to void const* here; that should not pose a problem.

OpenGL: Using VBO with std::vector

You want to do:

unsigned int vbo;
vector<float> vert;

...
vert.push_back(i*size);
vert.push_back(height*h);
vert.push_back(j*size);
...

glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vert.size() * sizeof(float), vert.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

It is always good to read the documentation. Also, I would suggest you pick up a good C++ book, which probably would be a good way for you to avoid doing mistakes like these.

std::vector and VBOs render only the last shape

As I suspected, the problem is with the (lack of) copy constructor. The default one just copies all the members. As a result your VAOs and buffers get deleted multiple times, even before you manage to draw anything (vectors move during reallocation, and if they can't move they copy). As a rule of thumb: if you have a non-default destructor, you must implement also a copy constructor and an assignment operator, or explicitly delete them if your class is not meant to be copyable.

For your concrete case the solutions are:

  1. Quick solution: store pointers to meshes in the vector:

    std::vector<Mesh*> meshes;
    meshes.emplace_back(&mesh1);
    meshes.emplace_back(&mesh2);
  2. Correct solution: use proper RAII for resource management. Using the unique_ptr technique from here your MCVE code becomes:

    class Mesh
    {
    public:
    Mesh(Vertex* vertices, unsigned int numVertices, const char& flag);
    void draw();
    private:
    //...
    GLvertexarray m_vertexArrayObject;
    GLbuffer m_vertexArrayBuffers[NUM_BUFFERS];
    unsigned int m_drawCount;
    char m_flag;
    };

    Mesh::Mesh(Vertex* vertices, unsigned int numVertices, const char& flag) : m_flag(flag), m_drawCount(numVertices)
    {
    GLuint id;
    glGenVertexArrays(1, &id);
    glBindVertexArray(id);
    m_vertexArrayObject.reset(id);
    for(int i = 0; i < NUM_BUFFERS; ++i)
    {
    glGenBuffers(1, &id);
    glBindBuffer(GL_ARRAY_BUFFER, id);
    m_vertexArrayBuffers[i].reset(id);
    glBufferData(GL_ARRAY_BUFFER, numVertices*sizeof(vertices[0]), vertices, GL_STATIC_DRAW);
    }

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

    void Mesh::draw()
    {
    switch(m_flag)
    {
    case 'P':
    glBindVertexArray(m_vertexArrayObject.get());
    glDrawArrays(GL_POINTS, 0, m_drawCount);
    glBindVertexArray(0);
    break;
    case 'L':
    glBindVertexArray(m_vertexArrayObject.get());
    glDrawArrays(GL_LINES, 0, m_drawCount);
    glBindVertexArray(0);
    break;
    case 'T':
    glBindVertexArray(m_vertexArrayObject.get());
    glDrawArrays(GL_TRIANGLES, 0, m_drawCount);
    glBindVertexArray(0);
    break;
    }

    }

    int main()
    {
    //...

    Mesh mesh1(vertices1, sizeof(vertices1)/sizeof(vertices1[0]), 'L');
    Mesh mesh2(vertices2, sizeof(vertices2)/sizeof(vertices2[0]), 'L');

    std::vector<Mesh> meshes;
    meshes.emplace_back(std::move(mesh1));
    meshes.emplace_back(std::move(mesh2));

    // ...

    return 0;
    }

    Notice how there is no more need for defining a destructor, and your class automatically becomes movable but not copyable. Furthermore, if you have OpenGL 4.5 or ARB_direct_state_access then things get even simpler.

std::vector Offset Calculation for VBO?

Simply, you can't.
The vector of vectors is essentially storing a vector of pointers to memory elsewhere, and is therefore not contiguous and cannot be offset.

You will need to use a multi-dimensional array; as you are already.

C++ - OpenGL - glBufferData with std::vector

The answer, seen HERE is:

glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(m_indicesEBO), &m_indicesEBO.front(), GL_STATIC_DRAW);

Using the pointer to the beginning of the vector with .front()

How to properly keep track of VBOs and VAOs for cleanup?

There is missing the address-of (&) operator

glDeleteVertexArrays(1, (unsigned int*)_vaos[i]);

glDeleteVertexArrays(1, &_vaos[i]);

Alternatively you can do:

glDeleteVertexArrays(1, _vaos.data()+i);

Anyway, you don't need the for loops at all (see std::vector):

void Model::_cleanup()
{
glDeleteVertexArrays(_vaos.size(), _vaos.data());
glDeleteBuffers(_vbos.size(), _vbos.data());
}

Using OpenGL VBOs with custom classes/datatructures

First of all you have to ensure that the vertex coordinates are in a contiguous and contiguous area in memory and are not fragmented into a lot of little pieces. Use Location bl, br, tr, tl instead of Location *bl ... and std::vector<Face> instead of std::vector<Face*>. Then you have a consecutive list of vertex coordinates which can be bound to a vertex buffer object:

class Face {
public:
Location bl;
Location br;
Location tr;
Location tl;
};

std::vector<Location> faces;

Create the vetrtex array object and bind the data

GLuint vbo;
glGenBuffers( 1, &vbo );
glBindBuffer( GL_ARRAY_BUFFER, vbo );
glBufferData( GL_ARRAY_BUFFER, faces.size()*sizeof(*faces.data()), faces.data(), GL_STATIC_DRAW );
glBindBuffer( GL_ARRAY_BUFFER, 0 );

Draw the mesh:

glBindBuffer( GL_ARRAY_BUFFER, vbo );
glVertexPointer( 3, GL_INT, sizeof(Location), nullptr );
glEnableClientState( GL_VERTEX_ARRAY );

glPushMatrix();
for (int i = 0; i < chunks.size(); i++) {
Chunk* chunk = chunks[i];
for (int j = 0; j < chunk->facesToRender.size(); j++) {
Face* f = chunk->facesToRender[j];
srand(i); // Create a color per chunk

glColor3ub(rand()%255, rand()%255, rand()%255);
glDrawArrays(GL_QUADS, j*4, 4);
}
}
glPopMatrix();

glDisableClientState( GL_VERTEX_ARRAY );



As an alternative you can create a list of vertex coordinates and a list of faces which each contains the 4 indices of the corner coordinates.

std::vector<Location> vertices;

struct Face
{
int bl;
int br;
int tr;
int tl;
};

std::vector<Face> faces;

Indexed vertex cordiaten can be drawn by glDrawElements.



Related Topics



Leave a reply



Submit