6
\$\begingroup\$

I am writing for OpenGL 2.0 and in the future porting to OpenGL ES 2.0. I only use VBOs and shaders (no immediate mode, no vertex arrays).

I already have working solutions, they just... feel wrong. All my calls related to OpenGL are tucked away in a separate class called RenderManager (this includes creation of VBOs and IBOs, texture IDs and shader programs) and rendering. I called the creation of OpenGL objects logging in and out, so majority of this action is invoked from the ResourceManager object upon loading of data. However, a lot of geometry (level) is generated dynamically and therefore some RenderManager calls to create the VBOs/IBOs is scattered throughout the level class.

Now, I have a Renderable interface which returns the (single) transformation matrix and a RenderOp object when it is time for rendering. RenderOps is an object that has Vertex/Index Buffer pointers (has actual geom. data which in turn has VBO/IBO indices) and some parameters such as whether to use the index buffer and if the RenderOp needs blending and stuff.

There is also the RenderView object; it has the viewport parameters, projection matrix and view matrix (camera).

The game objects reside in the World class (single-dimension arrays). These game objects are added upon their creation, and are derived from Entity interface. Entity is able to return the number of Renderable-type objects within as well as the actual pointer to a Renderable at a given index.

The magic happens when the main loop traverses the World. First it collects all Light objects visible from within Frustum. Then it collects Entity object that's within Frustum (it gets added to std::vector inside RenderView if it is), and then it checks that same object to see if it is inside any of the visible Light's bounding volumes (and gets added into Light's std::vector).

Then the RenderView is passed onto the RenderManager class, which extracts appropriate Renderables from each Entity, applies Renderable's shader, then applies Renderable's textures, then stores the transforms inside itself and promptly shoves them down the programmable pipeline's throat along with attributes stored inside the RenderOperation (that gets extracted from Renderable as well).

Last note - I have NO way to render debug data, which is extremely annoying.

A lot of what I am doing feels wrong. My question is, how do you organize all your Renderable and Transformation data to facilitate your rendering needs? I am burning out thinking of semi-flexible ways of managing this data and I want to hear your ways. I am not a big fan of scene graphs, and consequently don't really want to implement one as I feel there are no real hierarchies inside the game, but I feel like I'm running myself into a corner.

Please throw me a bone here, how do you manage all this data? And if you suggest an event based rendering system, how would you design it?

\$\endgroup\$
6
  • 3
    \$\begingroup\$ ^ You mean that wasn't the essay? \$\endgroup\$ Commented Mar 7, 2012 at 5:52
  • \$\begingroup\$ I've thought about an event based render system myself where all the specifics and actual rendering goes on in the graphics module, but each "drawable" class or some variant of it actually calls and tells the renderer when it needs to be rendered. I would think this would be faster since you're not polling for a million updates but IDK =p \$\endgroup\$
    – Griffin
    Commented Mar 7, 2012 at 6:50
  • \$\begingroup\$ @Daniel you should have seen the first one :) I threw it away in favor of trying to provide ("exchange"?) some information about what I have done, lending a clue of what I was doing so far. \$\endgroup\$
    – Kaa
    Commented Mar 7, 2012 at 14:37
  • \$\begingroup\$ @Griffin yeah I just had a thought so I threw it out there; maybe give someone an idea? I had a think about it for some time but I am not sure how to package up events if I were to start including matrices in them they would just get bloated. Still open to suggestions though! \$\endgroup\$
    – Kaa
    Commented Mar 7, 2012 at 14:37
  • 3
    \$\begingroup\$ Welcome to Gamedev.StackExchange. Ideally, question titles should be phrased as questions, to make questions easier to search and find in the future. If you're not really asking a question, then your problem might be better suited for discussion in chat, or on a different website altogether. \$\endgroup\$
    – thedaian
    Commented Mar 7, 2012 at 18:04

1 Answer 1

2
\$\begingroup\$

I'm not a professional and my answer is not OpenGL-specific, so take things with a grain of salt, please.

That said, what I did in my own little rendering framework was this:

Everything that would qualify as a "GameObject" (in a strict OOP perception model) is called an entity. Entities are represented by just integer keys retrieved from an entity store. Entities can consist of any number of components. Those contain the real functionality and would be Mesh, Material, Transform, CollisionVolume, AudioPlayer, etc. When one wants to attach a component to an entity, they hand the entity key to a store for the wanted component. Behind the scenes, that store creates another component in a linear array of same-type components and remembers that whenever someone wants the retrieve a component with the same entity key, it's the one just created.

That way, if some components can be "updated" in bulk without knowing about anything else (Collision Volumes for instance) they are all linearly laid out in the component store's memory and if someone wants to retrieve just one of them, they can do so via the key.

So much for the general thing. Now regarding rendering, I'm still left in some kind of halfway immediate mode, where I tell the renderer the entities I want rendered via entity key. When I'm done declaring entities to be rendered, the renderer fetches all the components required for rendering, e.g. Mesh, Material, Transform (wich is Scale, Rotation, Transformation). Mesh- and Material-ID as retrieved from their component stores are aggregated into a sort-key, so that "entities to be drawn" are then grouped by similar meshes and materials. The Transforms have to sorted alongside so I can pack them up and provide them to instanced draw calls where many entities with the same mesh are submitted with just a single draw call and all necessary position data. Christer Ericson has a great post on this on his blog.

I'm just throwing this out, not knowing whether that last bit is a good idea at all (in OpenGL ES, anyway). I'm also aware that I glossed over a lot of details but it ought to be kept simple so you can evaluate the idea. Anyway, this whole thing should scale pretty well (provided the component stores and sorting mechanisms are implemented efficiently) and should also lend itself well to be data-driven as one just needs a mechanism that reads entity/component descriptions and then hits the stores to plug the components together.

One big question mark for me is how to handle interaction between components, but you wanted to know about rendering, so that should do for now :)

EDIT: Check out Niklas Frykholm's blog for a clever way to manage associating entity-keys to components.

\$\endgroup\$
9
  • \$\begingroup\$ Essay answer to a esaay question :) \$\endgroup\$
    – user9790
    Commented Mar 7, 2012 at 11:14
  • \$\begingroup\$ (lol @Jaakko) Thank you for your answer Koarl. That looks to be an interesting alternative way to do it. Do you keep all the possible component indices in your Entity class and then just set them to point to the valid component as it becomes necessary? Kind of like handles? Components as I understood are stored in an array side-by-side (but not 1-to-1) with Entity objects, correct? That's interesting, I haven't tried a component based pattern yet, stuck to inheritance though it came out pretty ugly on my end. \$\endgroup\$
    – Kaa
    Commented Mar 7, 2012 at 14:42
  • 1
    \$\begingroup\$ No problem- It certainly was a wall of text :) For now, there is no such thing as an entity with multiple collision volumes. What I can do, though, is have multiple entities - each with their own collision volume - and tie them together so they move in the world coherently. For that reason I've got a component that's called LocalTransform which is basically a standard transform that generates it's positional data in relation to another (Non-local)transform that it is tied to upon initialization. So I can have one (base)transform and several LocalTransforms attached to it with, say, no offset. \$\endgroup\$
    – Koarl
    Commented Mar 8, 2012 at 8:49
  • 1
    \$\begingroup\$ As for the Transform redundancy thing - A Transform in my Framework consists of Translation (float3), Scale(float) and a Unit Quaternion for Rotation (float4). That's merely 32 Bytes of data. I don't think redundancy is killing me there. But it certainly helps keeping things uniform. I have a function that converts both types of Transforms (non-local and local) into world- or view-matrices, as the shaders still need matrices for vertex transformation. This also has the upside of being able to attach the viewpoint to whatever entity I want. \$\endgroup\$
    – Koarl
    Commented Mar 8, 2012 at 8:52
  • 1
    \$\begingroup\$ Got it! I really like your idea of component based design, and will definitely implement something similar. If I may follow up: the way I understand it is that you have 1 type of component per store, is that correct? So for renderable component you do not have a "regular" component, skinned component, etc. I guess that is the case since you probably want optimal cache hits when traversing the components in a given store. Do you feel that this limits the flexibility of the system? I'm sure it does wonders for multithreading :) \$\endgroup\$
    – Kaa
    Commented Mar 8, 2012 at 23:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .