Статья для понимания различных матричных отношений в THREE.js

WebGL three.js

Эти два дня переосуществляютсяmaptalks.jsизЛогика 3D-трансформации, алгоритм преобразования 3D-проекции необходимо переопределить с нижнего слоя. К счастью, алгоритм 3D-проекции имеет очень зрелую парадигму реализации.Я выбрал THREE.js в качестве эталонного объекта.Эта статья также является моим кратким изложением отношения преобразования матриц в THREE.js.

Эта статья предназначена для читателей, у которых есть определенный фундамент для разработки webgl Версия THREE является последней версией на момент написания.r88

Алгоритм 3D-проекции

Что такое трансформация 3D-проекции? Вкратце, это алгоритм преобразования, который проецирует объекты в трехмерном пространстве на плоскость обзора камеры, как показано на рисунке:

(Фото взято сwebglfundamentals):

В этой сцене поместите 5 букв F и камеру, как показано на рисунке.

Камера видит следующее:

Основываясь на реальном жизненном опыте, то, что видит камера, связано со следующими факторами, и любое изменение изменит мир, который видит камера:

  • Тип проекции камеры (Орфографическая проекцияещеперспективная проекция), перспективная проекция больше всего соответствует реальному миру, а также является наиболее часто используемым методом проекции.
  • Положение и ориентация камеры
  • Положение и деформация объекта (вращение/масштабирование/перемещение)

Алгоритм 3D-проекции заключается в преобразовании фактора привлекательности в математический алгоритм для расчета положения 3D-объекта в плоскости обзора камеры..

В практических приложениях мы делаем это с помощью матричных вычислений. Короче говоря, мы преобразуем положение и ориентацию камеры, тип камеры, положение и деформацию объекта вматрица, проведя ряд вычислений над этими матрицами, окончательно получимМатрица 3D-проекции:

u_matrix
На его основе по любым трехмерным координатам [x, y, z] мы можем вычислить положение в плоскости обзора камеры:
[x, y] = u_matrix * [x, y, z, 1]

Конечно, в практических приложениях ситуация будет сложнее.Например, для упрощения вычислений 3D-графический движок обычно организует 3D-объекты в иерархическую структуру и вычисляет их абсолютное положение в мире через локальное положение объекта. объект и его положение относительно верхнего слоя.Но в конце концов, все, что нам нужно, это окончательная матрица положения.

Матрица в ТРИ

Вернемся к THREE.js и посмотрим, как THREE организует и определяет матрицу проекций организации.

Мы знаем, что THREE определяет сцену (Scene) и камеру (Camera), Scene используется для добавления и управления 3D-объектами, а Camera используется для управления положением и углом камеры Код примерно выглядит следующим образом:

const scene = new THREE.Scene();
const mesh = new THREE.Mesh(new THREE.Cube());
scene.add(mesh);
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
scene.add(camera);
renderer.render(scene, camera);

Согласно приведенному выше резюме, мы можем найти следующие три матрицы в THREE:

  • Тип проекции камеры: проекционная матрица (ProjectMatrix)
  • Положение и ориентация камеры: матрица вида (CameraMatrixWorldInverseилиViewMatrix)
  • Положение и деформация объекта: Матрица положения объекта (ObjectWorldMatrix)

Формула расчета матрицы трехмерной проекции (u_matrix)

Формула расчета матрицы трехмерной проекции выглядит следующим образом:

const uMatrix = ProjectMatrix * CameraMatrixWorldInverse* ObjectMatrixWorld

Разве это не просто?

Если вам интересно, вы можете написать простейшую программу THREE, проследить логику рисования THREE и посмотреть, как THREE генерирует и использует эти матрицы.

Далее давайте объясним, как получить три вышеупомянутые матрицы в THREE:

Матрица проекции камеры (ProjectMatrix)

Матрица проекции камеры определяет, является ли камера камерой с перспективной проекцией или камерой с ортогональной проекцией.
В THREE разные типы камер получаются путем создания экземпляров разных классов камер, таких как определение камеры перспективной проекции:

