Скелетная анимация: Skeleton, Bone, SkinnedMesh

Скелетная анимация в Three.js позволяет создавать сложные деформации объектов, управляемые системой костей. Основные строительные блоки — это Skeleton, Bone и SkinnedMesh. Их правильная комбинация обеспечивает реалистичное движение персонажей и других объектов с гибкой структурой.


Bone: структура костей

Bone — это элементарный объект скелета. Он наследуется от Object3D и обладает всеми его свойствами: положением (position), вращением (rotation), масштабом (scale). Каждая кость может иметь дочерние кости, образуя иерархическую структуру.

Ключевые моменты:

  • Кость не визуализируется по умолчанию, но её можно отобразить с помощью SkeletonHelper.
  • Родительская кость передаёт трансформации дочерним костям.
  • Позиция кости определяется относительно родителя.

Пример создания кости и добавления дочерней:

const rootBone = new THREE.Bone();
rootBone.position.set(0, 0, 0);

const childBone = new THREE.Bone();
childBone.position.set(0, 5, 0);

rootBone.add(childBone);

Skeleton: объединение костей

Skeleton — это структура, которая хранит массив костей и управляет их влиянием на меш. Она обеспечивает связь между костями и вершинами меша через skinning.

Основные свойства Skeleton:

  • bones — массив объектов Bone.
  • boneInverses — массив матриц обратного преобразования костей, используемых для правильного позиционирования вершин.
  • pose() — метод, который возвращает скелет в исходное положение (bind pose).

Создание скелета:

const bones = [rootBone, childBone];
const skeleton = new THREE.Skeleton(bones);

Скелет может быть передан SkinnedMesh, чтобы управлять деформацией вершин.


SkinnedMesh: меш с костями

SkinnedMesh — это разновидность Mesh, который поддерживает скелетную анимацию. Для правильной работы требуется:

  1. Геометрия с skinIndices и skinWeights для каждой вершины.
  2. Скелет (Skeleton), который контролирует деформацию.

Skinning позволяет вершинам меша плавно перемещаться под влиянием одной или нескольких костей.

Пример создания SkinnedMesh:

const geometry = new THREE.BoxGeometry(2, 2, 2);
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00, skinning: true });

const skinnedMesh = new THREE.SkinnedMesh(geometry, material);
skinnedMesh.add(rootBone);
skinnedMesh.bind(skeleton);

Связь костей и вершин

Для работы скелетной анимации вершины геометрии должны содержать данные:

  • skinIndex — индекс кости, которая влияет на вершину.
  • skinWeight — степень влияния кости на вершину (от 0 до 1).
geometry.attributes.skinIndex = new THREE.Uint16BufferAttribute([0, 1, 0, 1], 4);
geometry.attributes.skinWeight = new THREE.Float32BufferAttribute([0.8, 0.2, 0.5, 0.5], 4);

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


SkeletonHelper: визуализация

Для отладки и визуализации структуры костей используется SkeletonHelper. Он отображает линии между костями, что помогает проверять и настраивать анимацию.

const helper = new THREE.SkeletonHelper(skinnedMesh);
scene.add(helper);

Анимация костей

Three.js поддерживает анимацию скелета через AnimationClip и KeyframeTrack. Каждый трек описывает изменение свойств кости (position, rotation, scale) во времени.

Пример создания анимации вращения кости:

const times = [0, 1, 2];
const values = [0, 0, 0, 0, Math.PI/2, 0, 0, Math.PI, 0];

const track = new THREE.QuaternionKeyframeTrack('.bones[1].quaternion', times, values);
const clip = new THREE.AnimationClip('rotateBone', 2, [track]);

const mixer = new THREE.AnimationMixer(skinnedMesh);
const action = mixer.clipAction(clip);
action.play();

AnimationMixer обновляется в основном цикле рендеринга:

const clock = new THREE.Clock();

function animate() {
    requestAnimationFrame(animate);
    const delta = clock.getDelta();
    mixer.update(delta);
    renderer.render(scene, camera);
}
animate();

Советы по оптимизации

  • Для сложных моделей использовать группы костей и минимизировать их количество.
  • Атрибуты skinIndex и skinWeight должны иметь минимальное количество влияющих костей на вершину (обычно 4).
  • Для больших скелетов применять SkeletonUtils.clone при дублировании моделей, чтобы сохранить независимые скелеты.

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