OpenGL crashing before it can render a frame - VBOs - c++

After giving up on the slow glBegin/glEnd technique, I finally decided to use VBOs. After hours and hours of frustration, I finally got it to compile. But it doesn't mean it works. The function "CreateVBO" executes without errors, but as soon as glutMainLoop() is called, the program crashes, it doesn't even call the Reshape() or Render() functions.
Here is the CreateVBO() function:
(note: the "lines" variable is equal to 4 million, the whole program is just a stress-test for rendering many lines before I can do something that actually makes sense)
void CreateVBO()
{
glGenBuffers = (PFNGLGENBUFFERSPROC)wglGetProcAddress("glGenBuffers");
glBindBuffer=(PFNGLBINDBUFFERPROC)wglGetProcAddress("glBindBuffer");
glBufferData=(PFNGLBUFFERDATAPROC)wglGetProcAddress("glBufferData");
glDeleteBuffers=(PFNGLDELETEBUFFERSPROC)wglGetProcAddress("glDeleteBuffers");
glMapBuffer=(PFNGLMAPBUFFERPROC)wglGetProcAddress("glMapBuffer");
for(float i=0; i<lines*2; i++)
{
t_vertices.push_back(i/9000);
t_vertices.push_back(5 * (((int)i%2)*2-1));
t_vertices.push_back(20);
vert_cols.push_back(0);
vert_cols.push_back(255);
vert_cols.push_back(0);
t_indices.push_back((int)i);
}
glGenBuffers(1, &VertexVBOID);
glBindBuffer(GL_ARRAY_BUFFER, VertexVBOID);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*t_vertices.size(), &t_vertices[0], GL_STATIC_DRAW);
glGenBuffers(1, &IndexVBOID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexVBOID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*t_indices.size(), NULL, GL_STATIC_DRAW);
GLvoid * buf = glMapBuffer( GL_ARRAY_BUFFER, GL_WRITE_ONLY );
memcpy( (void*)buf, &vert_cols[0], (size_t)(sizeof(float)*vert_cols.size()));
glBindBuffer( GL_ARRAY_BUFFER, 0 );
}
And here's the Render() function. I don't know what may be wrong with it since the program crashes before even calling that function.
void Display()
{
glRotatef(1, 0, 1, 0);
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
glBindBuffer(GL_ARRAY_BUFFER, VertexVBOID);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(t_vertices.size(), GL_FLOAT, 0, 0); //The starting point of the VBO, for the vertices
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(vert_cols.size(), GL_FLOAT, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexVBOID);
glDrawElements(GL_LINES, lines, GL_UNSIGNED_INT, 0);
glutSwapBuffers();
//Sleep(16);
glutPostRedisplay();
}

