OpenGL - координаты мыши в координатах пространства
Моя цель - поместить сферу прямо туда, куда указывает мышь (с координатой Z, равной 0).
Я видел этот вопрос, но я еще не понимал концепцию матриц MVP, поэтому я немного исследовал, и теперь у меня есть два вопроса:
Как создать матрицу вида из настроек камеры, таких как lookup, eye и up vector?
Я также прочитал этот урок о нескольких типах камер и этот для webgl.
Я все еще могу собрать все воедино, я не знаю, как получить матрицу проекции также...
Какие шаги я должен сделать, чтобы реализовать все это?
1 ответ
При рендеринге каждая сетка сцены обычно преобразуется матрицей модели, матрицей вида и матрицей проекции.
Матрица проекции:
Матрица проекции описывает отображение от трехмерных точек сцены к двухмерным точкам области просмотра. Матрица проекции преобразуется из пространства просмотра в пространство клипа, а координаты в пространстве клипа преобразуются в нормализованные координаты устройства (NDC) в диапазоне (-1, -1, -1) в (1, 1, 1) путем деления с компонентом w координат клипа.Посмотреть матрицу:
Матрица вида описывает направление и позицию, с которой просматривается сцена. Матрица вида трансформируется из мирового пространства в пространство зрения (глаза). В системе координат в области просмотра, ось X указывает влево, ось Y вверх и ось Z вне вида (Обратите внимание, что в правой системе Z-ось является перекрестным произведением X- Ось и ось Y).Модельная матрица:
Матрица модели определяет местоположение, ориентацию и относительный размер сетки в сцене. Матрица модели преобразует позиции вершин из сетки в мировое пространство.
Модель матрицы выглядит следующим образом:
( X-axis.x, X-axis.y, X-axis.z, 0 )
( Y-axis.x, Y-axis.y, Y-axis.z, 0 )
( Z-axis.x, Z-axis.y, Z-axis.z, 0 )
( trans.x, trans.y, trans.z, 1 )
Посмотреть
В области просмотра ось X направлена влево, ось Y вверх и ось Z вне вида (обратите внимание, что в правой системе ось Z является перекрестным произведением оси X и оси Y). Ось).
Код ниже определяет матрицу, которая точно инкапсулирует шаги, необходимые для вычисления взгляда на сцену:
- Преобразование координат модели в координаты области просмотра.
- Вращение, чтобы смотреть в направлении взгляда.
- Движение в положение глаз
Следующий код делает то же самое, что и gluLookAt
или же glm::lookAt
делает:
using TVec3 = std::array< float, 3 >;
using TVec4 = std::array< float, 4 >;
using TMat44 = std::array< TVec4, 4 >;
TVec3 Cross( TVec3 a, TVec3 b ) { return { a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0] }; }
float Dot( TVec3 a, TVec3 b ) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; }
void Normalize( TVec3 & v )
{
float len = sqrt( v[0] * v[0] + v[1] * v[1] + v[2] * v[2] );
v[0] /= len; v[1] /= len; v[2] /= len;
}
TMat44 Camera::LookAt( const TVec3 &pos, const TVec3 &target, const TVec3 &up )
{
TVec3 mz = { pos[0] - target[0], pos[1] - target[1], pos[2] - target[2] };
Normalize( mz );
TVec3 my = { up[0], up[1], up[2] };
TVec3 mx = Cross( my, mz );
Normalize( mx );
my = Cross( mz, mx );
TMat44 v{
TVec4{ mx[0], my[0], mz[0], 0.0f },
TVec4{ mx[1], my[1], mz[1], 0.0f },
TVec4{ mx[2], my[2], mz[2], 0.0f },
TVec4{ Dot(mx, pos), Dot(my, pos), -Dot(mz, pos), 1.0f }
};
return v;
}
проекция
Матрица проекции описывает отображение от трехмерных точек сцены к двухмерным точкам области просмотра. Он преобразуется из пространства глаза в пространство клипа, а координаты в пространстве клипа преобразуются в нормализованные координаты устройства (NDC) путем деления на w
компонент координат клипа. НДЦ находятся в диапазоне (-1, -1, -1) - (1,1,1).
Каждая геометрия, которая находится вне НДЦ, обрезается.
Объекты между ближней и дальней плоскостями усеченной камеры отображаются в диапазон (-1, 1) НЦД.
Ортографическая проекция
В ортогональной проекции координаты в глазном пространстве линейно отображаются на нормализованные координаты устройства.
Ортографическая матрица проекции:
r = right, l = left, b = bottom, t = top, n = near, f = far
2/(r-l) 0 0 0
0 2/(t-b) 0 0
0 0 -2/(f-n) 0
-(r+l)/(r-l) -(t+b)/(t-b) -(f+n)/(f-n) 1
Перспективная проекция
В перспективной проекции матрица проекции описывает отображение из трехмерных точек в мире, как они видны с камеры-обскуры, в двумерные точки видового экрана.
Координаты пространства глаза в усеченной области камеры (усеченная пирамида) отображаются в куб (нормализованные координаты устройства).
Матрица перспективной проекции:
r = right, l = left, b = bottom, t = top, n = near, f = far
2*n/(r-l) 0 0 0
0 2*n/(t-b) 0 0
(r+l)/(r-l) (t+b)/(t-b) -(f+n)/(f-n) -1
0 0 -2*f*n/(f-n) 0
где:
a = w / h
ta = tan( fov_y / 2 );
2 * n / (r-l) = 1 / (ta * a)
2 * n / (t-b) = 1 / ta
Если проекция симметрична, когда линия визирования находится в центре порта обзора, а поле обзора не смещено, матрицу можно упростить:
1/(ta*a) 0 0 0
0 1/ta 0 0
0 0 -(f+n)/(f-n) -1
0 0 -2*f*n/(f-n) 0
Следующая функция рассчитает ту же матрицу проекции, что и gluPerspective
делает:
#include <array>
const float cPI = 3.14159265f;
float ToRad( float deg ) { return deg * cPI / 180.0f; }
using TVec4 = std::array< float, 4 >;
using TMat44 = std::array< TVec4, 4 >;
TMat44 Perspective( float fov_y, float aspect )
{
float fn = far + near
float f_n = far - near;
float r = aspect;
float t = 1.0f / tan( ToRad( fov_y ) / 2.0f );
return TMat44{
TVec4{ t / r, 0.0f, 0.0f, 0.0f },
TVec4{ 0.0f, t, 0.0f, 0.0f },
TVec4{ 0.0f, 0.0f, -fn / f_n, -1.0f },
TVec4{ 0.0f, 0.0f, -2.0f*far*near / f_n, 0.0f }
};
}
3 решения для восстановления положения пространства обзора в перспективной проекции
- С полем зрения и аспектом
Поскольку матрица проекции определяется полем зрения и соотношением сторон, можно восстановить положение области просмотра с полем зрения и соотношением сторон. При условии, что это симметричная перспективная проекция и нормализованные координаты устройства, глубина и ближняя и дальняя плоскости известны.
Восстановить расстояние Z в поле зрения:
z_ndc = 2.0 * depth - 1.0;
z_eye = 2.0 * n * f / (f + n - z_ndc * (f - n));
Восстановить положение области просмотра по нормализованным координатам устройства XY:
ndc_x, ndc_y = xy normalized device coordinates in range from (-1, -1) to (1, 1):
viewPos.x = z_eye * ndc_x * aspect * tanFov;
viewPos.y = z_eye * ndc_y * tanFov;
viewPos.z = -z_eye;
2. С матрицей проекции
Параметры проекции, определяемые полем зрения и соотношением сторон, сохраняются в матрице проекции. Поэтому положение окна просмотра можно восстановить по значениям из матрицы проекции из симметричной проекции перспективы.
Обратите внимание на соотношение между матрицей проекции, полем зрения и соотношением сторон:
prjMat[0][0] = 2*n/(r-l) = 1.0 / (tanFov * aspect);
prjMat[1][1] = 2*n/(t-b) = 1.0 / tanFov;
prjMat[2][2] = -(f+n)/(f-n)
prjMat[2][2] = -2*f*n/(f-n)
Восстановить расстояние Z в поле зрения:
A = prj_mat[2][2];
B = prj_mat[3][2];
z_ndc = 2.0 * depth - 1.0;
z_eye = B / (A + z_ndc);
Восстановить положение области просмотра по нормализованным координатам устройства XY:
viewPos.x = z_eye * ndc_x / prjMat[0][0];
viewPos.y = z_eye * ndc_y / prjMat[1][1];
viewPos.z = -z_eye;
3. С матрицей обратной проекции
Конечно, положение окна просмотра может быть восстановлено с помощью матрицы обратной проекции.
mat4 inversePrjMat = inverse( prjMat );
vec4 viewPosH = inversePrjMat * vec4(ndc_x, ndc_y, 2.0*depth - 1.0, 1.0)
vec3 viewPos = viewPos.xyz / viewPos.w;
Смотрите дальше:
- Как визуализировать глубину линейно в современном OpenGL с gl_FragCoord.z во фрагментном шейдере?
- Преобразуйте модель Matrix
- Перспективная проекция и матрица вида: как буфер глубины, так и ориентация граней треугольника в OpenGL меняются местами
- Как рассчитать размер прямоугольника, который виден камере по заданной координате?
- Как восстановить положение пространства вида с учетом значения глубины пространства просмотра и ndc xy
- Возможно ли получить, какая поверхность куба будет щелкаться в OpenGL?