5

I'm writing a simple 3D engine using OpenGL. I've already implemented a simple scene graph with the following pattern :

ISceneNode
    IMeshSceneNode
         StaticMeshSceneNode
    ICameraSceneNode
         StaticCameraSceneNode
         TrackBallCameraSceneNode
    ILightSceneNode
         PointLightSceneNode

But I wonder if a 'Renderer' (the class which implement the shader program) could be a scene node too (extract the rendering code from MeshSceneNode to the RenderSceneNode). For me it could be a right choice because if I must render several meshes (for example 42 meshes) using the same vertex and fragment shaders it should be usefull to bind and unbind the shader program just one time and not 42 times!

So what do you think about the following schemas :

The first one represent my current conception (for a sake of simplicity I don't represent the 'Light' and 'Camera' scene nodes).

enter image description here

So, here, if I want to render my 3 meshes (with 3 shader programs using the sames shaders) I will bind and unbind 3 times my shader programs for each frame (in the 'render' method of each Mesh node).

Here's the other conception :

enter image description here

As you can see above, this time I'll bind a unique shader program in the render node for all the children nodes. So it could be faster.

What do you think about my idea ?

genpfault
  • 51,148
  • 11
  • 85
  • 139
user1364743
  • 5,283
  • 6
  • 51
  • 90
  • 1
    Anything that reduces the number of times you seriously change the bound GLSL shader program is going to perform better ("un"binding by using program **0** when you finish drawing is actually pretty pointless, just leave that state alone until you actually need to issue a command that is related to it and a lot of redundant changes will work themselves out). GLSL programs and framebuffer objects are generally the most expensive states to change because of complicated state validation the driver has to perform. Changing vertex state, uniforms, etc. is *much* cheaper. – Andon M. Coleman Apr 26 '14 at 20:18
  • 1
    The idea you describe certainly has been used before, and conceptually it wouldn’t be a bad idea - however do realize that the scene tree is a conglomerate of [all] your objects, and this idea changes the fundamental layout of the nodes (that is in an optimized graph with multiple objects), undoing the very application of a scene graph (hierarchal and logical grouping of objects). A single object may now have multiple leaf nodes that are scattered around the tree, but lacking any logical common ancestor. – Lawrence Kok Apr 26 '14 at 20:24
  • Thanks for your answers. So, you think that a scene graph should be only composed by meshes, cameras, lights and the root? the rendering part should be precise only within the 'render' method within the mesh scene node ? So all nodes have to have in common a transformation matrix (for the renderer it's not the case...). So to optimize my shader program binding I have to find another solution but not in the scene graph ? Is that right ? – user1364743 Apr 26 '14 at 22:20
  • 2
    Yes, the scene graph is not necessarily going to generate the optimal ordering of graphics commands. You can always add an additional layer to your software to take the batches generated by your scene graph and sort them to minimize the more expensive state changes. Opaque geometry, for instance does not have a lot of order dependence, you can sort the opaque draw batches by shader ID to prevent changing shader. Again, that works best if you never "un"bind a shader; there is not a lot of need to "un"bind resources in properly designed software, just bind something different when you need to. – Andon M. Coleman Apr 27 '14 at 01:41
  • In fact, a lot of what I just mentioned is discussed [here](http://qt-project.org/doc/qt-5/qtquick-visualcanvas-scenegraph-renderer.html). You may find the implementation details of Qt Quick's scenegraph renderer worth reading about. – Andon M. Coleman Apr 27 '14 at 01:52
  • Ok so the renderer is a class with the aim is to gather in batches all the geometry need to be rendered with a minimum of OpenGL calls like glDrawArrays or glBindProgram. So this class has a reference to the scene graph and analyse each node to make some batches. So I think that all thes shader programs have to be initialize out of the mesh node class, for example in a shader proram manager that store all the shader program, and after during the rendering the renderer class will use them when it's necessary (for example just one shader program (bind) for a specific batche). Is that right ? – user1364743 Apr 27 '14 at 12:06

1 Answers1

1

Another way to say what Anton said: if you want to optimize state changes, you don't want nodes in your scene graph to make any draw calls directly. Delegate that to your renderer, which will then be able to build an intermediate representation based on which it can reorder OpenGL calls for optimization.

Defining a clean API for your renderer will also allow you to separate your concerns:

  • what to draw, vs.
  • how to draw it.

Then you could even use double dispatch (like an evolved Visitor Pattern) to make things more generic.

Shadocko
  • 1,186
  • 9
  • 27