Your code doesn't make sense.
First, you create your vertexVBOID big enough to hold your t_vertices vector, and fill it with exactly that array.
Then, you map that VBO and overwrite the data in it with the data from the vert_color vector. For drawing, you specify both the vertex position and the color attribute to come from the same position in memory - so effectively using the color as position, too.
But that is not the reason of the crash. There are actually two main reasons for crashing:
You create IndexVBOID big enough to hold your index array, but you never initalize that buffer with some data. You instead specify NULL as the data pointer, so the storage is created, but left uninitialized. So you end up with an undefined content in that buffer, and the GL will access arbtrary memory positions when drawing with that.
Your glVertexPointer and glColorPointer calls are wrong. The first parameter, size, is not the size of an array. It is the size of a single vector, which can be 1,2,3 or 4. Your array size is probably something else, so this calls end up generating an GL_INVALID_VALUE error, and not setting the attrib pointers at all. And by default, those pointers are NULL.
So ultimately, you are asking the GL to draw from undefined array indices relative to a NULL pointer. That's very likely to crash. In general, it is just undefined behavior, and the result could be anything.
Furthermore, you also keep the VertexVBOID buffer mapped - you never unmap it. It is invalid to use a buffer as the source or destination for GL commands as long as it is mapped (unless a persistent mapping is created, which is a relatively new feature which doesn't really belong here).

Related

OpenGL Array Buffer from a vector of pointers

Problem
I have a vector of pointers to particles:
struct Particle {
vec3 pos; // just 3 floats, GLM vec3 struct
// ...
}
std::vector<Particle *> particles;
I want to use this vector as the source of data for an array buffer in OpenGL
Like this:
glGenBuffers(1, &particleBuffer);
glBindBuffer(GL_ARRAY_BUFFER, particleBuffer);
int bufferSize = sizeof(Particle) * particles->size();
glBufferData(GL_ARRAY_BUFFER, bufferSize, /* What goes here? */, GL_STATIC_DRAW);
glEnableVertexAttribArray(positionAttribLocation);
glVertexAttribPointer(positionAttribLocation, 3, GL_FLOAT, GL_FALSE, sizeof(Particle), (void *)0);
Where the interesting line is glBufferData( ... )
How do I get OpenGL to get that the data is pointers?
How do I get OpenGL to get that the data is pointers?
You don't.
The whole point of buffer objects is that the data lives in GPU-accessible memory. An pointer is an address, and a pointer to a CPU-accessible object is a pointer to a CPU address. And therefore is not a pointer to GPU-accessible memory.
Furthermore, accessing indirect data structures like that is incredibly inefficient. Having to do two pointer indirection just to access a single value basically destroys all chance of cache coherency on memory accesses. And without that, every independent particle is a cache miss.
That's bad. Which is why OpenGL doesn't let you do that. Or at least, it doesn't let you do it directly.
The correct way to do this is to work with a flat vector<Particle>, and move them around as needed.
glBufferData requires a pointer to an array of the data you wish to use. In your case, a GLfloat[] would be used for the vertices. You could write a function which creates a GLfloat[] from the vector of particles. The code I use creates a GLfloat[] and then passes it as a pointer to a constructor which then sets the buffer data. Here is my code;
Creating the Vertex Array - GlFloat[]
GLfloat vertices[] = { 0, 0, 0,
0, 3, 0,
8, 3, 0,
8, 0, 0 };
After I have created the vertices I then create a buffer object (Which just creates a new buffer and sets it's data);
Buffer* vbo = new Buffer(vertices, 4 * 3, 3);
The constructor for my buffer object is;
Buffer::Buffer(GLfloat* data, GLsizei count, GLuint componentCount) {
m_componentCount = componentCount;
glGenBuffers(1, &m_bufferID);
glBindBuffer(GL_ARRAY_BUFFER, m_bufferID);
glBufferData(GL_ARRAY_BUFFER, count * sizeof(GLfloat), data, GL_STATIC_DRAW); //Set the buffer data to the GLFloat pointer which points to the array of vertices created earlier.
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
After this array has been passed to the buffer, you can delete the object to save memory however it is recommended to hold onto it in case it is reused later.
For more information and better OpenGL practices I recommend you check out the following youtube playlist by TheChernoProject. https://www.youtube.com/watch?v=qTGMXcFLk2E&list=PLlrATfBNZ98fqE45g3jZA_hLGUrD4bo6_&index=12

glMultiDrawElements VBOs

I have a model i want to render with glMultiDrawElements. Preparing the data and rendering it using simple vectors works fine, but fails when i use vertex buffers. Apparently i make some kind of mistake when calculating the buffer offsets. First the working code:
I a first step i prepare the data for later use (contains pseudo code to make it easier to read):
for(each face in the model){
const Face &f = *face;
drawSizes.push_back(3);
for(int i=0;i<f.numberVertices;++i){
const Vertex &v = vertices[f.vertices[i]]]; // points to vertex array
vertexArray.push_back(v.x);
indexArray.push_back(vertexArray.size() - 1);
vertexArray.push_back(v.y);
indexArray.push_back(vertexArray.size() - 1);
vertexArray.push_back(v.z);
indexArray.push_back(vertexArray.size() - 1);
normalArray.push_back(f.normalx);
normalArray.push_back(f.normaly);
normalArray.push_back(f.normalz);
}
}
int counter = 0;
for(each face in the model){
vertexIndexStart.push_back(&indexArray[counter*3]);
offsetIndexArray.push_back(static_cast<void*>(0) + counter*3);
counter++;
}
drawSizes is a vector<Glint>
vertexArray is a vector<GLfloat>
indexArray is a vector<GLint>
vertexIndexStart is a vector<Glvoid *>
offsetIndexArray is a vector<GLvoid *>
I now draw this with the glMultiDrawElements-function in the following way:
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glVertexPointer(3,GL_FLOAT,3*sizeof(GLfloat),&vertexArray[0]);
glNormalPointer(GL_FLOAT,0,&normalArray[0]);
glMultiDrawElements(GL_POLYGON,&drawSizes[0],GL_UNSIGNED_INT,&vertexIndexStart[0],vertexIndexStart.size());
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
and it draws the model just as it should, altough the performance is not that much better than the immediate mode.
When i now try to buffer the created data and render the model using buffers it apparently does not work. Again in a first step i preprocess the already processed data:
glGenBuffers(2,buffers);
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glBufferData(GL_ARRAY_BUFFER,sizeof(vertexArray),&vertexArray[0],GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexArray),&indexArray[0],GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
buffers is a GLuint[]
Then i try to render the data:
glEnableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
glVertexPointer(3,GL_FLOAT,3*sizeof(GLfloat),0);
glMultiDrawElements(GL_POLYGON,&drawSizes[0],GL_UNSIGNED_INT,&offsetIndexArray[0],vertexIndexStart.size());
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
glDisableClientState(GL_VERTEX_ARRAY);
which leads to an empty screen. Any ideas?
Edit: I now use the correct indices as suggested but i still don't get the desired result.
This is wrong:
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(vertexIndexStart),&vertexIndexStart[0],GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
The element array buffer should contain the index array, which means the indices into the vertex arrays, not the indices into the index array.
Please also note that your code is using lots of deprecated GL features (builtin attributes, probably even the fixed-function pipeline, drawing without VAOs), and will not work in a core profile of modern OpenGL.
Speaking of modern GL: That further level of indirection, where the parameter array for glMultiDrawElements itself comes from a buffer object, is even supported in modern GL via glMultiDrawElemetnsIndirect.

glDrawElements doesn't render all the points

In the first place, I'm rendering a point cloud with OpenGL.
// The object pointCloud wraps some raw data in different buffers.
// At this point, everything has been allocated, filled and enabled.
glDrawArrays(GL_POINTS, 0, pointCloud->count());
This works just fine.
However, I need to render a mesh instead of just points. To achieve that, the most obvious way seems to be using GL_TRIANGLE_STRIP and glDrawElements with the good array of indices.
So I start by transforming my current code by something that should render the exact same thing.
// Creates a set of indices of all the points, in their natural order
std::vector<GLuint> indices;
indices.resize(pointCloud->count());
for (GLuint i = 0; i < pointCloud->count(); i++)
indices[i] = i;
// Populates the element array buffer with the indices
GLuint ebo = -1;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size(), indices.data(), GL_STATIC_DRAW);
// Should draw the exact same thing as the previous example
glDrawElements(GL_POINTS, indices.size(), GL_UNSIGNED_INT, 0);
But it doesn't work right. It's rendering something that seems to be only the first quarter of the points.
If I mess with the indices range by making it 2 or 4 times smaller, the same points are displayed. If it's 8 times smaller, only the first half of them is.
If I fill it with only even indices, one half of the same set of points is shown.
If I start it at the half of the set, nothing is shown.
There's obviously something that I'm missing about how glDrawElement behaves in comparison to glDrawArrays.
Thanks in advance for your help.
The size passed as the second argument to glBufferData() is in bytes. The posted code passes the number of indices instead. The call needs to be:
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
indices.size() * sizeof(GLuint), indices.data(), GL_STATIC_DRAW);

"Access Violation Reading Location" with Vertex Buffer

I am trying to convert the following piece of code into one that uses a vertex buffer:
glBegin (GL_QUADS);
glTexCoord2fv (&_vertex[ci->index_list[7]].uv.x);
glVertex3fv (&_vertex[ci->index_list[7]].position.x);
glVertex3fv (&_vertex[ci->index_list[5]].position.x);
glVertex3fv (&_vertex[ci->index_list[3]].position.x);
glVertex3fv (&_vertex[ci->index_list[1]].position.x);
glEnd ();
My faulty code partly looks like this:
GLfloat * p = (GLfloat *) malloc(sizeof(GLfloat)*14);
//Memcopies vertices into p pointer
memcpy(&p[counter+0], &_vertex[ci->index_list[7]].uv.x, sizeof(GLfloat)*2);
memcpy(&p[counter+2], &_vertex[ci->index_list[7]].position.x, sizeof(GLfloat)*3);
memcpy(&p[counter+5], &_vertex[ci->index_list[5]].position.x, sizeof(GLfloat)*3);
memcpy(&p[counter+8], &_vertex[ci->index_list[3]].position.x, sizeof(GLfloat)*3);
memcpy(&p[counter+11], &_vertex[ci->index_list[1]].position.x, sizeof(GLfloat)*3);
glGenBuffers(1, &vboId1);
glBindBuffer(GL_ARRAY_BUFFER, vboId1);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*14, p, GL_STATIC_DRAW_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(GLfloat)*14, (GLfloat*)0);
glVertexPointer(3, GL_FLOAT, 0, 2+(GLfloat*)0);
glDrawArrays(GL_QUADS, 0, 1);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
However, I get an "Access violation reading location" error on the glDrawArrays line. Any ideas what could be wrong here? I am very new to OpenGL/graphics and pretty sure I'm messing up something obvious.
This is not going to work. Immediate mode allowed you to omit respecifying unchanged attributes between vertices. But with vertex arrays, you cannot do that. What you currently do is telling the GL that it finds the TexCoords of the i-th vertex at byte offset 14*sizeof(GLfloat)*i in the buffer. For the first vertex, it will work, but for the second, you try to access data beyond the end of the buffer.
You have to duplicate that data, so that every vertex has exactly the same attributes, in the same layout. Basically, you need one vertex array per attribute, with one entry for every vertex, no matter it the value did change or not.
Better view a vertex as not just the position (specified by the glVertex command), but the complete n-tupel of relevant attributes. If any single component of any attribute differs, it is not to be considered the same vertex anymore.

