
Thrive: Heavy Lies the Crown is a medieval city builder with real-time strategy elements. The game, where the fate of the kingdom hinges on every decision a player makes, has both single-player and cooperative multiplayer functionality. Players can strategically expand their territory and their kingdom, and then build out along a large map.
As the team began developing the title, they encountered obstacles when it came to improving performance. After extensive testing, they learned where the bottlenecks were, and what they had to do – build an animation baking system and a custom vegetation system. Here’s how they enhanced character animation in the game.
How does a studio optimize performance while animating hundreds of characters?
As the game took shape, it was clear to the Zugalu Entertainment team that performance was going to be their biggest challenge. They were targeting a pretty low system requirement – an NVIDIA GeForce GTX 750 Ti graphics card for the GPU and a quad-core processor, which is a chip with four independent units called cores that read and execute CPU instructions.
“Any time you want to target a system, the preferable frame rate is 60 fps. There were parts of our system that we couldn't really change that were taking a huge chunk of the performance, so we had to find gains from anywhere that we could,” says Jackie Li, lead concept artist and technical artist at Zugalu Entertainment.
As they searched for areas to boost performance, they decided that the vast amount of character animations were a must fix since they used a large amount of RAM and caused many player systems to crash.
This content is hosted by a third party provider that does not allow video views without acceptance of Targeting Cookies. Please set your cookie preferences for Targeting Cookies to yes if you wish to view videos from these providers.
To optimize the character animation process, the team built an animation baking system. They needed to have hundreds of animated characters onscreen at once and initially looked at vertex animation asset solutions. This was a huge problem for their VRAM and RAM usage. They couldn’t find another solution, so they decided to construct their own.
For the animation system, the team started using vertex baking, which involves taking all the key frames of their animation and baking that data per vertex. “One texture would contain one animation, but the size of the texture for that one animation is pretty large. The memory cost is a factor of the number of vertices multiplied by the number of baked frames. So, 5000 vertices times 100 frames would be a 6 MB texture in the 32 bit float RGB format,” Li says. “When you need many different animations multiplied by a large number of diverse characters, the memory cost starts to get extreme.”
They needed to heavily reduce it, but still maintain the ability to use the GPU to accelerate the animations. They decided to migrate to bone baking, which provided a straightforward way to use less data since Unity’s mesh renderer uses bones to transform the vertex.

“All we needed to do was take the mesh skinning process, binding a 3D mesh to a skeleton or rig, allowing the mesh to deform and move realistically when the skeleton was animated, and move it over to the GPU,” says Garrett Hau, CTO at Zugalu Entertainment.
They then took the transforms of the bones per frame and baked them as textures. Baking that kind of information down saved them a lot of memory. “With bone baking, different characters with the same bone structure can share the baked animation data. We had characters like a farmer and a laborer, whose bone structures were the same. We reused the same baked data across multiple characters to get even more savings,” explains Li.
In the end, even though the game has a ton of characters and animations, they reduced their RAM usage from 20 GB to 500 MB.

When it came to animation, the team focused on skin rendering, applying materials, shaders, and textures to the mesh to simulate skin color, shading, and textures. Li explains that, “a benefit of doing GPU compute-based skin rendering is that we had access to GPU instancing. Instead of rendering each character one at a time, each being a single draw call, we rendered multiple characters with different animations using one draw call.”
This was possible since they took the animation data, textures, and packed them into one single texture array. This looks like a single texture to the GPU. “It’s possible to render every single character using one draw call, but in order to be more flexible, we only had four characters that shared bones.”

When moving from vertex baking to bone baking, the team reduced the number of character draw calls from 1,000 to 20 instanced draw calls. “Vertex baking was difficult since each individual submesh was considered different. A character could have multiple parts and each would have a draw call,” says Hau.
With bone baking, it varies based on how many different types of characters a game has instead. Each character would be one draw call at most since it combines all the submeshes into one mesh. “For example,” Hau explains, “even if there are 10 different types of characters onscreen and each has multiple submeshes, there will only be 10 draw calls.”


Learning mesh skinning helped the team overcome their big animation hurdles. They used Unity APIs to help them along the way.
To grab bone transforms, they accessed the public property of SkinnedMeshRenderer.bones. This API returns an array of transforms that contains information like any other GameObject transforms. For performance measurement, they used Unity Profiler’s automatic detection of development builds running on other computers on the local network. This allowed them to profile the game on their minimum requirement system while working from their main computers.
The performance testing team also applied ProfilerMarker.Begin() and ProfilerMarker.End() APIs to sample performance per frame. These can be used by creating a ProfileMarket.struct, then inserting the previous two method calls in place where they wanted to test CPU timing. This result then showed up in the Unity Profiler.

Li says, “Unity’s APIs have been great. They’ve helped make certain parts of development seamless.” The one bug the team experienced was with the coordinate space in the GPU. “We were getting world space, but we needed bone space.”
While sampling a frame of the bone transform during baking, they needed a transformation relative to the initial bone position, known as a bindpose. To achieve this, they constructed a matrix transform. First, they grabbed the bindpose matrix from SkinnedMeshRenderer.sharedMesh.bindposes. They then multiplied the bone’s world transformation matrix with the bindpose transformation matrix (e.g.,boneTransform.localToWorldMatrix * bindpose).


When it came to producing shaders for animating, the team chose Shader Graph. “It’s Unity's answer to creating shaders without having a deep understanding of the shader code itself. It was really convenient since we didn’t need to rewrite the entire shader ourselves,” says Hau.
For mesh skinning, they had to do a lot of shader math, and the nodes that Shader Graph provides allowed them to complete it. Li explains that, “it’s texture sampling and matrix math. If you wanted to, you could also use Unity’s custom function node to write the code itself.”
For the Editor tools, the animation director had specific requirements to bake animations since he created them all himself. “With C# and Unity’s APIs, it was quite easy to turn the interpolation for shaders on and off. They also helped us change the number of bones to bake and the number of frames to bake them,” says Li. “The user-friendly Inspector APIs allowed for these Editor features to be easily added to the baking tool.”

At the end of the day, while the game’s development was chock full of ups and downs, the team improved GPU performance from approximately 3.5 milliseconds on the GTX 750 Ti graphics card to 0.3 milliseconds on the 2080 Ti graphics card.
As Li puts it, “We’re thrilled with the performance savings and with how the game turned out.”

Start creating games that compete with, and surpass the quality and success of big studio releases with help from powerful tools, support, verified partners, and a vibrant community.