In my OpenGL program have a huge vertex buffer with data (normals,position,texcoords) for 2048x2048 points.
In each frame i reduce my indexed buffer with a LOD algorithm and bind GL_ELEMENT_ARRAY_BUFFER again.
I wonder if it makes sense to additionally reduce the vertex buffer as well, so that it only contains the used vertices from the index buffer.
So the question is, if there is a performance gain even with rebuilding and rebinding the vertex array per frame.
Related
I'm currently trying to implement sparse voxel octrees according to GPU insightss: https://www.seas.upenn.edu/~pcozzi/OpenGLInsights/OpenGLInsights-SparseVoxelization.pdf
In this book they describe how to voxelize a 3d mesh and how to create an octree as a compact represenation of the voxelized mesh. One intermediate step is to voxelize the mesh and to store the voxels in a preallocated array, where the target location in the array of any voxel is defined by an atomic counter (which I implemented)
Now I'm not sure if I can bind the first Gluint of DrawElementsIndirectCommand (which is used in the DrawElementsIndirect call) first as a GL_ATOMIC_COUNTER_BUFFER and then rebind it to the target GL_DRAW_INDIRECT_BUFFER because I want to draw the Voxels for debugging purposes now.
I assume I can rebind it, but I'm not supposed to call glBufferData again?
Currently, in my rendering engine, I have a VBO for each mesh data (1 VBO for vertices, 1 VBO for normals, 1 VBO for texture coordinates, 1 VBO for tangents and 1 VBO for bitangents) and all of them are bound together with a VAO.
I'm now thinking about changing the system to hold a single VBO containing all the mesh data (vertices, normals, etc.) but how mush will I gain from this? Speaking about speed and utility (because I may not have all the data and provide only vertices and normals if my mesh isn't textured).
You'll be seeking to reduce overall memory bandwidth. If your buffer object contains all of your attributes interleaved together then that means that your entire array object references only one single contiguous section of memory. Which is much easier for a memory subsystem to cache. It's exactly the same principle as for CPUs — the more local consecutive memory accesses are, the faster they're likely to be.
There is also a potential detriment: the general rule is that you should align your elements to whichever is the greater of the size of the element and four bytes. Which leads to some wasted space. But the benefit almost always outweighs the detriment.
Obviously the only thing that will be affected is the time the GPU takes to fetch the vertices. If you're tessellation or fill bound you won't immediately see any improvement.
I am trying to understand these two, how to use them and how they are related. Let's say I want to create a simple terrain and a textured cube. For both objects I have the array of triangles vertices and for the cube I have an array containing the texture's data. My question is: how do I use VAOs and VBOs to create and render these two?
Would I have to create a VAO and VBO for each object?
or should create a VAO for each object's VBO (vertices, texture data, etc.)?
There are many tutorials and books but I still don't get the very idea of how these concepts must be understood and used.
Fundamentally, you need to understand two things:
Vertex Array Objects (VAOs) are conceptually nothing but thin state wrappers.
Vertex Buffer Objects (VBOs) store actual data.
Another way of thinking about this is that VAOs describe the data stored in one or more VBOs.
Think of VBOs (and buffer objects in general) as unstructured arrays of data stored in server (GPU) memory. You can layout your vertex data in multiple arrays if you want, or you can pack them into a single array. In either case, buffer objects boil down to locations where you will store data.
Vertex Array Objects track the actual pointers to VBO memory needed for draw commands.
They are a little bit more sophisticated than pointers as you would know them in a language like C, however. Vertex pointers keep track of the buffer object that was bound when they were specified, the offset into its address space, stride between vertex attributes and how to interpret the underlying data (e.g. whether to keep integer values or to convert them to floating-point [0.0,1.0] by normalizing to the data type's range).
For example, integer data is usually converted to floating-point, but it is the command you use to specify the vertex pointer (glVertexAttribPointer (...) vs. glVertexAttribIPointer (...)) that determines this behavior.
Vertex Array Objects also track the buffer object currently bound to GL_ELEMENT_ARRAY_BUFFER.
GL_ELEMENT_ARRAY_BUFFER is where the command: glDrawElements (...) sources its list of indices from (assuming a non-zero binding) and there is no glElementArrayPointer (...) command. glDrawElements (...) combines the pointer and draw command into a single operation, and will use the binding stored in the active Vertex Array Object to accomplish this.
With that out of the way, unless your objects share vertex data you are generally going to need a unique set of VBOs for each.
You can use a single VAO for your entire software if you want, or you can take advantage of the fact that changing the bound VAO changes nearly the entire set of states necessary to draw different objects.
Thus, drawing your terrain and cube could be as simple as changing the bound VAO. You may have to do more than that if you need to apply different textures to each of them, but the VAO takes care of all vertex data related setup.
Your question is not easily answerable here, but rather in a tutorial. You probably already know these two websites, but if not, I'm leaving the references.
OGLDEV
OpenGL-Tutorial.org
Now trying to elucidate your questions, a Vertex Array Object is an OpenGL object designed with the goal of reducing API overhead for draw calls. You can think of it as a container for a Vertex Buffer and its associated states. Something similar perhaps to the old display-lists.
Normally, there is a 1 to 1 relationship between a VAO and a VBO; that is, each VAO contains a unique VBO. But this is not strictly necessary. You could have several VAOs referencing the same VBO.
The simplest way to model this in code, I think, would be for you to have a VAO class/type and a method to attach a VBO to it. Then give an instance of VAO to each mesh. The mesh in turn can have a reference to a VBO type that may be its own or a shared one.
What is an efficient way to pass a variably sized data (which is not unique for each vertex, but rather is common to groups of vertices) into shaders?
For example, I have three polygons with different numbers of vertices. Each polygon has a different color and is colored uniformly (each polygon's fragment has the same color). It seems ineffective to pass the polygon's color in the vertices attributes as a vector containing the same color values for each vertex in polygon. My thought is to assign to each polygon a unique number (starting from zero), create a vector with three color values (one color for each polygon), and to pass for each vertex not a color value (four floats), but the polygon number which the vertex belongs to (one integer). And have the shader fetch the polygon color from the color's vector using the polygon number as the index.
The color values for polygons can be passed in a vector of a variable length (vector whose size is not specified during compilation) through a "Shader Storage Block" where it can be accessed by the shader.
Is there other method (maybe commonly used technique) for passing variably sized vectors to shaders?
This is precisely the use case of Buffer Texture Objects.
The easiest approach is to manage the color apart from the vertex data and pass it ass a uniform to the shader. But only if the color is the same for each vertex in the vector. If however the color changes for every primitive (or each vertex) don't mind, the overhead implied by the computation with indexing etc. is way worse than simply having to flush the data on a per vertex basis to your video memory! (Unless this is already your bottleneck, but it shouldn't really be with nowadays hardware)
To rapidly flush the data from the vector for rendering, the best approach is to create a
vertex buffer object.
You basically create a large pool of vertices (and indices, depending on your precise use). Using glDrawElements (or glDrawArray) you can control how many primitive of what type shall be rendered.
Reserve a vertex buffer object with the maximal assumed size of memory you may require in the advance, so you avoid the overhead of recreating it again and again. Initialize the number of primitives to render, to 0. Each time the vector changes, copy the data to the vertex buffer object, from the first vertex to the last in the vector. Modify the number of primitives to be rendered. That's it, the complete overhead left is only flushing the vector to the vertex buffer object. No complex bookkeeping or similar required.
Would someone care to explain the difference to be between a VertexBuffer, a VertexArray, a VertexBufferObject, and a VertexArrayObject? I'm not even sure if these are all terms for different things, but I've seen all of them appear in the OpenGL spec.
I know that a VertexBuffer simply contains vertices and nothing else, once bound, and once I've set the vertex pointers, I can use DrawArrays to draw it. I've done it this way many times.
I am using what I think is a VertexArray, which stores the state of any vertex buffers that are set, and also any vertex pointers. Binding a VertexArray automatically binds the vertex buffer and sets the vertex pointers. I have used this (mostly) successfully too.
But what is a VertexBufferObject, and a VertexArrayObject? Are they better? Doesn't VertexArray give me everything I need?
A vertex array is simply some data in your program (inside your address space) that you tell OpenGL about by providing a pointer to it.
While more efficient than specifying every single vertex individually, they still have performance issues. The GL must make a copy at the time you call DrawElements (or a similar function), because that is the only time it can be certain that the data is valid (after all, nothing prevents you from overwriting the data right away). This means that there is a significant hindrance to parallelism, and thus a performance issue.
Vertex buffer objects ("vertex buffers") are raw blocks of data that you do not own, i.e. they are not in your address space. You can either copy data into the buffer object with Copy(Sub)Data or by temporarily mapping it to your address space. Once you unmap the buffer, it does no longer belong to you. The huge advantage is that now the GL can decide what to do with it, and when to upload it. It knows that the data will be valid, because you cannot access it. This makes CPU/GPU parallelism a lot easier.
Vertex array abjects are a bit of a misnomer. There are no vertices or arrays in them. They are merely a kind of "state description block" which encapsulate the bindings of one or several vertex buffer objects (including any VertexAttribPointer calls). As such, they are both a convenience function and somewhat more efficient (fewer function calls), but not strictly necessary. You could do anything that a VAO does by hand, too.
BufferObject: a GPU allocated memory buffer
Vertex Buffer Object: a BufferObject containing vertices informations (colors, position, custom data used by a shader, ...)
Pixel Buffer Object: a BufferObject containing pixel or texel informations. Mainly used to upload textures.
Element Buffer Object: a BufferObject containing indices (used by glDrawElements).
Vertex Array: memory used by gl*Pointer call. Might be host memory or a Vertex Buffer Object if it is bound using glBindBuffer command with GL_ARRAY_BUFFER.
Element Array: memory used by glDrawElements call. Might be host memory or an Element Buffer Object if it is bound using glBindBuffer command with GL_ELEMENT_ARRAY_BUFFER.