如何限制CCD中的关节旋转

时间:2019-06-10 15:37:50

标签: c# unity3d inverse-kinematics cyclic-coordinate-descent

我在数学上拼命拼搏,以尝试改进自己,一直在尝试在Unity中创建IK解决方案。

我制作了一个简单的CCD算法,其行为符合预期:https://www.youtube.com/watch?v=tZvdZGUxbbc

但是,当我尝试向关节角度添加约束时,该行为是不准确且不正确的:https://www.youtube.com/watch?v=k1YY9KqqaYY

当前,我有一个for循环,该循环遍历链中的所有关节,而没有达到目标,并且当前尝试为<尝试阈值。

一旦计算出每个关节的校正旋转量,就将其应用于关节[i]。 然后,我检查每个关节的旋转,并将其限制在最小-最大范围内。

以下是应用旋转的代码,然后检查旋转限制:

Vector3 vectorCurrJointToEndEffector = (joints[joints.Length - 1].transform.position - joints[i].transform.position).normalized; //normalised vector from current joint to end effector position
Vector3 vectorCurrJointToTarget = (target.transform.position - joints[i].transform.position).normalized; //normalised vector from current joint to targetposition

float cosineAngle = Vector3.Dot(vectorCurrJointToEndEffector, vectorCurrJointToTarget); //dot product gives the cosine of the angle for the corrective rotation

//limit possibilities
if (cosineAngle < 1)
{
    Vector3 crossProduct = Vector3.Cross(vectorCurrJointToEndEffector, vectorCurrJointToTarget).normalized; //normalised cross product gives the axis on which to rotate the joint

    float toRotateDegrees = Mathf.Acos(cosineAngle) * Mathf.Rad2Deg; //calculate joint rotation in degrees

    joints[i].transform.rotation = Quaternion.AngleAxis(toRotateDegrees, crossProduct) * joints[i].transform.rotation; //apply joint rotation

    joints[i].transform.rotation = Quaternion.AngleAxis(toRotateDegrees, crossProduct) * joints[i].transform.rotation; //apply joint rotation


    //clamp current joint rotation within set limits
    Vector3 currentJointEulerAngles = joints[i].joint.transform.localRotation.eulerAngles;

    if (currentJointEulerAngles.x > 180f)
        currentJointEulerAngles.x -= 360f;
    currentJointEulerAngles.x = Mathf.Clamp(currentJointEulerAngles.x, joints[i].XaxisMin, joints[i].XaxisMax);

    if (currentJointEulerAngles.y > 180f)
        currentJointEulerAngles.y -= 360f;
    currentJointEulerAngles.y = Mathf.Clamp(currentJointEulerAngles.y, joints[i].YaxisMin, joints[i].YaxisMax);

    if (currentJointEulerAngles.z > 180f)
        currentJointEulerAngles.z -= 360f;
currentJointEulerAngles.z = Mathf.Clamp(currentJointEulerAngles.z, joints[i].ZaxisMin, joints[i].ZaxisMax);

    joints[i].joint.transform.localEulerAngles = currentJointEulerAngles;

如第二个视频所示,结果非常糟糕。

任何人都可以提出解决方案,并可能解释为什么它不起作用吗?

已更新并更正了粘贴代码中的错字。

0 个答案:

没有答案
相关问题