Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

When creating a central rendering system for all game objects in a given scene I am trying to work out the best way to go about passing the scene to the render system to be rendered.

If I have a scene managed by an arbitrary structure, i.e., an octree, bsp trees, quad-tree, kd tree, etc. What is the best way to pass this to the render system?

The obvious problem is that if simply given the root node of the structure, the render system would require an intrinsic knowledge of the structure in order to traverse the structure.

My solution to this is to clip all objects outside the frustum in the scene manager and then create a list of the objects which are left and pass this simple list to the render system, be it an array, a vector, a linked list, etc. (This would be a structure required by the render system as a means to know which objects should be rendered). The list would of course attempt to minimise OpenGL state changes by grouping objects that require the same rendering operations to be performed on them.

I have been thinking a lot about this and started searching various terms on here and followed any additional information/links but I have not really found a definitive answer. The case may be that there is no definitive answer but I would appreciate some advice and tips.

My question is, is this a reasonable solution to the problem? Are there any improvements that I could make? Are there any caveats I should know about?

Side question: Am I right in assuming that octrees, bsp trees, etc are all forms of BVH?

share|improve this question
1  
There's no reason to assume your renderer shouldnt be aware of your scene data structure. You're likely going to have more than one for different types of objects rendered in different ways (static geometry vs dynamic objects, for example), and the renderer is going to be aware of that split at some level. Remember: if a design pattern is being a pain in the ass, you should abandon the design pattern, not try to shoehorn a solution into it. Not every interface is going to be an academically pure abstraction. –  Sean Middleditch Aug 5 '12 at 19:48
add comment

3 Answers

Here goes, hope I can answer all of your questions as some of them don't have a definitive answer but are more a personal preference. Also, some of it depends on things like the platform you develop for, how important speed is, how important extensibility is, etc.

When creating a central rendering system for all game objects in a given scene I am trying to work out the best way to go about passing the scene to the render system to be rendered.

Great start, but with one note. There is absolutely nothing wrong with a generalized system for rendering, but keep in mind that any generalized system is almost always a slower system and more important, costs a lot of extra code to write and maintain. There are cases where foregoing such systems for the simplest in place solution (in your case, no rendering manager or a render manager with intrinsic knowledge of the game) might be the best solution. That being said, go for it and write a complex system if you need it, or if you just feel like it. Just think about the reasons for everything you do.

If I have a scene managed by an arbitrary structure, i.e., an octree, bsp trees, quad-tree, kd tree, etc. What is the best way to pass this to the render system?

The obvious problem is that if simply given the root node of the structure, the render system would require an intrinsic knowledge of the structure in order to traverse the structure.

My solution to this is to clip all objects outside the frustum in the scene manager and then create a list of the objects which are left and pass this simple list to the render system, be it an array, a vector, a linked list, etc. (This would be a structure required by the render system as a means to know which objects should be rendered).

Good idea! I don't have much to say against this system, but since you asked for improvements and caveats, let's go through some.

First of, a good idea would be to keep a separate data structure for the objects in the scene and the renderable objects. Objects in the scene might be complete classes with lots of data on object state necessary for gameplay but totally irrelevant for rendering. So create a very simple struct for renderables, just add pointers to the data you need for rendering, or even simpler, make it a struct with two fields, a sort key and a pointer/index/id to the render data structure that resides somewhere else in memory.

Second, store your data in a way that makes multiple passes easy. You never want to render your scene just once, you may need multiple passes for certain graphical algorithms. Also, not every pass needs the same objects. To give a hypothetical example, you first render your shadow map from the light perspective (different objects visible/culled), then you want to render a quick depth pass with all opaque geometry to fill the depth buffer, then you render your main pass, followed by particles at a different resolution, and in the end you need to do some post processing using the scene you just rendered. If you want to do deferred rendering, that adds some more passes with different settings and objects.

Third, data may need to be sorted differently for each pass. For filling the depth buffer, you may want to sort front-to-back, for particles you may want to render back to front.

