Performance Optimization

Revision as of 05:36, 14 April 2011 by Egon (Talk | contribs)

Introduction

If you find that your Age is 'lagging' or having various performance issues, it may be the time to learn some optimizations tricks. Performance optimisation is a vast topic, but an important one. Especially for large Ages who are more prone to performance drops than smaller Ages. But for new Writers even small Ages can lead to some unsuspected performance troubles. This article covers the most common and most useful tricks.

Note: This is a ‘work in progress’ article.


Things to always keep in mind

As much as possible it is better to have in mind performance issues before starting work on an Age. If you need to optimize an Age after it is mostly completed you will find yourself retouching, or even losing, weeks of work; and that is not an enjoyable thing to do. Therefore here are a couple things to always have in mind:

Top things to avoid:

Decent performance can usually be accomplished in most Ages by avoiding in a couple key issues. Here are the top performance killers; keep them in mind at all times. In no specific order:

  • Polygon counts : ”Yay! my Age has more polygons than Riven! oh.. wait.."
  • Texture sizes : Plasma can handle texture sizes up to 1024*1024. That doesn't mean that all textures should be that size.
  • Age size / design : An open Age will always be more difficult to optimise. You need to think of ways to block the view at times.
  • Excessive shaders : Fancy effects and multi texturing are nice, but only up to a certain point. Do not over-do them.
  • Too many trees : Many people like forests, but trees are the death of performance: Polygons, transparency... Use them sparingly.
  • Collisions everywhere : Never enable collisions on all your meshes. Hand-made collisions meshes are a necessity.

Do not be excessive: not too many polygons/textures/objects etc.. It is perfectly possible to have an Age that is both 'reasonnable' and nice looking.

Measuring Performance

The first step to enhancing performance is to measure it. First of all: know you computer. Is it old? Is it new? Is it above Uru's Minimum System Requirements? Depending on your computer Uru Ages will perform differently. Once you know that download and install FRAPS. This tool will allow you to measure the framerate in Uru. It is free, small, and easy to configure. Your target is to keep the framerate above 30FPS on all computers. Uru was released in late 2003, so computers of this time are our baseline. Computer power tend to double every two years (roughly); if your Age runs at 120 FPS on your computer but you bought it in 2009 then divide that number by 5 or 6... (This isn't an exact formula, but it will give you an estimation). Once you start making some good progress on your Age it is a good idea to send it to people with different computers, so they can test the performance.

Design your Age with 'view blockers'

This cannot be stressed enough: Ages must be designed with performance in mind. It is possible to have a large Age perform correctly as long as it is designed correctly. Among other things that means you need to keep in mind Visibility issues. Cut up your Age in various sections so that you can never see the whole Age at a time. For instance, the City is a large Age but it is cut in different sections, with tunnels and small paths joining them. But try to use the FlyMode to see the whole City at a time and you'll notice the performance difference... This can also be used to make smaller Ages more detailed. For instance Eder Kemo is cut in small sections but they are very detailed. Blocking the view with large objects (walls, mountains, tunnels) at strategical spots is critical.
>> see 'visibility' management section


First things to take care of

Polygon & texture budgets

When actually modelling the Age, this is the first step to decent performance. Judging the 'correct' polygon count for an object is not always easy. Using your best judgement, along with Visregion (see bellow), try to keep the number of polygons in view bellow 150.000. You can't directly measure polycounts in Uru, so make sure to always keeps an eye on those numbers in Blender (or Max).

Again looking at the Cyan Ages is your best start. Here are a few metrics:

  • Relto Age: Polys: around 110.000 / Textures : xx MB
  • Teledahn: Polys: around 150.000 / Textures : xx MB
  • Ae'gura (the City): Polys: above 550.000 / Textures : xx MB
  • Male avatar (at max resolution) : around 5.000 / Textures : xx MB

Judging texture size is a little easier : the larger an object the larger the texture. A small book on a desk do not need to have 1024x1024 texture. There are some tricks to save up textures though:

  • Re-use textures : Don't create a unique textures for each object -- do you really need 20 different 'wood' textures in your Age?
  • Use multi-texturing or stencils for large objects (terrains) : To avoid repettitive textures on large surfaces use multitexturing.
  • Use vertex painting or multitexturing for color variety : If you have a texture that you want to re-use with different colors.

