Как ограничить совместные вращения в CCD - PullRequest
2 голосов
/ 10 июня 2019

Я отчаянно борюсь с математикой, чтобы попытаться улучшить Я пытался создать решение IK в Unity.

Я сделал простой алгоритм CCD, который ведет себя так, как задумано: https://www.youtube.com/watch?v=tZvdZGUxbbc

Но когда я пытаюсь добавить ограничения на углы соединения, поведение становится неточным и искаженным: https://www.youtube.com/watch?v=k1YY9KqqaYY

В настоящее время у меня есть цикл for, который перебирает все соединения в цепочке, пока цель не достигнута, а текущие попытки <порог попыток. </p>

Как только корректирующее вращение для каждого соединения рассчитано, я применяю его к суставу [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;

Как показано во втором видео, результат очень плохой.

Может ли кто-нибудь предложить решение и, возможно, объяснение, почему это не работает?

обновлена, исправлена ​​опечатка в вставленном коде.

...