What's the best practice for instance renderering? - opengl

I've created a renderer that works but I feel I can improve it. The biggest problem that I see right now is data duplication. Right now its batching all the objects into a VBO but this can lead to redundant data. What I thought of was having one VBO to store all the vertices of my models (only one of each) and because I'm using glMultiDrawElementsIndirect I can create instances of each of these models by putting them in their own draw command. What I thought of doing was then having another VBO to store per-instance data (model matrix, color, etc.) and then have an instance array and pass it in as an attribute using glVertexAttribDivisor. Is this way ok?
Thanks!

Related

OpenGL - Most efficient way to update model info (e.g. model matrix)

So lets say I have abstracted OpenGL's general buffer object workflow into a Model class. All I need to do for a 3D model to appear in the OpenGL context is to initialise a Model object, add it to a container, and draw all Models in the container to in the render loop.
Lets say I have 1000 Models in my scene. The way in which I set a model's global coordinates now becomes very important.
I know of a couple of ways I can go about updating Model info such as its model matrix. One would be sharing one shader program for every model, and using glUniformMatrix4fv to set the model matrix for the shader just before drawing each Model in the render loop. Another way would be for each Model object to contain its own shader program, and the model matrix for that shader is set upon initialisation of the Model object. Then, in the render loop, glUseProgram is used for each Models shader program just before it is drawn.
What is the most efficient way of going about updating Model info such as its model matrix (as I feel as if my currently known methods are extremely inefficient)?
Since your question is somewhat general, I'll keep the answer general as well.
In general, changing state between OpenGL draw calls is costly so best performance is achieved by minimizing state changes. However, not all state changes are equal. An exhaustive list of which state changes are more costly than others is not really possible because their cost changes between vendors, driver versions, etc. A good understanding of the complete OpenGL pipeline and how computer hardware works can provide an intuition of which code paths are better. It is also really helpful to read Nvidia and AMD presentations (from GDC, Siggraph, etc.) that focus on optimizing graphical engine performances.
For the specific question you asked, it will most likely be much slower to use different shaders each containing their own matrix than sharing a single shader and setting the matrix in a uniform value before each draw call. Changing the active shader requires much more work by the driver to reconfigure the GPU pipeline than simply writing 16 floats to GPU memory. There are also other techniques that would allow you to store all your matrices in a single buffer and issue a single draw call with all your models if they use the same shader.
One way is to have all matrices in an array in a single SSBO or UBO. Then each mesh has an index that indicates which matrix it should use. The index could come from a vertex attribute (like the w component of the vertex position).

OpenGL VBO batch best practices

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).

How to render multiple objects that can each have multiple shaders in OpenGL 3.3?

Im trying to make a 3D renderer with OpenGL using c++, well, so far I have a Scene class that contains a list of Objects and Materials objects (I also have classes for those and I written my code so an object can have multiple shaders (every shader will be able to affect a group of vertices in an object) but now I'm trying to find a good way to send all that information to openGL.
I've seen people suggest taking everything that uses the same shader and rendering that at once, and do the same for every shader, well If I understood well enough,but is that a good idea if you can get the same shaders included in different objects, if I merged every vert that has shader A for example, won't it hurt that that group contains verts of separate objects when I try to draw them at once ? And if I take each object and separate each object according to their shaders, so for the rendering I would take Object A then split into its shader groups, then draw shadergroup1 in object1 then shader group2 in object 2 and so on.. Won't that be too many draw calls too.
What strategy do you recommend to accomplish that ?
The first things I recommend is, that you stop thinking in terms of "objects", as far as the rendering process is concerned. When rendering the only sensible grouping are drawing batches (of a certain primitive, points, lines, triangles) for which the same rendering steps (render pipeline) is executed. The modern rendering APIs that were released over the past months (Vulkan, DirectX 12 and Metal) make this explicit.
When rendering your scene the recommended strategy is to iterate over all your objects, split them into render pipeline groups and perform a single drawing batch call once for each primitive-by-pipeline group. The overall goal should be to minimize the total number of drawing calls made.
If you are using OpenGL 3.3, you are using Vertex Array Objects (VAO) and Vertex Buffer Objects (VBO). You have an object, a table for example, which can have three (or more or less) VBO:s, one for vertex data, one for normal data and one for texture coordinate data. You enclose your VBO:s of that table inside one VAO. So every object have its own VAO stored in a GPU memory.
When you want to render your objects or a part of them, you bind one of your shaders at use and call those VAO:s you want to render by that shader. It may be important that you render right objects on right order and use right shaders (of course!) on each VAO.

Multiple VBOs and IBOs How to Handle

Actually, I have a lot of models that are produced by cpu.(around 100K and one of them around 100 triangle) and all model has its vbo and ibo. If I try to draw each model with glDrawElements() it is quite slow. also if I try to draw combine all vbos and ibos if a model is deleted I need to update vbo also almost all ibo because of removed points change index order and then I need the buffer all of these again it is slow. Also I am not sure about instancing performance and picking I need to know which triangle belongs to which model.Is there any way to buffer and than one draw function draw all individual model with its own vbo and index?
You can set a base vertex per mesh and pass it to the glDrawElementsBaseVertex call. This will still require a call per mesh which can be solved with glMultiDrawElementsBaseVertex with which you can combine them all into a single draw call.

OpenGL Model Class requirements

I've been wondering this for a while when loading in your mesh and textures and whatnot in your model class, what do you keep? I figure once the vertices are passed with glBufferData() I don't need them anymore, since the call to glDrawArrays() depends on the last glBindBuffer() This is all my Model class keeps after the loadModel() method is called.
GLuint vboID;//for... something
GLuint vaoID;//for glBindVertexArray(vaoID);
GLuint textureID;//for glBindTexture(GL_TEXTRUE2D, textureID);
GLuint vboElementCount;//for glDrawArrays(GL_TRIANGLES,0,vboElementCount);
From what I can tell that would be all I need to render a model. Other then that what else should I keep for a simple model?
Edit: Before someone mentions position rotation scale and what have you, I have a ModelInstance class that contains the matrices for those, and I pass it a pointer to the Model object so I can have multiple instances of the same Model.
I keep
VBO ids, so I can delete VBOs when I no longer need them.
VAO id, so I can bind before drawing and delete eventually.
Number of indices to pass to glDrawElements()
ids of all required textures.
Material and transformation properties (uniforms in general).
This works fine as long as meshes are static. As soon as you want to manipulate your meshes on the CPU, for example smoothen or split them, you have to keep a copy in main memory.
Maybe you also want to keep a low resolution placeholder, for example for more specialized rendering techniques like occlusion culling. But again, this is a special case; your question lists everything needed for basic rendering
Note: you should think about switching to glDrawElements(). It will reduce the amount of vertex data you have to store and transfer.