Drawing VBO causes segmentation fault - c++

I am trying to draw a quad using a VBO, here is the full code but I'll post the code step by step: here is how I initialize the buffer:
data= vector<GLfloat> { // Global variable vector<GLfloat> data;
// Viewport: glViewport(0,0,width,height);
width/2+20,height/2+20,0.0,
width/2+20,height/2-20,0.0,
width/2-20, height/2-20,0.0,
width/2-20, height/2+20,0.0
};
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, 12*sizeof(GLfloat), data.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
Then in the display function I try to draw the quad (I use double buffering):
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, data.data());
glDrawArrays(GL_QUADS, 0, 4); // Here I get segmentation fault
glDisableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glutSwapBuffers();
I get segmentation fault at the line where I call glDrawArrays, I also tried to get the OpenGL errors with glGetError(), but there's no error (it returns zero).

You are using the following line in the initialization:
glBufferData(GL_ARRAY_BUFFER, 12*sizeof(GLfloat), data.data(), GL_STATIC_DRAW);
When drawing you set up your attrib pointers like this:
glVertexPointer(3, GL_FLOAT, 0, data.data());
I suspect that data.data() is the same in both cases - making this an error. When an ARRAY_BUFFER is bound, the pointer argument of the various gl*Pointer() functions does not refer to a client memory address, but to a byte offset in the VBOs. When drawing, the GL will try to fetch this data which is very likely to be way out of bounds of the buffer object - hence the crash. You probably meant:
glVertexPointer(3, GL_FLOAT, 0, NULL);
Note that the original VBO extension has this often-used macro in the examples section:
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
Using that, you can conveniently hide those ugly pointer arithmetic nicely and can address byte offsets in your buffer:
glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));

Related

Order of arguments in glBindBuffer

I'm creating a VBO, populating it with data, then that data is being rendered using the following code:
// Buffer data
glGenBuffers(1, &VBOID);
glBindBuffer(VBOID, GL_ARRAY_BUFFER); // Shouldn't these be the other way around?
glBufferData(GL_ARRAY_BUFFER, bufferSize, buffer, GL_STATIC_DRAW);
glVertexPointer(3, GL_FLOAT, 0, buffer);
// Draw arrays
glBindBuffer(VBOID, GL_ARRAY_BUFFER);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_TRIANGLES, 0, bufferSize);
glDisableClientState(GL_VERTEX_ARRAY);
However, the openGL reference (https://www.opengl.org/sdk/docs/man/html/glBindBuffer.xhtml) says that the glBindBuffer function takes the target TYPE of buffer, then the buffer ID, not the other way around. When I put them in that way around, nothing draws to the screen, however when they're the 'wrong' way around, it seems to work just fine.
To clarify:
// Should be this
glBindBuffer(GL_ARRAY_BUFFER, VBOID);
// Only this works
glBindBuffer(VBOID, GL_ARRAY_BUFFER);
I feel like this is one of those really dumb issues, but I just can't see where the problem is. Could anyone shed some light on the situation?
Thanks.
It should definitely be written like this:
glBindBuffer(GL_ARRAY_BUFFER, VBOID);
I can't explain why reversing those arguments results in successful drawing. However, there's a few oddities you have in your code that you need to revise:
glVertexPointer(3, GL_FLOAT, 0, buffer);
This is immediate mode code. I don't think it's been deprecated, but the correct way to write this is
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, nullptr);
On top of that, you have two references to setting client state—glEnableClientState(GL_VERTEX_ARRAY); and glDisableClientState(GL_VERTEX_ARRAY);—These are also part of immediate mode, and should be removed.
Finally, the whole thing should be wrapped up inside a Vertex Array Object, like so:
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &VBOID);
glBindBuffer(GL_ARRAY_BUFFER, VBOID);
glBufferData(GL_ARRAY_BUFFER, bufferSize, buffer, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, nullptr);
glEnableVertexAttribArray(0);
// Draw arrays
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, num_of_vertices); //num_of_vertices is usually the number of floats in the buffer divided by the number of dimensions of the vertex, or 3 in this case, since each vertex is a vec3 object.

OpenGL VBO Segfault when calling glDrawArrays()

I've been trying to get VBOs working in my latest project and the program segfaults when I try to call glDrawArrays.
Generating the VBO
bool Renderer::init()
{
GLfloat verticies[]=
{0,0,
0,32,
32,32,
32, 0};
glGenBuffersARB(1, &vboTest);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vboTest);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verticies), verticies, GL_STATIC_DRAW);
}
And then the rendering the VBO
void Renderer::renderScene()
{
glClear(GL_COLOR_BUFFER_BIT);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vboTest);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, 0);
glDrawArrays(GL_QUADS, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
glLoadIdentity();
SDL_GL_SwapWindow(window);
}
Nevermind, it was a stupid arbitrary error. I loaded the functions using SDL_GL_GetProcAddress, but then in the header for the renderer class defined GL_EXT_PROTOTYPES instead of re-prototyping the functions.

