November 19 2019
By Rubén Torres Bonet
November 19, 2019
Last week, I wrote a post to show you how your unity scene hierarchy is reducing the performance of your game. That post arose awareness across many of you developers. And so, many of you asked great questions that I’ll answer in today’s entry.
Yes… I confess.
The examples I often show you in my blog posts are not real-life projects. This is one of the points you have been commenting on.
Ruben, this is an artificial scenario.
Ruben, this doesn’t happen in games.
You see, I understand. It’s easy to doubt the information I provide you when the only cases you see are extreme. I’d even add salt to the wound on the Reddit threads if the author wasn’t me (see how I got owned).
But here’s the thing: all the information I give you is based on the pain and gains of real-life projects I worked on. I do my research before I write here too.
Doing research is great. But that takes time. A lot.
So I won’t set up a new game for every weekly post that I publish. What I do instead is to create a small project to make a point…
…A very real point that I experienced in production games.
You’re never going to come across the exact dummy project in your games. But you’re likely to suffer from the issues these points reveal.
And that’s what matters.
So I took some of the feedback you provided for today’s post. I’ll elaborate on some of the problematic hierarchy patterns you’ll commonly see in production games. We will address unity scene hierarchy bottlenecks based on the tools I gave you in the last article:
In the previous post we established a guideline for diagnosing and optimizing unity scene hierarchies.
Let’s quickly recap The Gamedev Guru’s golden rules:
These apply especially to hierarchy trees that have dynamic objects. And by dynamic I mean, game objects whose transforms are altered. It can be a position, a rotation, a scale or any of the attributes you find in a RectTransform.
If an entire tree is static, i.e. no periodical transform changes, then don’t worry about that tree.
You see, propagating these transform changes takes time. And it takes more time when you have more game objects in the same tree.
But it’s not the total CPU time that concerns me the most. The issue that I see is that it is pretty hard for Unity to do these transform operations in parallel when they happen to be in the same hierarchy tree.
So changes in complex trees take a higher CPU time for two main reasons:
I’m a pragmatic and practical professional developer. So let’s see all this theory in action.
What I have here for you is a scene full of props, particle systems and characters. This is how the unity scene hierarchy looks like:
That’s it. No magic. 4-5 levels of depth, plus all the bones required for the characters. Nothing too crazy apart from the 300 simple characters, which probably accounts for all the missing pieces that a real game has.
Have a look at World. It’s a single root game object containing way too many children. This fact violates the first golden rule of an efficient unity scene hierarchy.
Is that bad? I don’t know. The way to find out is by measuring its relative cost.
I’m using free assets I found in the asset store. That means, I can’t upload this project to GitHub or I’ll risk ending up in jail. Yeah, thanks for that restrictive license, Unity.
And so I start the scene. Not much happening, just a slight amount of movement. I cannot say this is the funniest game I ever played.
Well, I’m not an artist or designer. I’m excused for the looks but not for the performance. Point which brings me to using the profiler now.
I captured a 300-frame profile and here’s what I got:
Was that useful?
Nah, don’t even bother to look at the image.
We don’t know whether that’s good or bad, because we don’t have a reference point.
But we can compare… We can compare against an equivalent, flattened hierarchy.
Let’s try that out.
Analyzing the previous hierarchy, we can notice something of interest.
Most of the introduced game objects are there for organization purposes in this setup. That means, some added hierarchy levels are useful for developers to structure content around them. We incorporate these objects to make development easier.
Game objects such as World, City, Props don’t serve any other purpose than organizing. Our characters, particles, UI and props do not really depend on those to accomplish their goals.
I see a potential gain here.
But on the other side, we don’t want to break the only organizational tool we have. I don’t want to deal with a flat hierarchy during development. That sucks.
We want to keep things structured on the editor and yet we want our game to be performant on run-time.
Ehmm… Is this possible?
You bet it is. That we can do by making use of the script you downloaded in the first part of the blog series: DetachGameObject. This script will let you maintain the original hierarchy when you develop your game but will unparent the gameobject of your choice to squeeze all its performance juice on run-time.
So I’ll add right now our DetachGameObject component to the Character prefab, to all particle systems and to the dynamic canvas we have in place. I’ll ask our component to unparent the game object after a delay of 15 seconds so I can take two profiles: one before detaching and another after it.
Below you find the DetachGameObject asset applied to an example particle effect.
Now that I have set up all DetachGameObject components, there’s only one thing remaining. That’s right, press the play button!So I run the game and after 15 seconds…
All my characters, particles and UI have been detached. Now the hierarchy is much flatter.
So I wonder…
How do both profiles compare? Let’s use the neat profile analyzer to get some fresh numbers.
I’ll translate for you what this chart means…
This comparison says that there’re significant differences between the deeper and flatter hierarchies.
The flatter hierarchy improves performance significantly over the deeper one.
Yes, you might not have 300 characters, but you will surely have many over 100 times more complexity in real gameplay elements, scripts, networking and such.
The conclusion is simple: there’s a performance penalty you’re paying if you don’t have a flat hierarchy. Can you afford it? That’s a question only you can answer. And you better answer that with data and metrics. My metrics in my previous games always reach the same conclusion: I don’t want to pay that expensive bill. I let instead DetachGameObject pay it for me.
That’s my advice for you. Measure your game through the profiler and FAP Hierarchy Tool. Both tools will immensely help you finding scene hierarchy bottlenecks in your Unity game.
Flattening your hierarchy will improve your Unity CPU performance.
What were your scores before and after flattening your hierarchy? Share below.