The problem I am having is that once I create a VBO for the main geometry in a level, when I create a second for the objects, the object VBO does not work. I am assuming I have some buffer bound incorrectly but I can't for the life of me find it. I create the level VBO first and then the object VBO and again, when I disable the creation of the level VBO, the object VBO creates correctly.
Here is my code.
in level.h:
// Zone VBO
GLuint zoneVBO;
GLuint zoneVAO;
GLuint zoneIBO;
// Object VBO
GLuint objVBO;
GLuint objVAO;
GLuint objIBO;
Creation of zone (geometry) VBO - just as a note, the creation works correctly in both VBOs so the data moving around isn't the issue, it is I think, a binding error:
void WLD::createZoneVBO()
{
// Get the size for our VBO
int numVert = 0;
int numPoly = 0;
int VBOsize = 0;
int IBOsize = 0;
// Get the count of vertices and polygons
for(int i = 0; i < zoneFragMap[0x36]; i++)
{
numVert += zmeshes[i].numVert;
numPoly += zmeshes[i].numPoly;
VBOsize += zmeshes[i].numVert * sizeof(Vertex);
IBOsize += zmeshes[i].numPoly * 3 * sizeof(GLuint);
}
// Create the IBO and VBO data
GLuint* iboData = new GLuint[zonePolyProcessed * 3];
Vertex* vboData = new Vertex[zoneVertProcessed];
int iboPos = 0;
int vboPos = 0;
// Create the VBO and IBO
for(int i = 0; i < zoneFragMap[0x36]; i++)
{
// Copy the data to the IBO
memcpy(&iboData[iboPos], zmeshes[i].indices, zmeshes[i].numPoly * 3 * sizeof(GLuint));//sizeof(*zmeshes[i].indices));
// Advance the position
iboPos += zmeshes[i].numPoly * 3;
// Copy the data to the VBO
memcpy(&vboData[vboPos], zmeshes[i].vertices, zmeshes[i].numVert * sizeof(Vertex));//sizeof(*zmeshes[i].vertices));
// Advance the position
vboPos += zmeshes[i].numVert;
}
//Create VBO for the triangle
glGenBuffers(1, &zoneVBO);
glBindBuffer(GL_ARRAY_BUFFER, zoneVBO);
glBufferData(GL_ARRAY_BUFFER, zoneVertProcessed * sizeof(Vertex), vboData, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
//Create the IBO for the triangle
//16 bit indices
//We could have actually made one big IBO for both the quad and triangle.
glGenBuffers(1, &zoneIBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, zoneIBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, zonePolyProcessed * 3 * sizeof(GLuint), iboData, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// Create the VAO
glGenVertexArraysAPPLE(1, &zoneVAO);
glBindVertexArrayAPPLE(zoneVAO);
glBindBuffer(GL_ARRAY_BUFFER, zoneVAO);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glVertexAttribPointer(opaque["position"], 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(0));
glVertexAttribPointer(opaque["normal"], 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(sizeof(float) * 3));
glVertexAttribPointer(opaque["texcoord"], 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(sizeof(float) * 6));
glVertexAttribPointer(opaque["color"], 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(sizeof(float) * 8));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArrayAPPLE(0);
delete[] iboData;
delete[] vboData;
}
And the objects - again, the object geometry is loaded perfectly, but only if the zone geometry hasn't been loaded yet:
void WLD::createObjectVBO()
{
// Get the size for our VBO
int numVert = 0;
int numPoly = 0;
int VBOsize = 0;
int IBOsize = 0;
// Get the count of vertices and polygons
for(int i = 0; i < objFragMap[0x36]; i++)
{
numVert += objMeshes[i].numVert;
numPoly += objMeshes[i].numPoly;
VBOsize += objMeshes[i].numVert * sizeof(Vertex);
IBOsize += objMeshes[i].numPoly * 3 * sizeof(GLuint);
}
// Create the IBO and VBO data
GLuint* iboData = new GLuint[objPolyProcessed * 3];
Vertex* vboData = new Vertex[objVertProcessed];
int iboPos = 0;
int vboPos = 0;
// Create the VBO and IBO
for(int i = 0; i < objFragMap[0x36]; i++)
{
// Copy the data to the IBO
memcpy(&iboData[iboPos], objMeshes[i].indices, objMeshes[i].numPoly * 3 * sizeof(GLuint));//sizeof(*zmeshes[i].indices));
// Advance the position
iboPos += objMeshes[i].numPoly * 3;
// Copy the data to the VBO
memcpy(&vboData[vboPos], objMeshes[i].vertices, objMeshes[i].numVert * sizeof(Vertex));//sizeof(*zmeshes[i].vertices));
// Advance the position
vboPos += objMeshes[i].numVert;
}
//Create VBO for the triangle
glGenBuffers(1, &objVBO);
glBindBuffer(GL_ARRAY_BUFFER, objVBO);
glBufferData(GL_ARRAY_BUFFER, objVertProcessed * sizeof(Vertex), vboData, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
//Create the IBO for the triangle
//16 bit indices
//We could have actually made one big IBO for both the quad and triangle.
glGenBuffers(1, &objIBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, objIBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, objPolyProcessed * 3 * sizeof(GLuint), iboData, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Create the VAO
glGenVertexArraysAPPLE(1, &objVAO);
glBindVertexArrayAPPLE(objVAO);
glBindBuffer(GL_ARRAY_BUFFER, objVAO);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glVertexAttribPointer(opaque["position"], 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(0));
glVertexAttribPointer(opaque["normal"], 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(sizeof(float) * 3));
glVertexAttribPointer(opaque["texcoord"], 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(sizeof(float) * 6));
glVertexAttribPointer(opaque["color"], 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(sizeof(float) * 8));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArrayAPPLE(0);
}
Rendering these two VBOs:
opaque.Use();
glBindVertexArrayAPPLE(getVAO(2));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, zoneIBO);
glBindBuffer(GL_ARRAY_BUFFER, zoneVBO);
glUniformMatrix4fv(opaque("camera"), 1, GL_FALSE, glm::value_ptr(cameraMat));
renderGeometry(&cameraMat, 0, curRegion);
glBindVertexArrayAPPLE(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArrayAPPLE(objVAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, objIBO);
glBindBuffer(GL_ARRAY_BUFFER, objVBO);
glUniformMatrix4fv(opaque("camera"), 1, GL_FALSE, glm::value_ptr(cameraMat));
renderObjects(&cameraMat);
glBindVertexArrayAPPLE(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
opaque.UnUse();
To summarize, I think it's an issue in the creation of the VBOs. I think I am doing something wrong and keeping something bound when it should be bound.
// Create the VAO
glGenVertexArraysAPPLE(1, &zoneVAO);
glBindVertexArrayAPPLE(zoneVAO);
glBindBuffer(GL_ARRAY_BUFFER, zoneVAO); //<-------
glEnableVertexAttribArray(0);
In the line I have highlighted, this looks like it should be zoneVBO, not zoneVAO.
You should be checking for errors with glGetError, it might have spotted this mistake.
Also it's not required to bind the buffers before calling renderObjects. If you have the vertex pointer stored in the VAO, then you do not need to bind the buffer, as the vertex pointers already point to the correct location.
Related
Im having problems to add a struct to a OpenGL VBO
This is my struct
struct Vertex {
//vertices
std::vector<glm::vec3> vertices;
//texture coordinates
std::vector<glm::vec3> texCord;
}
This is how im assigning and initializing the VBO
glGenVertexArrays(1, &buffer.VAO);
glGenBuffers(1, &buffer.VBO);
glGenBuffers(1, &buffer.EBO);
glBindBuffer(GL_ARRAY_BUFFER, buffer.VAO);
//Initialize buffer data
glBindBuffer(GL_ARRAY_BUFFER, buffer.VBO);
glBufferData(GL_ARRAY_BUFFER,
vertex.vertices.size() * sizeof(glm::vec3) +
vertex.texCord.size() * sizeof(glm::vec3)
&vertex,
GL_STATIC_DRAW);
//indices attribute
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer.EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, vertex.indices.size() * sizeof(glm::vec2), &vertex.indices[0], GL_STATIC_DRAW);
//vertices coordinates attribute
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, vertices));
//texture coordinates attribute
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, texCord));
And my draw command looks like this
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(buffer.VAO);
glDrawElements(GL_TRIANGLES, vertex.indices.size(), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
Is it possible to initialize buffer data with a raw struct and if yes how?
std::vector stores a pointer to dynamically allocated memory. However, you must pass a consecutive buffer to glBufferData.
Create the object's data store with glBufferData, but use glBufferSubData to initialize the buffer:
size_t vertexSize = vertex.vertices.size() * sizeof(glm::vec3);
size_t texCordSize = vertex.texCord.size() * sizeof(glm::vec3);
glBufferData(GL_ARRAY_BUFFER, vertexSize + texCordSize, nullptr, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, vertexSize, vertex.vertices.data());
glBufferSubData(GL_ARRAY_BUFFER, vertexSize, texCordSize, vertex.texCord.data());
Thanks to #Rabbid76 I now solved my problem. Code is down below.
Note: I need to create the buffer before filling data with glBufferSubData
glGenVertexArrays(1, &buffer.VAO);
glGenBuffers(1, &buffer.VBO);
glGenBuffers(1, &buffer.EBO);
glBindBuffer(GL_ARRAY_BUFFER, buffer.VAO);
int vertexSize = sizeof(glm::vec3) * vertex.vertices.size();
int texCordSize = sizeof(glm::vec2) * vertex.texCord.size();
int totalSize = vertexSize + texCordSize;
int indicesSize = sizeof(unsigned int) * vertex.indices.size();
//Create Buffer dynamically
glBufferData(GL_ARRAY_BUFFER, totalSize, NULL, GL_DYNAMIC_DRAW);
//Fill the buffer with data
glBindBuffer(GL_ARRAY_BUFFER, buffer.VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, vertexSize, vertex.vertices.data());
glBufferSubData(GL_ARRAY_BUFFER, vertexSize, texCordSize, vertex.texCord.data());
//indices attribute
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer.EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesSize, vertex.indices.data(), GL_STATIC_DRAW);
//position attribute
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3) + sizeof(glm::vec2), (void*)0);
//texture attribute
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec3) + sizeof(glm::vec2), (void*)sizeof(glm::vec3));
glBindVertexArray(0);
Is there a way to share data between shaders?
Do i just create a VAO and then swich shader programs as needed?
I guess shaders probably need to have the same layout then.
Or do i create VBO-s and per object-shader pair i create the VAO that binds data to shader variables?
This should load most data only once to the OpenGl + i could reuse quite alot.
I tried the second approach, but im not sure if it has reduced memory usage or not. The code pieces in question are below, i hope its enough.
Or is there some other, even better way?
Idea is to reduce the memory usage, and general speedup of the process.
void Mesh::bind()
{
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, verticesCount * sizeof(GLfloat), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, nbo);
glBufferData(GL_ARRAY_BUFFER, normalCount * sizeof(GLfloat), normals, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, uvbo);
glBufferData(GL_ARRAY_BUFFER, uvCount * sizeof(GLfloat), UVs, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesCount * sizeof(GLuint), indices, GL_STATIC_DRAW);
}
void MeshRenderer::init()
{
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, mesh->getVertexBufferId());
GLuint posId = shaderProgram->getAttribute("LVertexPos2D");
glVertexAttribPointer(posId, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), NULL);
glEnableVertexAttribArray(posId);
glBindBuffer(GL_ARRAY_BUFFER, mesh->getNormalBufferId());
GLuint normId = shaderProgram->getAttribute("LVertexNorm");
glVertexAttribPointer(normId, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), NULL);
glEnableVertexAttribArray(normId);
glBindBuffer(GL_ARRAY_BUFFER, mesh->getUVBufferId());
GLuint uvId = shaderProgram->getAttribute("uv");
glVertexAttribPointer(uvId, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), NULL);
glEnableVertexAttribArray(uvId);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->getIndexBufferId());
glBindVertexArray(0);
}
GameObject* GameObject::createCustom(Mesh* mesh)
{
Texture* texture = new Texture();
texture->loadFromFile("UV.png", NULL);
GenericShaderProgram* shader = new GenericShaderProgram("basic.vs", "basic.fs");
shader->loadProgram();
return new GameObject(texture, shader, mesh);
}
GameObject::GameObject(Texture* texture, ShaderProgram* program, Mesh* mesh)
{
this->texture = texture;
dir = new Vector3(1, 0, 0);
meshRenderer = new MeshRenderer(mesh, program);
transform.setRotation(1.57, 1, 0, 0);
transform.translate(Vector3(0, -2, 0));
transform.setScale(Vector3(1, 1, 1));
}
//In main.cpp
Mesh* mesh = new Mesh();
mesh->cubePrimitive();
mesh->init();
object = GameObject::createCustom(mesh);
object2 = GameObject::createCustom(mesh);
object3 = GameObject::createCustom(mesh);
I am attempting to create a simple graphics system using modern (3.3) OpenGL for use in a game. Dynamic objects will have dynamic geometry and VBOs will be updated whenever there is a change. This part was very easy to implement. While everything works well so long as only one VAO is used, further calls to glGenVertexArrays don't create another object (printing the ID for the first and the second both returns 1) and something in the VAO initialization for the new objects renders the first one unable to perform any edits. Every "modern OpenGL" tutorial either only uses one object or has some pretty significant conflicts (most often the use of glVertexAttribPointer). The following code is involved with the graphics system of the objects. (Don't know how important this is, but I am using glfw3 for window and and context creation).
Init Game Object (graphics snippet)
glGenVertexArrays(1, &vertexArrayID);
glBindVertexArray(vertexArrayID);
glGenBuffers(1, &vertexCoordBufferID);
glBindBuffer(GL_ARRAY_BUFFER, vertexCoordBufferID);
glBufferData(GL_ARRAY_BUFFER, 2000 * 3 * sizeof(float), nullptr, GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(0);
allocatedVerticies = 2000;
Update Mesh
//generate mesh
std::vector<float> vertices;
vertices.reserve(voxels.size() * 3 * 12);
//Vertices are added to the vector. This part works. Removed this code for clarity.
vertexCount = vertices.size() / 3;
glBindVertexArray(vertexArrayID);
glBindBuffer(GL_ARRAY_BUFFER, vertexCoordBufferID);
if (allocatedVerticies < vertexCount)
{
//reallocate the buffers
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
allocatedVerticies = vertexCount;
}
else
{
/////////////////////////////
//reallocate the buffers- originally a reallocation was not going to be used, but glBufferSubData does not work
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
allocatedVerticies = vertexCount;
////////////////////////////////////////this does not work for some reason
//reset data
//glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size() * sizeof(float), vertices.data());
}
edited = false;
Render Object
glBindVertexArray(vertexArrayID);
glDrawArrays(GL_TRIANGLES, 0, vertexCount);
If anyone more experienced with OpenGL could point out my mistake, (or some other problem) that would be fantastic.
In code that you provided I see nothing that can cause such a behaviour. Maby you should provide your entire solution that is connected with your rendering for better understanding what is going on in your program?
By the way: if you already defined glVertexAttribPointer() for your buffor you don't have to do it every time you update the data you stored in your vertexCoordBufferID if of course you don't change the data layout and its type. Instead of:
vertexCount = vertices.size() / 3;
glBindVertexArray(vertexArrayID);
glBindBuffer(GL_ARRAY_BUFFER, vertexCoordBufferID);
if (allocatedVerticies < vertexCount)
{
//reallocate the buffers
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
allocatedVerticies = vertexCount;
}
You can use just:
vertexCount = vertices.size() / 3;
glBindBuffer(GL_ARRAY_BUFFER, vertexCoordBufferID);
if (allocatedVerticies < vertexCount)
{
//reallocate the buffers
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_DYNAMIC_DRAW);
allocatedVerticies = vertexCount;
}
I've just started learning opengl and I was trying to implement VBOs.
this is what I'm doing:
in the main method before I iterate, for each mesh I initialize its VBOs.
The mesh->pos and mesh->norm contain the points and the normals of the triangles and the quads of the mesh.
The mesh->triangle and mesh->quad contain the indices.
for (auto mesh : scene->meshes)
{
mesh->vboPos = 0;
glGenBuffers (1, &mesh->vboPos);
glBindBuffer (GL_ARRAY_BUFFER, mesh->vboPos);
glBufferData (GL_ARRAY_BUFFER, 3 * mesh->pos.size() * sizeof(GL_FLOAT), mesh->pos.data(), GL_STATIC_DRAW);
mesh->vboNorm = 0;
glGenBuffers (1, &mesh->vboNorm);
glBindBuffer (GL_ARRAY_BUFFER, mesh->vboNorm);
glBufferData (GL_ARRAY_BUFFER, 3 * mesh->norm.size() * sizeof(GL_FLOAT), mesh->norm.data(), GL_STATIC_DRAW);
mesh->vbiTriangle = 0;
glGenBuffers (1, &mesh-> vbiTriangle);
glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, mesh-> vbiTriangle);
glBufferData (GL_ELEMENT_ARRAY_BUFFER, 3 * mesh->triangle.size() * sizeof(GL_UNSIGNED_INT), mesh->triangle.data(), GL_STATIC_DRAW);
mesh->vbiQuad = 0;
glGenBuffers (1, &mesh->vbiQuad);
glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, mesh->vbiQuad);
glBufferData (GL_ELEMENT_ARRAY_BUFFER, 4 * mesh->quad.size() * sizeof(GL_UNSIGNED_INT), mesh->quad.data(), GL_STATIC_DRAW);
}
while(not glfwWindowShouldClose(window))
{
...
}
After this inside the shade method I call the draw for each mesh I have. This is how the mesh code looks like:
struct Mesh {
frame3f frame = identity_frame3f; // frame
vector<vec3f> pos; // vertex position
vector<vec3f> norm; // vertex normal
vector<vec3i> triangle; // triangle
vector<vec4i> quad; // quad
Material* mat = new Material(); // material
GLuint vboPos = 0;
GLuint vboNorm = 0;
GLuint vbiTriangle =0;
GLuint vbiQuad =0;
int count = 0;
void draw()
{
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, vboPos);
glBindBuffer(GL_ARRAY_BUFFER, vboNorm);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbiTriangle);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbiQuad);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawElements(GL_TRIANGLES, triangle.size() * 3, GL_UNSIGNED_INT, 0);
glDrawElements(GL_QUADS, quad.size() * 4, GL_UNSIGNED_INT, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
}
I don't really know what's the problem causing this, but I'm pretty sure I didn't understand something of how VBOs work. Can you enlighten me?
You are trying to do too many things at once here and I have a feeling the driver is overrunning an array trying to read the wrong element array.
Your draw function needs to be re-written:
void draw()
{
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
/* Setup your Position array */
glBindBuffer(GL_ARRAY_BUFFER, vboPos);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
/* Then setup your Normal array */
glBindBuffer(GL_ARRAY_BUFFER, vboNorm);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
/* DO NOT DO THIS -- you are using generic vertex attributes. */
//glEnableClientState(GL_VERTEX_ARRAY);
/* First the Triangles */
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbiTriangle);
glDrawElements(GL_TRIANGLES, triangle.size() * 3, GL_UNSIGNED_INT, 0);
/* Now the Quads */
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbiQuad);
glDrawElements(GL_QUADS, quad.size() * 4, GL_UNSIGNED_INT, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
}
I'm attempting to copy two vertex buffer objects from one Mesh object to another, through the copy assignment operator. Initially, my Vertex Array Object and the Buffers are initialized as follows:
void Mesh::construct(Vertex* vertices, unsigned int nVerts) {
vertexCount = nVerts;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
std::vector<glm::vec3> positions;
std::vector<glm::vec2> texCoords;
positions.reserve(nVerts);
texCoords.reserve(nVerts);
for (unsigned int i = 0; i < nVerts; i++) {
positions.push_back(vertices[i].getPosition());
texCoords.push_back(vertices[i].getTexCoord());
}
for (int i = 0; i < NUM_BUFFERS; i++) {
glGenBuffers(1, &vab[i]);
}
glBindBuffer(GL_ARRAY_BUFFER, vab[POSITION_VB]);
glBufferData(GL_ARRAY_BUFFER, nVerts * sizeof (positions[0]), &positions[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, vab[TEXCOORD_VB]);
glBufferData(GL_ARRAY_BUFFER, nVerts * sizeof (texCoords[0]), &texCoords[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
This works fine when instantiating a Mesh object, and calling:
void Mesh::render() {
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, vertexCount);
glBindVertexArray(0);
}
However, when I try to copy the mesh into another, and render it, I get a segmentation fault on the glDrawArrays(GL_TRIANGLES, 0, vertexCount); line.. This is my copy assignment operator:
Mesh& Mesh::operator=(const Mesh& param) {
if (this == ¶m) {
return *this;
} else {
GLint size = 0;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
for (int i = 0; i < NUM_BUFFERS; i++) {
glGenBuffers(1, &vab[i]);
}
// Vertices
// Bind Buffers
glBindBuffer(GL_COPY_READ_BUFFER, param.vab[POSITION_VB]);
glGetBufferParameteriv(GL_COPY_READ_BUFFER, GL_BUFFER_SIZE, &size);
glBindBuffer(GL_COPY_WRITE_BUFFER, vab[POSITION_VB]);
glBufferData(GL_COPY_WRITE_BUFFER, size, nullptr, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
// Copy Data
glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, size);
// Texture Coords
// Bind Buffers
glBindBuffer(GL_COPY_READ_BUFFER, param.vab[TEXCOORD_VB]);
glGetBufferParameteriv(GL_COPY_READ_BUFFER, GL_BUFFER_SIZE, &size);
glBindBuffer(GL_COPY_WRITE_BUFFER, vab[TEXCOORD_VB]);
glBufferData(GL_COPY_WRITE_BUFFER, size, nullptr, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
// Copy Data
glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, size);
// Unbind buffers
glBindVertexArray(0);
this->vertexCount = param.vertexCount;
return *this;
}
}
Can anyone see any problems with this? I've checked that the size being returned from glGetBufferParameteriv(GL_COPY_READ_BUFFER, GL_BUFFER_SIZE, &size); is correct in both cases (for both position and texture coordinate buffer). I've also checked glGetError() after both calls to glCopyBufferSubData, which both return 0. Not sure what to try next? My error may be elsewhere, but this is the first time I have tried copying buffers, so want to check that I'm doing that part right. If it helps, my Mesh destructor is:
Mesh::~Mesh() {
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(NUM_BUFFERS, vab);
}
Through a debugger I can see that this is, of course, being called once, after the line:
this->mesh = Mesh(*texture);
Which is simply constructing a mesh, then assigning it (the texture just sizes the quad to the size of the texture, and calls the constructor shown at the start with the correct vertex positions).
You copy the arrays, but you never bind the copied versions to GL_ARRAY_BUFFER, meaning your glVertexAttribPointer calls are pointing to nothing.
I'm also a little wary of this code:
glBindBuffer(GL_ARRAY_BUFFER, vab[POSITION_VB]);
glBufferData(GL_ARRAY_BUFFER, nVerts * sizeof (positions[0]), &positions[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, vab[TEXCOORD_VB]);
glBufferData(GL_ARRAY_BUFFER, nVerts * sizeof (texCoords[0]), &texCoords[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
It seems like the position vertex pointer will be referring to the texture data, because that's the currently bound vertex buffer when you call glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
I'd think you'd want the order to be like so:
glBindBuffer(GL_ARRAY_BUFFER, vab[POSITION_VB]);
glBufferData(GL_ARRAY_BUFFER, nVerts * sizeof (positions[0]), &positions[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vab[TEXCOORD_VB]);
glBufferData(GL_ARRAY_BUFFER, nVerts * sizeof (texCoords[0]), &texCoords[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
But I'm not certain. I usually interleave all my vertex attributes into a single vertex buffer.