Framerate Optimization
Visual Range
There are some considerations to be taken into account when optimizing an elastic scene with respect to the framerate. The most important setting is the extents parameter every Spawner provides. Decreasing the extents by 50% leads to about a quarter the amount of objects, but the smaller the extents, the more obviously objects will popup from nowhere. However, popups can be concealed using techniques such as fade-in (from fog), fly-in, scale-in, etc.. Also the terrain can be spawned with reduced extents by using the quarter size terrain option on the ElasticSceneGenerator. Note that this option does not quarter the data that is processed underneath so you still maintain control over Poses, Spawners and Map data of the ElasticSceneGenerator's full extents.
- Decrease the extents of Spawners and find other methods to conceal popup-effects.
- Try the quarter size terrain option on the ElasticSceneGenerator.
Spawner Tweaks
There are strategies to optimize more Spawners more specifically. Using the distance transform on the road mask gives you an idea how close objects can potentially appear as the vehicle drives by. If the potential minimum distance to the road is large enough, objects don't need to be as detailed. Even billboards do a great job in the distance. Avoid spawning too many objects in general. Combining objects in one single prefab is a good idea to avoid unnecessary operations. To wrap it up, the framerate benefits from the following best practices:
- Spawn extra simple objects like billboards at places the vehicle cannot get close to.
- Combine objects and spawn multiple objects with a single Spawner if possible.
Furthermore, If the objects to spawn are very dense (i.e. less than 20 meters apart), like rocks, grass, trees or other scene decoration, it makes sense to use the GridSpawner instead of a PoseSetSpawner which is less versatile but way faster in processing. The GridSpawner still provides options to randomize object transforms, set the height by a Map, mask permitted regions and select from different prefabs by using a PickPrefab* node.
- For dense decoration objects, replace PoseSetSpawners by GridSpawners.
Further general optimizations on objects to be spawned are:
- Make good use of Unity's LOD system for GameObjects.
- If you have to spawn many objects using the same mesh data, activate GPU instancing.
- Avoid scripts with heavy update methods.
- Revisit the physics settings of the objects. Can unnecessary rigidbodies and colliders be removed?
Overdraw Mitigation
Overdraw is another big topic. Rasterized geometry should overlap as rarely as possible. Even an early z-test of opaque objects has impact on the performance - especially if the triangles cannot be sorted and end up being rendered back-to-front, overdrawing the depth buffer multiple times. Therefore, all objects should be optimized to not contain hidden geometry under the opaque surface. This also counts for the generated terrain. The more hills and valleys are generated between the camera and the horizon the more overdraw happens. Using the distance transform on the road mask lets you determine regions that are rather far away from the road. Those regions should be as smooth as possible without alternating heights if you won't see them anyway behind the rows of hills next to the road. To mitigate the workload needed for the rasterization process/step mind the following:
- Refine every object geometry by eliminating hidden surfaces that are't visible but will still be rasterized.
- When using a terrain, avoid hills that are never visible.
Rendering Optimizations
The Elastic SDK is independent from the actual render pipeline and therefore doesn't add any options beside the selection of the terrain shader. Still, the biggest impact on the framerate in most VR applications has the render pipeline with shader operations in particular. Fragment operations have the largest computational share and are the first address to start optimizing. Especially on mobile VR devices that usually come with large pixel resolutions, the fragment shader should be as lightweight as possible. Hence, when choosing your art style, you should mind the following guidelines:
- Reduce dynamic lighting effects to a minimum by baking shadows and highlights into textures.
- Choose an art style that is not depending on too many texture layers (including normal or gloss textures).
- Use as few terrain layers as possible with 4 as the maximum number.
- Only use the diffuse texture for terrain layers.
- Reduce texture sizes to a bearable minimum.
- Avoid transparency.
- Don't make use of post-processing effects.
- Don't use shaders with multiple render passes.
Resolution Trade-Offs
There are other strategies to decrease the global fragment output such as using a lower resolution render target. While decreasing the render resolution and up-scaling the render buffer is an effective solution to generally reduce the fragment count and therefore drastically speed up the framerate, it leads to unwanted pixelization. The quality loss is particularly noticeable with fine lines such as display text. Anti-aliasing is a good way to conceal some of the low resolution artifacts and some art styles even benefit from a lower output resolution with therefore anti-aliased edges. However, since anti-aliasing isn't cheap either, this trade-off should be carefully decided. Foveated rendering, as often provided by the HMD's SDK, is a technique to reduce the pixel resolution in the peripheral view only and is therefore a recommended trade-off for VR experiences you definitely should consider activating. As a summary, mind the following guidelines:
- Find a trade-off between decreased output resolution and increased anti-aliasing.
- Make use of foveated rendering if provided by the HMD.
Other Savings
Last but not least, some global options have impact on the performance as well. Double check the following settings for maxing the framerate:
- Revisit Unity's physics settings. Disable Auto Sync Transforms if it doesn't induce collision accuracy problems as the car moves fast (it may also disturb UI interaction).
- The build should not be a debug build and no profiler should be attached.
- The stack trace should be disabled when logging.