The Relationship between Subsets, Dynamic Lights and Drawcalls
To draw anything on the screen, the engine has to send a command to the graphics subsystem, such as OpenGL or Direct3D. drawcalls often require a fair amount of resources, so especially on weaker devices such as mobiles, reducing your drawcalls is a very common optimization technique.
Before you measure, you have to know that you not only measuring your game, but also the ShiVa Editor helpers as well as your own measurement tools. An empty scene has 0 drawcalls. Drawing a HUD on screen for measuring your drawcalls already introduces additional drawcalls, 6 in our case. Displaying ShiVa gizmos like the grid and axis colors will further increase the number drawcalls, which will play no part in the exported application.
Materials and Subsets
An object with one subset, one subset and no light in the scene will use exactly 1 drawcall (from our baseline of 6 for the measuring HUD):
An object with 3 subsets and 3 different materials will require 3 drawcalls.
Even though these materials are all on the same model, you have to remember that every material must be rendered separately:
The engine will not help you if a material is assigned to multiple subsets. In the picture below, the wall material is also assigned to the floor subset, however we are still using 3 drawcalls.
TIP: If your object uses subsets, make sure that every material is unique.
Every object, unless automatically or dynamically batched, will send drawcalls, no matter if another instance of the object is already in the scene, or if its materials have been used elsewhere. A single floor results in 1 call…
… while 4 tiles result in 4 calls:
When the camera is pitched down (-X) so that one tile goes out of the camera frustum, the drawcall is reduced by 1:
This actually works on the basis of subsets and materials. If we move our test model slowly out of the frame, the drawcalls drops by 1 as soon as the floor material goes out of the camera frustum:
TIP: An invisible material will not use a drawcall, even if it is part of a bigger structure.
Of course, batching is always ahead in terms of drawcalls, reducing these 4 tiles to just 1:
local t1 = scene.createRuntimeObject ( hS, "plane" ) local t2 = scene.createRuntimeObject ( hS, "plane" ) local t3 = scene.createRuntimeObject ( hS, "plane" ) local t4 = scene.createRuntimeObject ( hS, "plane" ) local p = scene.createRuntimeObject ( hS, "" ) object.setParent ( t1, p, true ) object.setParent ( t2, p, true ) object.setParent ( t3, p, true ) object.setParent ( t4, p, true ) local g = scene.combineRuntimeObjectsGroup ( hS, p ) if (g ~= nil) then scene.destroyRuntimeObject ( hS, p ) object.setVisible ( g, true ) end
Materials and Dynamic Lighting
A material that does not use dynamic lighting will always only produce 1 drawcall, no matter how many dynamic lights are shining on it. Remember that every light gizmo adds 4 drawcalls in the debug view:
For using normal mapping, per-pixel lighting is required. You can use up to 12 lights in a single drawcall:
The 13th light will add 1 additional drawcall to the scene:
Toon shading behaves just like per-pixel lighting. Developers often shy away from per-pixel lighting on mobile platforms in order to optimize for rendering performance. While this is generally not a bad idea, make sure you do not run into the drawcall trap: Materials with vertex lighting can only handle 3 lights in one drawcall…
… adding 1 additional drawcall for every 4th light. In a scene with 12 lights, you will have 3 additional drawcalls with vertex lighting compared to per-pixel lighting!
If you mix per-pixel and vertex-lit materials in the subsets of one object, you are are getting the worst of both worlds: the reduced performance of per-pixel shaders and the increased drawcalls of vertex lighting. In the following pictures, the floor uses vertex lighting, while the walls switch between per-pixel lighting and vertex lighting. See how the drawcalls are dramatically increased:
TIP: Do not mix vertex and per-pixel lighting if you rely on more than 3 lights.
The location of the light does not matter. As soon as a model is lit, the draw call will go up, even if the light is only affecting a single subset of a multi-subset object:
ShiVa has a built-in limit of 128 lights per subset. If you exceed this limit, ShiVa 1.9.2 will randomly remove previously placed lights…
… while ShiVa 2.0 will stop adding new lights:
This limitation goes for both per-pixel as well as vertex lighting.
You can get around this limit breaking up your geometry into multiple chunks. It does not matter whether the materials are the same as long as the models are separate:
However, as soon as you use combineRuntimeObjectsGroup, the 128 light limit applies to the entire group:
This limit refers to on-screen lights. If you pan the camera around and lights fall out of the frustum, you can have many more lights: