Image for Title

Optimizing Rendering Performance

Here are some guidelines for how to extract maximum from Seroius Engine (SE). There are simply too many thing that are more or less related to engine performances that you cannot get just one number out. What you're about to read in this chapter will clarify some things, but practicing will help you to increase performance factor from SE.

There are some rules that you should stick with:

Visibility: Serious Engine implements dynamic visibility rendering algorithm based on idea of advancing trough sectors (also called zones) connected with portals (polygons between sectors). Models are then rendered if the sector they are classified in is rendered. Common world in SE is actually a soup of entities, but there is one major zoning entity, entity that controls visibility. This huge zoning entity is used to define sectors. Sector is actually group of polygons. Some of them are portals, serving as a link to another sector, some of them are occluders, some detail polygons (don't occlude anything). Generally, you have to build major world architecture on the initial 'WorldBase' brush (you may change its name if you wish) which is 'Zoning'. Zoning means that sectors of that brush will define visibility zones in the world. Non-zoning brushes are not involved in zoning process.

We will explain in more detail how visibility determination and rendering in SE works:

In the simplest case you have only one brush entity which is zoning and has some sectors. The rendering process begins by starting from camera position and adding all the zoning sectors that directly contain the camera (camera is not one point, but rather considered as entire bounding box of a player).

All the walls and portals of those sectors are tested to see if some of the occlude another. (This process is the heart of the SE, it is called ASER - advancing sorted edge rasterizer, and is very fast).

If some portal is found visible (i.e. not occluded by any walls), the sector(s) on the other side of that portal is added too. That means adding their walls and portals too. The procces loops until there are no more visible portals to add. Now all the walls and portals (portals are rendered as semi-transparents if translucent flag is set, like water surface) of all those sectors are rendered to screen.

Effectively, if one zoning sector is not visible, then it is not even considered by the algorithm. This is where the speed ups come from and you should try to maximize that speed up by sectorizing your world properly.

Now, all the models and non-zoning brushes in the world are classified with respect to which zoning sector(s) they are in, and they get rendered if those sectors are determined visible.

Now, if you stand in a room and you don't see the door out, because e.g. there is a column between you and the door, or if the door is closed, the room on the other side of the door will not be rendered. This means that all the models, brushes, particles, lensflares etc, in that other room will not even be considered for rendering and will spend 0 CPU time.

Let's consider how you should create a world utilizing terrain, water, and building filled with columns:

1. Start from a room primitive. Create the terrain as a room, not material, and then select all the polygons around it and mark them as portals (to see through to the background. And make the terrain zoning. This gives you the first room to start working with.

2. Major buildings. Not join, but add the two buildings, so that they define new zoning sectors inside the buildings. Do so with every major building. Those little ones, I'd advice to make non-zoning, but create two mips, so that second mip doesn't have the interior.

3. Doors. Add doors to the passages leading inside the buildings, so you cannot see inside from far away.

4. Full bright. Make terrain's polygons 'full bright'. It is wise to make terrain texture exactly as you want it in the game (of exact brightness, rendered with shadows directly on terrain texture). Then you can turn on flag 'full bright' on all terrain polygons, which will turn off the shadow on them. That way you keep the visual quality, but gain rendering speed and conserve memory.

5. Water. Split terrain sector horizontally, where you want to put water surface. Then simply select this newely created portal (from both sides), give it 'transparent' flag and water texture via blending mode, so you can adjust translucency.

6. Sector content. If you want player to swim in water, just select water sector and change content to 'water' (at sector properties tab). Simple as it is.

7. Adding. You don't add brushes to one another where they can stand separated, When you make a new brush, you know that you can either 'join', 'add' or 'substract' it. If you join it, it becomes a new entity in the world - it means you'd create a non-zoning brush. If you add it, it is CSG added to the current 'target brush' (displayed on the toolbar). Make sure you take care what to add to what. You shouldn't e.g. added some columns to one another, etc. You can see what was added to what by selecting entities in the entity mode and observing what becomes blue. Generally, you should have one zoning brush and add all major architecture to it. Each of the columns, small houses and such detailed objects should be non-zoning brushes. And keep each column, house, etc. to itself, Don't merge them together.

8. Detail polygons. Maybe the most important performance increasers. What are detail polygons? These polygon aren't included in visibility determination process. This is due the fact that some polygons are not much of a occluders. For instance, if you have big wall, it IS occluder and therefore should not be detail. On the other hand, tiny little stairs aren't much of an occluder, so it is best to be rendered as detail polygons. Pillars, little brushes, anything that doesn't block the view has to be detail. This helps performance big time!

9. Mip-brushing. The case of stairs. Stairs are nice, but there are lot of polygons which you can't quite see from a distance. You're stairs looks great when I walk over them, but form a distance, they look just like one slope. And this is the school case for mip-brushing usage. Let first mip-brush be stairs at they are, but you make next mip-brush just with slope. Adjust mip-brush switching distance and see how your stairs switch to slope (lower mip-brush). When you can't see much of a difference, than you have optimal quality-performance ratio. From near, your stairs looks great, and from far no one will see the difference except CPU. :)
It'll be much faster.

10. Use models as architecture. Some things are better made from models than brushes. Columns especially. That way you can have columns with lots of polygons that render very fast and have automatic LOD. You make a model of a column and put it in world. Since models have inexact collision, you then build a simple brush with much less polygons and mark all its polygons as invisible (so that they are not rendered). Take a look at how those rounded columns are made in the beginning of our demo level (Karnak Temple Complex).

11. Mirrors. Handle mirrors with care! Mirror have one nasty habbit - it reflect world. This means that everything in the world must be rendered twice. So, you must be very carefull with what you want to be reflected. Closed rooms with hight frame reate are ideal for mirrors. But be carefull! If mirror reflects something that comes thru the door, this might be the problem. If your level has lot of details, everything has to be calculated once again for the mirror reflection, EVEN IF IT IS NOT DIRECTLY VISIBLE IN THE MIRROR. This results in 2x performance drop.

12. Drop entities to floor. This is nice little feature in SED that is used to drop trees, items and other entities to drop down. Select entities, click RMB, and select 'drop to floor'. This will let the gravity do the biz.

13. Decadic grid. Don't use it. Humans think decadic, machines not. They prefer binary. So, it is much better to use binary grid (there are lotta reasons, I can't mention them here). The main issue is precision. You can have some glitches in geometry that are directly caused by decadic grid imperfection.

14. Directional light. You should use it. You can adjust ambient color of directional light which is infact the color of the shadows. Experiment! Also, sectors can have their ambient light. You can find it in sector property page. They work best in combination with dark lights and gradiental shadows.

15. Polygon splitting. Cut polygons with many edges, they tend to slow-down physics considerably.

16. Detail textures. just two basic rules:
(a) have to be in 3rd layer (you can easly switch this layer off to gain performance on slower 3d accelerators)
(b) detail textures must be 'equalized' and applied with 'shade' blending mode. This will produce both best visuals and best performance.

Equilized texture means exactly what 'equilize' function does in Photoshop. It spreads all the gray levels equally over tones. This means that last texture's mipmap will have middle-gray tone (128 value, +-3). In shade blending mode, this texture can be removed and no-one will ever see the difference. So, when you're looking at the wall from far distance, detail texture won't be rendered at all, but everything still looks the same.
Console variable for adjusting mipmap in which detail textures won't be rendered is 'wld_iDetailRemovingBias'. If you turn 'wld_bShowDetailTextures' on, the textures that satisfy the 'equalization' rule will be rendered in magenta if it is on 3rd layer, or cyan if on 2nd layer.