As a solution to some of these issues, you could decouple clipping/culling from the scene manager and add it to the chain, so you just pass all objects from the scene manager through the clipping manager which only adds visible objects to the render queue. This might also make it easier to optimize culling by first storing all objects to be rendered in an array and then going through them sequentially, which might be more efficient in terms of cache usage etc. Then again, maybe you already do this in a very efficient manner in your scene manager, which I can imagine if you use an octree or something like that. Up to you.

What comes to my mind right now is a solution where you create different buckets for different render passes. Each bucket could have its own culling system and have an efficient tree structure that automatically sorts data when it's added (trees are great for that). So the scene manager just walks through its set of objects to be rendered and adds a "Render Struct" to the render manager. This render struct is now copied and passed to each bucket. If it gets through the culling system, it's added to the tree.

Then again, this is a really complex solution, maybe it's waaaay to complex for your situation. Also, I have no idea if all the things I just said are actually that efficient. It all depends, as always, on the data and what you need to do with it. So, know your data and always profile/test your code to see if the beautiful and complex generic system you worked so hard on is that much faster than the simple and fast solution (note that I'm not advocating quick and dirty solutions, simple and fast does not mean it's a hack! You should never use hacks!)

The list would of course attempt to minimise OpenGL state changes by grouping objects that require the same rendering operations to be performed on them.

That's pretty old advice actually. It's bandied around a lot, but it's origins lie in the very first generations of GPUs. It was definitely good advice back 10 years ago, but there isn't much advice from those days that's still true today so I would want to do some further research on that if I were you, before you base your rendering code on that.

I have been thinking a lot about this and started searching various terms on here and followed any additional information/links but I have not really found a definitive answer. The case may be that there is no definitive answer but I would appreciate some advice and tips.

There is no definitive answer to anything in the world of computer science and gaming. Ideas that were great 10 years ago are useless now, and the latest and greatest innovations of today will be outdated 5 or 10 years from now. The reason is simple and two-fold: data and architecture. Both change constantly. What works on an ARM system with limited CPU power and memory may be useless on a 3+ GHz quad core with 8 GB of RAM. What works on a close to metal PowerPC based console may be useless on an Android game that runs JIT-ed bytecode. So architecture changes, but data used in games changes a lot too. How many objects in your game? How many polygons, how many lights, what kind of shaders do you use. How many objects change and how much of the scene is static?

My question is, is this a reasonable solution to the problem? Are there any improvements that I could make? Are there any caveats I should know about?

Know your data and your architecture through and through and you will be able to tell what the best solutions are. Not sure, then profile it! Never assume, always measure. So is your solution a good one? It certainly is, but there are also cases where it might be overkill, either because your data does not need a complex solution like that, or because it might kill performance if you use low-power hardware. It might also be too general where a system tailored to your scene could be a lot faster. You know your situation better than anyone, so you tell us :) Hope this helps!

share|improve this answer
add comment

The best way? No such thing. Depends on the needs of your game.

As for a good way, there are two.

  • There's a common scene structure that the renderer draws and does some caching internally, if necessary - this works great for simple games but might add unnecessary overhead on AAA-like games.
  • Renderer is a factory of the associated items (meshes, lights etc.). This lets you associate rendering caches with per-instance data easier at the cost of manually managing these items everywhere.

There are also a few things to avoid:

  • Do not mix scene graphs in the renderer as the renderer does not need to care about them. Culling doesn't care if a Handle is a child of Door. Performance suffers from such things. Batching such constructs is impossible if you render the tree top-down. Want to hierarchially stick items together? Just send the calculated world matrices to the renderables.

  • Don't use retrieval-based interfaces like GetAllRenderables() - they unnecessarily slow down the processing with extra copies of the data. Store the data as you're going to process it.

P.S. I'd suggest you avoid using Ogre, Irrlicht and such "engines" as examples. They're so poor that no one who's serious about game development uses them.


