CPU and GPU optimisation methods

crt_s03_game_art_principles___nonplayer_characters_22

#1

This topic is regarding work for the challenge in Lecture 16 - Non-Player Characters 2/2.

The following is what I could recall of the optimisation methods:

List:

  • Polygon count - CPU: No, GPU: Yes, Rule of thumb: 300-1500 mobile, 1500-4000 desktop
  • Fewer materials - CPU: Yes, GPU: No, Rule of thumb: 2 or less per mesh
  • Fewer bones - CPU: Yes, GPU: Yes, Rule of thumb: 15-30 mobile, 15-60 desktop
  • Separate Forward and Inverse Kinematics - CPU: Yes, GPU: No
  • Single Skinned Mesh Renderer - CPU: Yes, GPU: No

Explanations for methods:

Polygon count:

Reducing the polygon count per character reduces the amount of work the GPU has to do to render the scene.

Fewer materials:

Using fewer materials on each mesh reduces the number of calls the CPU has to make to the GPU (one per material), which reduces the preparation that the CPU has to do.

Fewer bones:

Using less bones reduces the mesh deforming that the CPU has to calculate, which in turn reduces the GPU’s work rendering it.

Separate Forward and Inverse Kinematics:

Animation software sometimes uses inverse kinematics to determine where limbs, etc. should be to get from one place to another.
Unity only uses forward kinematics, so keeping everything as forward kinematics in Unity avoids it having to perform its own translation to forward kinematics.
This reduces load on the CPU.

Single Skinned Mesh Renderer:

Using multiple mesh renderers for a single character can prevent Unity from performing certain optimisations, such as avoiding rendering a part of the character that is blocked from view
by another mesh renderer on the character.
These calculations are sometimes done on the CPU and sometimes on the GPU, so it could reduce load on either of them.

Final thoughts:

I’m pretty pleased with what I could remember, though I think a couple of my explanations are a bit off. I’ll go and check them now. I also had the rule of thumb for polygon count wrong (30-1500 for mobile, rather than 300-1500) but that was the only correction I made to the list.

Update
Turns out that the part about calculations possibly being performed on either the CPU or GPU was in regards to the fewer bones optimisation, rather than the Single Skinned Mesh Renderer one. The game may choose to calculate where the polygons are on the deformed meshes on either the CPU or the GPU, so it could reduce load on either of them.

For the Single Skinned Mesh Renderer method of optimisation, the culling optimisation that Unity performs reduces the number of polygons and hence reduces GPU load, and the CPU also doesn’t need to calculate as much for the deforming of the meshes.

_I also had the explanation for Separate Forward and Inverse Kinematics slightly wrong. You can only create forward kinematics in Unity, so it has various optimisations that it can perform for them. Getting the animation software to “bake” or produce forward kinematics versions of the animation, allows Unity to do these optimisations and not use it’s own inverse kinematics, which are not as optimised (if at all).


#2

For this task, I referenced the Unity Manual to gain a better understanding. Under Animation, Performance and Optimization is where I found relevant information. Also various other areas of the manual.

Number of Bones: CPU is what we learned. Mobile: 15-30 per character; Desktop 15-60 per character.

To add to that, some items to keep in mind are extra bones will increase the size of the build, additional bones can be in either ‘generic’ or ‘humanoid’ mode, and the developer has to think about the cost (in terms of resources) before just adding bones. Also by selecting Humanoid rather than Generic, IK goals or fingers can be removed if not needed which is less expensive.

An example would be developing for the Android platform where the build max size is 50MB, with two (2 GB) expansions. It may be helpful to do small prototypes at various stages of development to ensure you are getting the performance that you want before going too far.

Multiple Skinned Meshes: CPU intensive; no more than two materials per mesh.

The Unity Manual goes on to say combine skinned meshes whenever possible. Splitting into two Skinned Mesh Renderers is a bad idea, which is what was explained in the video I believe when talking about Ethan’s body and Ethan’s glasses. It does go on to say there are situations where a developer might want to use more than one material so that will likely become more apparent as we progress through training.

I am a little confused with the Ethan example because Ethan’s body is a skinned Mesh, but the glasses are joints that do not bend in the same fashion, but rather like hinges as explained in the Manual. So, could it be that the non-skinned mesh has a much less performance hit, and in this case it would work fine?

Polygon Count: We learned this is GPU intensive; mobile 300-1500 per character, desktop 1500-4000 per character. Which is echoed in the Unity Manual under Modeling Characters for Optimal Performance.

