Как динамически анимировать часть 3d-модели на что-то


8

Мне любопытно, как такая анимация обычно делается в коде.

Несколько примеров:

  • Персонаж поднимает что-то - только рука анимируется к цели. Http://www.youtube.com/watch?v=rW-7uatehx4 См. С 4:50, когда игрок поднимает оружие.
  • Персонаж свисает с уступа - руки устанавливаются в определенное место (выступ) http://www.youtube.com/watch?v=SOiwArn4Bmw в самом начале.
  • Персонаж смотрит на что-то - голова направлена ​​на цель (NPC смотрит на ПК)

Ответы:


4

Это называется обратной кинематикой. Google, вероятно, ваш лучший друг, поскольку он может быть сложным.


Я понял, я должен рассчитать движения, необходимые для достижения желаемой позиции. В этом случае я бы рассчитывал движения только для нужной кости.
Герстманн

Действительно, в описании видео говорится: «... система анимации, полностью основанная на обратной кинематике ...»
MichaelHouse

0

Оригинальная статья: Как кодировать систему IK

Иногда встроенного в Unity IK недостаточно. Я собираюсь показать вам, как создать свой собственный IK-скрипт для Unity. Вы можете применить этот IK к любому сочлененному телу - пальцам, рукам или ногам. IK, который я собираюсь рассмотреть, в настоящее время используется Unity, Unreal, Panda и несколькими другими игровыми движками. Это называется FABRIK.

FABRIK - это итерационный метод. Итерационный метод - это метод, который не сразу решает проблему. Итерационный метод становится все ближе и ближе к правильному решению с большим количеством итераций метода - иными словами, итераций цикла.

Любая проблема IK имеет заданное сочлененное тело (набор связанных конечностей с длинами и углами). Конечный эффектор (позиция конечной точки конечности) имеет начальную позицию с позицией цели. Это может иметь другие цели, такие как углы.

Каждая итерация FABRIK состоит из двух основных частей.

void FABRIK() {
    while( abs(endEffectorPosition  goalPosition) > EPS ) {
        FinalToRoot(); // PartOne
        RootToFinal(); // PartTwo
    }
}

Первая часть переходит от конечной конечности к корневой. Для конечной конечности вам нужно изменить угол / вращение конечности так, чтобы он указывал на положение цели (сохраняя привязанную внутреннюю позицию и позволяя внешней позиции переводиться путем изменения угла). Затем вы переводите конечную конечность по обновленному углу в направлении цели, пока внешнее положение конечности не станет равным целевому положению (сохраняя угол, но позволяя внутреннему положению конечности измениться). Это в значительной степени так и для последней конечности, за исключением того, что теперь вам нужно обновить текущую позицию цели. Текущая позиция цели теперь установлена ​​на обновленную внутреннюю позицию конечности.

Для каждой последующей внутренней конечности вы делаете то же самое. Чтобы было понятно, я обрисую это. Для текущей конечности вам нужно изменить угол / поворот конечности, чтобы он указывал на текущую позицию цели. Затем вы переводите текущую конечность вдоль обновленного угла в направлении текущей позиции цели, пока внешняя позиция конечности не станет равной текущей позиции цели. Наконец, вы обновляете текущую позицию цели, чтобы она была равна обновленной внутренней позиции текущей конечности.

Повторяйте эти операции до тех пор, пока вы не завершите эти операции на корневой ветви. После этого первая часть была завершена.

/* Part One */
void FinalToRoot() {
    currentGoal = goalPosition;
    currentLimb = finalLimb;
    while (currentLimb != NULL) {
        currentLimb.rotation = RotFromTo(Vector.UP,
            currentGoal  currentLimb.inboardPosition);
        currentGoal = currentLimb.inboardPosition;
        currentLimb = currentLimb->inboardLimb;
    }
}

Вторая часть повторяется в обратном направлении: от корневой конечности до конечной. Для корневой конечности вам необходимо обновить ее внутреннюю позицию до корневой позиции. Это должно переводить всю конечность (без растяжения). Это в значительной степени относится к корневой конечности, за исключением того, что вам теперь нужно обновить текущую внутреннюю позицию. Текущая внутренняя позиция теперь установлена ​​на обновленную внешнюю позицию корневой конечности. Для каждой последовательной подвесной конечности вы делаете то же самое. Чтобы было понятно, я обрисую это. Для текущей конечности вам необходимо обновить ее внутреннюю позицию до текущей внутренней позиции. Это должно перевести всю конечность. Это в значительной степени так и для текущей конечности, за исключением того, что теперь вам нужно обновить текущую внутреннюю позицию. Текущая внутренняя позиция теперь установлена ​​на обновленную внешнюю позицию текущей конечности.

Повторяйте эти операции до тех пор, пока вы не завершите эти операции на конечной конечности. После этого вторая часть была завершена.

/* Part Two */
void RootToFinal() {
    currentInboardPosition = rootLimb.inboardPosition;
    currentLimb = rootLimb;
    while (currentLimb != NULL) {
        currentLimb.inboardPosition = currentInboardPosition;
        currentInboardPosition = currentLimb.outboardPosition;
        currentLimb = currentLimb->inboardLimb;
    }
}

Как только первая часть и вторая часть были завершены, вы завершили первую итерацию метода FABRIK. Продолжайте итерации по первой и второй частям до тех пор, пока конечный эффектор не окажется настолько близким, насколько вам нужно, чтобы он был к целевой позиции, определенной некоторым EPS (значение epsilon).

Это оно! Это метод FABRIK. Часть первая повторяется в обратном направлении от конечной конечности. Часть вторая переходит вперед от корневой конечности. Метод FABRIK выполняет итерации первой и второй частей до тех пор, пока конечный эффектор не окажется достаточно близко к целевой позиции.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.