Three.js

Three.js

Следующие действия

      Как это все обновлять

Все объекты по умолчанию автоматически обновляют свои матрицы, если были добавлены на сцену при помощи
var object = new THREE.Object3D;
scene.add( object );
или если они являются дочерними по отношению к другому объекту, уже добавленному на сцену:
var object1 = new THREE.Object3D;
var object2 = new THREE.Object3D;
object1.add( object2 ); scene.add( object1 ); //object1 and object2 will automatically update their matrices //object1 и object2 будут автоматически обновлять свои матрицы
Впрочем, если известно что объект будет статичным, можно запретить автоматическое обновление и обновлять матрицу трансформации вручную, когда потребуется.
object.matrixAutoUpdate  = false;
object.updateMatrix();

Geometries

Примечание переводчика: Здесь рассматривается обновление геометрических параметров объекта, т.е. вершины, грани, их расположение, нормали, цвета и т.д.

BufferGeometry

BufferGeometries сохраняют информацию (такую как положение вершин, индексы граней, нормали, цвета, текстурные координаты (
и координатами на текстуре (U, V - эти буквы обозначают оси двумерной текстуры,
потому что «X», «Y» и «Z» уже используются для обозначения осей 3D-объекта
в пространстве модели). Значения U и V обычно изменяются от 0 до 1.');" onmouseout="hide()">UV
) и все атрибуты, установленные пользователем) в буферах, которые являются типизованными массивами (здесь описание этих массивов на русском языке). Это делает работу BufferGeometries в общем-то быстрее, по сравнению с обычными Geometries за счет того, что с ними сложнее работать.

Что касается обновления BufferGeometries, то самое главное для понимания, не стоит изменять размер буферов (это очень затратно, по существу равнозначно созданию новой геометрии). Однако можно обновлять содержимое буферов.

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

В качестве примера попробуем нарисовать линию, которая увеличивается во время визуализации. Выделим место в буфере для 500 вершин, но сначала, при помощи метода BufferGeometry.drawRange, нарисуем только две.
var MAX_POINTS = 500;
// geometry (геометрия) var geometry = new THREE.BufferGeometry();
// attributes (атрибуты) var positions = new Float32Array( MAX_POINTS * 3 ); // 3 vertices per point (3 вершины на точку) geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
// draw range (рисуем ряд точек) var drawCount = 2; // draw the first 2 points, only (рисуем только первые две точки) geometry.setDrawRange( 0, drawCount );
// material (материал) var material = new THREE.LineBasicMaterial( { color: 0xff0000, linewidth: 2 } );
// line (линия) var line = new THREE.Line( geometry, material ); scene.add( line );
Далее будем случайным образом добавлять точки к линии при помощи шаблона в виде:
var positions = line.geometry.attributes.position.array;
var x, y, z, index; x = y = z = index = 0;
for ( var i = 0, l = MAX_POINTS; i < l; i ++ ) {
positions[ index ++ ] = x; positions[ index ++ ] = y; positions[ index ++ ] = z;
x += ( Math.random() - 0.5 ) * 30; y += ( Math.random() - 0.5 ) * 30; z += ( Math.random() - 0.5 ) * 30;
}
Если нужно изменить количество точек, отображаемых после первой визуализации, сделайте следующее:
line.geometry.setDrawRange( 0, newValue );
Если, после первой визуализации, нужно изменить значения данных положения, следует установить флаг needsUpdate, вот так:
line.geometry.attributes.position.needsUpdate = true;
 // required after the first render (запрашивается после первой визуализации)
Вот пУтанка, представленная анимированной линией, которую можно приспособить под свои нужды.

Примеры:

WebGL / custom / attributes
WebGL / buffergeometry / custom / attributes / particles

Geometry

Следующие флаги управляют обновлением различных атрибутов геометрии. Устанавливайте флаги только для атрибутов, требующих обновления, так как обновления - затратная вещь. После изменения буферов эти флаги автоматически сбрасываются обратно к значению false. Если требуется продолжать обновление буферов, нужно сохранить их как true. Обратите внимание, что это относится только к Geometry, а не к BufferGeometry.
var geometry = new THREE.Geometry();
geometry.verticesNeedUpdate = true;
geometry.elementsNeedUpdate = true;
geometry.morphTargetsNeedUpdate = true;
geometry.uvsNeedUpdate = true;
geometry.normalsNeedUpdate = true;
geometry.colorsNeedUpdate = true;
geometry.tangentsNeedUpdate = true;
Кроме этого, в версиях, предшествующих r66, сеткам (mesh) необходимо включать флаг dynamic (для сохранения внутренних типизованных массивов):
// removed after r66 (удаляется после версии r66)
geometry.dynamic = true;

Пример:

WebGL / geometry / dynamic

Материалы

Все однотипные значения могут быть свободно изменены All uniforms values can be changed freely (например, цвета, текстуры, непрозрачность и так далее), значения отправляются в шейдер с каждым кадром. values are sent to the shader every frame.
Примечание переводчика: В области компьютерной графики, шейдер - это компьютерная программа
... читать далее
используемая для создания оттенков (т.е. для шейдинга, от англ. слова shade - оттенок, тон цвета, тень): производства соответствующих уровней освещенности, затемнения и окрашивания изображения, или, на современном этапе, также для создания спецэффектов и пост-обработки видео.

Шейдеры рассчитывают эффекты визуализации с помощью процессора видеокарты, хотя это и не обязательное условие. Языки программирования шейдеров обычно используются для написания
рендеринга – конвейер графического процессора (GPU) с
изменяемыми (перепрограммируемыми) функциями');" onmouseout="hide()">программируемого конвейера рендеринга

- блок графических вычислений или графический
процессор или попросту - процессор видеокарты');" onmouseout="hide()">GPU
, который в основном заменил
(постоянными) функциями, не предусматривающий
программирования (перепрограммирования)');" onmouseout="hide()">конвейер с фиксированными функциями
, допускающий только общие преобразования геометрии и функции закрашивания пикселей; с использованием шейдеров могут быть применены и настраиваемые эффекты. Положение, оттенок, насыщенность, яркость и контрастность всех пикселей вершин или текстур, используемых для построения окончательного изображения могут быть изменены "на лету", с использованием алгоритмов, определенных в шейдере, а также могут быть изменены при помощи внешних переменных и текстур, вводимых программой, вызывающей шейдер.

(из Википедии, перевод мой)   

Параметры связанные с GLstate также могут быть изменены в любой момент (depthTest, blending, polygonOffset, и т.д.).

Плоское (flat) / плавное (smooth) shading is baked into normals. Требуется сброс буфера нормалей (смотрите выше).

Следующие свойства нельзя просто так изменить во время выполнения (после того, как материал был визуализирован хотя бы раз): Изменения в них требуют создания новой шейдерной программы. Нужно будет установить
material.needsUpdate = true
Имейте в виду, что это может быть довольно медленно и вызывать подергивание кадров (особенно в Windows, поскольку шейдерная компиляция в DirectX медленнее, чем в OpenGL).

Для повышения плавности работы можно в некоторой степени имитировать изменения этих функций, с помощью «фиктивных» значений, таких как освещение с нулевой интенсивностью, белых текстур или тумана с нулевой плотностью.

Можно свободно изменять материал, используемый для частей геометрии, однако нельзя изменять способ разделения объекта на части (в соответствии с материалами грани). You can freely change the material used for geometry chunks, however you cannot change how an object is divided into chunks (according to face materials).

Если во время выполнения нужны разные конфигурации материалов:

Если число материалов / частей невелико, можно заблаговременно предварительно разделить объект (например, для человека - волосы (hair) / лицо (face) / тело (body) / верхняя одежда (upper clothes) / брюки (trousers), для автомобиля - перед (front) / боковые стороны (sides) / верх (top) / стекла (glass) / шины (tire) / салон (interior)).

Если число велико (к примеру каждое лицо/грань может быть потенциально различным), рассмотрите другое решение, такое как использование атрибутов/текстур для приведения к другому внешнему виду.

Примеры:

WebGL / materials / cars
WebGL / webgl_postprocessing / dof

Текстуры

Если текстуры изображения, элемента canvas, видео и данных были изменены, то у них должен быть установлен следующий флаг: Image, canvas, video and data textures need to have the following flag set if they are changed:
texture.needsUpdate = true;
Обновление целей визуализации произойдет автоматически. Render targets update automatically.

Примеры:

WebGL / materials / video
WebGL / rtt

Камеры

Положение в пространстве и направление съемки камеры обновляются автоматически. Если нужно изменить параметры
  • fov (поле просмотра)
  • aspect (соотношение сторон)
  • near (ближняя плоскость отсечения)
  • far (дальняя плоскость отсечения)
то требуется пересчитать матрицу проекции:
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();


      Матричные преобразования

