onsdagen den 16:e april 2008

Retained or Immediate?

This topic is based on a discussion with a friend, Johannes, so many creds to him for sharing his experience and knowledge! Here you are Johannes, a can of coke! :)



Now, with that taken care of, let's get started :)

There are nowadays two ways of visualizing data, either using retained or immediate mode. In retained mode you have no control over the rendering your self, but put all your rendering setup in an internal data structure, which then is used by the renderer to know what to render. You don't tell the renderer directly how to render it, but "hey, here is my stuff, can you cache it for me and then render it when you want to". In immediate mode you render your data directly, by explicitly telling the rendering framework (OpenGl/DirectX) what you want to render.

Retained Mode
In games, retained rendering would typically be represented by a scene graph, looking something like this:
void SetupRenderer()
{
SceneNode node = new SceneNode();
node.Mesh = myMesh;
node.Transform = Matrix.Create(...);
renderer.SceneGraph.AddNode(node);
}

In gui rendering, this is often represented by gui controls holding their own states. For example a checkbox having an internal state "checked", which typically represents some logical value you store elsewhere in your application.
void SetupGui()
{
CheckBox b = new CheckBox();
b.Checked = myCheckedState;
b.OnCheckedChanged += OnCheckBoxCheckedChanged;
}

void OnCheckBoxCheckedChanged(object o, EventArgs e)
{
myCheckedState = (o as CheckBox).Checked;
}

As you see, because the gui caches the value for you, you need to make sure to update your own internal state "myCheckedState" when the gui control chances state. And of course, if you change the value of myCheckedState you probably want to update the gui as well.

Immediate Mode
In the opposite method, immediate mode, you instead render all objects your self in an explicit rendering call. Instead of caching your state, and then letting an external renderer handle the rendering, you collect all your rendering into your own function, which when called renders your current state to the screen.
void Render(State myState)
{
Mesh playerMesh = getPlayerMesh();
foreach( Player p in myState )
{
renderer.RenderMesh(playerMesh, p.Position, p.Orientation);
}
}

This is good because you don't need to cache your values anywhere, and have better control over the rendering. Instead of adding new nodes to your scene graph, which would probably be represented as new instances of a scene node class, you just add your function calls directly in your rendering method.

For window applications, this type of rendering hasn't been quite as accepted as in game rendering. In Java, though, I think most of their gui controls are represented as a view and a model (the so called model view controlled (mvc) approach). This is a good way of defining guis, as a view of some model. The gui should not store any values it self, but only reflect a model you define and maintain elsewhere. Unfortunately this is not possible in many other gui-platforms, such as in .Net.

There is another technique for gui rendering which, as far as I know, is relatively new. It is called IMGUI, or immediate gui. For a nice video explaining imgui, see:

http://www.mollyrocket.com/video/imgui.avi

IMGUI basically means that the gui has no state at all, and even no callbacks. The gui is only responsible for drawing the current state, which is drawn every frame, and at the same time returning any state. For example, to find out if a button is pressed, you make a rendering call such as:
if (gui.DoButton(x, y, "Press me!"))
{
// Button was pressed
}

This code will both render the button at position x, y, and return true if the button is being pressed. Because of this you need to render the gui ever frame (several times each second), but with todays graphic cards this shouldn't be a problem.

I won't go into detail about how to use IMGUI, but for another more complex example of how to use it, see Johannes post on www.spellofplay!

Which One is Best?
Now, the big difference between immediate and retained rendering is that in immediate rendering you specify, in your rendering loop, exactly what you want to render. This makes it more coupled, as the rendering must know of all the different types of models, instead of, as when using a scene graph, only telling the renderer that you want to render something that has "these properties". But in this case the renderer doesn't know what it is rendering. This is the reason immediate rendering is so much better. You know for sure what you are rendering, and can, based on this knowledge have more control over the rendering. You never get to a situation where you need to question yourself "am I rendering a can of coke?".

And that is where I want to get to in this post, that you always should strive for writing code so that you always know what data you are working on. Avoid using a generic base class for everything where you put a lots of virtual methods doing all your magic stuff, because
  1. Reading such code is a hell because you never know what will happen when you call that function, until you actually run it
  2. The code will get very coupled as you need to put all your specific implementations at the same place, unless you:
    1. Use the visitor pattern (requires a lots of code, and a new class for each new type of action to perform on the types).
    2. Use reflection (non-portable solution, what if you change an entity type to another?).
So, instead of writing:
void Render()
{
foreach(Entity e in entities)
{
e.Render();
}
}
you should write:
void Render()
{
foreach(Player p in players)
{
RenderPlayer(p);
}
foreach(Enemy e in enemies)
{
RenderEnemy(p);
}
foreach(CanOfCoke c in canOfCokes)
{
RenderCanOfCoke(c);
}
}
You move the render specific stuff out from the entity you are trying to render and into the rendering code, where it should belong. You also know for sure exactly what types of entities you have in your world, and can thus perform different tasks depending on the type directly, instead of first trying to resolve the type using different techniques.

In school you learn to use scene graphs, to structure your code into a big hierarchy of classes, and to always prepare for the case when you "need to expand". Don't do that! Make it simple, don't prepare for the worst, don't make your classes super generic. Write code that does exactly what it should, no more, no less, and always try to make it as readable as possible. That is my tip to you today!

1 kommentar:

johno sa...

Hoho thanks for the references Xian :)

The whole "are you a can of coke?" thing was coined by Valli Noghin, and it was initially in reference to class heirarchies called "Entity", not necessarily related to rendering.

It's important to note that you are really touching on two things in your last example. The first example (Entity.draw()) is all about having a heirarchy of externally opaque "things" that know how to draw themselves.

The second one is about getting rid of said heirarchy and ALSO decoupling the visualisation of these "things" from their representation.

Both aspects of the second approach are interesting and important:

In regards to the original "can of coke" dilemma, when doing some logic in your code you often need to look at all instances of a given type, and having those readily accessible by type helps a lot, as opposed to querying some huge list of everything and checking each instance for it's concrete type via some RTTI method.

In regards to visualisation, think about what would happen in the Entity.draw() case if you want to have multiple visualisations of the same thing in your program. You would probably have to have Entity.draw1(), Entity.draw2(), etc = tight coupling.

In the second style, you never have to change your "entity" at all, because the code that is visualising the "entity" is completely external to the "entity" itself = loose coupling.