Problems using VBOs to render vertices - OpenGL

I am transferring over my vertex arrays functions to VBOs to increase the speed of my application.
Here was my original working vertex array rendering function:
void BSP::render()
{
glFrontFace(GL_CCW);
// Set up rendering states
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(Vertex), &vertices[0].x);
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), &vertices[0].u);
// Draw
glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, indices);
// End of rendering - disable states
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
Worked great!
Now I am moving them into VBOs and my program actually caused my graphics card to stop responding. The setup on my vertices and indices are exactly the same.
New setup:
vboId is setup in the bsp.h like so: GLuint vboId[2];
I get no error when I just run the createVBO() function!
void BSP::createVBO()
{
// Generate buffers
glGenBuffers(2, vboId);
// Bind the first buffer (vertices)
glBindBuffer(GL_ARRAY_BUFFER, vboId[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Now save indices data in buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboId[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
}
And the rendering code for the VBOS. I am pretty sure it's in here. Just want to render whats in the VBO like I did in the vertex array.
Render:
void BSP::renderVBO()
{
glBindBuffer(GL_ARRAY_BUFFER, vboId[0]); // for vertex coordinates
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboId[1]); // for indices
// do same as vertex array except pointer
glEnableClientState(GL_VERTEX_ARRAY); // activate vertex coords array
glVertexPointer(3, GL_FLOAT, 0, 0); // last param is offset, not ptr
// draw the bsp area
glDrawElements(GL_TRIANGLES, numVertices, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));
glDisableClientState(GL_VERTEX_ARRAY); // deactivate vertex array
// bind with 0, so, switch back to normal pointer operation
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
Not sure what the error is but I am pretty sure I have my rendering function wrong. Wish there was a more unified tutorial on this as there are a bunch online but they are often contradicting eachother.
In addition what Miro said (the GL_UNSIGNED_BYTE should be GL_UNSIGNED_SHORT), I don't think you want to use numVertices but numIndices, like in your non-VBO call.
glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, 0);
Otherwise your code looks quite valid and if this doesn't fix your problem, maybe the error is somewhere else.
And by the way the BUFFER_OFFSET(i) thing is usuaully just a define for ((char*)0+(i)), so you can also just pass in the byte offset directly, especially when it's 0.
EDIT: Just spotted another one. If you use the exact data structures you use for the non-VBO version (which I assumed above), then you of course need to use sizeof(Vertex) as stride parameter in glVertexPointer.
If you are passing same data to glDrawElements when you aren't using VBO and same data to VBO buffer. Then parameters little differs, without FBO you've used GL_UNSIGNED_SHORT and with FBO you've used GL_UNSIGNED_BYTE. So i think VBO call should look like that:
glDrawElements(GL_TRIANGLES, numVertices, GL_UNSIGNED_SHORT, 0);
Also look at this tutorial, there are VBO buffers explained very well.
How do you declare vertices and indices?
The size parameter to glBufferData should be the size of the buffer in bytes and if you pass sizeof(vertices) it will return the total size of the declared array (not just what is allocated).
Try something like sizeof(Vertex)*numVertices and sizeof(indices[0])*numIndices instead.