Separate Forward and Inverse Kinematics: We learned that it is better to do inverse kinematics in a 3D application and bake it. I was thinking the baking happened before import but now I see the ideal workflow is to keep IK and FK separate in the 3D application during modeling. When imported into Unity the model’s inverse kinematics nodes are baked into forward kinematics. It sounds like this is automated and gives latitude to go back to the 3D application at any time, munipulate IK nodes, and then reimport. Without baking, this has a CPU overhead with no gain in functionality so clearly a waste of resources.

Update When Offscreen: I may have understood this incorrectly when watching the video. I was thinking that checking it was the good thing, but actually ensuring it is not checked is what we want. Unchecked (disabled), then when the GameObject is off screen the animations will not run, which will save on resources. More specifically on CPU resources.


#3

Awesome work. The Unity manual is a great resource for this.


#4

Thanks! The manual helps a lot.


#5

During the CPU and GPU optimization section, we learned several methods to keep the use of GPU and CPU resources balanced. Here is my reflection on each:

  1. Polygon count between 300-1500 on mobile while desktop 1500-4000. This is solely GPU dependent. Per character. What I drew from this is that every time a polygon needs to be drawn and rendered it takes graphic resources to process. One thing I didn’t consider during the talk is also the impact that lighting effects/reflections can have on the ability for hardware to manage character polygons: reflections imply multiple drawings, etc.

Keep Materials low: CPU intensive and ideally no more than 2 materials per mesh. In my reading up on materials/mesh I came across “draw calls:” seems each material that needs to be drawn = 1 draw call. Multiple materials = multiple draw calls, plus whatever effects lighting does. Keep this number low for best performance. I now understand why assets like “Mesh Baker” on the store are so popular and useful: combining meshes and materials in a way that reduces pull on resources.

Bones: Both GPU and CPU dependent; 15-30 bones on mobile and up to 60 recommended on desktop. I remember in the video that every new bone implies more deforming of mesh around that area, thus needing more resources. In consulting some forums though I have heard people using anywhere from 30-156 bones in multiple characters and being fine on desktop environments. Certainly an aspect I can imagine that requires much prototyping and testing with on-screen character count as Dan mentioned above. Also made me start to wonder what parts of the body one can get away with having minimal bones…some Unity users on forums mentioned foot and ankle since it really just needs to hinge in most cases. Certainly app and context dependent.

Separating Kinematics: My understanding is that forward kinematics = programmer rotates object and where the objects joint is is determined. Inverse implies programmer assigns a hinge/joint and the software determines how the object will rotate to achieve a desired motion around the hinge. My takeaway is to render/‘bake’ the inverse kinematics so that the project does not need to determine how the object will rotate every time it is drawn in realtime. Do this as a separate step before importing the animation into Unity?

Finally, minimize amount of renderers for Skin Meshes. We have an option to optimize CPU use: discouraging skeleton updates and mesh deformations when character is offscreen.

EDIT: Just a note for my own use thanks to quiz. “___ bound” is a title assigned to the aspect of hardware that takes longer to process a given frame. Ex: “GPU bound” implies that the CPU takes a shorter amount of time to process and so there is a wait when the GPU is rendering.


#6

To simplify my understanding of what we learned, here’s what I came up with:

Reduce polygon count for each character (300-1500 on mobile, 1500-4000 on desktop) to save rendering time on GPU.

Use no more than two materials on each mesh; this will save the CPU time to prepare the frame.

Keep number of bones on each character to a minimum (15-30 on mobile, 15-60 on desktops). This will reduce time to factor in mesh deformation, saving both CPU’s preparing time and GPU’s rendering time.

If using packages that allow Inverse Kinematics, remember to bake them into Forward Kinematcs, since the latter is the only kind Unity itself is familiar with; this will save the CPU more time in calculating the rotations of the bones.

Use only one Skinned Mesh Renderer for the whole character, not on each mesh. And leave Update When Offscreen unchecked so that if the mesh is not supposed to appear on the screen, CPU doesn’t have to calculate it and the GPU doesn’t have to render it.


#7

Polygon count - GPU - Mobile 300-1500 / PC 1500-4000 - Fewer things to render
Fewer Bones - CPU / PGU -Mobile 15-30 / PC 15-60 - Less deformation to calculate
One material - CPU - Preparation Overhead
One Mesh - CPU - Preparation Overhead
One MeshRenderer - CPU - optimizations disabled. Deforamtions don’t have to be calculated offscreen
CPU - other optimizations