I'm doing this mainly for the learning experience, as well as trying to optimize my own renderer, so be specific and use examples, please
I'm making a renderer for a framework I'm working on. The framework has all the workings for OpenGL and such, and now I'm building a layer on top of that so I can use this framework to start easily pumping out game after game. This framework would need to be very flexible and, preferably, fast and inexpensive.
I want this renderer to render everything. Any graphical object in the game would go in and be processed. If I should have a 2D background, the renderer would know to render it first and then everything on top of it. But, lets say in another game I'm using a Skybox. The renderer would still be able to sort this object and put it in the front of the render list.
Every object may have different blending modes turned on. Would it be best to group these together for common objects with the same blending? Would this really give me a big optimization?
Now, I've read a lot on scenegraphs and scenes, and I still can't seem to really grip it in my mind. Scenegraphs and such, from what I've surmised, regard grouping maxtrix calculations together (kinda like how animations are done). Is there any benefit that they would have to a renderer?
Currently I have a vector of objects to be rendered. They get sorted by what "roll" the object would play in the game (background, world, HUD, etc.). I feel like there should be a better way to manage the objects for a renderer, like some other data structure. Is there? Mind you, I'm also retrieving this list from the Object Manager.
Any tips and tricks to making a really efficient renderer would really help. Thanks guys!
(Also, if you must know, I'm developing this renderer for Android using libgdx as the engine and building this framework on top of that, but I feel these questions would apply to any renderer one would write.)
Theory to a Good Renderer
When I started my engine, I also started by the scene graph approach, where you can parent entities, and transformations are hierarchical. After I had it working, I realized it was pretty useless, and just switched to a simple render list.
By the way, you would want to render the sky last, not first (but still before transparent objects!). That way it you can usually minimize the fill operations in the framebuffer, since most of the fragments/pixels will get discarded early in the pipeline.
By the way, you would want to render the sky last, not first (but still before transparent objects!). That way it you can usually minimize the fill operations in the framebuffer, since most of the fragments/pixels will get discarded early in the pipeline.
Scene management, transformation hierarchies, etc are something that lie outside the scope of a renderer, in terms of a design. Like a wrapper.
I think for your renderer, you should try to emulate the capabilities of OpenGL first (however minimal)
You can then add a layer on top of your renderer that encapsulates logical/spatial grouping, scene management, etc and forwards draw calls to your renderer.
I think for your renderer, you should try to emulate the capabilities of OpenGL first (however minimal)
You can then add a layer on top of your renderer that encapsulates logical/spatial grouping, scene management, etc and forwards draw calls to your renderer.
Yeah, another vote here for avoiding Scenegraph-based systems. The whole time I've used them, I've ended up with an almost completely flat hierarchy with little to no benefits over a standard, flat renderlist.
Scene graphs these days are built a layer above the render interface, not directly connected with it.
This high-level part is that there is a "scene" of some kind, which you can "traverse" somehow, which produces lists of renderables. These flat lists are then given to the low-level renderer.
I personally hate GL's API design due to it being one big state-machine... DX11's state-object design is much easier to reason about, so when building a render API I prefer to hide the global-state-machine nature of GL/DX as much as possible.
I like to arrange things into these concepts:
DrawCall -- has all the information required to call functions such as glDrawElements.
RenderState -- has blend modes, shader variables, texture bindings, etc..
Renderable -- has a RenderState , and a DrawCall.
RenderLayer -- has a list of Renderables. Can optionally sort them based on some property. Also can have a RenderState.
RenderGroup -- has a list of RenderLayers. Also can have a RenderState.
In your game, you could make a RenderGroup with 3 RenderLayers - Background, World, HUD, etc..Then, each frame you traverse your scene and put renderables into each of the layers. Then you send the RenderGroup off to the renderer.
Each Renderable contains the unique state required for that draw-call, such as VBO bindings, shader parameters, etc...
Each RenderLayer can also have layer-wide states, like fog, etc...
The RenderGroup can also have some scene-wide states, like sunlight shader parameters, etc...
I'd usually just make an 'opaque' layer and a 'translucent' layer, and put all blended geo into the latter (which will be sorted by depth).
This high-level part is that there is a "scene" of some kind, which you can "traverse" somehow, which produces lists of renderables. These flat lists are then given to the low-level renderer.
I personally hate GL's API design due to it being one big state-machine... DX11's state-object design is much easier to reason about, so when building a render API I prefer to hide the global-state-machine nature of GL/DX as much as possible.
I like to arrange things into these concepts:
DrawCall -- has all the information required to call functions such as glDrawElements.
RenderState -- has blend modes, shader variables, texture bindings, etc..
Renderable -- has a RenderState , and a DrawCall.
RenderLayer -- has a list of Renderables. Can optionally sort them based on some property. Also can have a RenderState.
RenderGroup -- has a list of RenderLayers. Also can have a RenderState.
In your game, you could make a RenderGroup with 3 RenderLayers - Background, World, HUD, etc..Then, each frame you traverse your scene and put renderables into each of the layers. Then you send the RenderGroup off to the renderer.
Each Renderable contains the unique state required for that draw-call, such as VBO bindings, shader parameters, etc...
Each RenderLayer can also have layer-wide states, like fog, etc...
The RenderGroup can also have some scene-wide states, like sunlight shader parameters, etc...
Every object may have different blending modes turned on. Would it be best to group these together for common objects with the same blending? Would this really give me a big optimization?Usually you group things based on blend modes to ensure correctness, not performance. E.g. if you don't separate alpha-blended geo from opaque geo, then your results will be plain wrong. Or, another example, you don't need to depth-sort an additively blended scene, but you do need to depth-sort an alpha-blended scene.
I'd usually just make an 'opaque' layer and a 'translucent' layer, and put all blended geo into the latter (which will be sorted by depth).
Now, I've read a lot on scenegraphs and scenes, and I still can't seem to really grip it in my mind. Scenegraphs and such, from what I've surmised, regard grouping maxtrix calculations together (kinda like how animations are done). Is there any benefit that they would have to a renderer?Strangely enough, they're more use to physics systems than renderers
Every object may have different blending modes turned on. Would it be best to group these together for common objects with the same blending? Would this really give me a big optimization?
Now, I've read a lot on scenegraphs and scenes, and I still can't seem to really grip it in my mind. Scenegraphs and such, from what I've surmised, regard grouping maxtrix calculations together (kinda like how animations are done). Is there any benefit that they would have to a renderer?
Currently I have a vector of objects to be rendered. They get sorted by what "roll" the object would play in the game (background, world, HUD, etc.). I feel like there should be a better way to manage the objects for a renderer, like some other data structure. Is there? Mind you, I'm also retrieving this list from the Object Manager.
I recommend against a Scene Graph, unless your game will specifically require it. It sounds nice and all, but like PlayfulPuppy said, you'll probably end up using a flat hierarchy for most things anyhow. It really complicates things. I also highly recommend keeping things simple. It can be tempting to want to build your system to be super flexible, but renderers can become extremely complex, and there's a point where you just need to start developing your game(s). Practically, you could try to write your code to be as modular as possible, and then only implement what you need for the game you are making. If you want to be able to reuse the framework later, try to keep the framework code separate from the game code.
Also, state changes in OpenGL can be expensive, so grouping your common objects into batches is wise. Try to focus on batching based on shaders and texures, but as I understand it, those require more time to swap out. You could create a simple material system that assigns an id to a certain texture/shader combination, and then sort the vector based on that. Also, you are correct in partitioning the objects into background, world, HUD sections (and I would add an alpha section as well for transparent objects, those needs to be rendered last).
Now, I've read a lot on scenegraphs and scenes, and I still can't seem to really grip it in my mind. Scenegraphs and such, from what I've surmised, regard grouping maxtrix calculations together (kinda like how animations are done). Is there any benefit that they would have to a renderer?
Scene Graphs allow you to create hierarchies of objects. If you wanted to mount a turret on a spaceship, for instance, you could add that node onto the ship node, and the renderer would concatenate those matrices for you. Then you could treat the ship as a single object, and changes to the ship would propagate to the turret. That can be a nice benefit, but like I said before, most objects in your game will probably be single entities. In the event that you needed to do something like mount a turret, I would think you could do the matrix math yourself pretty easily.
OK, if there's at least one thing to pull away from this is to not have scene graphs interact directly with the renderer. Hodgman has a point to use them with physics, and to use them as a per-state object manger would work nice.
Also, thanks for all the tips on OpenGL in terms of switching states and such.
And good point, Triton, on rendering the sky last! That makes perfect sense.
Thanks guys! If anyone else wants to add anything else, feel free!
Also, thanks for all the tips on OpenGL in terms of switching states and such.
And good point, Triton, on rendering the sky last! That makes perfect sense.
Thanks guys! If anyone else wants to add anything else, feel free!
Regarding scene graphs, having the optional ability to attach objects hierarchically does have its uses. For example things like attaching objects to your character's skeletal joints; if both the objects and the joints derive from a common scene node class, you probably end up with rather clean code, instead of having to special-case skeletal attachments later.
But I'd advise against the style of engines like OGRE, where you *must* attach the object to a root scene node for it to be visible at all. Also driving per-frame scene updates from a scene graph is probably not a good idea, because I'd imagine a large part of the scene (anything static) actually requiring no update each frame.
But I'd advise against the style of engines like OGRE, where you *must* attach the object to a root scene node for it to be visible at all. Also driving per-frame scene updates from a scene graph is probably not a good idea, because I'd imagine a large part of the scene (anything static) actually requiring no update each frame.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement