坐标下降逆动态学)"/>
CCD IK(循环坐标下降逆动态学)
CCDIK(循环坐标下降逆动态学)
策略思路
1.骨骼间的结构为子父层次链接(父节点的变换会影响子节点的)
2.每个骨骼都以【自身轴点到尾叶子节点的方向】旋转到【自身轴点到目标点方向】,开始趋近
3.最终效果与迭代次数成正比
更多细节查看 IK
Arrow类
[Serializable]public class Arrow{public float len; //箭头长度public float angle; //相对父箭头方向的角度public Vector2 angleLimt = new Vector2(-180f,180f); //角度限制public Color color; //Gizmo Colorpublic Vector2 a { get; private set; } //起点public Vector2 b { get; private set; } //终点public Vector2 forward { get { return (b - a).normalized; } }/// <summary>/// 箭头看向目标位置/// </summary>/// <param name="target">目标位置</param>/// <param name="end">评估节点位置</param>/// <param name="limt">角度限制</param>public void Follow(Vector2 target, Vector2 end, bool limt){angle = (angle + Vector2.SignedAngle(end - a, target - a)) % 360f;if (limt && (angleLimt.x != -180 || angleLimt.y != 180)){angle = Mathf.Clamp(angle, angleLimt.x, angleLimt.y);}}/// <summary>/// 计算箭头 A、B 点位置/// </summary>/// <param name="origin">起点</param>/// <param name="right">父箭头方向</param>public void Calculate_AB(Vector2 origin, Vector2 right){a = origin;b = a + Rotate(right, angle) * len;}/// <summary>/// 返回旋转后的角度/// </summary>/// <param name="v">normal</param>/// <param name="a">rad</param>private Vector2 Rotate(Vector2 v, float a){a = a * Mathf.Deg2Rad + Mathf.Atan2(v.y, v.x);return new Vector2(Mathf.Cos(a), Mathf.Sin(a));}}
IKSolverCCD 类
[Serializable]public class IKSolverCCD {public Arrow[] arrows = new Arrow[] { }; //箭头集合public Vector2 target; //目标位置public bool useLimt = false; //是否启用角度限制public int iterations = 4; //迭代次数/// <summary>/// 箭头线段跟踪目标位置/// </summary>/// <param name="maxIterations">迭代次数</param>public void FollowTarget(){for (int n = 0; n < iterations; n++){for (int i = arrows.Length - 1; i >= 0; i--){arrows[i].Follow(target, arrows[arrows.Length - 1].b, useLimt);UpdatePosition(i == 0 ? Vector2.right : arrows[i - 1].forward, i);}}}/// <summary>/// 集合箭头从指定顺序索引开始更新箭头 A、B 点位置/// </summary>/// <param name="arrows">箭头集合</param>/// <param name="right">父箭头方向</param>/// <param name="n">指定顺序索引</param>public void UpdatePosition(Vector2 right, int n = 0){Vector2 origin = arrows[n].a;for (; n < arrows.Length; n++){arrows[n].Calculate_AB(origin, right);origin = arrows[n].b;right = arrows[n].forward;}}}
CCDTest类
public class CCDTest : MonoBehaviour{public IKSolverCCD iKSolverCCD; //CCD 解算器public Transform targetP; //目标位置public Transform anchorP; //固定位置public bool useLimt = true; //使用限制public bool update = false; //实时更新[Range(1,10)]public int iterations = 1; //迭代次数[Button("UpdateAnchor")]void UpdateAnchor(){iKSolverCCD.useLimt = useLimt;iKSolverCCD.iterations = iterations;iKSolverCCD.arrows[0].Calculate_AB(anchorP.position, Vector2.right);iKSolverCCD.UpdatePosition(Vector2.right);iKSolverCCD.FollowTarget();}[Button("Calculate")]void Calculate(){iKSolverCCD.useLimt = useLimt;iKSolverCCD.iterations = iterations;iKSolverCCD.target = targetP.position;iKSolverCCD.FollowTarget();}private void OnDrawGizmos(){if (update) {Calculate();}Arrow last = null;foreach (var item in iKSolverCCD.arrows){Gizmos.color = item.color;Mov.GizmeDrawArrow(item.a, item.b);if (useLimt){Mov.GizmeDrawCircleLimt(item.a, item.forward, item.angleLimt, 0, item.len / 4f, last == null ? (item.a-Vector2.right): last.a);}last = item;}}}
更多推荐
CCD IK(循环坐标下降逆动态学)
发布评论