Vertex Buffer Object Slides are adapted from: http://www.songho.ca/opengl/gl_vbo.html http://www.opengl.org/wiki/Vertex_Buffer_Objects CPU/Client Data for rendering Main Memory GPU/Server Video Memory Host to the main application Host to the rendering task Rendering speed depends on how fast data (vertices and vertex attributes) can be sent to the GPU. OpenGL tries to minimize the number of function calls needed for data transfer and rendering Display List GlBegin-GlEnd pair Vertex Array Vertex Buffer Object Immediate mode: using GlBegin() and GlEnd() What is the most basic way to render a model? glBegin(GL_TRIANGLES); for(int i=0; i<num_vertices*3; i=i+3) { glVertex3f( vertices[i], vertices[i+1], vertices[i+2] ); // Optionally other vertex attributes glNormal3f( normals[i], normals[i+1], normals[i+2] ); } glEnd(); Slow because of very high number of OpenGL commands issued !! Vertex Array • Store vertex data in a set of arrays including vertex coordinates, normal, texture coordinates and color information • Draw geometric primitives by dereferencing the array elements with array indices. • Basically you need to specify (instead of writing a loop): – Array location – Primitive type – Number of primitives to draw • OpenGL v1.2 or greater needed Vertex Array: Implementation // array holding vertex coords GLfloat vertices[] = {...}; In your case, this will be the Array containing polygons of The model Read your model here ... // activate and specify pointer to vertex array glEnableClientState(GL_VERTEX_ARRAY); // and specify pointer to vertex array glVertexPointer(3, GL_FLOAT, 0, vertices); // draw a cube glDrawArrays(GL_QUADS, 0, 24); // deactivate vertex arrays after drawing glDisableClientState(GL_VERTEX_ARRAY); Similarly, Normal Array, Color Array etc are enabled here Similar pointers to other arrays Are specified here In your case, your model Drawing vertices with indices May be useful since your .ply model contains vertices, and then indices // vertex co-ords: 8 in this example GLfloat vertices[] = {...}; // 24 of indices GLubyte indices[] = {0,1,2,3, 0,3,4,5, 0,5,6,1, 1,6,7,2, 7,4,3,2, 4,7,6,5}; ... // activate and specify pointer to vertex array glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, 0, vertices); glDrawElements(GL_QUADS, 24, GL_UNSIGNED_BYTE, indices); // deactivate vertex arrays after drawing glDisableClientState(GL_VERTEX_ARRAY); Display List • Group of OpenGL commands stored (compiled) for later execution • One time process: All vertex and pixel data are evaluated and copied into the display list memory on the server • For optimal performance, put matrix transforms, lighting and material calculation inside display list, if possible • Fastest method to draw static data Display List: Implementation // create one display list GLuint list = glGenLists(1); void draw() { If NOT created // compile the display list, store a triangle in it glNewList(list, GL_COMPILE); Red block // GLBegin-GLEnd pair // Or, your vertex array code here else glEndList(); Blue block ... // draw the display list glCallList(index); ... // delete it if it is not used any more glDeleteLists(index, 1); } Vertex Buffer Object (VBO) • Motivation – Combine the benefits of vertex array and display list, shredding off their disadvantages – Vertex array is a client (CPU) side implementation – Display list works on server (GPU) side, but data cannot be updated – VBO is a server side functionality which allows reading and updating of data (vertices) by the client side • Definition (from OpenGL) – Mechanism for storing vertex data in "fast" memory (for example video RAM), thereby allowing for significant increases in vertex throughput between the application (CPU) and the GPU Creating a VBO • 3 steps: – – Generate a new buffer object with glGenBuffers() • creates buffer objects and returns the identifiers of the buffer objects • Syntax: void glGenBuffers(GLsizei n, GLuint* ids) Bind the buffer object with glBindBuffer() • hook the buffer object with the corresponding ID • – Syntax: void glBindBuffer(GLenum target, GLuint id) Copy vertex data to the buffer object with glBufferData() • copy the data into the buffer object • Syntax: void glBufferData(GLenum target, GLsizei size, const void* data, GLenum usage) – Specify Access pattern • • STATIC, STREAM, DYNAMIC DRAW, COPY, READ Implementation // ID of VBO GLuint vboId; // create vertex array GLfloat* vertices = new GLfloat[vCount*3]; Read Model Here ... // generate a new VBO and get the associated ID glGenBuffers(1, &vboId); // bind VBO in order to use glBindBuffer(GL_ARRAY_BUFFER, vboId); // upload data to VBO glBufferData(GL_ARRAY_BUFFER, datasize, vertices, GL_STATIC_DRAW); // it is safe to delete after copying data to VBO delete [ ] vertices; ... // delete VBO when program terminated glDeleteBuffers(1, &vboId); In bytes Drawing a VBO • Rendering VBO is similar to vertex array • Only difference: the pointer to the vertex array is now an offset to a currently bound buffer object • Example: // Activate vertex array glEnableClientState(GL_VERTEX_ARRAY); // activate vertex coords array glVertexPointer(3, GL_FLOAT, 0, 0); // last param is offset, not ptr // draw 6 quads using offset of index array glDrawElements(GL_QUADS, 24, GL_UNSIGNED_BYTE, 0); // deactivate vertex array glDisableClientState(GL_VERTEX_ARRAY); Updating a VBO • Recall the advantage over display list: client can read and modify the buffer object data • Option 1: – Copy new data into the bound VBO with glBufferDataARB() or glBufferSubDataARB() – Need to have 2 copies of vertex data: one in your application and the other in VBO • Option 2: – map the buffer object into client's memory, so that client can update data with the pointer to the mapped buffer Details of option 2 • map the buffer object into client's memory – Syntax: void* glMapBuffer(GLenum target, GLenum access) • synchronization issue – If GPU is still working with the buffer object, glMapBuffer() will not return until GPU finishes its job • After modifying the data of VBO, it must be unmapped the buffer object from the client's memory – Syntax: GLboolean glUnmapBuffer(GLenum target) Implementation // bind then map the VBO glBindBuffer(GL_ARRAY_BUFFER, vboId); float* ptr = (float*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); // if the pointer is valid (mapping was successful), update VBO if(ptr) { updateMyVBO(ptr, ...); // modify buffer data glUnmapBuffer(GL_ARRAY_BUFFER); // unmap it after use } // you can draw the updated VBO ...