Using VBO to draw lines from a point vector in OpenGL

I have a simple OpenGL program that I'm trying to use Vertex Buffer Objects to render instead of the old glBegin () - glEnd (). Basically, the user clicks on the window indicating the starting point, and then presses the key to generate subsequent points that OpenGL draws as a string.

I implemented this with glBegin () and glEnd (), but did not manage to use VBO. I am wondering, the problem is that after initializing VBO, I add more vertices for which it does not have allocated memory, and therefore does not display them.

Edit: Also, I'm a little confused about how he knows exactly which values ​​in the vertex structure to use for x and y, as well as for r, g, b. I could not find a clear example of this.

#include <windows.h> #include <stdio.h> #include <stdlib.h> #include <Math.h> #include <iostream> #include <vector> #include <GL/glew.h> #include <GL/glut.h> struct vertex { float x, y, u, v, r, g, b; }; const int D = 10; // distance const int A = 10; // angle const int WINDOW_WIDTH = 500, WINDOW_HEIGHT = 500; std::vector<vertex> vertices; boolean start = false; GLuint vboId; void update_line_point() { vertex temp; temp.x = vertices.back().x + D * vertices.back().u; temp.y = vertices.back().y + D * vertices.back().v; temp.u = vertices.back().u; temp.v = vertices.back().v; vertices.push_back(temp); } void update_line_angle() { float u_prime, v_prime; u_prime = vertices.back().u * cos(A) - vertices.back().v * sin(A); v_prime = vertices.back().u * sin(A) + vertices.back().v * cos(A); vertices.back().u = u_prime; vertices.back().v = v_prime; } void initVertexBuffer() { glGenBuffers(1, &vboId); glBindBuffer(GL_ARRAY_BUFFER, vboId); glBufferData(GL_ARRAY_BUFFER, sizeof(vertex) * vertices.size(), &vertices[0], GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); } void displayCB() { glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0, WINDOW_WIDTH, 0, WINDOW_HEIGHT); if (start) { glBindBuffer(GL_ARRAY_BUFFER, vboId); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glVertexPointer(2, GL_FLOAT, sizeof(vertex), &vertices[0]); glColorPointer(3, GL_FLOAT, sizeof(vertex), &vertices[0]); glDrawArrays(GL_LINE_STRIP, 0, vertices.size()); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glBindBuffer(GL_ARRAY_BUFFER, 0); } /***** this is what I'm trying to achieve glColor3f(1, 0, 0); glBegin(GL_LINE_STRIP); for (std::vector<vertex>::size_type i = 0; i < vertices.size(); i++) { glVertex2f(vertices[i].x, vertices[i].y); } glEnd(); *****/ glFlush(); glutSwapBuffers(); } void mouseCB(int button, int state, int x, int y) { if (state == GLUT_DOWN) { vertices.clear(); vertex temp = {x, WINDOW_HEIGHT - y, 1, 0, 1, 0, 0}; // default red color vertices.push_back(temp); start = true; initVertexBuffer(); } glutPostRedisplay(); } void keyboardCB(unsigned char key, int x, int y) { switch(key) { case 'f': if (start) { update_line_point(); } break; case 't': if (start) { update_line_angle(); } break; } glutPostRedisplay(); } void initCallbackFunc() { glutDisplayFunc(displayCB); glutMouseFunc(mouseCB); glutKeyboardFunc(keyboardCB); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH); glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT); glutInitWindowPosition(100, 100); glutCreateWindow("Test"); initCallbackFunc(); // initialize glew GLenum glewInitResult; glewExperimental = GL_TRUE; glewInitResult = glewInit(); if (GLEW_OK != glewInitResult) { std::cerr << "Error initializing glew." << std::endl; return 1; } glClearColor(1, 1, 1, 0); glutMainLoop(); return 0; } 
+7
opengl vertex-buffer
source share
2 answers

If you have a VBO binding, then the pointer argument for gl*Pointer() calls is interpreted as the byte offset from the start of the VBO, not the actual pointer. However, your use is consistent with using an array of vertices.

So, for your vertex struct x starts at byte zero and r starts at sizeof(float) * 4 byte.

In addition, your mouse callback will reset your vertex vector on each call, so you can never have multiple vertices in it at any time. He also passed the VBO names through glGenBuffers() in initVertexBuffer() .

Take a picture:

 #include <GL/glew.h> #include <GL/glut.h> #include <iostream> #include <vector> struct vertex { float x, y; float u, v; float r, g, b; }; GLuint vboId; std::vector<vertex> vertices; void mouseCB(int button, int state, int x, int y) { y = glutGet( GLUT_WINDOW_HEIGHT ) - y; if (state == GLUT_DOWN) { vertex temp = {x, y, 1, 0, 1, 0, 0}; // default red color vertices.push_back(temp); glBindBuffer(GL_ARRAY_BUFFER, vboId); glBufferData(GL_ARRAY_BUFFER, sizeof(vertex) * vertices.size(), &vertices[0], GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); } glutPostRedisplay(); } void displayCB() { glClearColor(1, 1, 1, 0); glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); double w = glutGet( GLUT_WINDOW_WIDTH ); double h = glutGet( GLUT_WINDOW_HEIGHT ); glOrtho( 0, w, 0, h, -1, 1 ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); if ( vertices.size() > 1 ) { glBindBuffer(GL_ARRAY_BUFFER, vboId); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glVertexPointer(2, GL_FLOAT, sizeof(vertex), (void*)(sizeof( float ) * 0)); glColorPointer(3, GL_FLOAT, sizeof(vertex), (void*)(sizeof( float ) * 4)); glDrawArrays(GL_LINE_STRIP, 0, vertices.size()); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glBindBuffer(GL_ARRAY_BUFFER, 0); } glutSwapBuffers(); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH); glutInitWindowSize(500, 500); glutInitWindowPosition(100, 100); glutCreateWindow("Test"); // initialize glew glewExperimental = GL_TRUE; GLenum glewInitResult = glewInit(); if (GLEW_OK != glewInitResult) { std::cerr << "Error initializing glew." << std::endl; return 1; } glGenBuffers(1, &vboId); glutDisplayFunc(displayCB); glutMouseFunc(mouseCB); glutMainLoop(); return 0; } 
+4
source share

VBO is a buffer located somewhere in memory (almost always in dedicated GPU memory - VRAM) of a fixed size. This size is specified in glBufferData , and you also provide the GL pointer for copying at the same time. The key word here is copy. Everything you do with the vector after glBufferData is not reflected in VBO.

You must be bound and make another call to glBufferData after changing the vector. You will probably also get better performance from glBufferSubData or glMapBuffer if VBO is already large enough to handle new data, but in a small application like this, there is basically no performance hit when calling glBufferData every time.

Also, to answer another question about the values ​​you need to select, x, y, etc. The way you set up your VBO is that the values ​​alternate. so in memory your vertices will look like this:

 +------------------------------------------------- | x | y | u | v | r | g | b | x | y | u | v | ... +------------------------------------------------- 

You tell OpenGL where your vertices and colors are located with glVertexPointer and glColorPointer respectively.

  • The size parameter determines the number of elements for each vertex. In this case, it is 2 for vertices and 3 for flowers.
  • The type parameter indicates the type of each element. In your case, this is GL_FLOAT for both.
  • The stride parameter is the number of bytes to skip from the beginning of one vertex to the beginning of the next. With interlacing like yours, it's just sizeof(vertex) for both.
  • The last parameter, a pointer, is not really a pointer to your vector in this case. When a VBO is bound, the pointer becomes a byte offset in the VBO. For vertices, this should be 0 , since the first vertex begins with the very first VBO byte. For colors, this should be 4 * sizeof(float) , since the first color is preceded by 4 floats.
+4
source share

All Articles