I've been using std::vector<glm::vec3>'s for storing vertex attributes and everything was working just fine, rendering all kinds of different meshes. But after refactoring so that my vertex attributes are stored in a struct I can't get the simplest thing to render. Here is the struct (simplified):
struct Vertex{
GLfloat x, y, z; //Vertex
GLfloat r, g, b, a; //Color
};
I have two std::vector's, one for storing the vertex attributes and one for the index:
std::vector<GLushort> indices;
std::vector<struct Vertex> vertices;
In the initialization function I fill these vectors with a simple green triangle:
struct Vertex vertex1;
vertex1.x=1.0;
vertex1.y=0.0;
vertex1.z=0.0;
vertex1.r=0.0;
vertex1.g=1.0;
vertex1.b=0.0;
vertex1.a=1.0;
vertices.push_back(vertex1);
struct Vertex vertex2;
vertex2.x=0.0;
vertex2.y=1.0;
vertex2.z=0.0;
vertex2.r=0.0;
vertex2.g=1.0;
vertex2.b=0.0;
vertex2.a=1.0;
vertices.push_back(vertex2);
struct Vertex vertex3;
vertex3.x=1.0;
vertex3.y=1.0;
vertex3.z=0.0;
vertex3.r=0.0;
vertex3.g=1.0;
vertex3.b=0.0;
vertex3.a=1.0;
vertices.push_back(vertex3);
indices.push_back(1);
indices.push_back(2);
indices.push_back(3);
Then I bind the buffers:
glGenBuffers(1, &ibo_elements);
glBindBuffer(GL_ARRAY_BUFFER, ibo_elements);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(struct Vertex), &vertices[0], GL_STATIC_DRAW);
glGenBuffers(1, &elementbuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLushort), &indices[0], GL_STATIC_DRAW);
Then after setting up the shader program and binding attribute names I use glutDisplayFunc to run this callback:
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
void onDisplay()
{
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glUseProgram(program);
glBindBuffer(GL_ARRAY_BUFFER, ibo_elements);
glVertexAttribPointer(
attribute_v_coord,
3,
GL_FLOAT,
GL_FALSE,
sizeof(struct Vertex),
BUFFER_OFFSET(0)
);
glEnableVertexAttribArray(attribute_v_coord);
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
glVertexAttribPointer(
attribute_v_color,
4,
GL_FLOAT,
GL_FALSE,
sizeof(struct Vertex),
BUFFER_OFFSET(sizeof(GLfloat)*3)
);
glEnableVertexAttribArray(attribute_v_color);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer);
int size; glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &size);
glDrawElements(GL_TRIANGLES, size/sizeof(GLushort), GL_UNSIGNED_SHORT, 0);
glDisableVertexAttribArray(attribute_v_coord);
glDisableVertexAttribArray(attribute_v_color);
glutSwapBuffers();
}
Everything is very similar to what I had working before. So I'm guessing it has something to do with the change of data structure. Valgrind shows this error:
==5382== Invalid read of size 4
==5382== at 0x404EF6A: ??? (in /tmp/glR69wrn (deleted))
==5382== by 0x870E8A9: ??? (in /usr/lib/libnvidia-glcore.so.325.15)
==5382== by 0x200000003: ???
==5382== by 0x404EEBF: ??? (in /tmp/glR69wrn (deleted))
==5382== by 0x2: ???
==5382== by 0xAFFC09F: ???
==5382== by 0x41314D3: ???
==5382== by 0x40E6FFF: ??? (in /dev/nvidia0)
==5382== by 0xFFFFFFFE: ???
==5382== Address 0x28 is not stack'd, malloc'd or (recently) free'd
Am I not defining the vertex attribute pointers correctly? It looks like OpenGL is trying to read a float that was never set properly.
You should use a single VBO for every vertex attrib pointer in this situation. You are supplying a single datastore, with interleaved data. All you need to do is alter the calls that setup the vertex attrib pointers so that they have the correct stride and base offset address. So this "colorbuffer" VBO (which is a poor choice of names, since OpenGL already has something called a colorbuffer) is more than likely a source of your problems.
Another problem, as mentioned elsewhere, is that your element indices are starting at 1. You have 3 vertices in this example, the element buffer should be populated with some combination of 0,1,2. Having 3 in your element buffer is going to lead to undefined behavior at draw-time. A lot of times drivers will not crash if you use an invalid index, and the GL unfortunately does not have an error state for index out of bounds. Often you only know something is wrong in this situation because garbage appears on your screen.
I am concerned that you don't even know how many elements are in your IBO without querying that information from the GL state machine. That is poor application design, sorry to say. You should definitely know how many elements you want to draw before hand. VBOs should be wrapped in a data structure or class anyway (that includes at the very least the number of elements allocated), you don't want to simply toss around buffer object handles with no idea what they represent.
Also it can be wasteful to use floating-point values for vertex color, you almost never need them (GLubyte and 0-255 usually works well enough). 1 GLfloat takes as much memory as 4 GLubytes, and you are using 4 GLfloats... Using 4 GLubytes can also help with alignment if you opt to use xyz instead of xyzw for vertex position.
On older hardware 4x GLubyte colors were a "fast path" for hardware T&L. They still take less memory on newer hardware so they're a win in virtually all situations :)
indices.push_back(0);
indices.push_back(1);
indices.push_back(2);
also, what do you get when you print out size?
I'm also in the habit of unbinding buffers when not needed:
glBindBuffer(GL_ARRAY_BUFFER, 0); //etc
and finally...
glBindBuffer(GL_ARRAY_BUFFER, colorbuffer); //what's colorbuffer?
(should this line be here at all since you're interleaving from the same ibo_elements buffer?)
Related
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).
I've hopefully understood the following correct:
When making different VBO:s in OpenGL for vertices, normals and indices I can use less memory because of reusing but it isn't as effective.
When using interleaved VBO:s the normal routine is that the same vertices and normals will be written more than once, right?
My question is if the use of more memory is something people just accept for the gain in speed, or is it worth it to do some kind of trick to "reuse" already given data with indices or something similar?
interleaved VBO holds essentially a array of structs:
struct vertexAttr{
GLfloat posX, posY, posZ;
GLfloat normX, normY, normZ;
}
glBindBuffer(GL_ARRAY_BUFFER, vert);
vertexAttr* verts = new vertexAttr[numVerts];
//fill verts
glBuffer(GL_ARRAY_BUFFER, numVerts, verts, GL_STATIC_DRAW);
delete[] verts;
glBindProgram(prog);
glVertexAttribPointer(posAttr, 3, GL_FLOAT, false, sizeof(vertexAttr), 0);
glVertexAttribPointer(normAttr, 3, GL_FLOAT, false, sizeof(vertexAttr), offsetof(vertexAttr, normX));
you still need to use a separate buffer for the indexes.
I have generally learned OpenGL Interoperability with CUDA, but my problem is like this:
I have a lot of arrays, some for vertex, some for norm and some for alpha value alone, and some pointers to these arrays on device memory (something like dev_ver, dev_norm) which are used in kernel. I have already mapped the resource and now I want to use these data in shaders to make some effects. My rendering code is like this:
glUseProgram (programID);
glBindBuffer (GL_ARRAY_BUFFER, vertexBuffer_0);
glBufferData(GL_ARRAY_BUFFER, size, _data_on_cpu_0, GL_DYNAMIC_DRAW);
glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glBindBuffer (GL_ARRAY_BUFFER, vertexBuffer_1);
glBufferData(GL_ARRAY_BUFFER, size, _data_on_cpu_1, GL_DYNAMIC_DRAW);
glVertexAttribPointer (1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glBindBuffer (GL_ARRAY_BUFFER, vertexBuffer_2);
glBufferData(GL_ARRAY_BUFFER, size, _data_on_cpu_2, GL_DYNAMIC_DRAW);
glVertexAttribPointer (2, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray (0);
glEnableVertexAttribArray (1);
glEnableVertexAttribArray (2);
glDrawArrays (GL_TRIANGLES, 0, _max_);
glDisableVertexAttribArray (0);
glDisableVertexAttribArray (1);
glDisableVertexAttribArray (2);
However, now I have no _data_on_cpu_, is it still possible to do the same thing ? The sample in cuda 6.0 is something like this:
glBindBuffer(GL_ARRAY_BUFFER, posVbo);
glVertexPointer(4, GL_FLOAT, 0, 0);
glEnableClientState(GL_VERTEX_ARRAY);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, normalVbo);
glNormalPointer(GL_FLOAT, sizeof(float)*4, 0);
glEnableClientState(GL_NORMAL_ARRAY);
glColor3f(1.0, 0.0, 0.0);
glDrawArrays(GL_TRIANGLES, 0, totalVerts);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
I don't exactly understand how this could work and what to do in my case.
By the way, the method I have used is to cudaMemcpy the dev_ to host and do the render like usual, but this is obviously not efficient, because when I do rendering I again send the data back to GPU by OpenGL (if I'm right).
It's not really clear what your asking for, you mention CUDA yet none of the code you have posted is CUDA specific. I'm guessing vertexbuffer_2 contains additional per vertex information you want to access in the shader?
OpenGL calls are as efficient as you will get it, they aren't actually copying any data back from device to host. They are simply sending the addresses to the device, telling it where to get the data from and how much data to use to render.
You only need to fill the vertex and normal information at the start of your program, there isn't much reason to be changing this information during execution. You can then change data stored in texture buffers to pass additional per entity data to shaders to change model position, rotation, colour etc.
When you write your shader you must include in it;
attribute in vec3 v_data; (or similar)
When you init your shader you must then;
GLuint vs_v_data = glGetAttribLocation(p_shaderProgram, "v_data");
Then instead of your;
glBindBuffer (GL_ARRAY_BUFFER, vertexBuffer_2);
glBufferData(GL_ARRAY_BUFFER, size, _data_on_cpu_2, GL_DYNAMIC_DRAW);
glVertexAttribPointer (2, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
You use;
glEnableVertexAttribArray (vs_v_data);
glBindBuffer (GL_ARRAY_BUFFER, vertexBuffer_2);
glBufferData(GL_ARRAY_BUFFER, size, _data_on_cpu_2, GL_DYNAMIC_DRAW);
glVertexAttribPointer (vs_v_data, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
This should let you access a float3 inside your vshaders called v_data that has whatevers stored in vertexBuffer_2, presumably secondary vertex information to lerp between for animation.
A simple shader for this that simply repositions vertices based on an input tick
#version 120
attribute in float tick;
attribute in vec3 v_data;
void main()
{
gl_Vertex.xyz = mix(gl_Vertex.xyz, v_data, tick);
}
If you want per entity data instead of/in addition to per vertex data, you should be doing that via texture buffers.
If your trying to access vertex buffer obj data inside kernels you need to use a bunch of functions;
cudaGraphicsGLRegisterBuffer() This will give you a resource pointer to the buffer, execute this once after you initially setup the vbo.
cudaGraphicsMapResources() This will map the buffer (you can use it in CUDA but not gl)
cudaGraphicsResourceGetMappedPointer() This will give you a device pointer to the buffer, pass this to the the kernel.
cudaGraphicsUnmapResources() This will unmap the buffer (you can use it in gl, but not CUDA)
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.
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.