Latest  | Search | Go
Edit this page   |   Attach file 

  Home | Tutorials | Technical Reference | Runtime | API Documentation | SceneOptimizations  

Scene Optimizations

Author: TimJohnson

Reality is a very flexible engine, supporting fully dynamic per-pixel lighting and shadowing, and unlimited numbers of shader passes and effects. Because there are so few real constraints, it's very easy to lose sight of what rules you should be following for optimal performance. This tutorial aims to set out the most important of these rules so your scenes performance as good as they look!

Interior Lighting

This is perhaps the most troublesome type of lighting. If you're coming from previous-generation lightmapped engines, you may be used to placing as many lights as you want to fully illuminate a room. However, the move to dynamic per-pixel lighting means there is a fixed overhead for each light added, and great care must be taken to light the scene with minimal performance impact.

For each additional light touching a Prefab or Actor item, that item will get rendered once more. The performance impact is therefore directly and linearly proportional to the number of lights in the scene. Two things influence the performance when more lights are added, fillrate and draw count.

  • Fillrate: This is simply how many pixels are rendered * how complex the shader is for that pixel. Therefore if your mesh has 4 lights and covers your entire view at 800x600, the number of pixels is 4*800*600. If the mesh fills half the screen, the number of pixels is 4*800*600*0.5, and so on.

  • Draw Count: For each additional light pass on a mesh, that mesh is rendered once more, increasing the draw count. Additionally, one draw will occur for each material on a mesh. Therefore 100 prefabs with 2 lights is 200 draws, and 100 prefabs with two materials each and one light is 200 draws. High draw counts hurt CPU. Clicking a prefab will tell you the number of draw calls for that prefab in the mesh information property of the General tab. You may be surprised to find this count is higher than you anticipated because the mesh overlaps the corner of a light.

So how do you reduce fillrate and draw count? As said above, the first thing is to limit the number of lights touching any one mesh. However, it is often the case that a light primarily influences only a few objects, and while others are in its radius they shouldn't be lit, such as geometry behind a room wall or backfacing geometry. The solution to this problem is light include/exclude lists.

Light Include/Exclude Lists allow you to define exactly which meshes a light influences. Your light can either include certain meshes or exclude certain meshes. This list is visible on the General tab of the light you have selected. Wherever possible consider carefully which items really need to be lit, and include only these.

Prefab Size is another vital element of lighting. If you make a single prefab for your entire building, and each of the 10 rooms has 2 lights in, the entire prefab will be rendered 20 times! You must therefore break prefabs into more logical chunks such as walls, floors, and items in rooms. If breaking a mesh would be messy, for example one huge floor, then you can use...

Mesh Split Modifier accessed from the modifiers menu allows you to supply a number of internal splits for your mesh along X/Y/Z axes. These splits form smaller internal bounding boxes used for light culling, and can help reduce overlapping draws. However, be careful, 3 splits along each axis would be 3*3*3 or 27 draw calls! You must find the balance between fewer draw calls and fewer overlapping calls, CPU v GPU.

Shadow Projectors are particularly nasty when it comes to performance, as they require a pass for the objects being shadowed and a pass for the objects casting shadows, and these are usually the same set of objects. Where possible we'd encourage the use of per-object "Drop" shadows which are very high performance. Where you must use shadow projectors, set up minimal inclusion lists.

Exterior Lighting

Outdoors lighting is generally much simpler, because there is typically only one light on most objects - the sun or moon. However, the use of Precomputed Radiance Transfer can create new performance bottlenecks. In its most raw form, PRT is highly performance demanding when used on a large number of objects. In a typical scene we would recommend selective use of this technique for where it is most effective. So what do you use elsewhere?

Baked PRT (Lightmapping) is a technique we support which results in the performance and memory benefits of lightmapping, yet retains visual continuity with other PRT-lit objects, and can handle dynamic lighting color adjustments such as day/night cycles. To use this technique you generate PRT as normal, either per-pixel or per-vertex, then use the Modifiers->Bake PRT option to convert the PRT into its respective per-vertex or per-pixel lightmapped form. The lightmap will bake the shadows at the time of day it was generated, though the current light color will not be baked.

Draw Count can quickly become a bottleneck in a large outdoors scene. Keep an eye on this using your engine statistics print-out. If it's heading towards 1000 or more in a relatively small scene you need to take action! The most effective way to reduce draw count outside is simply to combine meshes. If two meshes share the same material and are close to each other, then use Modifiers->Combine so they can be converted into a single mesh. Be ruthless here - as long as there is no other reason to keep them seperated (such as many overlapping lights), combine meshes. We've seen some insane things in the past, such as artists filling fields of individual blades of grass or placing dozens of individual prefabs to form rock piles.

SceneOptimizations   Edit | Attach | Ref-By | Printable | Diffs | r1.2 | > | r1.1 | More