The My Talking Angela 2 Hair System

Aleksander Gregorka
Outfit7
Published in
13 min readNov 16, 2022

TL;DR: The making of an easy-to-configure hair system for our hit game, including what it took to make it, and how everything came together. With all the hairy details.

I’m Aleksander Gregorka and I’m a Senior Software Engineer at Outfit7. I’ve been with the company since 2014, and during that time I’ve implemented tons of things that moved across millions of screens. And what better way to put my skills to the test than by making bouncy hair.

Today we’ll take a look at the hair system I implemented for our hit mobile game, My Talking Angela 2. At the time of publishing this article, the game had achieved over 300 million downloads in its first year.

The game was made using our own proprietary game engine called Starlite. We’ll get into the details of Starlite and its editor in one of our upcoming blog posts, but for now, the only thing you need to know is that we’re using C++ for runtime development, so any code samples in this article will also be in C++.

Goals

Having a proprietary game engine has some downsides, but also a lot of benefits. An example of this would be that you can’t just take a hair system package from the app store and call it a day. The benefit of implementing it yourself, though, is that you can integrate it into the rest of the app using the same architecture used elsewhere in the game. If something goes wrong, you can fix it yourself, which is extremely important in a project as big as My Talking Angela 2.

The goal of the system was to support stylized hair, meaning that the simulation wouldn’t have to be completely physically realistic.

One of the important things was also that we should avoid hair mesh clipping with other items as much as possible, but this is really hard to achieve in real-time dynamic games where characters can interact with other items, such as toys, hats, and furniture. Even their own arms sometimes move dangerously close to the hair.

It was also very important for the system to be easily used by artists without much back and forth between 3D and Dev teams. We knew we’d be importing a large number of hair rigs, so we wanted to make it as simple as possible for them. Currently, we have 65 hair configurations in the game, including those with the same style but different lengths.

How to Approach the Task

Facing a challenge like this was very interesting, because there were a lot of unknowns at the start of the project. We only had concept art at the time, so the exact style of the hair wasn’t yet known.

When we start projects at Outfit7, we start with the pre-production phase. Typically, we mainly want to solve the difficult technical challenges as soon as possible in order to make the actual production smooth. However, at such an early stage, the art isn’t usually ready yet, so we have to make some assumptions. So for the hair system for My Talking Angela 2, I took a look at the art styles of our previous games, and used some assets from there as a starting point.

Prototyping systems like this early in the production phase is absolutely necessary to avoid project delays in the future — at this stage, we have time to scrap everything and try something else if we need to. It’s also important to plan for things to go wrong. There should be some time dedicated for asset integration.

I tried to predict as many use cases as possible without overengineering for the end of the world — I knew that some things could be fixed later if problems arose during production.

Possible Approaches

Hair Cards

Hair cards are simple polygonal meshes used to shape the hair strands. They are UV wrapped in a way that you can texture them to display hair strands with a simple shader. They can be animated by rigging them, or even applying a vertex shader so they sway a bit when moving. But for our needs, this approach would be a bit too complicated, and we wanted something simpler in terms of geometry.

A developer visualization of how a hair card setup for a sloppy mohawk could look like.

Animated Hair

With this approach we could have hair items rigged and animated traditionally. This would result in a larger application size because we were planning to have up to 30 bones per hair style, with multiple hair types. This would add a lot of animations to the game, just for the hair. Basically each of the character animations would require a matching hair animation. We would need to simplify it with reusing hair rigs, or blending idle poses.

But why is application size an issue? Well, mainly because we’re working with mobile games, and there are limits to how big of a game you can download over a cellular connection. For Android, this is currently 150MB, and it’s 200MB on iOS. From our experience, the increase in installs from being able to download the game via a cellular connection makes it worth it to stick to these limits.

Fitting such a big game into 150MB? Well, that’s a topic for another blog post, but it involves a lot of clever tricks.

Procedural Animation

Ah yes, now we’re talking. When in doubt, you should always use procedural animation.

We’d still be able to use a traditional rigging setup with each hair style having up to 20 strands, but they would be animated dynamically based on world inputs. This would greatly simplify our workflows and make our animation team’s life easier. The downside to this approach is that you have less control over the final looks — unexpected things can happen due to the hair being simulated in real time.

