Unity stepping on the pit - multi-level quaternion rotation (multi-level bones)

Unity stepping on the pit - multi-level quaternion rotation (multi-level bones)


== It is only for study and notes, please correct me if there is any mistake ==

foreword

The above mentioned that a single object uses a quaternion for local or local rotation. If the object being rotated has sub-objects, and the sub-objects want to be rotated correctly then the handling becomes different again.
It should also be noted that for bones, unlike static models, the displacement and rotation attributes can be frozen in DCC before the static model is imported. But the skeleton does not allow this, so his initial displacement and rotation in the world space itself has values, so it will be more difficult to understand.
Here we still use Euler angles to quaternions for demonstration.
This time to take advantage of this API Transform.localRotation. Change the global information of the joints of the skeleton into relative information, and then fill in this API.

When a single object becomes a multilevel object. . .

According to the previous section, adding LeftLowerArma new rotation (0, 0, 0) here should mean that the joint will not undergo any rotation changes in the joint space, and it is also a world attribute, but in fact, if according to the previous section When thinking about it, an error will occur, as shown in the figure below
insert image description here

public class test : MonoBehaviour
{
    
    
    Animator animator;
    Vector3 upperArm = new Vector3(0f, 0f,67.5f);
    Vector3 lowerArm = new Vector3(0f, 0f, 0f);
    Quaternion prevQUp;//upper关节原始世界空间的旋转
    Quaternion prevQLo;//lower关节原始世界空间的旋转

    void Start()
    {
    
    
       
        // 获取动画控件
        animator = this.GetComponent<Animator>();
        // 获取原始旋转
        prevQUp = animator.GetBoneTransform(HumanBodyBones.LeftUpperArm).rotation;
        prevQLo = animator.GetBoneTransform(HumanBodyBones.LeftLowerArm).rotation;
        //upper的父关节
        Quaternion Lshoulder = animator.GetBoneTransform(HumanBodyBones.LeftShoulder).rotation;
        //lower的父关节
        Quaternion Lelbow= animator.GetBoneTransform(HumanBodyBones.LeftUpperArm).rotation;
        //欧拉角转为四元数
        Quaternion currentQ1 = Quaternion.Euler(upperArm.x, upperArm.y, upperArm.z);
        Quaternion currentQ2 = Quaternion.Euler(lowerArm.x, lowerArm.y, lowerArm.z);

        animator.GetBoneTransform(HumanBodyBones.LeftUpperArm).rotation = currentQ1 * prevQUp;
        animator.GetBoneTransform(HumanBodyBones.LeftLowerArm).rotation = currentQ2 * prevQLo;
    }
}


inspire

At this time, the world space is not very useful. But the abstract of this article gives the answer.
insert image description here
According to the forward dynamics, the world information can be converted into local relative information. The method is to multiply the world rotation inverse of a parent joint to the left. In other words, this operation pulls the information of the joint from the world back to the local.

rotation correction

According to this idea, modify the code

public class test : MonoBehaviour
{
    
    
    Animator animator;
    Vector3 upperArm = new Vector3(0f, 0f,67.5f);
    Vector3 lowerArm = new Vector3(0f, 0f, 0f);
    Quaternion prevQUp;//upper关节原始世界空间的旋转
    Quaternion prevQLo;//lower关节原始世界空间的旋转

    void Start()
    {
    
    
       
        // 获取动画控件
        animator = this.GetComponent<Animator>();
        // 获取原始旋转
        prevQUp = animator.GetBoneTransform(HumanBodyBones.LeftUpperArm).rotation;
        prevQLo = animator.GetBoneTransform(HumanBodyBones.LeftLowerArm).rotation;
        //upper的父关节
        Quaternion Lshoulder = animator.GetBoneTransform(HumanBodyBones.LeftShoulder).rotation;
        //lower的父关节
        Quaternion Lelbow= animator.GetBoneTransform(HumanBodyBones.LeftUpperArm).rotation;
        //欧拉角转为四元数
        Quaternion currentQ1 = Quaternion.Euler(upperArm.x, upperArm.y, upperArm.z);
        Quaternion currentQ2 = Quaternion.Euler(lowerArm.x, lowerArm.y, lowerArm.z);

        //animator.GetBoneTransform(HumanBodyBones.LeftUpperArm).rotation = currentQ1 * prevQUp;
        //animator.GetBoneTransform(HumanBodyBones.LeftLowerArm).rotation = currentQ2 * prevQLo;

        animator.GetBoneTransform(HumanBodyBones.LeftUpperArm).localRotation =  Quaternion.Inverse(Lshoulder) * currentQ1 * prevQUp;
        //后两项代表全局,第一项代表转换成本地
        animator.GetBoneTransform(HumanBodyBones.LeftLowerArm).localRotation = Quaternion.Inverse(Lelbow)* currentQ2 * prevQLo;
    }
}

insert image description here

Guess you like

Origin blog.csdn.net/qq_43544518/article/details/125872207