How we created our climber - Part 4

Calculating support

By Geert Beuneker

How we created our climber Part 4 thumbnail

Our primary goal was to make a realistic climbing simulator. This means that it uses the actual topology of the rock for climbing. There are no pre-placed markers to grab onto, everything is completely determined by the shape of the 3D mesh and the position of the character. When climbing in real life, the movement you can do and the forces you can apply is determined by what you’re grabbing, how you’re grabbing it, the amount of grip you have and how you position your body. Building a system that takes all of this into account will be the last piece of the puzzle to solve to make our realistic climbing game.

Normals and dot-products

The most important part of the support system is to use the normals of the triangles in the mesh we’re climbing. That is to say, we want to look at the direction of the surface we’re grabbing and compare that to the position of our climber.

When grabbing a surface you can either push or pull to move your body around. For pulling you want the surface to be pointing away from you, and inversely for pushing the surface should be pointing towards you. For calculating support there is actually not really any difference between the two. All that matters is how the surface is aligned to your body. For those familiar with linear algebra you probably already know exactly what to use for this: the dot product. What that does is calculate the alignment of two vectors. So if you take the dot product of two vectors it will give you 1 if they are pointing in the same direction, -1 if they are pointing in the opposite direction and 0 if they are orthogonal to each other. This is exactly what we need! Imagine trying to push a box. You can move it forward by pushing on a surface on the front (surface is pointing towards you: dot product -1), you can pull it backward when grabbing the surface on the back (that surface points away from you: dot product 1) but you can’t really move it by pushing on the top of the box (dot product 0).

Push Pull

But which directions should we be comparing to each other? For the longest time we simply looked at the center of mass (CoM) of the character and compared the direction of the CoM towards the surface you’re grabbing to the normal of that surface. So if your center of mass is hanging directly below a ledge you have a really good grip, as it gradually moves up past the ledge your grip becomes worse until you are able to transition from a pulling to a pushing motion. This worked well enough for the longest time but as we’re testing and playing the game some small things felt off. It looked unnaturally difficult to transition from pulling to pushing.

At some point after hanging off of a bunch of the tables in the office it hit us. Just like with our rigidbody in the previous part we shouldn’t be using the center of mass. What we should really do is compare the direction from our key joint (shoulder/hip) to the surface instead of the center of mass. Because really, as soon as your shoulder (or hip) passes the ledge that is when you can transition from pulling to pushing. This made a huge difference and suddenly pulling the body up from a ledge looked much more natural!

Center of Mass

Accounting for gravity

We already have a large part of our logic down, but nothing in our logic so far accounts for the fact that you are always struggling against gravity. Hanging off a ceiling is certainly more difficult than doing the same thing on the floor, but so far nothing accounts for that.

Like with all of our problems we started out with a simple approach. We simply added a gravity penalty to our grip values. So we simply looked at the direction of the surface, compared that to the gravity direction and calculated a penalty. The worse the surface supported against gravity the higher the penalty and the lower the resulting support factor. This served us quite well for a while. But just like all of our early decisions things feel slightly off if we take shortcuts, so once again we had to look at real world physics to figure out what was wrong.

The solution came to us by taking gravity out of the equation for a bit. Because ultimately gravity is just another force on the body. So our logic should be sound regardless of the strength and direction of gravity. Ultimately what is happening is that you are trying to apply a force to your body in a certain direction. That force may include the force required to counteract gravity, or wind or simply the force you want to apply to move towards your target. The first step is to determine what direction that force needs to be. So we take the direction our body wants to go (determined by the targets of the keyjoints discussed in the previous part) and add to that the gravitational vector that we always have to work against. The result is the force required to move our body towards our target while also working against gravity. The next step is to take this resulting force and determine how well our grabbed surfaces can help us in applying that force. To do this we once again take the dot of the normal of the surface and the force calculated in the previous step. The more the force is aligned with the normal of the surface the better it is. We can even add a minimum value to account for “friction” of the surface. This gives us a value between 0-1 depending on the alignment with the surface. The final result is to take this value and to scale it with the desired force.

Gravity Dot

This was a much better approach for accounting for gravity and also allows us to take other outside forces into account. And the results once again looked much more natural.

Inverse and local inverse support

Climbing is more than just pushing and pulling, there is also pinching and jamming. So we also need to account for either pinching a pointy part of the rock or jamming your fist into a hole for extra support. But this also happens on a bigger scale, because you can also clamp yourself in between two walls with your arms and feet or tightly hug a pillar for more support. In the game we call this inverse support, because you are using inverse pointing surfaces to increase your support.

