I have been thinking about split joints an unhealthy amount of time and finally found a solution that feels satisfying. I will discuss the pros & cons of some alternatives first, but feel free to skip to my approach or the downloads directly.

# The problem

Using two bones for organic limbs has an inherent flaw: The area around the middle joint collapses. Most noticeably at extreme angles, such as 180degrees: The two bones coincide and your geometry completely crashes into itself:

# Pseudo-Solutions

Let us first look at some options that are easy to set up. These help to preserve volume, but do **not **fix the problem of the bones & geometry collapsing onto themselves at extreme angles.

## Dual Quaternion

Using the Dual Quaternion or Weight Blended option of Maya’s skinCluster helps to prevent the corner geometry from collapsing (“candy wrapping”). This might be your simplest solution if your deformation is not too extreme.

## Average middle joint(s)

Sometimes Dual Quaternion is not an option (games) or you might need more control. In that case, a common alternative to prevent volume loss, is an extra mid-joint whose rotation is constrained half-way between the first and second bone. You can add any number of such joints, offset them, or even add drivenKeys.

# Solution: Split middle joint

To truly prevent the bones from collapsing onto each other, you have to split the middle joint. The total rotation is split between the two joints and because they are slightly offset from each other, your geometry won’t collapse into itself as much, even at extreme bends:

## Split options

Splitting the middle joint of an IK chain is an old concept. But the question is: where do you place the split joints? I can think of two good candidates. Unfortunately they are mutually exclusive:

### A: Matching orientation

**PRO**: The *orientation *of the **first and last bone** matches the **original chain**.

**CON**: The *total length* of the **split chain **is different from the **original chain**. This can be alleviated by gradually scaling the joints, as the chain approaches its maximum length.

### B: Matching total length

**PRO**: The *total length *of the **split bone chain** matches the length of the **original chain**.

**CON**: The **split bone** *orientations *do not match the **original chain**. The original orientation can be maintained by adding a simple offset transform to the split joints.

Quick note why I bring up the total length of the chain so often: When layering multiple IKs on top of each other (one IK driving the next), it becomes quite crucial that they reach their full extension at the same distance (otherwise a child-chain might pop into a straight line while your main IK chain is still bent). For example in a limb that has an overall “Main IK” but needs a split in one of its joints:

This is doable with both options, but when you **match the total length** you see exactly what is going on and do not have to scale joints (and therefore geo that is skinned to them):

## Option A: Matching orientation

This setup is quite easy: To maintain the original angles, your split joints *must *be somewhere along the axis of the **original bones**. Simply add two middle joints and slide **these split joints** along the original bones into a position you are happy with:

The joints of the resulting 3 bone chain can be scaled to match the total length of the original chain, as the IK approaches its full extension:

Feel free look through my scene, which uses this node setup:

## Option B: Matching total length

Now onto the reason why I am writing this post. This inconspicuous alternative took me various attempts, spread over multiple years. I chased my flawed intuition *twice*! I was so sure that the split joints would lie on a circle, defined by the intersection of the perpendiculars in the middle of either extreme. This GIF is probably easier to understand than that last sentence:

As you can see at the top: It is a tiny bit off. “*A tiny bit?!*“, I hear you scream, and I agree:

Let us solve this issue properly!

### System inputs

I chose to expose three values to the user: **Split Length**, **Split Bias** & **Rotation Bias**:

- The
**Split Length**is a positive float and simply the distance between the**upper mid**&**lower mid**. - We want to maintain the total length. Therefore the Split Length must be subtracted from the two bones we start out with. I call the factor of how much we remove from the upper or lower bone the
**Split Bias**(0.0 to 1.0):- Split bone length = Split Length
- Upper bone length = original upper bone length – Split Length * (1- Split Bias)
- Lower bone length = original lower bone length – Split Length * Split Bias

- Lastly, we can rotate the split joints around the original
**mid**joint, which I call the**Rotation Bias**(0.0 to 1.0).