VBO: not drawing correctly. Manual drawing works

so I will need to edit this question. As stated in one of the comments, I changed to rendering method to use buffers. However, the geometry isn't being drawn correctly. If I use the same buffer and draw the vertices manually, it looks alright (without the texture though, something is messed up with it). I also tried constructing a buffer with just vertex information but that didn't help at all.
void ModelHandler::DrawModels(){
//go through each of the models
for(int i=0;i<Models3D.size();i++){
//glEnableClientState(GL_VERTEX_ARRAY);
//glVertexPointer(3, GL_FLOAT, 0, Models3D[i]->object.m_pVertice);
//now draw all the material groups with their vertices for the model
for(int j=0;j<Models3D[i]->object.mtlGroups.size();j++){
//Drawing the vertices manually from the buffer object seems to work
/*
for(int lj=0;lj<Models3D[i]->object.mtlGroups[j]->m_vecgroupVerticeIndex.size();lj++){
int mtlIndex2 = Models3D[i]->object.FindMaterial(Models3D[i]->object.mtlGroups[j]->mtlName);
bool tOn = false;
//check if there was a texture for this material
if(Models3D[i]->object.materials[mtlIndex2]->texturePresent){
glEnable(GL_TEXTURE_2D);
//glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glBindTexture(GL_TEXTURE_2D, Models3D[i]->object.materials[mtlIndex2]->textureIDDiffuse);
tOn = true;
}
if(tOn){
glBegin (GL_QUADS);
glTexCoord2f (0.0, 0.0);
glVertex3f (0.0+5, 0.0, -2.0f);
glTexCoord2f (1.0, 0.0);
glVertex3f (1.4f+5, 0.0, -2.0f);
glTexCoord2f (1.0, 1.0);
glVertex3f (1.4f+5, -1.0, -2.0f);
glTexCoord2f (0.0, 1.0);
glVertex3f (0.0f+5, -1.0, -2.0f);
glEnd ();
}
glBegin(GL_TRIANGLES);
glColor3f(Models3D[i]->object.mtlGroups[j]->VBO[lj*3].colour[0],Models3D[i]->object.mtlGroups[j]->VBO[lj*3].colour[1],Models3D[i]->object.mtlGroups[j]->VBO[lj*3].colour[2]);
if(tOn){
glTexCoord2f (Models3D[i]->object.mtlGroups[j]->VBO[lj*3].tex[0], Models3D[i]->object.mtlGroups[j]->VBO[lj*3].tex[1]);
}
glVertex3f(Models3D[i]->object.mtlGroups[j]->VBO[lj*3].location[0], Models3D[i]->object.mtlGroups[j]->VBO[lj*3].location[1], Models3D[i]->object.mtlGroups[j]->VBO[lj*3].location[2]);
glColor3f(Models3D[i]->object.mtlGroups[j]->VBO[lj*3+1].colour[0],Models3D[i]->object.mtlGroups[j]->VBO[lj*3+1].colour[1],Models3D[i]->object.mtlGroups[j]->VBO[lj*3+1].colour[2]);
if(tOn){
glTexCoord2f (Models3D[i]->object.mtlGroups[j]->VBO[lj*3+1].tex[0], Models3D[i]->object.mtlGroups[j]->VBO[lj*3+1].tex[1]);
}
glVertex3f(Models3D[i]->object.mtlGroups[j]->VBO[lj*3+1].location[0], Models3D[i]->object.mtlGroups[j]->VBO[lj*3+1].location[1], Models3D[i]->object.mtlGroups[j]->VBO[lj*3+1].location[2]);
glColor3f(Models3D[i]->object.mtlGroups[j]->VBO[lj*3+2].colour[0],Models3D[i]->object.mtlGroups[j]->VBO[lj*3+2].colour[1],Models3D[i]->object.mtlGroups[j]->VBO[lj*3+2].colour[2]);
if(tOn){
glTexCoord2f (Models3D[i]->object.mtlGroups[j]->VBO[lj*3+2].tex[0], Models3D[i]->object.mtlGroups[j]->VBO[lj*3+2].tex[1]);
}
glVertex3f(Models3D[i]->object.mtlGroups[j]->VBO[lj*3+2].location[0], Models3D[i]->object.mtlGroups[j]->VBO[lj*3+2].location[1], Models3D[i]->object.mtlGroups[j]->VBO[lj*3+2].location[2]);
glEnd();
}
glDisable(GL_TEXTURE_2D);
*/
//####
glBindBuffer(GL_ARRAY_BUFFER, Models3D[i]->object.mtlGroups[j]->vboID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Models3D[i]->object.mtlGroups[j]->indexvboID);
/*
//this could also be used BUT if glDrawElements uses the indices (m_pgroupVerticeIndex), we will need to give the array with all the
//vertices to glVertexPointer. That array would be m_pVertice
//glVertexPointer(3, GL_FLOAT, 5, Models3D[i]->object.mtlGroups[j]->buffer);
*/
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
//Get the material that belongs to this mtlGroup
int mtlIndex = Models3D[i]->object.FindMaterial(Models3D[i]->object.mtlGroups[j]->mtlName);
//check if there was a texture for this material
if(Models3D[i]->object.materials[mtlIndex]->texturePresent){
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glBindTexture(GL_TEXTURE_2D, Models3D[i]->object.materials[mtlIndex]->textureIDDiffuse);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(12));
//glTexCoordPointer(2, GL_FLOAT, 5, Models3D[i]->object.mtlGroups[j]->buffer);
//glTexCoordPointer(2, GL_FLOAT, 0, Models3D[i]->object.m_pTexture);
}
// Resetup our pointers. This doesn't reinitialise any data, only how we walk through it
glNormalPointer(GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(20));
glColorPointer(3, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(32));
glVertexPointer(3, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(0));
glDrawElements(GL_TRIANGLES, Models3D[i]->object.mtlGroups[j]->m_vecgroupVerticeIndex.size()*3, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));
//glDrawElements(GL_TRIANGLES, Models3D[i]->object.mtlGroups[j]->m_vecgroupVerticeIndex.size()*3, GL_UNSIGNED_INT, Models3D[i]->object.mtlGroups[j]->m_pgroupVerticeIndex);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisable(GL_TEXTURE_2D);
}
}
}
My buffer contains the vertices (array of Vertex structs):
struct Vertex {
GLfloat location[3];
GLfloat tex[2];
GLfloat normal[3];
GLfloat colour[3];
GLubyte padding[20]; //apparently to get 64 bytes -> improved performance
};
And here is how I initialize/generate buffers for each of the materials:
//This function was implemented based on the tutorial shown at
//http://sdickinson.com/wordpress/?p=122
void CObjLoader::GenerateVBO(){
for(int mj=0;mj<mtlGroups.size();mj++){
glGenBuffers(1, &mtlGroups[mj]->vboID);
//printf("bufferID: %d", mtlGroups[mj]->vboID);
glBindBuffer(GL_ARRAY_BUFFER, mtlGroups[mj]->vboID); // Bind the buffer (vertex array data)
// Allocate space. We could pass the mesh in here (where the NULL is), but it's actually faster to do it as a
// seperate step. We also define it as GL_STATIC_DRAW which means we set the data once, and never
// update it. This is not a strict rule code wise, but gives hints to the driver as to where to store the data
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * mtlGroups[mj]->m_vecgroupVerticeIndex.size()*3, NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vertex) * mtlGroups[mj]->m_vecgroupVerticeIndex.size()*3, mtlGroups[mj]->VBO); // Actually upload the data
// Set the pointers to our data. Except for the normal value (which always has a size of 3), we must pass
// the size of the individual component. ie. A vertex has 3 points (x, y, z), texture coordinates have 2 (u, v) etc.
// Basically the arguments are (ignore the first one for the normal pointer), Size (many components to
// read), Type (what data type is it), Stride (how far to move forward - in bytes - per vertex) and Offset
// (where in the buffer to start reading the data - in bytes)
// Make sure you put glVertexPointer at the end as there is a lot of work that goes on behind the scenes
// with it, and if it's set at the start, it has to do all that work for each gl*Pointer call, rather than once at
// the end.
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(12));
glNormalPointer(GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(20));
glColorPointer(3, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(32));
glVertexPointer(3, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(0));
// When we get here, all the vertex data is effectively on the card
// Our Index Buffer, same as above, the variable needs to be accessible wherever we draw
glGenBuffers(1, &mtlGroups[mj]->indexvboID); // Generate buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mtlGroups[mj]->indexvboID); // Bind the element array buffer
// Upload the index array, this can be done the same way as above (with NULL as the data, then a
// glBufferSubData call, but doing it all at once for convenience)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mtlGroups[mj]->m_vecgroupVerticeIndex.size()*3*sizeof(GLubyte), mtlGroups[mj]->index, GL_STATIC_DRAW);
}
}
For the sake of simplicity, my index array looks like this: 0, 1, 2, 3, 4, 5, .... This means that my buffer contains some of the vertices twice. VBO and index have therefore the same length.
Maybe I am messing something up with the initialization?
So the error was the following (I will just copy my previous comments explaining the solution):
Ok, I've found the error. Apparently, I was using GLubyte for the indices and in my case, I have way more than 255 vertices. Changing to GLuint has resolved the issue. However, my texture still isn't drawn correctly onto the object. The object stays grey. But colors seem to work.
The .obj loader is yielding better results now and is ok with simpler models. I will do some further testing and in case of trouble, I will be back.