In the end I chose this approach because I believed it would best fit our needs.

Individual hair strands.

Architecture

I wanted the system to be designed in such a way that items should be independent of the other character systems. Basically, you just equip an item (hair, in this case), and the hair system takes care of the simulation.

The system I designed consists of multiple parts. I tried to create it in such a way that it’s not specific to hair, but could also be used for other purposes. If you had some joints and you wanted them to move, for example, you could use this system with little effort. We’re calling it “Bone Physics”. Many jokes came to mind, but for now let’s focus on the topic at hand (I would prefer keeping my job if I can).

Physics Joint

This is the smallest unit in the system. It’s a one-on-one wrapper for your world transform. It keeps references to the previous and current simulated positions, so we can make some calculations based on the differences between the two.

Physics Chain

This is a collection of physics joints. In the example of hair, one hair strand is represented by one chain. Each chain can have its own physics settings, so hair strands (chains) in the front can behave differently than strands in the back.

Simulator Data

In every frame of the simulation, we gather all the chain data, join it in SimulatorData, and feed it to the simulator.

Physics Simulator

I will describe what the simulator does in the next section, but let’s call it a black box, one which takes in simulator data, processes it, and moves the physics joints to their new simulation positions.

After the simulator finishes its job, we take the new joint positions and apply them to the actual 3D transforms. This completes our frame, and the same process is repeated for the next frame.

System architecture.

Simulation

For the simulation itself, the most important thing is that we’re using a fixed time step. This means that our simulation output won’t be affected by the frame rate of the device.

A simplified example of this can be seen below. A fixed time step means that if we want to do something in 160 milliseconds and one step takes 16 milliseconds, we’re getting 10 steps, no matter the FPS of the device. If we have a variable time step, on the other hand, we’re tied to the rendering speed of the device. Frames can take from 16.66 milliseconds (when targeting 60 FPS — 1s/60) to X milliseconds, where X depends on how badly our game is performing.

In the example below, we want to move the ball from position 0 to position 20. Each step, we increase the position by 2 and, with a fixed time step, we get to position 20 after 10 steps. When the time step is variable (16–32 milliseconds between steps in the example), we only get to execute 7 steps in 160 milliseconds. This only brings us to position 14, which is not what we wanted.

The end result for our physical simulation would be incorrect, and the behavior would appear different on slower devices.

To fix this problem, most game engines will provide you with a fixed time step update loop. If you want to do it yourself, you have to measure the time between two frames, then break it up into equal parts.

Calculation

We use Verlet integration for calculating joint movement, which means that we store the previous and current joint positions and calculate the next position based on those, as opposed to storing and using velocity as you usually do with Euler integration. This approach results in a more stable simulation.

Verlet integration is often used for rope physics in game development. If you think about it, hair strands are kind of like tiny ropes, just a bit more rigid.

The simulation itself is basically split up into two steps:

  1. Calculate forces (gravity, other world influences like wind, etc.); and
  2. Apply constraints.
void BonePhysicsSimulator::Simulate(const SimulatorData& data) {
DebugAssert(data.chain_.Count(), "Empty chain");
SetInitialJointPositions(data);
ApplyForce(data);
ApplyConstraints(data);
ApplySimulationUpdates(data);
}

Constraints are what limits or enhances the movement of joints to achieve the desired effect. You can apply the constraints multiple times — the more you do it, the more accurate the simulation result will be. But it comes at a cost as you will burn more precious CPU cycles.

Simulation Constraints

Damping

This is used to reduce the effect of position change. The effect is applied from the start to the end of the chain.

Vector3 BonePhysicsSimulator::DampPositionDelta(const Vector3& velocity, const Ref<BonePhysicsConfiguration>& physics_configuration) {
return velocity * (1 - physics_configuration->damping_);
}

Bounciness

This is used to enhance the effect of joint movement down the chain.

Vector3 diff = previous_position - joint->simulation_position_;
joint->simulation_position_ += diff * (1 - bounciness);

Collision

I decided to implement my own collision system because it was simple enough to add to the simulation, and it enabled me to fine-tune hair collision without relying on external dependencies.

We ended up supporting multiple types of colliders — sphere, plane, capsule.

Sphere-to-sphere collision and sphere-to-plane collision.
Sphere-to-capsule collision and the character collider setup.

