
Optimizing Your Game: How to Process 3D Models

When creating a 3D model for a video game, modelers usually take into account various hardware and software limitations of the target platforms that will be running the game. When models are too complex, they can slow down processes on the device and ruin the player’s experience with delays and artifacts. In this case, 3D artists need to optimize the resources to boost the performance.
In this article, we’re going to cover such techniques as batching and LOD to help you produce a well-tuned 3D model
Optimization is the process of reducing a 3D model’s file size to ensure a higher frame rate. An optimized game works at the same frame rate across a wide range of hardware – including low-end configurations – and provides a better gameplay experience.
Every model in a game consists of polygons that are converted into triangles during the rendering process. A higher number of polygons means that the assets are more realistic and detailed, but their rendering requires many more resources.
Inexperienced modelers often try to reduce the number of triangles in order to optimize the 3D model representation. Although the lower number of polygons per mesh can improve the performance, optimization is not always about squashing everything into 5,000 triangles.
Check statistics in the engine to find out the frame rate
You should always bear in mind that the most important factor here is the time spent rendering a frame. This critical background process can be evaluated by:
Frame Debugger (Unity) decomposes a frame and evaluates the number of required draw calls
The number of draw calls is a very comprehensive parameter that shows the complexity of the frame. The more draw calls rendering has to push, the more time it takes to deliver one frame.
You should always focus on the number of draw calls you can have per frame based on your hardware and software requirements. Check this target value before you start decomposing the rendering process into separate commands.
The average number of draw calls per frame is as follows:
For example, Battlefield and the third Witcher game push about 1,000-2,000 draw calls, while the same value for PUBG varies from a reasonable amount of 5,000 up to an enormous one of 50,000.
These figures may not be relevant now, as technical capabilities of modern devices change very quickly. However, you should always target a certain number of draw calls for your game because it can easily become a bottleneck.
You can handle optimization in different ways depending on a particular render pipeline in your project.
Render pipeline is a model that describes what steps a graphics system needs to perform to render a 3D scene to a 2D screen. For example, Unity provides three pre-built render pipelines with different capabilities and performance characteristics, and you can also create your own system.
All pipelines are unique, complex systems, and each of them embraces optimization in its own way. However, you can use RenderDoc, Nvidia Nsight, or Intel Graphic Performance Analysis to check out frame rendering in a random PC game.
Generally, you can reduce the rendering time by:
Batching means combining multiple objects into batches for simultaneous processing.
Look at the picture below: there are ten boxes and one tree in a frame. All boxes have the same shader, material, and number of polygons. One can assume that we will have eleven draw calls because there are eleven objects in the frame. In fact, this frame requires only three draw calls.
The system sees that we have ten identical boxes in the frame and puts them together into one mesh. When we play the game, the GPU commands our video memory to draw this mesh as ten separate boxes on the screen.
Depending on the situation, you can use either dynamic or static batching.
Dynamic batching works with dynamic objects. It is a built-in automatic process that analyses the geometry and groups small details such as small fragments separated from the wall.
Dynamic batching reduces the number of draw calls but requires more CPU resources as each frame is processed separately.
Most render pipelines in Unity provide dynamic batching for dynamic geometry, so you can use it if you need to draw a lot of small, similar objects. For example, thousands of fish in a frame in Abzu are actually particles, with their geometry additionally animated by a vertex animation shader.
Note that dynamic batching has very strict limits, and you can’t use it for heavy geometry with more than 900 vertices.
Static batching works with static objects and is usually performed manually. You need to specify that this object is static, so that it will never be changed or shifted.
Static batching doesn’t reduce the number of draw calls per frame. Instead, it reduces the number of render state changes between them as it transforms the static objects into world space—that’s why you can’t destroy a wall or move a chair in a vast amount of games.
💡 Batching is a very effective technique in terms of optimizing your game performance, but it has some drawbacks. For example, when you apply batching, you can’t use Occlusion Culling that allows you to skip drawing objects that are not visible to the camera, such as a box blocked by another larger box.
If you don’t want to use batching, you can always manually merge your geometry for a specific scene and render the entire location in a single mesh.
Both dynamic and static batching require the objects to have the same shader, the material on this shader (see “Materials” in Unreal Engine), texture, and the lightmap location.
You need to combine individual textures into a single texture atlas; otherwise, the objects will be batched separately. Texture atlasing also helps to save on the time you would spend on uploading and downloading each texture.
The same thing happens with lighting because two identical boxes will be divided into two batches if they use different lightmaps.
In addition, you need to consider where the final material will be stored.
Level of Detail (LOD) allows you to reduce the number of triangles rendered for an object as its distance from camera increases.
Although all LODs are produced automatically, each of them requires some space in memory, so it’s better to set a limit. Usually, four LODs are used:
You can also add LOD4 that will be a simple 2D sprite, and sometimes you need to make an extremely full-detail model for cut scenes that will have more polygons than LOD0. For example, a mug in one of the starting scenes of Dead Space 2 has a high number of polygons to avoid being displayed as a square, while similar objects in the game don’t have this level of detail.
LOD can split objects into different batches, so it doesn’t reduce the number of Draw Calls.
Overdraw refers to the system’s drawing a pixel on the screen multiple times in a single frame of rendering.
A certain type of overdraw comes from transparent objects in the frame. The larger the transparency area in the frame, and the more transparent objects are stacked, the longer the render pipeline draws the final pixel because it has to redraw it every time. As the transparency information is stored in the alpha channel, the resulting overdraw is called Alpha Overdraw.
Alpha overdraw can significantly affect the rendering time, and you may need to add extra triangles to replace the transparent area, and to speed up the rendering process.
Whenever you decide to optimize your model, you need to take into account lots of details before you choose a specific tool:
You should always follow these three steps if you don’t want to waste several hours on optimization that doesn’t work.
Gift for registering a person a list of 10 tips for those who want to change their profession.