First, there is “local” inverse support. Which means any support you can get from a single hand of foot. To simulate either pinching of jamming we gather all the surfaces around an appendage, for example your hand. Our first approach was to check all of the surfaces within a small radius of the hand and to calculate the maximum dot product between any of those surfaces. So basically we compare any surface to all the other surfaces and check which two surfaces are pointing the most away/towards each other. This determined a bonus for the amount of support on that limb. This approach had two drawbacks:

  1. It wasn’t very accurate, because it ultimately only used 2 surfaces for the bonus.
  2. It was very computationally expensive. We had to do this every frame for all the surfaces near each appendage (hands/feet). For dense parts of a mesh this completely tanked the framerate.

So we came up with a better approach. Instead of comparing each of the surfaces against each other, we now simply add up all of the normals of the surfaces. The closer that value is to 0, the better the inverse support. For example, think of a sphere which is very easy to grab because it has perfect inverse support. If we add up all the normals in the sphere they will each point away from each other so the final result will be zero. If we instead take a flat surface and add all its normals together you will get a very high value which means very bad inverse support. This way we only have to go over all the surfaces once (O(n)) instead of comparing them all to each other (O(n²)) making it both more accurate and much more performant. We then use this value to calculate a support bonus that gets added on top of the support our character already has.

Local Inverse

This same principle applies to non-local inverse support, where we look at what the limbs are holding. We take the normals of all the surfaces our hands and feet are currently grabbing, we compare them to each other, we calculate a support value and add it as a bonus to our character’s total support. The more the normals are pointing in opposite directions the better our support bonus.

Global Inverse

Final details

There are a couple of extra details to wrap it all up. First of all the surface size. Smaller surfaces (triangles in a mesh) will provide less support than bigger surfaces because they’re harder to grab. So we also plot the surface size on a curve which gives us a value for how much support any surface size can give us. We use this value to scale the support calculations of all the surfaces (triangles) to take the surface size into account. Otherwise grabbing a tiny pebble would give you just as much support as grabbing a huge boulder.

Next is a leverage calculation. Because, depending on the angle, the further your shoulder is from the point it’s grabbing the harder it is to pull/push yourself up. By projecting the vector from the grabbed surface to the keyjoint (e.g. shoulder) onto the target force vector, we get a new vector whose length is determined by not only the distance from the shoulder to the grabbed surface but also how much the shoulder is in line with the force we are trying to apply. Because when you are hanging directly beneath a ledge, the distance doesn’t really matter for the amount of force you need to apply. This leverage factor is used as a penalty on the amount of support you get from a surface.

Leverage

Finally we still need to make the player fall when their support isn’t good enough. We started out with a more complex algorithm by calculating the amount of pressure on each limb and comparing that to the limb’s support. If the pressure was greater than the support, then the limb would slowly slip and eventually let go completely. But while playtesting it just didn’t feel good and was kind of confusing to most players. So instead we simplified it and just set a threshold for the total support. Each limb has a support value of 0-1 so if adding those together exceeds our support threshold you’re good and stamina gets regenerated. But if it’s below the threshold your stamina runs out. The lower your support is, the quicker your stamina drains. So for example with a threshold of 1, each of your limbs only needs a value of 0.25 to support your weight. But if you let go of 1 limb your total support drops to 0.75 and you will start losing stamina. If your stamina is completely empty your character will completely let go and start falling down.

Support to force

So now that we have this support value, what do we actually do with it? Well we can use this value to scale the amount of force we can apply with our limbs. In the previous article we determined the forces required to keep us still and to move towards our targets. But now that we have the support value, we can use that to determine the amount of force we have available. To put the two together, we simply scale the support value (0-1) with the maximum amount of force each limb can apply and voila, we have our realistic climbing system!

Now we can determine what direction we want to move in, we can grip any part of the wall and that will in turn influence how well we can move our body. Shifting our body weight, choosing which surfaces to grab, properly positioning our limbs, all of these are taken into account with the system we created. After a long journey and a lot of struggles we feel pretty happy about our climbing system. So far we haven’t found any game that is using a more realistic climbing simulation than the one we have created for New Heights. Our goal was ultimately to create something that didn’t exist before and we really wanted to exist: a game that realistically simulates our favourite hobby, climbing! And we’re happy we succeeded in bringing that to life.

Related articles