Collisions

Collisions can be the worst performance hit, but they are pretty easy to take care of. Never enable collision on all your meshes. Especially if you have complex meshes. It is a better idea to build low-poly custom collider meshes. Have a look a Cyan's Ages (use the PyPRP importer version) to see how they handle those. For many objects it is not even necessary to model a custom collider, often a simple automatic 'box' 'hull' or 'cylinder' collision setting (depending on the mesh) will do the trick. For instance on a tree a 'cylinder' collision setting might do a decent approximation. 'Static triangle mesh' setting should be avoided unless absolutely necessary (for instance on a complex terrain object). Remember : if there is an object that you cannot reach in game it shouldn't have collisions.
>> http:// wiki link ?

Shadow buffers

By default in Blender dynamic shadows are enabled for all materials; this is the 'ShadowBuff' button. It uses up tons of performance and should be disabled for most objects except for some rare dynamic objects (animated objects/kickables). Shadows can (and should) be done with lightmaps or approximated with vertex painting.
>> http:// wiki link ?


Visibility Management

Vis regions

On large Ages this is the most important performance optimization. Visregions allow you to 'remove' objects from the scene depending on the camera position. If you are in one part of a large Age you may not see the rest of the Age but it is still loaded and it takes up memory. A vis region can be used to unload that. For instance if you are inside a tunnel you do not need to have the rest of the Age loaded; use a vis region here. Used with a good Age design and visibility blockers, this will save a lot of performance and allow you to make detailed Ages.
Designing 'visblockers' is often simple, for instance if you have a tunnel joining two sections of an Age don't make it straight or you will see through the other side. (again Kemo and the City are good examples of that.) For instance, if you have a twisty tunnel going from point A to point B; when you enter the tunnel from region A, region B is not loaded in memory yet, then you take a turn in the tunnel and you can load region B and unload region A and the player won't notice the transition. >> http://www.guildofwriters.com/wiki/Soft_Volumes#Visregions

Occluders

An occluder is a special type of mesh that stops object behind it from being rendered. Occluders take time for the engine to calculate, so they should be large, very simple meshes with few faces. Occluders can be single-sided or double-sided. Occluders are not a replacement for visRegions. Use visRegions wisely, and occluders should be for special cases.

Examples of Occluders in Uru:

  • The volcano in the Cleft occludes the terrain behind it.
  • The desert floor occludes the rooms in the Cleft.
  • Zandi's trailer occludes the brushes and rocks.
  • Some giant occluders hide the two main sections of Eder Kemo from each other

Use an occluder if you already have a large solid object that will block viewing of objects behind it. Note that occluders are "all or nothing": you cannot specify which objects to occlude. Everything behind the occluder will not be rendered. >> Occluders are not currently available in PyPRP 1.6

Page swapping

This is a pretty extreme measure, and no Cyan Age uses it.By default all of the Age pages are loaded in memory on the initial linking. Unlike vis regions who can load(unload objects, Page swapping is used to load/unload whole Age pages via Python. This saves up memory, and shortens loading times; but the tradeback is that when you load/unload a page it freezes the game for several seconds. It is also discouraged as it can cause problems online (because not all players have the same objects in memory).

This is an 'old' method and has only ever been used on one Age (Ahra Pahts).
>> http:// wiki link ?

Relevance regions

<This section needs to be expanded>


Misc. things

Kickables

Kickables are fun, just make sure to use custom collider meshes. (alternatively, 'box' 'cylinder' collision settings can work)

Transparency Overdraw reduction

Too many transparent textures on the screen at the same time ('overdraw') can quickly lead to performance drop. If possible when designing an Age, avoid having too many transparent textures on top of each other. (for instances: a glass in front of a tree in front of water etc)
>> http:// wiki link ?

Mesh LODs

For large objects that can be seen from a long distance it is a good idea to create LOD (Level Of Detail) low-polygons versions. For instance this is done by Cyan in the City for most buildings. Those can be displayed/hidden with Vis regions or 'soft distance' softvolumes.
>> http:// wiki link ?

Loading times

PyPRP does not compress vertex data due to floating-point errors that leave visual artefacts. However, you can use libHSPlasma's prc utilities to unpack and repack your DrawableSpans objects. libHSPlasma always compresses vertex data when repacking. <This section needs to be expanded>