Rotation Lock

I implemented rotation lock, which allows you to limit the maximum angle of rotation from parent to child joint. For example, you could say that the maximum bend is 90 degrees, which could be useful in some cases. However, in the end we didn’t use it for the hair system.

Pinned Joints

My Talking Angela 2 features a bathroom where you can bathe your Talking Angela by applying some soap to her. This spawns soap bubbles all over the character, and you have to wash them off using a shower head.

To animate the shower hose, we used the bone physics system. However, the final joint needed to be moveable as the player was going to drag it around.

We could simply override the joint’s position in the simulation, and the rest of the joints would react to that. We called this process “joint pinning”.

Joint Rotation

Just a tip if you’re ever working on something similar yourself — if you want to keep the chain mesh volume consistent, an important step is to always rotate the child joint towards the parent. If you don’t, the mesh will appear stretched.

Simulation Weight

Simulation weight is a variable that tells the simulator how strongly to apply the simulation result to the final joint position. It lerps between the original joint position and the simulated joint position.

This would allow us to have stylized physics in cases where physically correct simulations would break the desired hairstyle. For example, if we have a braid over the shoulder, we want to keep it on the shoulder at all times, while allowing it to bounce a bit when moving. If we were to use the simulation fully, the braid would simply fall down, being pulled by gravity.

Debugging hair texture — the final result is much nicer.
Stylized physics example — the braid over the shoulder.

With this, we could also animate parts of the hair with traditional animation, if needed. This would be useful in complex cases, like when Angela is getting up in the morning.

We are now also able to combine different physics behaviors per hair style, because each chain has its own properties. A ponytail could be fully physically simulated, for example.

Applying the System to a Hair Rig

We have 1 to 20 chains per hair rig. There is no need to cross-connect the chains like you would do for cloth simulation. As each of the chains is standalone, we can have some mesh clipping for more complex hair. Angela’s arms can pass between the strands in some cases, but we decided that that would be acceptable.

Each hair style has from 1 to 3 different lengths, so we reused a lot of rigs to minimize the app size as much as possible.

Results

Workflow for Artists

It’s a two-step process. When a rig is imported from 3D software to our engine, you can right-click it and use a context menu that runs a hair setup script on it. What it does is finds the root joint, then adds a BonePhysicsChain object for each chain that it finds, and automatically links all the child joints. It also automatically creates a physics setup configuration object with some defaults that suit most of the hair dynamics, so in an ideal case you probably don’t even have to tweak the settings that much.

The second part is testing the hair, which is done using another context menu. It will spawn the hair for you, to quickly verify if it’s working.

Other Applications

One of the other use cases is the shower hose, as previously mentioned above. We also used it to animate some headwear, as shown below.

Headwear and some bouncy spheres that were used when testing the system in development.

Conclusion

Working on the hair system for My Talking Angela 2 was a challenging project for me. There were so many unknowns, the biggest and the most important of which was the fact that the style of the game wasn’t yet finalized. (Although artists might say that the style is never final — at least until it’s final, final). I had to guess some things and, in the end, I created some small features that weren’t used. That was a shame because I probably made some cool bugs that will never see the light of day.

Looking at it now, the system is kind of simple. But you know what? If I were to do it again, I would simplify it even further, and get an artist on board as soon as possible to help prototype the custom-made assets.

Performance-wise, we haven’t had any issues so far, which is great. But we’re targeting mobile devices, so every bit of extra performance helps — if nothing else, the battery of the device lasts longer. As the Bone Physics system is designed in a self-sufficient way — I called it a “black box” before — all the calculations could also be run on a different thread, and then at the end we could just apply them on the main thread.

In the future, I think we could improve some clipping issues by pairing up the joints in the Physics Chain, and treating them as capsule colliders, which would improve hair behavior when Angela’s arm passes through a hair strand. But overall, I’m very proud of the end result, and I’m looking forward to doing something similar in the future.

The best thing about this whole process is that it was pretty hilarious. Some of the bugs I produced were ridiculous and I’m sorry I didn’t record more of them. I’m leaving you with these, as a taste.

Thank you for reading.

--

--

Aleksander Gregorka
Outfit7
Writer for

Senior Software Engineer, Game Developer, Maker of Things.