В three.js для кодирования 3-мерных преобразований - перемещения (изменения положения), вращения и масштабирования используются матрицы. Каждый экземпляр Object3D имеет свойство matrix, в котором хранится положение, угол поворота и масштаб этого объекта. На этой странице описывается как обновлять преобразование (трансформацию) объекта.

Преимущества свойств и matrixAutoUpdate

Существует два способа обновления преобразования объекта:
  1. Изменить свойства объекта position, quaternion и scale, и позволить Three.js пересчитать матрицу объекта с этими свойствами:
    object.position.copy(start_position);
        object.quaternion.copy(quaternion);
    По умолчанию, свойство matrixAutoUpdate устанавливается равным true, так что матрица будет пересчитана автоматически. Если объект статичен или нужно вручную определять когда будет происходить пересчет матрицы, наилучшую производительность можно получить установкой этого свойства как false:
    object.matrixAutoUpdate = false;
    И после изменения каких-либо свойств, вручную обновить матрицу:
    object.updateMatrix();
  2. Непосредственно изменить матрицу объекта. Класс Matrix4 имеет различные методы для изменения матрицы:
    object.matrix.setRotationFromQuaternion(quaternion);
        object.matrix.setPosition(start_position);
        object.matrixAutoUpdate = false;
    Обратите внимание, что в этом случае свойство matrixAutoUpdate должно быть установлено как false, при этом следует убедиться, что не было вызова updateMatrix. Вызов updateMatrix перебьет изменения матрицы, сделанные вручную, пересчитав матрицу для position, scale и так далее.

Матрицы объекта и world

An object's [page:Object3D.matrix matrix stores the object's transformation relative to the object's [page:Object3D.parent parent; to get the object's transformation in world coordinates, you must access the object's [page:Object3D.matrixWorld.

При изменениях в преобразовании родительского или дочернего объекта можно запросить обновление свойства matrixWorld дочернего объекта вызовом метода updateMatrixWorld.

Вращение и кватернионы

Three.js предоставляет два способа представления трехмерных вращений: углы Эйлера и Quaternions, а также методы конвертирования между ними. Three.js provides two ways of representing 3D rotations: Euler angles and Quaternions, as well as methods for converting between the two. Euler angles are subject to a problem called "gimbal lock," where certain configurations can lose a degree of freedom (preventing the object from being rotated about one axis). По этой причине, вращение объекта всегда сохраняется в его свойстве quaternion. For this reason, object rotations are always stored in the object's quaternion.

Предыдущие версии библиотеки включали в себя свойство useQuaternion, которое, будучи установленное как false, приводило к расчету матрицы объекта из углов Эйлера. Эта практика устарела - взамен следует использовать метод setRotationFromEuler method, which will update the quaternion.

      Система анимации

Обзор

В рамках анимационной системы three.js можно анимировать различные свойства модели: кости (bone) skinned and rigged model, цели морфинга (morph targets), различные свойства материала (цвета, непрозрачность, логику), видимость и преобразования. Свойствами анимации могут быть постепенное появление (faded in), постепенное исчезновение (faded out), плавное появление на фоне плавного исчезновения (crossfaded) и деформация (warped). «Веса́» (weight) и временны́е масштабы (time scales) различных одновременных анимаций как на одном и том же объекте, так и на разных объектах, могут быть изменены независимо друг от друга. Можно синхронизировать различные анимации как на одном и том же объекте, так и на разных объектах.

Чтобы достичь всего этого в единственной однородной системе, система анимации three.js полностью изменилась в 2015 году (помните об устаревшей информации!), и теперь его архитектура, походит на Unity/Unreal Engine 4. На этой странице дается краткий обзор основных компонентов этой системы и способов их совместной работы.

Анимационные клипы Animation Clips

Если имеется успешно импортированный анимированный 3D объект (неважно имеются ли в нем кости или цели морфинга, или и то и другое) - например, экспортированный из Blender'а с помощью Blender exporter и загруженный на сцену three.js загрузчиком JSONLoader, - то одним из свойств геометрии загружаемой сетки (mesh) должен быть массив, поименованный как "animations", содержащий AnimationClip'ы для данной модели (смотрите ниже список возможных загрузчиков). If you have successfully imported an animated 3D object (it doesn't matter if it has bones or morph targets or both) - for example exporting it from Blender with the [link:https://github.com/mrdoob/three.js/tree/master/utils/exporters/blender/addons/io_three Blender exporter] and loading it into a three.js scene using [page:JSONLoader] -, one of the geometry's properties of the loaded mesh should be an array named "animations", containing the [page:AnimationClip AnimationClips] for this model (see a list of possible loaders below).

Каждый «AnimationClip» обычно содержит данные для определенной активности объекта. Если сеткой, например является персонаж, то для цикла ходьбы может быть один AnimationClip, для прыжка - второй, третий для уклонения в сторону и так далее. Each *AnimationClip* usually holds the data for a certain activity of the object. If the mesh is a character, for example, there may be one AnimationClip for a walkcycle, a second for a jump, a third for sidestepping and so on.

Треки ключевых кадров Keyframe Tracks

Внутри такого «AnimationClip» данные для каждого свойства анимации хранятся в отдельном KeyframeTrack. Допустим, персонифицированный объект имеет скелет и один трек ключевого кадра может хранить данные изменений положения кости предплечья во времени, другой трек - данные изменения поворота этой же самой кости, а третий отслеживать положение, поворот или изменение масштаба другой кости и так далее. Понятно, что AnimationClip может состоять из множества подобных треков.

Предположим, что у модели имеются цели морфинга (например, одна цель морфинга показывает приветливое лицо, а другая - сердитое), каждый трек хранит сведения о том, как воздействие (influence) некоторой цели морфинга изменяется во время выполнения клипа. Assumed the model has [page:Geometry.morphTargets morph targets] (for example one morph target showing a friendly face and another showing an angry face), each track holds the information as to how the [page:Mesh.morphTargetInfluences influence] of a certain morph target changes during the performance of the clip.

Микшер анимации (Animation Mixer)

Сохраненные данные формируют только основу анимации - фактическое воспроизведение контролируется AnimationMixer. Можно представить это не только как игрока для анимации, но и как симуляцию аппаратного обеспечения, например, реальной микшерной консоли, которая может одновременно управлять несколькими анимациями, смешивая и объединяя их. The stored data form only the basis for the animations - actual playback is controlled by the [page:AnimationMixer]. You can imagine this not only as a player for animations, but as a simulation of a hardware like a real mixer console, which can control several animations simultaneously, blending and merging them.

Действия анимации (Animation Actions)

Собственно сам «AnimationMixer» имеет только очень мало (общих) свойств и методов, потому что им можно управлять с помощью AnimationActions. The *AnimationMixer* itself has only very few (general) properties and methods, because it can be controlled by the [page:AnimationAction AnimationActions]. Настройкой «AnimationAction» можно определять когда конкретный «AnimationClip» будет воспроизводиться, устанавливаться в паузу или быть остановленным на одном из микшеров, будет ли он повторяться и если будет, как часто, должен ли он выполняться с затуханием или масштабироваться по времени, и другими дополнительными особенностями вроде кроссфейдинга или синхронизации. By configuring an *AnimationAction* you can determine when a certain *AnimationClip* shall be played, paused or stopped on one of the mixers, if and how often the clip has to be repeated, whether it shall be performed with a fade or a time scaling, and some additional things, such crossfading or synchronizing.

Анимация групп объектов

Если нужно чтобы группа объектов приобрела совместно используемое состояние анимации, можно использовать AnimationObjectGroup.

Поддерживаемые форматы и загрузчики

Обратите внимание, не все форматы моделей включают анимацию (в частности OBJ не включает), и что только некоторые загрузчики three.js поддерживают последовательности AnimationClip. Note that not all model formats include animation (OBJ notably does not), and that only some three.js loaders support [page:AnimationClip AnimationClip] sequences. Several that do support this animation type: Обратите внимание, что в настоящее время 3ds max и Maya не могут экспортировать несколько анимаций (то есть, анимаций, которые не находятся на одном и том же временном промежутке) непосредственно в один файл.

Пример

var mesh;
// Create an AnimationMixer, and get the list of AnimationClip instances // Создаем AnimationMixer и получаем список экземпляров AnimationClip var mixer = new THREE.AnimationMixer( mesh ); var clips = mesh.animations;
// Update the mixer on each frame (обновляем микшер в каждом кадре) function update () { mixer.update( deltaSeconds ); }
// Play a specific animation (проигрываем конкретную анимацию) var clip = THREE.AnimationClip.findByName( clips, 'dance' ); var action = mixer.clipAction( clip ); action.play();
// Play all animations (проигрываем все анимации) clips.forEach( function ( clip ) { mixer.clipAction( clip ).play(); } );