Performance Matters

Hi all. A quick note of getting great performance in your PlayCanvas app/game. Sometimes, a game engine can seem like a magic black box. Who knows what it’s doing internally? It helps that the PlayCanvas Engine is open sourced - you can browse the source code and figure out exactly what it’s doing. But often, it’s hard to figure out why you’re not getting the frame rate you expect.

This morning, I jotted down some general guidelines for getting good performance and added them to the user manual. Check 'em out:

http://developer.playcanvas.com/en/user-manual/optimization/guidelines/

While I’m at it, let me also draw your attention to the beta of the PlayCanvas Profiler tool which we added a few weeks back. If you haven’t used it yet, you should familiarize yourself with it. It’s seriously cool for pointing out why you’re getting the performance that you are.

http://developer.playcanvas.com/en/user-manual/optimization/profiler/

Enjoy! :smile:

1 Like

That’s a fantastic summary. Just a few things.

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.

Ouch. I didn’t know that. Seems I’m going to end up doing my spot-lght-shadow trick. (With a spotlight and some clever positioning/width angle control you can get it really close. This was done with 3 spotlights. Instead of just pointing it at the camera, you point it at where the camera is facing…)


In PlayCanvas, a mesh instance is a draw call (a command to draw an
individual graphical primitive). … You can see a list of
the draw calls for a particular Model

What do you mean by “Model” Is that an asset? If I upload an asset with multiple meshes, is each mesh a separate draw call? Is there any way to join multiple meshes into a single draw-call?


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.

Surely this only influences startup time (and if you load a model mid-game?). How can I set two models to have the same shader with different textures? I thought shaders/materials had attached images.


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.

How does this compare with the alternative of having two faces one facing each direction?


Physics

You may like to add that the sphere type is the cheapest to calculate. Many people think that because a sphere takes lots of polygons, it must be the most expensive physics type when it is actually the cheapest.

You can occasionally get away with a spot rather than a point light for casting shadows. In which case, it is certainly much cheaper.

When I say ‘Model’, I mean Model Asset, yes. Model Assets are shown in the Asset Panel at the bottom of the Editor window. Select a Model Asset to view it’s details (including the mesh instance list) in the Inspector panel on the right hand side of the Editor UI. To merge mesh instances that share the same material, you’d have to attach/join/merge them in your 3D modelling app. We will probably do some of this automatically at runtime in the engine at some point though.

Shader generation certainly affects load time, yes. But it also affects runtime performance. The fewer shaders you use in your scene, the fewer WebGL state changes have to be made every frame. Materials have textures assigned to them - not shaders. Shaders are shared between materials. If a material generates a shader, if the shader with the same GLSL has previously been generated, the engine just uses that previously generated shader and both materials share the same one.

Two faces facing opposite directions is more expensive than having one face that is not backface culled. This is because you have to send twice the number of indices to the GPU. For many faces, this can cost memory to store the extra indices and cause the GPU to do more work to process more vertices.

As for sphere vs box vs cone vs capsule, I’m not sure what the performance difference is there actually, so I didn’t make any claims. :smile: To be honest, I would expect box and sphere to be very similar in performance but I don’t have any stats.