[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ] [ Search: ]

6.4 Rendering Loop

Written by Jorrit Tyberghein, jorrit.tyberghein@gmail.com.

Note: this explanation is now slightly outdated with the new render manager and is eagerly anticipating an update.

Here is a short run-through of the main rendering loop. This document is not an explanation of portal technology. It just explains how the main rendering loop in Crystal Space works so that you can have a quick idea of where you have to go to see a particular part of the algorithm work. This is a rather technical document and not intended for people who are only interested in using Crystal Space in their own projects. It is intended for people who want to know how Crystal Space works internally.

To understand this you should know how portals are used in Crystal Space. You should also read the tutorial (see section Simple Tutorial 1: Basic Setup, World Creation) as this explains the basics for using Crystal Space. This document is based upon the ‘simple’ application (‘CS/apps/tutorial/simple1/’) because this discussion looks a lot like a tutorial.

First we start in ‘apps/tutorial/simple1/simple1.cpp’. In the main() function we initialize our engine. This is an instance of the plugin ‘iEngine’ which actually represents the engine. I will not explain how all the initialization works. This is explained in the tutorial. But I will go straight to iEngine::Draw() which is called indirectly from within Simple::NextFrame(). It is called indirectly because first we call iView::Draw() which then calls iEngine::Draw().

World Rendering (iEngine::Draw())

The method iEngine::Draw() is located in ‘CS/plugins/engine/3d/engine.cpp’.

iEngine::Draw() first sets up the initial ‘iRenderView’ structure. This structure is defined in ‘CS/include/iengine/rview.h’ and is the main structure which is used throughout the entire rendering process. It collects all data that is required for rendering the recursive portal structure.

Basically, it contains the following information:


This is the current clipper. A clipper is a 2D polygon which defines what is visible. Every object is clipped to the view first. Every time we go through a portal the view is modified.


These are pointers to our 3D and 2D graphics subsystems.


This is a special plane. If ‘do_clip_plane’ is used then we clip all geometry in 3D to ‘clip_plane’. This is normally not used except in special cases where we have portals that arrive in the middle of a sector. In that case the portal will be used as an extra clipping plane because we don't want to render everything that is behind the arrival plane of the portal.

Another important thing is that ‘iRenderView’ is actually a subclass of ‘iCamera’ (‘CS/include/iengine/camera.h’) so all camera functionality is present as well.

To set up the initial ‘iRenderView’ structure iEngine::Draw() creates a new instance based upon the given camera.

After this iEngine::Draw() gets the current sector from the camera and calls iSector::Draw() (‘CS/plugins/engine/3d/sector.cpp’). This will essentially draw the whole screen as discussed below.

After doing this (now that the screen is fully updated) we optionally draw halos. Halos are drawn on top of everything else since they are an effect in the eyes.

Sector Rendering (iSector::Draw())

This method iSector::Draw() is located in ‘CS/plugins/engine/3d/sector.cpp’.

iSector::Draw() is responsible for rendering everything in the current sector. Before it does that it will ask the current visibility culler (‘frustvis’ or ‘dynavis’) what objects are likely to be visible or not. It will then render all visible objects sorted by render priority (see section Render Priorities and Objects in Sectors) and using the z-buffer mode that is associated with every object. It is up to the map designer to make sure that the objects in their render priority and z-buffer mode will actually cause the sector to be rendered ok.

Every object that is rendered will get the current camera transformation so it can correctly transform its coordinates from world to camera space: (0,0,0) is the camera pointer, (1,0,0) is one to the right, (0,1,0) is one unit above the camera, and (0,0,1) is one unit in front of the camera.

Every object also gets the current movable (iMovable) which indicates where the object currently is in the world. The transform created from the camera and the movable can be used to transform from object space to camera space. Note that some objects leave this transformation up to the 3D renderer which is good because that means hardware accelerated transforms can be used.

Every mesh object is responsible for drawing itself (see section Mesh Object Plug-In System). The engine decides when to render an object, the object decides on how to render itself. Finally the 3D renderer will process the actual rendering operations done by the mesh object.

The ‘portalmesh’ mesh object type supports portals. When such a portal is rendered the destination sector will be rendered recursively. This means that rendering of the current sector will be temporarily suspended while first the destination sector through that portal is rendered. Going through a portal results in the current ‘iRenderView’ instance to get a new clipper (a smaller clipper usually). Objects can use that clipper to decide if they want to be rendered or not. In some special cases a portal can also transform space (like a mirror). In that case the world=>camera transformation will also be modified in the current iRenderView.

When a sector has finished rendering we conclude by optionally fogging the current sector if this is needed.

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

This document was generated using texi2html 1.76.