Opengles mixing VBO and non VBO renders gives EXC_BAD_ACCESS

Hey guys. Im trying to render two methods shown below. RenderA() is using VBOs and RenderB() isnt. Im getting an EXC_BAD_ACCESS error when it reaches glDrawArrays() in RenderB().
RenderB() works fine though if i dont create and use any VBOs, ie when i comment out CreateVBOs() and RenderA().
So does this mean once you start using VBOs, all renderings must use VBOs?
Or what am I doing wrong here?
Render() {
CreateVBOs(); //glGenBuffers,glBindBuffer,glBufferData etc
RenderA();
RenderB();
}
RenderA(){
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo->indexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vbo->vertexBuffer);
glVertexPointer(3, GL_FLOAT, sizeof(Vertex), 0);
glColorPointer(4, GL_FLOAT, sizeof(Vertex), colorOffset);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glDrawElements(GL_TRIANGLES,vbo->indexCount, GL_UNSIGNED_SHORT, bodyOffset);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
}
RenderB(){
static GLfloat vertices[] = {1.0,1.0,1.0,2.0,1.0,1.0};
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glDrawArrays(GL_POINTS, 0, 2);
glDisableClientState(GL_VERTEX_ARRAY);
}
Edit(Solved)
Figured it out. Apparently you have to make sure you unbind the buffer if it was binded before in order to render without vbo.
My CreateVBOs() function binded but did not unbind the buffer so thats what created bad access when RenderB() was trying to use glDrawArrays. Unbinding the buffer is just binding it to 0 like so:
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
Try binding GL_ELEMENT_ARRAY_BUFFER and GL_ARRAY_BUFFER to zero before doing your non-VBO draw calls.
Add the following lines of code to the end of your VBO draw calls (RenderA):
glBindBuffer(GL_ElEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);

