Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>To draw primitives, you give OpenGL a list of vertices and the pattern in which to connect them (eg to form lines, triangles etc). The simplest way to do this is immediate mode (<code>glBegin</code>/<code>glVertex3f</code>/<code>glEnd</code>). Immediate mode is quite slow and it's much faster to pass all vertices at once via "vertex arrays" (not vertex array objects (VAO), they're different), where they're laid out sequentially in a 1D array just like your <code>g_vertex_buffer_data</code>. Vertex arrays are when you pass a pointer to your array in main memory to <code>glVertexPointer</code>. This is faster but sends the entire array to the GPU every time you draw. A vertex buffer object (VBO) allows you to send and store the array in GPU memory. With a VBO, only a draw call is needed to be sent and the data is already on the GPU so there's no transfer and it's much faster. VAOs group the <code>glVertexPointer</code> arguments to make binding faster and <code>glDraw*Indirect</code> allow drawing using parameters already in GPU memory, but I'd leave those for later.</p> <p>Most tutorials start off with hard coded vertices, but of course for an end application this isn't practical. You want to store many bits of arbitrary geometry. A mesh class, similar to your <code>lines</code> is quite common. The key point is that a mesh has a list of vertices. You can add an array of indices to re-reference existing vertices to form primitives, saving memory and computation of duplicate vertices.</p> <p>But I'd start with immediate mode rendering for now - less things can go wrong.</p> <p>To start you off,</p> <pre><code>struct vec3f { float x, y, z; vec3f(float nx, float ny, float nz) : x(nx), y(ny), z(nz) {} }; class Mesh { std::vector&lt;vec3f&gt; vertices; public: void add(float x, float y, float z) { vertices.push_back(vec3f(x, y, z)); } void draw() { glBegin(GL_LINE_STRIP); for (size_t i = 0; i &lt; vertices.size(); ++i) glVertex3f(vertices[i].x, vertices[i].y, vertices[i].z); glEnd(); } }; </code></pre> <p>and to use it,</p> <pre><code>Mesh square; ... //Lots of add() and push_back is slow. Much faster to use //dynamic allocation yourself and copy data in bigger blocks, //but this will do for an example. square.add(-1,-1,0); square.add(-1,1,0); square.add(1,1,0); square.add(1,-1,0); square.add(-1,-1,0); //these could also be read from a file ... line.draw(); </code></pre> <p>This idea allows you to have a global <code>std::list&lt;Mesh&gt; lines;</code> for example. You can add lines to it once at initialization, from a file, or at runtime. Then your drawing code just has to call draw on each element. Later you could extend this idea to support triangles as well (eg. make <code>GL_LINE_STRIP</code> a <code>primitive</code> member). Later you can add indices, normals (here you'll want to look up interleaving vertex/normal data using the <code>stride</code> parameter of <code>gl*Pointer</code> functions), colours/materials etc.</p> <p>On to your question about using VBOs. <code>glGenBuffers</code> will gives you a unique handle to reference your VBO - simply an integer. When ever you modify or use that VBO you need to bind it.</p> <p><code>glBufferData(GL_ARRAY_BUFFER...</code> does the actual initialization/resize of the currently bound <code>GL_ARRAY_BUFFER</code> (if not already) and transfers data if the data argument is non-NULL.</p> <p><code>glVertexAttribPointer</code> will assume you're passing it an array in main memory for "vertex arrays" mentioned above unless you <code>glBindBuffer(GL_ARRAY_BUFFER, vbo)</code>, in which case the final argument becomes an offset into that VBO. After you've called <code>glVertexAttribPointer</code>.</p> <p>So,</p> <pre><code>1. glGenBuffers 2. glBufferData (while the buffer is bound) </code></pre> <p>that's initialization taken care of. On to drawing...</p> <pre><code>3. glVertexAttribPointer (while the buffer is bound) </code></pre> <p>then</p> <pre><code>4. glDrawArrays </code></pre> <p>or</p> <pre><code>4. glDrawElements (while an element array buffer is bound, containing the order in which to draw the vertices) </code></pre> <p>So to extend the mesh class, you'd want at least a <code>GLuint vertexBuffer;</code>. Maybe add a function <code>upload()</code> to generate a handle and buffer the current data. You could then call <code>vertices.clear()</code> (actually, for std::vector use <a href="https://stackoverflow.com/questions/3172571/force-a-stdvector-to-free-its-memory">this</a>) assuming you don't need the vertex data in main memory anymore. Then change the draw function to bind the vbo, call <code>glVertexPointer</code>, unbind and <code>glDrawArrays</code> (from a <code>numVertices</code> member as <code>vertices.size()</code> might be zero now).</p> <p>Here's some related posts:</p> <ul> <li><a href="https://stackoverflow.com/questions/15923075/the-best-way-to-use-vbos">The best way to use VBOs</a></li> <li><a href="https://stackoverflow.com/questions/166356/what-are-some-best-practices-for-opengl-coding-esp-w-r-t-object-orientation">What are some best practices for OpenGL coding (esp. w.r.t. object orientation)?</a></li> <li><a href="https://stackoverflow.com/questions/5091570/most-basic-working-vbo-example">Most basic working vbo example</a></li> <li>From your tutorial, <a href="http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-9-vbo-indexing/" rel="nofollow noreferrer">tutorial-9-vbo-indexing</a></li> <li><a href="http://goanna.cs.rmit.edu.au/~pknowles/SimpleVBO.c" rel="nofollow noreferrer">SimpleVBO.c</a></li> <li><a href="http://www.opengl.org/wiki/VBO_-_just_examples" rel="nofollow noreferrer">http://www.opengl.org/wiki/VBO_-_just_examples</a></li> </ul>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload