Before we discuss the IK Rig and Fullbody IK in Unreal Engine 5, we need to take a look at the inverse kinematics algorithm in the past. The inverse kinematics was not original from the game industry but the robot industry. Solving the problem that how should the robotic arms rotate when setting the target as a given location.
We emphasize that the noun that we used in gameplay IK is as same as the robotic kinematics, such as the effectors. The IK has been a core topic in robotic kinematics for a long while. In game development, there are also differences between the IK used in robotic kinematics. For example, we do not require for definitely accurancy but request for a highly responsive algorithm to limit the calculation in 0.03ms or even faster for real time gameplay.
We have a lot of IK algorithm, Up to now, the most advanced IK system in Unreal Engine is the Fullbody IK. While the other concept in the title, the IKRig, is a new method proposed by Ubisoft in 2016 in GDC to reuse the animation in different characters.
To discuss on the IKRig and Fullbody IK, we need a knowledge about the ik algorithms in the history, this article focus on the ik methods who have been history in gameplay IK, but they could still inspire us on animation programming.
1. Two bone IK
The two bone IK is the most simple IK, and could be understand with high school mathmetical knowledge. In two bone IK, we only have 2 bones and 3 joints. Note the length of the bone with L1 and L2. After setting the location of the target, we move the effector to the target and then we can calculate the length from the root to the effector by the the law of consines:
\theta_1 = \cos^{-1}(\frac{L_1^2+L_2^2-L_3^2}{2L_1L_2}) \\ \theta_2 = \cos^{-1}(\frac{L_1^2+L_3^2-L_2^2}{2L_1L_3}) \\
It is simple, however, when we come to the 3D space, it will be different, there are infinilty solutions of the angle in a 3D space, in the following image, the solution of every possible location of the joint JB forms a circle.
As a result, we use another vector to determine which plane the solution should in as we know that if three points are not on same line, these points will determine a plane.
In Unreal Engine 5, the two bone IK is called the Basic IK, and the third vector to determine where the solution plane should be is called the Pole Vector.
Unreal Engine 5 provides two methods to calculate the pole vector, one is the direction and the other one is the location. A lot of person have discussed about how to find the best pole vector, like the interpolate of the rotation of the root bone and the efftor bone and so on, however, by my experience, the simplest but most useful way is to try and find a best value. That is because the two bone IK is only used for hand IK or foot IK in gameplay, for these usage try to find a value matches a natural biomechanics result.
Yes, we can find that the two bone IK is only useful for IK chains with 3 joints(or 2 bones). However, it is fast for it provides a numerical analitical solution and the result is natural. So up to now the two bone IK is still useful in foot IK for slope landscape or stairs.
2. the Jacobian Matrix
Assume that there is a giant snake in our game, and the snake need to crawl in a rugged landspace, we need IK to adjust the position of each joints of the snake. Now we have a lot of bones instead of 2 bones we have discussed in two bone IK. What should we do?
Actually, there are a lot of methods, we first discuss about a numerical method, the Jacobian Matrices.
In the following image, let C be the location of the target(the final location of the effector). B as the final location of the joint B. A as the root joint.
We have:
X = L_1\cos{(\theta_1)}+L_2\cos{(\theta_1+\theta_2)} \\ Y = L_2\sin{(\theta_1)}+L_2\sin{(\theta_1+\theta_2)}
The derivetive of them is:
dX = -L_1\sin{(\theta_1)}d\theta_1 - L_2\sin{(\theta_1+\theta_2)d(\theta_1+\theta_2)} \\ dY = L_1\cos{(\theta_1)}d\theta_1 + L_2\cos{(\theta_1+\theta_2)d(\theta_1+\theta_2)}
which is:
dX = (-L_1\sin\theta_1-L_2\sin(\theta_1+\theta_2))d\theta_1-(L_2\sin{(\theta_1+\theta_2))d\theta_2} \\ dY = (L_1\cos\theta_1+L_2\cos(\theta_1+\theta_2))d\theta_1+(L_2\cos{(\theta_1+\theta_2))d\theta_2}
Write it in the form of the matrice:
\begin{bmatrix} dX \\ dY \end{bmatrix} = \begin{bmatrix} -L_1\sin{(\theta_1)}-L_2\sin{(\theta_1+\theta_2)} & -L_2\sin{(\theta_1+\theta_2)} \\ L_1\cos{(\theta_1)}+L_2\cos{(\theta_1+\theta_2)} & L_2\cos{(\theta_1+\theta_2)} \end{bmatrix} \begin{bmatrix} d\theta_1\\ d\theta_2 \end{bmatrix}
We can write it as:
\overset{-}{X} = J\overset{-}{\theta}
derivate them by time:
\frac{d\overset{-}{X}}{dt} = J\frac{d\overset{-}{\theta}}{dt} \\ \overset{-}{V} = J\overset{-}{\omega}
where the V is the linear velocity, and the omega is the angular velocity of the joints. while the matrix J is called the Jacobian matrix.
Most of the time, by moving the target, we can easily get the linear velocity of the joint in the world space, we use the Jacobian matrix to get the angular velocity for inverse kinematics, so we can write it as:
\overset{-}{\omega} = J^{-1}\overset{-}{V}
In our example, the jacobian matrix is a square matrix, but you can easily find that by simple adding degree of freedom or remove degree of freedom of the joints in a 3D space, the Jabobian square will not be a square matrix, which means, it has no inverse matrix. What’s more, even for a square matrix there will be the sigular problem, so solving the inverse matrix of the Jacobian matrix is not always the best method.
There are many methods to solve the sigular problem like using the transpose matrix instead of the inverse matrix, using the Pseudo-inverse, using the SVD decomposite and the Damped least squares and many other methods, we do not introduce them in detail.
3. the CCDIK
We emphasize that from now on, we are not discussing about the numerical methods but heuristics methods. Which means the CCDIK and the FabrIK mentioned later do not in responsibility to provide the correct solution, but enough for gameplay.
the CCDIK is the short of the Cyclic Coordinate Descent Inverse Kinematics. The algorithm of the CCDIK is much more easier than the Jacobian matrix, the Jacobian matrix requires for the knowledge of the linear algebra, while the CCDIK only requires for middle school math.
The following image shows the basic concept of the CCDIK:
By the following expression you can calculate the angle and the axis, the readers should be familiar with the dot product and the cross product:
\theta = \arccos{(\frac{P_e-P_c}{\lvert P_e-P_c \rvert}\cdot\frac{P_t-P_c}{\lvert P_t-P_c \rvert})} \\ axis = \arccos{(\frac{P_e-P_c}{\lvert P_e-P_c \rvert}\times\frac{P_t-P_c}{\lvert P_t-P_c \rvert})}
The following image decribe the procession of the CCDIK:
Optimization
the sequence of the CCDIK have a influence on the result, by limits the sequence of the CCDIK, we can have a better result and a faster optimization:
the optimization based on the idea that for some joints, continue to rotating them still produce good result, so we keep rotating a joint until it provides tiny influence to the result and then we continue to the next joint:
It is easy to add restriction to the joints in the CCDIK, just simply check if the rotation is in the limitation for each bones in each itegration, UE5 provides CCDIK for us and allow to set the rotation limitation for the joints. While the following algotithm, the FabrIK is hard to add restriction. As a result, the Fabrik provided by Unreal Engine 5 doest not allow the restriction.
4. FabrIK
the main idea of the FabrIK is even easier than the CCDIK, it is also a heuristic algorithm and based on iteration. the speed of the fabrIK is much faster than all methods except the two bone IK we have mentioned. For gameplay, we only need about 4 iterations to get a good result.
The algorithm of the FabrIK can be divided into 2 stages. In the first stage, we start from the last joint Jn, move it to the effector, draw a line pass the new location of the Jn and Jn-1, move the previous joint Jn-1 and makes the distance of Jn and Jn-1 equals the bone length. then continue it with the Jn-1 and Jn-2. In the second stage, we move the root to the original location of the root bone since the root location of the bone should never change. and continue this iteration from the root to the effector.
The layout of the original paper is hard to paste, so if you would like to take a look at the algorithm given by the paper, check the references. The following is a implementation in python:
def fabr_ik(skeleton: Skeleton, effector: Joint, target: (float, float), iteration: int):
chain = []
current_joint = effector
chain_max_length = 0
while current_joint.parent_joint is not None:
chain.append(current_joint)
chain_max_length += distance_vec2(current_joint.position, current_joint.parent_joint.position)
current_joint = current_joint.parent_joint
chain.append(skeleton.root_joint)
bone_num = len(chain)
target_length_to_root = distance_vec2(target, skeleton.root_joint.position)
if chain_max_length < target_length_to_root:
return False
chain[0].position = target
for j in range(0, iteration, 1):
for i in range(1, bone_num - 1, 1):
lam = skeleton.get_bone_length(chain[i], chain[i - 1]) / distance_vec2(chain[i].position,
chain[i - 1].position)
new_position = vector_add(vector_multi(chain[i].position, lam, 2),
vector_multi(chain[i - 1].position, 1 - lam, 2))
chain[i].position = new_position
for i in range(bone_num - 2, 0, -1):
lam = skeleton.get_bone_length(chain[i + 1], chain[i]) / distance_vec2(chain[i].position,
chain[i + 1].position)
new_position = vector_add(vector_multi(chain[i].position, lam, 2),
vector_multi(chain[i + 1].position, 1 - lam, 2))
chain[i].position = new_position
return True
So, is the FabrIK a final solution? of course not. there are several problems for FabrIK.
First of all, the result of the FabrIK could change sharply in some situations, the following shows the case:
What’s more, it is hard to add limitation to the bones, it requires for calculating the derivative and find the tangent lines of a strange shape, which is unacceptable for bad performance in real time gameplay. We do not decribe what should we do to add restrctions, you can check the reference.
Wait, what would happen if there is no limitation for the joints? Well. Consider about the following, we want to implment a footIK by using the FabrIK as the following:
By the fabrIK, the calf and foot are on the same line, the algorithm works, and the result is given in the right. However, it does not match the natural result, it finally provides the result like:
Unacceptable right? So it is not a good idea to use fabrIK as the foot IK.
There are also other traditional IK methods, we don’t introduce them one by one in detail here. In a conclusion, the histroy of the development of the inverse kinematics is a long story, many algorithms are invented. In Unreal Engine 5, Epic provides a new idea called Fullbody IK, with IKRig which is invented by Ubisoft and mant other new tools, which will be introduced in the following articles of this series.
And what is the implementation of the Fullbody IK? Well, in Unreal Engine 4, it is implemented by the Jacobian matrix method, however, in Unreal Engine 5, it is implemented by the XPBD(Extended Position Based Dynamics), which is a physically based simulation method, this method is well-known recently for the usage of the rope simulation in the Last of Us Part II. We will introduce this method in the future.
References
This piece of writing is truly a nice one it helps new the
web viewers, who are wishing for blogging.
Just desire to say your article is as surprising. The clearness in your put up is
simply spectacular and that i could assume you are an expert on this
subject. Well along with your permission allow me to take
hold of your RSS feed to keep up to date with coming near near post.
Thanks a million and please keep up the rewarding work.
Thank you for your kind words, it is my pleasure that my article is helpful for you.
It is the best time to make some plans for the longer term and it is time to be happy.
I have learn this submit and if I may just I want to recommend you few interesting issues or advice.
Perhaps you could write subsequent articles referring to this article.
I wish to learn more issues about it!
Thank you for your advice, I’ll give it a try in the future
After looking over a handful of the blog articles on your web
page, I honestly appreciate your way of blogging. I book-marked it to my bookmark webpage list and will be checking back
in the near future. Take a look at my website as well and
tell me what you think.
Pretty! This was a really wonderful article. Thank you for providing this information.
I have been browsing online more than 2 hours today, yet I never
found any interesting article like yours. It is pretty worth
enough for me. In my opinion, if all website owners and bloggers made good content as you did, the web will be a lot more
useful than ever before.
Thank you for your kind words!
Howdy! This blog post couldn’t be written any better!
Reading through this post reminds me of my previous roommate!
He constantly kept talking about this. I most certainly will send this article to him.
Fairly certain he’s going to have a good read. Thank you
for sharing!
Glad that my work is helpful for you.