循环坐标下降反向动力学(CCD Ik)

正向动力学:根据父骨骼的移动,一步步正向推导出子骨骼的位置。

反向动力学:根据骨骼末端位置的移动,反向推导出父骨骼及其余上级骨骼的位置。

CCD Ik(循环坐标下降反向动力学):

2D:以当前骨骼起点为轴,分别连接目标点与骨骼末端,保持目标点与骨骼起点的连线不动,旋转当前骨骼(注意子骨骼也会随之转动),使得骨骼末端位置与当前骨骼起点的连线重合。从子骨骼开始到全部父骨骼完成一次转动,视为一次迭代,迭代次数越多,效果越好。

 循环坐标下降反向动力学(CCD Ik)_第1张图片

其核心代码思想及相关注释如下:

//bones[i].a表示骨骼起点,bones[i].b表示骨骼终点,bones[i].len表示骨骼长度,bones.Length表示骨骼数目,target表示目标点
    for (int n = 0; n= 0; i--)//遍历每根骨骼
			{
                bones[i].angle = (angle + Vector2.SignedAngle(bones[bones.Length - 1].b - a, target - a)) % 360f;//angle表示相对于父骨骼的角度,获取目标点到当前骨骼起点与末端位置到当前骨骼起点两条线间的夹角

                int j = i;

                Vector2 origin = bones[j].a;
                if(j!=0)
                        Vector2 right = bones[i - 1].forward;
                else
                        Vector2 right = Vector2.right; //(1,0)
                for(; j

 

3D:将当前骨骼起点连接目标点和骨骼末端,再做这两条相交向量的法向量,以该法向量为轴,做上述旋转,迭代。

循环坐标下降反向动力学(CCD Ik)_第2张图片

 

其核心代码思想及相关注释如下:

for (int n = 0; n < iterations; n++)//迭代次数
		{
			for (int i = bones.Length - 1; i > 0; i--)//遍历骨骼
			{
				Vector3 tolastbone = bones[bones.Length - 1].b - bones[i].a;//当前骨骼起点到末端位置

				Vector3 totarget = target - bones[i].a;//当前骨骼起点到目标点

				Vector3 axis = Vector3.Cross(tolastbone, totarget).normalized;//去上述二向量的法向量做旋转轴

				float angle = Vector3.SignedAngle(tolastbone, totarget, axis);//以该旋转轴所需旋转的角度

				for (int j = i; j < bones.Length; j++)//依次修改每根骨骼及其子骨骼的位置
				{
					bones[j].b = bones[i - 1].b + Quaternion.AngleAxis(angle, axis) * (bones[j].b - bones[i - 1].b);
				}

			}
		}

参考文献:

https://blog.csdn.net/f980511/article/details/123316988

https://zhuanlan.zhihu.com/p/469221237

你可能感兴趣的:(c#,visual,studio,算法,unity,骨骼绑定)