- Home /
I answered the question myself.
Problem combining transform.rotation and hierarchical rotations
Hi, I try to implement a forward kinematics system to transfer absolute joint positions of a skeleton to joint rotations and to rotate the whole skeleton in the scene. I already transferred the positions in global orientations for each joint and I can transfer all hierarchical rotations i need, but I can't rotate the whole body in the scene. To demonstrate my problem I made an example scene where the joint system represent a simple skeleton model:
Each joint system consists of an empty game object called System and three Joints which are represented by a coordinate systems. The first joint is a child of the System game object and its position is at the top center of the numbers you see in the scene. The second joint is a child of the first and the third is a child of the second joint (see the hierarchy screenshot).
System 1 (the selected/highlighted one) shows the 3 hierarchical joints pointing in the needed directions with LookRotation. Y/up shall point to the next joint position and z/forward simply points to Vector3.forward. For simplicity these values are set and not calculated in this example. If I apply a rotation to the whole system, in the editor I can see that the empty parent game object is rotated but the joints (the child objects) are not. This is the update code for this system:
void Update () {
transform.Rotate(Vector3.up, currAngle);
transforms[0].localRotation = Quaternion.Inverse(transform.rotation) * Quaternion.LookRotation(Vector3.forward, new Vector3(1.0f, 0.0f, 0.0f));
transforms[1].localRotation = Quaternion.Inverse(transforms[0].rotation) * Quaternion.LookRotation(Vector3.forward, new Vector3(0.0f, -1.0f, 0.0f));
transforms[2].localRotation = Quaternion.Inverse(transforms[1].rotation) * Quaternion.LookRotation(Vector3.forward, new Vector3(0.0f, -.5f, -.5f));
// just some value generation
if (currAngle > 1)
{
raise = false;
}
else if (currAngle < 0)
{
raise = true;
}
currAngle += raise ? step : -step;
}
The script is attached to the System game object. So transform is the joint system's transform. The array transforms consists of the three joints (transforms[0] is the first joint, transforms[1] the second and so on).
In system 2 I don't multiply the inverse of the parent rotation to the global rotation of the joint. Now the whole system can be rotated but the orientation of the second and third joints are wrong.
transform.Rotate(Vector3.up, currAngle);
transforms[0].localRotation = Quaternion.LookRotation(Vector3.forward, new Vector3(1.0f, 0.0f, 0.0f));
transforms[1].localRotation = Quaternion.LookRotation(Vector3.forward, new Vector3(0.0f, -1.0f, 0.0f));
transforms[2].localRotation = Quaternion.LookRotation(Vector3.forward, new Vector3(0.0f, -.5f, -.5f));
If i apply the inverse to the second and third joint again (system 3), the orientation of them stays the same for the whole rotation.
transform.Rotate(Vector3.up, currAngle);
transforms[0].localRotation = Quaternion.LookRotation(Vector3.forward, new Vector3(1.0f, 0.0f, 0.0f));
transforms[1].localRotation = Quaternion.Inverse(transforms[0].rotation) * Quaternion.LookRotation(Vector3.forward, new Vector3(0.0f, -1.0f, 0.0f));
transforms[2].localRotation = Quaternion.Inverse(transforms[1].rotation) * Quaternion.LookRotation(Vector3.forward, new Vector3(0.0f, -.5f, -.5f));
The first system shows the correct joint orientations, but the system as a whole is not rotated. How can I apply the system rotation to all child joint rotations like in system 2 and 3 without overwriting their local orientation?
Solution:
While describing the problem more clearly, I had the idea to multiply LookRotate with transform.rotation. For a skeleton model, this means that all global joint rotation must be multiplied with the global rotation of the skeleton, before they are multiplied with the inverse rotation of the parent. System 1 now shows the effect I wanted:
The new code for this system is:
transform.Rotate(Vector3.up, _currAngle);
Transforms[0].localRotation = Quaternion.Inverse(transform.rotation) * transform.rotation * Quaternion.LookRotation(Vector3.forward, new Vector3(1.0f, 0.0f, 0.0f));
Transforms[1].localRotation = Quaternion.Inverse(Transforms[0].rotation) * transform.rotation * Quaternion.LookRotation(Vector3.forward, new Vector3(0.0f, -1.0f, 0.0f));
Transforms[2].localRotation = Quaternion.Inverse(Transforms[1].rotation) * transform.rotation * Quaternion.LookRotation(Vector3.Cross(new Vector3(0.0f, -.5f, -.5f), Vector3.right), new Vector3(0.0f, -.5f, -.5f));
Answer by JVene · Jul 30, 2018 at 05:22 PM
When you say "in the editor I can see that the empty parent game object is rotated but the joints (the child objects) are not"
That's likely the problem. I don't see how they are actually children of the object being rotated.
Thank you for your reply. I updated the question with a screenshot of the hierarchy. They are actually children of the System object.
Answer by Bunny83 · Jul 30, 2018 at 06:02 PM
Your code is very confusing. Your title talks about absolute positions but you don't ever read any position information and only work on rotations. Also keep in mind that the "rotation" property returns the worldspace rotation of an object. Objects without parent have equal localRotation and rotation values.
It's not clear what is your incoming data and how are all those transforms you're using in your code arranged hierachically?
All your LookRotations are aligned with the forward axis and just rotate around the z axis. Also taking the inverse of a worldspace rotation and using it as localspace rotation doesn't make much sense.
Finally if you really have absolute position data for each joint you should keep in mind that not every position data can be translated into a rotational motion except each joint is allowed to stretch or shrink. Also keep in mind that just the positions of the joints do not define a complete localspace for that joint. Assuming that each joint's extending along it's local forward axis just from the positions you can only derive 2 of the 3 angles as the joint can rotate around that axis.
The given information is not enough to understand your specific issue nor to suggest any corrections. In your image we can't even tell which is the parent in each of the 3 figures,
Thanks for your reply. I updated the question and hope I could clarify some misunderstandings. I also found a solution for my problem by trying to find some better explanations for you. The absolute positions of the joints are already converted to directions which I use for the LookRotation function. It was just an opener to describe the setting.
Follow this Question
Related Questions
GameObject facing fowards 1 Answer
Changing the parent transform of the First Person Controller 1 Answer
I am having an issue with the rotation of a child 1 Answer
How do I rotate the propellers on this drone? 1 Answer
1st person Camera rotates suddenly in another direction when unparenting from a platform 1 Answer