Here are some tips and hints on how to achieve good performance in your PlayCanvas app.
- As the value for texture anisotropy increases, visual improve but performance decreases. Be careful to balance visuals against performance.
- Look for opportunities to pack multiple textures into single images. For example, a greyscale opacity map can be stored in the alpha channel of a diffuse map. Or a greyscale gloss map can be stored in the alpha channel of a specular map. This results in lower VRAM usage.
- Be mindful of the number of dynamic lights in your scene. Keep them to a minimum.
- Enabling shadow casting on dynamic lights is expensive. Point light shadows are particularly expensive. For each point light that casts shadow, the scene must be rendered 6 times into a shadow map.
- In PlayCanvas, a mesh instance is a draw call (a command to draw an individual graphical primitive). Each draw call requires some effort on the CPU to dispatch to WebGL. Therefore, keeping the number of draw calls low is advisable, particularly on mobile. You can see a list of the draw calls for a particular Model by selecting the model asset and viewing it in the Inspector. 100-200 draw calls is a rough target for low end mobile devices. High end desktop machines on the other hand can process thousands every frame and still maintain 60fps.
- Use Batching to reduce draw calls. By creating Batch Groups in your Project and assigning them to Model and Element components, the engine will try to merge them in as few mesh instances as possible, reducing draw calls and increasing performance.
- Be careful when enabling 'Use Device Pixel Ratio' in your project settings. This will cause your PlayCanvas app to utilize the native resolution of a device reducing pixellation but can result in many more pixels being filled, which can cause a significant drop in framerate.
- Keep the number of blended mesh instances in your scene to a minimum. Blended meshes are deferred until all opaque mesh instances have been dispatched and are then submitted in back to front camera depth order. This results in pixels being filled multiple times and can result in a lot of render state changes since blended meshes cannot be sorted by material.
- Try to keep the number of shaders generated by your app as low as possible. Shaders have to be compiled and linked on demand and this operation is expensive, causing delay in app startup and glitches in framerate. If material A has an emissive map but material B doesn't, two shaders will be generated. If you set a black emissive map on material B, the materials can share the same shader. Reducing the number of materials in your scene should also reduce the number of generated shaders.
- Post effects can be expensive so think carefully before you enable them. They can cost a lot in terms of pixel fill.
- Only enable frustum culling on a camera component if, on balance, it is likely to save more performance than it costs to calculate visiblity. If you are rendering a scene where all mesh instances are always visible, definitely disable this option.
- Enabling backface culling on a material will be cheaper than disabling it. Generally speaking, backface culling reduces the number of pixels that the GPU has to fill. This is the default setting for newly created materials.
- Collision meshes do not need to be the same level of detail as the renderable mesh. It is recommended that you set a lower resolution mesh for collision.
- Keep the number of dynamic rigid bodies in your scene to a minimum, particularly on mobile.