OpenGL Vertex Buffer Object code giving bad output

My Vertex Buffer Object code is supposed to render textures nicely but instead the textures are being rendered oddly with some triangle shapes.
What happens - http://godofgod.co.uk/my_files/wrong.png
What is supposed to happen - http://godofgod.co.uk/my_files/right.png
This function creates the VBO and sets the vertex and texture coordinate data:
extern "C" GLuint create_box_vbo(GLdouble size[2]){
GLuint vbo;
glGenBuffers(1,&vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
GLsizeiptr data_size = 8*sizeof(GLdouble);
GLdouble vertices[] = {0,0, 0,size[1], size[0],0, size[0],size[1]};
glBufferData(GL_ARRAY_BUFFER, data_size, vertices, GL_STATIC_DRAW);
data_size = 8*sizeof(GLint);
GLint textcoords[] = {0,0, 0,1, 1,0, 1,1};
glBufferData(GL_ARRAY_BUFFER, data_size, textcoords, GL_STATIC_DRAW);
return vbo;
}
Here is some relavant code from another function which is supposed to draw the textures with the VBO.
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glColor4d(1,1,1,a/255);
glBindTexture(GL_TEXTURE_2D, texture);
glTranslated(offset[0],offset[1],0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexPointer(2, GL_DOUBLE, 0, 0);
glEnableClientState(GL_VERTEX_ARRAY);
glTexCoordPointer (2, GL_INT, 0, 0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDrawArrays(GL_TRIANGLES, 1, 3);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
I would have hoped for the code to use the first three coordinates (top-left,bottom-left,top-right) and the last three (bottom-left,top-right,bottom-right) to draw the triangles with the texture data correctly in the most efficient way. I don't see why triangles should make it more efficient but apparently that's the way to go. It, of-course, fails for some reason.
I am asking what is broken but also am I going about it in the right way generally?
Thank you.
If you want to use the one VBO for both vertex and texture coordinates you need to group them using a struct.
Define your data:
typedef struct {
GLdouble x, y;
GLint s, t;
} VertexData;
VertexData data[] = {
// x y s t
{0.0, 0.0, 0, 0},
{0.0, size[1], 0, 1},
{size[0], 0.0, 1, 0},
{size[0], size[1], 1, 1}
};
Copy it into VBO:
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(data), (GLvoid*)data, GL_STATIC_DRAW);
Set pointers. Note that stride is your struct's size and pointer itself serves as offset:
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexPointer(2, GL_DOUBLE, sizeof(VertexData), (GLvoid*)offsetof(VertexData, x));
glTexCoordPointer(2, GL_INT, sizeof(VertexData), (GLvoid*)offsetof(VertexData, s));
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
And draw.
EDIT: Implemented offset with offsetof() as Bahbar suggested.
You're loading data twice to the vbo. The second call to glBufferData is replacing the first one. Then both calls to gl*Pointer actually use the same data when calling draw.