Это первое руководство, объясняющее основы javafx-ik , библиотеки для обратной кинематики с JavaFX. Исходники библиотеки можно скачать с GitHub .
Что такое объект Bone ?
Рисунок 1: Одиночная кость
Кость является фундаментальным строительным блоком для обратной кинематики с библиотекой javafx-ik . Кость имеет длину и сустав, вокруг которого она может вращаться. Конец с суставом называется головкой кости, другой конец называется хвостом. На рисунке 1 показана одна кость, ее голова, хвост и длина.
В библиотеке javafx-ik кость напоминает класс Bone . Чтобы инициализировать это, длина должна быть передана как минимум, но обычно также угол устанавливается во время построения. Пример кода выше устанавливает кость длиной 50 и вращением 0, что означает, что она будет указывать горизонтально вправо.
|
1
2
|
// Adding bone b2 to the children of bone b1b1.getChildren().add(b2); |
Посмотреть код на Gist .
Сборка костей
Рисунок 2: Сборка двух костей
Кости могут быть собраны, чтобы определить каркас анимированного объекта. Две кости связаны путем прикрепления хвоста одной кости b1 к головке другой кости b2 . Кость b1 называется родителем кости b2 , кость b2 называется потомком кости b1 . На рисунке 2 показаны две соединенные кости b1 и b2 .
Класс Bone предлагает два свойства для структуры. Свойство только для чтения parent хранит родительский элемент кости, а свойство children представляет собой ObservableList всех дочерних костей. Следующий фрагмент показывает, как можно соединить две кости b1 и b2 :
|
1
2
|
// Adding bone b2 to the children of bone b1b1.getChildren().add(b2); |
Посмотреть код на Gist .
Рисунок 3: Структура манекена
Угол свойства «только для чтения» определяет поворот между костью и расширением ее родительской кости. Значение 0 приводит к прямой линии, значение 180 приводит к тому, что дочерняя кость перекрывает своего родителя, но указывает в противоположном направлении. Хотя наличие родителей и детей накладывает порядок на кости в скелете, обычно не имеет значения, какая кость является родителем, а какая — ребенком. Путем многократного связывания голов и хвостов объектов Bone можно создать цепочку. Эта простая структура используется в образце гусеницы. Сложные объекты определяются с помощью дерева костей. Точное положение кости зависит от положения родителя и поворота. Кость в верхней части дерева, у которой нет родителя, называется корневой костью. Корневая кость немного отличается во время инициализации. Угол свойства корневой кости определяет ее вращение в общей сцене. Вы можете думать об этом как о наличии родительской кости, которая направлена горизонтально вправо. Теперь мы можем определить структуру нашего манекена, как показано на рисунке 3. Код для генерации каркаса манекена можно увидеть в примере кода ниже.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
// Definition of headfinal Bone head = new Bone(30, 90); // Definition of torsofinal Bone torso = new Bone(80, 0);head.getChildren().add(torso); final Bone[] upperArm = new Bone[2];final Bone[] upperLeg = new Bone[2]; for (int i=0; i<2; i++) { // Definition upper arms upperArm[i] = new Bone(60, 60 - 90 * i); // Definition of lower arms final Bone lowerArm = new Bone(60, -90); upperArm[i].getChildren().add(lowerArm); // Definition of upper legs upperLeg[i] = new Bone(60, 30 - 90*i); // Definition of lower legs final Bone lowerLeg = new Bone(75, 90); upperLeg[i].getChildren().add(lowerLeg);} // Connect arms and legs to head and torsohead.getChildren().addAll(upperArm);torso.getChildren().addAll(upperLeg); |
Посмотреть код на Gist .
Присоединение визуальных компонентов
Сами кости не видны. Они только определяют структуру. Содержимое свойства, которое представляет собой ObservableList объектов Node , может использоваться для присоединения видимых элементов к кости.
|
1
2
3
4
5
6
7
|
// Attaching visual elements to a bonefinal Bone bone = new Bone(50, 30);bone.getContent().addAll(new Circle(20),new Ellipse(45, 0, 25, 15),new Circle(80, 0, 10)); |
Посмотреть код на Gist .
Рисунок 4: Добавление визуальных элементов
Положение и вращение прикрепленных объектов Node определяется базовой костью. Источником локальной системы координат для всех прикрепленных узлов является положение головы кости. Если положение головы перемещается, то же самое происходит и с его узлами. Вращение кости также передается узлам. Если кость вообще не вращается и угол имеет значение 0, она направлена горизонтально вправо. В приведенном выше примере кода кость определяется двумя кружками и эллипсом. Эта кость показана на рисунке 4. В приведенном ниже примере кода показаны необходимые изменения, которые определяют внешний вид нашего манекена путем добавления кругов и эллипсов. Получившуюся манекен можно увидеть на рисунке 5. На рисунке я добавил символы для костей, чтобы сделать их видимыми. Обратите внимание, что ни один из визуальных компонентов не вращается самостоятельно, и все положения являются локальными для кости. Окончательные положения и повороты в сцене рассчитываются только из положений и поворотов костей.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
// Definition of headfinal Bone head = new Bone(30, 90);head.getContent().add(new Ellipse(20, 15));// Definition of torsofinal Bone torso = new Bone(80, 0);torso.getContent().add(new Ellipse(40, 0, 50, 20));head.getChildren().add(torso);final Bone[] upperArm = new Bone[2];final Bone[] upperLeg = new Bone[2];for (int i=0; i<2; i++) { // Definition upper arms upperArm[i] = new Bone(60, 60 - 90 * i); upperArm[i].getContent().add(new Ellipse(22.5, 0, 30, 12.5)); // Definition of lower arms final Bone lowerArm = new Bone(60, -90); lowerArm.getContent().addAll( new Circle(12.5), new Ellipse(30, 0, 20, 12.5), new Circle(60, 0, 12.5) ); upperArm[i].getChildren().add(lowerArm); // Definition of upper legs upperLeg[i] = new Bone(60, 30 - 90*i); upperLeg[i].getContent().add(new Ellipse(20, 0, 30, 15)); // Definition of lower legs final Bone lowerLeg = new Bone(75, 90); lowerLeg.getContent().addAll( new Circle(15), new Ellipse(40, 0, 30, 15), new Ellipse(75, -10, 10, 22.5) ); upperLeg[i].getChildren().add(lowerLeg);}// Connect arms and legs to head and torsohead.getChildren().addAll(upperArm);torso.getChildren().addAll(upperLeg); |
Посмотреть код на Gist .
Рисунок 5: Пустышка со всеми прикрепленными визуальными элементами
Добавление всего на сценограф
Теперь отсутствует только одна последняя часть, чтобы можно было отобразить манекен на экране: класс Skeleton . Класс Skeleton — это мост между Scenegraph и костями с прикрепленными объектами Node . Он расширяет Parent и поэтому может быть добавлен в любое место в Scenegraph. Это может быть переведено, повернуто, масштабировано и преобразовано как любой другой узел в Scenegraph.
Скелетный объект и кости анимированного объекта связаны установкой свойства скелета любой кости. Вы заметите, что скелет свойства всех костей в одной и той же структуре будет обновлен, чтобы впоследствии указывать на один и тот же объект Skeleton . Невозможно, чтобы две кости в одной структуре указывали на разные объекты скелета .
Чтобы увидеть результат, загрузите полный файл Dummy.java . Чтобы скомпилировать скрипт, вам нужно добавить библиотеку javafx-ik в ваш путь к классам. Вы можете скачать исходники с GitHub .
Что дальше?
Первая часть этого урока показала, как определить статическую структуру — или скелет — анимированного объекта и как прикрепить видимые компоненты. Вторая часть объяснит, как эта структура может быть анимирована для создания естественно выглядящих анимаций.
Ссылка: библиотека JavaFX для обратной кинематики 2.0 от нашего партнера по JCG Майкла Хайнрихса в блоге Майка .