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 grayscale opacity map can be stored in the alpha channel of a diffuse map. Or a grayscale 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 pixelation but can result in many more pixels being filled, which can cause a significant drop in frame rate. This can be adjusted at runtime after assessing the user's device capabilities. Read more at Adjusting Device Pixel Ratio.
- 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 frame rate. 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 visibility. 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.
- For applications where there is little visual change over a period such as product configurators, there is a specialist property to reduce CPU and GPU usage.
pc.Application#autoRendercan be set to
falseso that frames are rendered on demand via
pc.Application#renderNextFramewhen there is a visual change such as the user moving the camera or adding a part to the product.
- 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.