So I read somewhere that I should use fewer VBOs as possible and render many objects from a single VBO.
I get the point, but isn't that less organized?
I planned on creating 3d shapes classes where each instance of the class has its own VBO that will be bound when it needs to be drawn. This comes in contrast to what I wrote earlier.
How do 3D applications (video games etc.) get this done?
Firstly a VBO is just a collection of vertices that is stored in your video card memory. You can use a single VBO and model matrix to transform it, you can also apply different shaders and textures on top of it.
This is best explained with a 2D game in mind where every graphic is basically a quad; 4 vertices.
Would you really need to flood your video card memory with repeated allocations for a VBO of 4 vertices?
Instead we can have a pointer to the VBO and model matrix that transforms it. The VBO is usually stored in a resource manager so it stays in memory for as long as we like.
So now we're reusing a single VBO for everything, we're applying different transformations and textures to it. It looks like there are lots and lots of VBO's but actually we're being very efficient with our video card memory.
Here's some pseudo code:
class Sprite {
mat4 transform;
GLuint VBO = ResourceManager.quadVBO;
}
Related
I am creating a 2d game engine as a side project. I've been doing some experimenting and research and have come across a lot of people suggesting that you batch (store multiple objects to draw) in the same VBO. For example, if I my scene had a lot of trees I could put all the trees in the same VBO because they have the same memory footprint and then use a single glDrawArrays to draw all of them.
This is fine and it makes total sense... but then I started to wonder how I can send the different transforms for each tree? How do I get that to the shader? Or is this approach assuming I do the calculations on CPU and send the entire VBO each draw?
Here are two of the main questions i've been looking at:
OpenGL VAO best practices
OpenGL How Many VAOs
The term you're looking for is Instancing.
You create a VAO that contains the model of the tree, and then instead of passing the model matrix through the uniforms, you put it as an instanced vertex attribute in the VAO. Then each instance of your tree will get drawn with a different model matrix.
You can utilize compute shaders or transform feedback to update and store the model-view product in the VAO once per instance per frame (rather than calculating it per each vertex of each instance).
I'm trying to use modern OpenGL and shaders, instead of the immediate mode I have been using so far. I recently learned about VBOs and VAO, and I'm still trying to get my head round them, but I know that a VBO takes an array of floats that are vertices, which it then passes to the GPU etc
What is the best way to draw multiple objects (which are all identical) but in different positions, using VBOs. Will I have to draw one, then modify the array passed in beforehand, and then draw it again and modify and draw and modify and so on... for all blocks in the screen every frame? Or is there a better way?
I'm trying to achieve this: http://imgur.com/cBgJ0sK
Any help is appreciated - I don't want to learn bad (deprecated, old) immediate mode habits, when I could be learning a more modern way!
You should not modify the vertices in your program, that should be done in the shaders. For this, you will create a matrix that represents the transformation and will use that matrix in the vertex shader.
The main idea is:
You create a VAO holding the information of your VBO (vertices, normals, texture coordinates, tangent information, etc.)
Then, for every different object, you generate a model matrix that holds the information of the position, orientation and scale (and other homogeneous tranformations) and send that to your shader to make the transformations.
The idea is that you bind your VAO just once and then draw all the different objects just sending the information that change (model matrix, may be textures) and draw the objects.
To learn about how to use the model matrix, read tutorials like this:
http://ogldev.atspace.co.uk/www/tutorial06/tutorial06.html
There are even better ways to do this, but you can start from here.
Other information that would be good for your case is using instancing.
http://ogldev.atspace.co.uk/www/tutorial33/tutorial33.html
Later, you can move on indirect drawing for even better performance. Later...
So I've been learning OpenGL 3.3 on https://open.gl/ and I got really confused about some stuff.
VAO-s. By my understanding they are used to store the glVertexAttribPointer calls.
VBO-s. They store vertecies. So if I am making something with multiple objects do I need a VBO for every object?
Shader Programs - Why do we need multiple ones and what exactly do they do ?
What exactly does this line do : glBindFragDataLocation(shaderProgram, 0, "outColor");
The most important thing is how does all of this fit into a big program? For what exactly are used the VAO-s? Most tutorials just cover the things just to drawing a cube or 2 with hard coded vertices, so how would one go to managing scenes with a lot of objects? I've read this thread and got a little bit of understanding on how the scene management happens and all but still I can't figure out how to connect the OpenGL stuff to it all.
1-Yes. VAOs store vertex array bindings in general. When you see that you're doing lots of calls that does enabling, disabling and changing of GPU states, you can do all that at some early point in the program and then use VAOs to take a "snapshot" ,of what is bound and what isn't, at that point in time. Later, during your actual draw calls, all you need to do is bind that VAO again to set all the vertex states to what they were then. Just like how VBOs are faster that immediate mode because they send all vertices at once, VAOs work faster by changing many vertex states at once.
2-VBOs are just another way to send your glPosition, glColor..etc coordinates to the GPU to render on screen. The idea is, unlike with immediate mode where you send your vertex data one by one with the gl*Attribute* calls, is to upload all your vertices to the GPU in advance and retrieve their location as an ID. At time of rendering, you're only going to point the GPU (you bind the VBO id to something like GL_ARRAY_BUFFER, and use glVertexAttribPointer to specify details of how you stored the vertices data) to that location and issue your order to render. That obviously saves lots of time by doing things overhead, and so it's much faster.
As for whether one should have one VBO per object or even one VBO for all the objects is up to the programmer and the structure of the objects they want to render. After all, VBOs themselves are just a bunch of data you stored in the GPU, and you tell the computer how they're arranged using the glVertexAttribPointer calls.
3-Shaders are used to define a pipeline - a routine - of what happens to the vertices, colors, normals..etc after they've been sent to the GPU until they're rendered as fragments or pixels on the screen. When you send vertices over to the GPU, they're often still 3D coordinates, but the screen is a 2D sheet of pixels. There still comes the process of re-positioning these vertices according to the ProjectionModelView matrices (job of vertex shader) and then "flattening" or rasterizing the 3D geometry (geometry shader) into a 2D plane. Then it follows with coloring the flattened 2D scene (fragment shader) and finally lighting the pixels on your screen accordingly. In OpenGL versions 1.5 core and below, you didn't have much control over those stages as it was all fixed (hence the term fixed pipeline). Just think about what you could do in any of these shader stages and you will see that there is a lot of awesome things you can do with them. For example, in the fragment shader, just before you send the fragment color to the GPU, negate the sign of the color and add 1 to have colors of objects rendered with that shader inverted!
As for how many shaders one needs to use, again, it's up to the programmer to decide whether to have many or not. They could merge all the functionalities they need into one big giant shader (uber shader) and switch these functionalities on and off with boolean uniforms (very often considered as a bad practice), or have every shader do a certain thing and bind the right one according to what they need.
What exactly does this line do :
glBindFragDataLocation(shaderProgram, 0, "outColor");
It means that whatever is stored in the out declared variable "outColor" at the end of the fragment shader execution will be sent to the GPU as the final primary fragment color.
The most important thing is how does all of this fit into a big
program? For what exactly are used the VAO-s? Most tutorials just
cover the things just to drawing a cube or 2 with hard coded vertices,
so how would one go to managing scenes with a lot of objects? I've
read this thread and got a little bit of understanding on how the
scene management happens and all but still I can't figure out how to
connect the OpenGL stuff to it all.
They all work together to draw your nice colored shapes on the screen. VBOs are the structures where the vertices of your scene are stored (all aligned in an ugly fashion), VertexAttribPointer calls to tell the GPU how the data in the VBO is arranged, VAOs to store all these VertexAttribPointer instructions ahead of time and send them all at once with simply binding one during rendering in your main loop, and shaders to give you more control during the process of drawing your scene on the screen.
All of this can sound overwhelming at first, but with practice you will get used to it.
I'm making a 2D batch renderer in OpenGL inspired by the XNA/MonoGame interface, but I've run into a small design problem and I'm looking for some input. Currently, you can submit vertex data in four general ways:
void Render(const Sprite& sprite);
void Render(const Shape& shape);
void Render(const Vertex* vertices, unsigned int length);
void Render(const Vertex* vertices, unsigned int length, const Texture* texture);
A sprite contains four vertices, color and texture coordinates while the other three can contain an arbitrary number (the sprite and shape have unique transformations). Everything can be textured or untextured. I want to batch everything to reduce the number of state changes and OpenGL draw calls. I feel it reasonable to assume that most submissions will have shared vertices so that I can use glDrawElements instead of glDrawArrays, but I have trouble figuring out how to batch things properly given what I described above.
The XNA/MonoGame sprite batchers work because they work solely with textured quads/triangles and not arbitrary shapes. Alternatively, I could do like the SFML renderer and issue a draw call for each drawable object, but that defeats the purpose of batch rendering.
I feel like my renderer is trying to "do everything" which is something I want to avoid since it usually quickly becomes too complex in my experience.
What I'm asking is: How could I redesign my renderer? Could I keep separate batch lists for different submissions? Could I modularize my renderer somehow? Should I just allow only textured objects as done in XNA/MonoGame?
Alright, so we need to minimize the number of state changes and draw calls. I'm assuming you're using modern OpenGL, including Vertex Buffer Objects and shaders.
One approach is to ensure that all vertex data has the same format. For example, each vertex has a position, color and texture coordinate (xyz, rgba, uv). If we interleave our vertex data in a VBO, we only need a single call to glVertexAttribPointer and glEnableVertexAttribArray, before rendering.
This means some redundant data for untextured objects, but we get to cram everything into a single batch, which is nice.
To handle the untextured objects, you could either bind a blank white texture and treat it as a textured object. Or, you could have a uniform variable (a float between 0 and 1) in your fragment shader, and blend between texture color and vertex color using the mix function.
To batch sprites and shapes we should first handle the transformations on the CPU, so that we always upload "world"-coordinates to the GPU. This saves us from having to set a transformation uniform for each sprite, which would each be require individual draw calls.
Furthermore, we need to sort by texture whenever possible, as texture bindings are among the more expensive operations you can do.
Our approach basically boils down to the following:
Maintain a single Vertex- and Index Buffer Object to store the data
Keep all vertex data in a single format and interleave the data in the VBO
Sort by texture
Flush the data (draw elements/arrays) in the buffers whenever we change texture (or set the texture-blend uniform, if we go with that option)
Getting the data from the CPU to GPU memory can be done in different ways. For example, by first allocating a large enough, empty memory buffer on the GPU, and using glBufferSubData to upload a subset of vertex/index data, whenever you do one of your Render calls.
Remember to profile!
It is very important to do profiling when doing this kind of work. For example, to compare the performance between batching and individual draw calls, or glDrawArrays vs glDrawElements. I recommend using gDebugger, which is a free and very good OpenGL profiler.
Also note that too big of a VBO can hurt your performance. So keep it to a reasonable size, and flush it with a draw call whenever it fills up.
Imagine I want to draw a pyramid made of triangles.
-Should I create a VBO for each triangle or one containing all triangles?
Selecting a VBO into a context is a rather expensive state change, so using fewer VBOs is definitely advantageous.