Эти два дня переосуществляются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 и пользователь сети дали замечательный ответ.