const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  • получатьProjectionMatrix
    camera.projectMatrix

Матрица обзора камеры (CameraMatrixWorldInverse)

Некоторые 3D-движки или учебные пособия относятся к матрице вида какViewMatrix(например, основы веб-сайтов)
Смысл матрицы обзора в том, что после фиксации других факторов, после того как мы изменим положение и угол камеры, изменится и мир в ее глазах, и это изменение и есть матрица обзора.

Как упоминалось ранее, положение камеры в 3D-пространствеcamera.matrixWorld, а его матрица вида обратна матрице положения камерыCameraMatrixWorldInverse, что также соответствует нашему жизненному опыту:

  • Фиксированная камера, человек движется влево
  • Закрепите человека, сдвиньте камеру вправо

Обе ситуации одинаковы для глаз камеры.

В THREE мы обычно устанавливаемcameraположение и выше, вызовlookAtизменить матрицу обзора камеры

camera.position.set(x, y, z);
camera.up.set(x, y, z);
camera.lookAt(x, y, z);
  • получатьCameraMatrixInverse
    camera.matrixWorldInverse

Мы знаем, что окончательная проекция рассчитывается в вершинном шейдере GLSL. На одном рисунке,ProjectionMatrixа такжеCameraMatrixWorldInverseобычно не меняется, аObjectMatrixWorldКаждый объект может быть разным, поэтому, чтобы уменьшить количество вычислений в вершинном шейдере, некоторые 3D-движки будут вычислять его заранее в программе на javascript.ProjectionMatrix * CameraMatrixWorldInverseзначение передается в вершинный шейдер, эта матрица обычно называетсяViewProjectionMatrix

Матрица положения объекта (ObjectWorldMatrix)

ObjectWorldMatrix описывает положение объектов в 3D-сцене.

  • получатьObjectWorldMatrix
    object.matrixWorld

Как упоминалось ранее, объекты в THREE иерархичны, поэтому объекты в THREE имеют иерархические отношения.matrixWorldчерез локальную матрицу (object.matrix) с отцомmatrixWorldОн получается рекурсивным умножением, а принцип можно найти в webglfundamentals.этот учебник

некоторые приложения

Получить 2D-координаты экрана

Учитывая трехмерные координаты [x, y, z], как получить их двумерные координаты на экране? Рассчитывается следующим образом:

const [x, y] = ProjectionMatrix * CameraWorldMatrixInverse * [x, y, z]

THREE оборачивает метод в Vector3:

const v = new THREE.Vector3(x, y, z);
const xy = v.project(camera);

Исходный код выглядит следующим образом:

project: function () {

    var matrix = new Matrix4();

    return function project(camera) {

        matrix.multiplyMatrices(camera.projectionMatrix, matrix.getInverse(camera.matrixWorld));
        return this.applyMatrix4(matrix);

    };
}(),

Преобразование экранных координат в 3D-координаты

Зная двумерные координаты экрана [x, y], как получить его трехмерные координаты в трехмерном пространстве? Рассчитывается следующим образом:

const [x, y, z] = CameraWorldMatrix * ProjectionMatrixInverse * [x, y, z]

THREE оборачивает метод в Vector3:

const v = new THREE.Vector3(x, y, z);
const xyz = v.unproject(camera);

Исходный код выглядит следующим образом:

unproject: function () {

    var matrix = new Matrix4();

    return function unproject(camera) {

        matrix.multiplyMatrices(camera.matrixWorld, matrix.getInverse(camera.projectionMatrix));
        return this.applyMatrix4(matrix);

    };

}(),

Однако преобразовать экранные координаты в трехмерные координаты не так просто, потому что двумерные координаты на экране фактически соответствуют лучу в трехмерном пространстве, которому может соответствовать бесконечное количество трехмерных координатных точек. , Для более подробных принципов вы можете прочитать эту статьюВопросы по stackoverflow, автор THREE mroob и пользователь сети дали замечательный ответ.