# How should rendering be architected?

## Recommended Posts

Currently if I was to program a game using C++ with SFML or Java with LibGDX I would render game objects by calling "object.render()" on the game object. Although this makes it easy to access the information necessary to render the game object, it also couples rendering to the game logic which is something I would like to move away from. How can rendering be implemented so that it is decoupled from the game objects?

I wish to know how this can be done in the standard object oriented paradigm, so please don't suggest that I use an ECS. Thank you.

##### Share on other sites

This is very much simplified, and purposefully so.

class Object {
RenderingData _renderData;
...
};

int main()
...
while(stillRunning) {
stillRunning = updateGameLogic(allObjects);
renderAllObjects(allObjects, renderer);
}
}

The renderAllObjects function takes in the renderer interface, or a concrete renderer object, or whatever you have or want to pass in, grabs each object in the list and pulls out the render data (which can also be anything you want it to be, textures, models, buffers, shaders, etc), and passes it into the renderer in a renderer specific way.

If you just need to decouple game logic and rendering, this is one way to do it, but not the only way, as i'm sure others will chime in with their ideas.

##### Share on other sites
5 hours ago, Seer said:

I wish to know how this can be done in the standard object oriented paradigm, so please don't suggest that I use an ECS

ECS is an architectural pattern which follows composition over inheritance principles. And as such this is an object-oriented design.

##### Share on other sites
On 11/16/2018 at 11:07 PM, Seer said:

Currently if I was to program a game using C++ with SFML or Java with LibGDX I would render game objects by calling "object.render()" on the game object. Although this makes it easy to access the information necessary to render the game object, it also couples rendering to the game logic which is something I would like to move away from. How can rendering be implemented so that it is decoupled from the game objects?

Instead of game objects containing rendering logic, have them own a renderable sub-object. Instead of "for each object, render", use "for each object, add renderables to queue". Then pass the queue of renderable items to your renderer object.

e.g. instead of a Monster having a "Render" function that actually goes and draws some things, the Monster class might be composed out of a Sprite or a Model class. You can then have some code like this can extract all the monster sprites to be drawn:
std::vector<Drawable*> queue; for( auto& monster : monsters ) queue.push_back( monster.GetSprite() );

You can take this a step further by removing the specific game objects (e.g. Monster) from this process. When you create a Sprite/Model/etc, it can have it's lifetime owned by the Monster (or whatever created it), but also be weakly owned by a "Scene". The scene then internally has a list of all Drawables at all time, which it can iterate through without any knowledge of your specific gameplay classes.

On 11/17/2018 at 4:49 AM, _Silence_ said:

ECS is an architectural pattern which follows composition over inheritance principles. And as such this is an object-oriented design.

This is off-topic, but ECS is much more closely related to the relational model (so much that I'd go as far as to say that is the relational model, reinvented, badly). In ECS you put logic in systems and non-abstracted data layouts in components, whereas OO typically ties the two together. Also, ECS has the silly restriction that you can only have one level of composition -- Entities can be composed from components, but components can't utilize composition. Some particular ECS implementations also force the silly restriction on composition that Entities can only have one component of a particular type. Neither relational or OO have those kinds of strange restrictions.

##### Share on other sites

I especially like this approach. Great for ordering sensitive objects later on. i.e. handling transparencies that exist within an object.

Edited by orange451

##### Share on other sites

I might have been wrong here. But actually

Quote

ECS follows the composition over inheritance principle

and

Quote

Composition over inheritance (or composite reuse principle) in object-oriented programming (OOP) is the principle that classes should achieve polymorphic behavior and code reuse by their composition (by containing instances of other classes that implement the desired functionality) rather than inheritance from a base or parent class.[2] This is an often-stated principle of OOP, such as in the influential book Design Patterns

Sources:

##### Share on other sites

... basically draw everything at one spot in your code (kind of centralized), NOT with "object.DrawMe();". reuse DATA whenever possible, because it doesnt make sense to have 2 times the vertices and indices of the same mesh in your buffers. minimize the state changes so that you dont call "glUseProgram(xyz);" and other API functions many times unnecessarily.

if "world" contains everything you have, then "class Graphics" can be the spot where to do the job:

class Graphics
{

void Render(const World& world);

};

	struct RenderState
{
int program;
int vertexarray;
bool depthtest;
bool culling;

void Set(/* change renderstate here */);
};
struct Drawable
{
mat4 transformation;
int material_reference;
int mesh_reference;
};
struct Batch
{
RenderState State;
std::vector<Drawable> Drawables;
};
std::vector<Batch> Batches;
/* ... fill "Batches" with all you need to draw ... */
/* ... sort this array first to minimize state changes ... */
/* ... draw everything ... */
for (auto& batch : Batches)
{
batch.State.Set();

for (auto& drawable : Drawables)
{
/* set transformation */

/* set material, bind textures if necessary */

/* get drawcall parameters for mesh */
auto parameters = global_array_of_parameters[mesh_reference];
/* => to reuse meshes wherever possible !! */

/* issue draw calls */
Draw(parameters);
}
}

Edited by john_connor

## Create an account

Register a new account

• ### Game Developer Survey

We are looking for qualified game developers to participate in a 10-minute online survey. Qualified participants will be offered a \$15 incentive for your time and insights. Click here to start!

• 15
• 30
• 9
• 16
• 22