Реализация инверсной кинематики (не работает)

Программирование на Юнити.

Реализация инверсной кинематики (не работает)

Сообщение AndreyMust19 19 дек 2011, 23:54

Пока самый простой в реализации CCD.

Алгоритм
начало
1) i = номер посл. кости
2) вычисляем углы, на к-е нужно повернуть i-кость, чтобы эффектор совместился с вектором от корня i-кости до цели
3) поворачиваем i-кость на эти углы с применением прямой кинематики
4) i = i - 1
Если эффектор не достиг цели, переходим к началу, пока не кончится допустимое число итераций.


Код
Синтаксис:
Используется csharp
static Quaternion r;
static float dist;
static uint maxIterations = 30;

static public bool Solve1(KinematicLimb limb, Vector3 target)
{
        if (target.magnitude > limb.Maxlen) return false;
        uint iter = maxIterations;
        do {
                --iter;
                uint i = limb.Num-1;
                do {
                        r = Quaternion.FromToRotation(limb.Effector - limb.bones[ i ].Pos, target - limb.bones[ i ].Pos);
                        limb.bones[ i ].Rotate(r);
                } while(i-- != 0);
                dist = Mathf.Abs((limb.Effector - target).magnitude);
        } while((dist > imprecision) && (iter != 0));
        if (iter == 0) return false;
        Debug.Log("iter = "+iter+", dist = "+dist);
        return true;
}


Описание переменных:
limb - это объект "кинематическая конечность", к-я хранит положения костей и их ориентации относительно начала конечности (т. е. точка отсчета - пивот корневой кости).
target - координаты точки, куда нужно переместить эффектор (кончик последней кости), тоже относительно корневой кости.

limb:
Num - число костей в конечности
Maxlen - сумма длин всех костей (длина конечности)
iter - номер след. попытки расчета.
Effector - возвращает координаты эффектора конечности в родной системе координат
limb.bones[ i ].Rotate(r) - поворачивает i-кость на r-кватернион (а вместе с ней, все дочерние кости, т. к. в Unity есть прямая кинематика).
imprecision - минимальное расстояние до цели, при к-м цель считается достигнутой


Результат
Рука вращается как угорелая если цель движется. Если координаты цели не меняются, то вращается по постоянной траектории.
По отладочной информации видно что чаще всего возвращается false из-за истечения количества итераций.
Все выходные бился над этим кодом, не могу понять - в чем ошибка.

Если требуется, выложу весь код, занимающийся рукой.
Нужна помощь? Сами, сами, сами, сами, сами... делаем все сами
AndreyMust19
Адепт
 
Сообщения: 1119
Зарегистрирован: 07 июн 2011, 13:19

Re: Реализация инверсной кинематики (не работает)

Сообщение AndreyMust19 21 дек 2011, 11:54

Если работать напрямую с трансформами и передавать цель в глобальных координатах, то работает:

Синтаксис:
Используется csharp
        static public bool Solve_1(Transform[] trans, Vector3 target) {
                uint iter = maxIterations;
                uint num = (uint)(trans.Length-1);
                do {
                        --iter;
                        uint i = num;
                        do {
                                trans[i].rotation *= Quaternion.FromToRotation(trans[num].position - trans[i].position, target - trans[i].position);
                        } while(i-- != 0);
                        dist = Mathf.Abs((trans[num].position - target).magnitude);
                } while((dist > imprecision) && (iter != 0));
                if (iter == 0) return false;
                Debug.Log("iter = "+iter+", dist = "+dist);
                return true;
        }


Неужели придется отказаться от написанных классов?
Столько мучений ради нулевого результата.
Нужна помощь? Сами, сами, сами, сами, сами... делаем все сами
AndreyMust19
Адепт
 
Сообщения: 1119
Зарегистрирован: 07 июн 2011, 13:19


Вернуться в Скрипты

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 11