Since I've posted something controversial here, I'm adding some explanations (which I shouldn't really but I guess there's no harm in being explicit about things).

Irrlicht: scene nodes are renderables. As I've noted above, this leads to poor batching possibilities, let alone obvious problems with having a component system built with the engine (like not having a place for such things - but hey, it's supposed to be a -game- engine...). There's also a problem with logical grouping of code in the sense that all rendering code is scattered all over the source code.

Ogre: it's so overdesigned (?) and so heavy that the code is unreadable and compiles slowly. Whatever problem they had come upon, they just applied an STL container on it. Well, it's not Boost but it's still bad. Such a design is guaranteed to be slow because of the insane amount of memory allocations required. Multimap? Seriously? Just use a sorted array (vector)... And the in-code documentation really doesn't help anyone understand what happens under the hood, which is why people actually refer to source code of any API.

If this is not enough, just ask me in the comments.

share|improve this answer
    
Give some reasons why Ogre and Irrlicht are so poor, besides being open-source and having a somewhat steep learning curve. As a day-to-day professional Ogre user, I'd say you're going to become even more ignorant of the logic and construction of a 3D engine if you use some commercial closed-source, editor-based alternatives that really do not offer much more. If you have a team of 2-3 programmers, it will take you a lot of reading and coding hours to come up with an engine "as poor" as Irrlicht or Ogre, more to surpass it. Ask Gameloft about Irrlicht, they're not serious about games either. –  teodron Sep 10 '12 at 15:30
    
Here you go, added some. As for my experience, I've been building and studying games and game engines (both 2D and 3D) for the last 5 years. I'm pretty sure I could hack up something better than that. And as much as I wanted to find out more about Gameloft and Irrlicht, I didn't find anything worth looking at, just some forum talk. –  snake5 Sep 10 '12 at 18:52
    
Well, those are fair things, point taken, +1 then! Agreed that Ogre is overdesigned and that both engines don't do well on AAA games, but nevertheless, not making use of the whole bunch of intricate constructs (you can do that with both engines once you get accustomed to their particularities), then one can come up with a more than decent 3D game. Gameloft: rumors and eye-witnesses confirm they used a slightly modified version of Irrlicht for the Nova FPS. Probably an experiment, but they managed it. That being said, thanks for making your answer a much better one. –  teodron Sep 11 '12 at 7:40
add comment

You can take OGRE 3D as reference. It allows API user to use arbitary scene management data structure.

One thing i learnt when going down this road is that the more genric the rendering engine, the less optimisation and less efficiently it will run. At some point when dealing with more advanced rendering, will definitely complicate things a lot. e.g. billboards, UI, particle system, tranparency, color picking, stencils, multiple viewports, render to some-other-buffer-or-file. Perhaps placing a limit somewhere is not too bad.

You might already be thinking to create an abstract SceneManager from which all scene management strutures are derived, and let the renderer query it through its interface methods such as an Renderable* getRenderables() function (C/C++). You might also want to make your SceneManager graphics API agnostic at the same time.

But really, when you have so many possible types of Renderables, I don't know if you still can easily "minimise OpenGL state" changes and still have both worlds.

The last time I did it, there were 2 options: create a very all-encompassing SceneManager interface; or just make OpenGL state changes calls from inside SceneManager.

I would be interested to see how you approached it.

share|improve this answer
    
My goal isn't to make it as generic as possible. At the moment I'm implementing only an Octree for the scene management and to be honest I probably won't take it much further than that. I do understand that the more layers of abstraction there are the slower it will get. My plan is to make the SceneManager agnostic to the graphics API used and I don't plan on having too many renderables either. This just started as a venture into implementing an Octree and I wish to keep it that way. Currently my plans are just to get some objects on the screen and stopping rendering clipped objects. –  ctor Aug 5 '12 at 18:06
    
Yea, so I have answered your question: reasonable solution - see Ogre 3D; improvements - set limits; caveats - getting too complicated with different types of renderables. –  Jake Aug 5 '12 at 18:20
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.