**Start**: The start position of the IK.**Upper mid**: The split position closer to the start.**Mid**: The middle position of the underlying two bone IK.**Lower mid**: The split position closer to the end.**End**: The end position of the IK.**Pole vector**: Defines the plane and direction of the IK (check this other post for more info about poleVectors).**Original chain**: The two bone chain we start out with.**Split chain**: The chain after splitting. The length is equal to the starting chain, even if it might not look like it.

### Main IK

The **original chain** is the foundation for any solution we pursue. Therefore our first goal is to find the **mid **joint. I implemented a simple IK solver in Bifrost, but for brevity’s sake I won’t go into any detail on that. The most special thing about it is that it uses **reference (=”rest”) lengths **of the two bones, instead of a

**reference**

*position**of the three joints. Defining the reference pose this way simplified some parts of the setup (we will use this IK solver multiple times).*

Somewhat underwhelming, but we have our **mid **position. Yay!

### IK inception

If we find **one of the split joints** (I just happen to have chosen the lower), the ** other split joint** becomes a trivial two bone IK problem:

### Two extremes

For a given **Split Length** and **Split Bias** combination (both values are defined by the artist) we can find two extremes by creating a triangle where either the ** upper **or

**lower**split joint is the corner:

Both look a lot like a two bone IK as well, right?! We can find the **Extreme A** and **Extreme B** position by using our Bifrost IK solver with the appropriate reference lengths. This is where it comes in handy that the reference pose for our custom solver is defined by lengths, instead of positions.

### Find the lower mid

We know that the **lower mid **position lies somewhere between its two extremes. An artist can use the **Rotation Bias **to dial in where exactly that is:

- Use the
**Rotation Bias**to blend between the**Extreme A**and**Extreme B**position - Get the vector from the
point to that blended position.**end** - Normalize the vector from step 2.
- Multiply the vector from step 3. by the lower bone length.
- We get the
**lower mid**, defined by**Split Length**,**Split Bias**and**Rotation Bias**.

### Find the upper mid

Now that we have the **lower mid **position, we get the ** upper mid** position with another two bone IK between the

**start**and

**lower mid**position, using appropriate reference lengths.

And we are done. We can adjust the **Split Length**, **Split Bias** and **Rotation Bias** to dial in the exact split joint positions, without affecting the overall length of the chain:

### Bifrost graph overview

This is the example scene and the Bifrost nodes I created. I grouped the Bifrost Graph according to the sections in this post:

- Calculate main IK to get
**mid**position. - Get the
**Extreme A**&**Extreme B**position. - Get the
**lower mid**position. - Get the
**upper mid**position.

## Notes

I only require initial joint positions from this setup. Therefore I did not make it a full-fledged IK solver:

- The resulting split IK chain is not very robust and does not support parenting.
- I did not run any tests, but the Bifrost graph is most definitely much slower than a C++ node.
- It might be better to define the split length as a
*factor*of the original chain length, instead of as a*length*. The split would remain the same, in relation to the rest of the bones, when the rig is scaled.

# Conclusion

Getting exactly what you see with this “match total length” option is nice, but it is by no means *THE *way. Often times a double joint is not even necessary (thin limbs and/or limited range of motion).

I hope this post gives you an idea of some of the different options to deal with limb deformation, so you can chose a suitable solution for your case. And if you ever need to match the limb length: Hopefully my approach can help you in some way.

Please share any question or insight to make this post better for the next visitor 🙂

❤

I was hoping to see a better deforming mesh at the end of all that. 😦

😀 that’s fair – sorry for the disappointment.

The deformation in the GIF here is basically what you end up with:

https://mykolbe.wordpress.com/2021/04/19/better-limb-deformation/#split-joints

I didn’t spend much time on the weight painting, so the deformation isn’t amazing. But I hope it gives an idea for what’s possible with the setup.