Unity踩坑-多级四元数旋转(多级骨骼)
== 仅供学习、笔记之用 ,如有错误望指正==
前言
上文讲了单个物体利用四元数进行局部或本地的旋转。如果被旋转对象带有子物体,子物体想要正确的旋转那么处理又变得不一样了。
对于骨骼还需要注意的是,与静态模型不一样,静态模型导入之前可以在DCC中可以冻结位移和旋转属性。但是骨骼不允许这么做,所以他在世界空间中初始位移和旋转本身就是带数值的,所以理解会更难些。
这里还是使用欧拉角转四元数进行演示。
这次要利用这个API Transform.localRotation
。 将骨架的关节的全局信息变为相对信息,然后填到这个API。
当单个物体变为多级物体。。。
按照上节,给LeftLowerArm
增加新的旋转(0,0,0)这里的本意应该是该关节在关节空间中不会发生任何旋转变化,同时他也是世界属性的,但事实上,如果按上节的思路来,会发生错误,如下图
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;
}
}
启发
这个时候世界空间不怎么顶用了。但是这篇文章的摘要给出了答案。
可以根据正向动力学,对世界信息转换为局部相对信息。做法就是左乘一个父关节世界旋转逆,换句话说这个操作是把该关节的信息从世界拉回到局部。
旋转更正
按照这个思路,修改代码
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;
}
}