"projectionMatrix"
и "viewMatrix"
- однородные переменные.Унифицированное местоположение можно получить по glGetUniformLocation
, а не glGetAttribLocation
, что вернет индекс атрибута активного атрибута:
GLint projLoc = glGetUniformLocation( mProgramID, "projectionMatrix" );
GLint viewLoc = glGetUniformLocation( mProgramID, "viewMatrix" );
В перспективеПроекция Матрица проекции описывает отображение из трехмерных точек в мире, как они видны из камеры-обскуры, в двумерные точки видового экрана.
Координаты глазного пространства в усечении камеры (усеченная пирамида) сопоставляются скуб (нормализованные координаты устройства).
При перспективной проекции пространство вида (объем) определяется усеченным конусом (усеченной пирамидой), где вершина пирамиды является положением зрителя.Направление обзора (прямая видимости), а также ближнее и дальнее расстояние определяют плоскости, которые обрезали пирамиду до усеченного конуса (направление обзора - это вектор нормали этих плоскостей).
Это означает оба значения, расстояниедо ближней плоскости и расстояние до дальней плоскости должны быть положительными значениями:
Matrix4x4f lookAt;
setLookAt(lookAt, { 0.0f, 0.0f, 3.0f }, { 0.0f, 0.0f, -1.0f }, { 0.0f, 1.0f, 0.0f });
glUniformMatrix4fv(viewLoc, 1, GL_TRUE, lookAt);
Matrix4x4f projection;
setPerspectiveMatrix(projection, 45.0f, width / height, 0.1f, 100.0f); // 0.1f instead of -0.1f
glUniformMatrix4fv(projLoc, 1, GL_TRUE, projection);
Пространство обзора - это локальная система, которая определяется точкой обзора на сцене.Положение вида, линия взгляда и направление взгляда вверх определяют систему координат относительно мировой системы координат.
Матрица вида должна преобразовываться из мирового пространства в пространство вида, поэтому матрица видаобратная матрица системы координат вида.
Если система координат пространства обзора представляет собой правую систему, где ось X указывает влево, а ось Y вверх,затем ось Z указывает вне поля зрения (обратите внимание, что в правой системе ось Z является перекрестным произведением оси X и оси Y).
Линия визирования оси Zявляется вектором с точки зрения eye
до трагета center
:
template<typename Type>
void setLookAt(Matrix4x4<Type>& matrix, const Vector3<Type> eye, const Vector3<Type> center, const Vector3<Type> up) noexcept
{
Vector3f mz( { eye.getX()-center.getX(), eye.getY()-center.getY(), eye.getZ()-center.getZ() } );
mz = mz.normalize();
Vector3f my = up.normalize();
Vector3f mx = cross(my, mz).normalize();
Type tx = dot( mx, eye );
Type ty = dot( my, eye );
Type tz = -dot( mz, eye );
matrix = {
mx.getX(), mx.getY(), mx.getZ(), tx,
my.getX(), my.getY(), my.getZ(), ty,
mz.getX(), mz.getY(), mz.getZ(), tz,
0.0, 0.0, 0.0, 1.0
};
}
template<typename Type>
Vector3<Type> cross(Vector3<Type> vector, Vector3<Type> anotherVector) noexcept
{
const Type x = vector.getY()*anotherVector.getZ() - vector.getZ()*anotherVector.getY();
const Type y = -(vector.getX()*anotherVector.getZ() - vector.getZ()*anotherVector.getX());
const Type z = vector.getX()*anotherVector.getY() - vector.getY()*anotherVector.getX();
return { x, y, z };
}
template<typename Type>
Vector3<Type> Vector3<Type>::normalize(void) const
{
Type len = std::sqrt(mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]);
return { mV[0] / len, mV[1] / len, mV[2] / len };
}
template<typename Type>
Type dot(Vector3<Type> vector, Vector3<Type> anotherVector) noexcept
{
Type ax = vector.getX(), ay = vector.getY(), az = vector.getZ();
Type bx = anotherVector.getX(), by = anotherVector.getY(), bz = anotherVector.getZ();
return ax*bx + ay*by + az*bz;
}
Матрица перспективной проекции может быть определена как frustum .
Расстояния left
, right
, bottom
и top
- это расстояния от центра вида до боковых граней усеченного конуса в ближней плоскости.near
и far
определяют расстояния до ближней и дальней плоскостей в усеченном контуре.
r = right, l = left, b = bottom, t = top, n = near, f = far
x y z t
2*n/(r-l) 0 (r+l)/(r-l) 0
0 2*n/(t-b) (t+b)/(t-b) 0
0 0 -(f+n)/(f-n) -2*f*n/(f-n)
0 0 -1 0
Если проекция симметрична, где линия визирования является осью симметрии усеченного вида, томатрица может быть упрощена:
x y z t
1/(ta*a) 0 0 0
0 1/ta 0 0
0 0 -(f+n)/(f-n) -2*f*n/(f-n)
0 0 -1 0
где:
a = w / h
ta = tan( fov_y / 2 );
2 * n / (r-l) = 1 / (ta * a)
2 * n / (t-b) = 1 / ta
Далее матрица проецирования переключается с правосторонней системы на левостороннюю, поскольку ось z повернута.
template<typename Type>
void setPerspectiveMatrix(Matrix4x4<Type>& matrix, Type fov, Type aspect, Type znear, Type zfar) noexcept
{
const Type yScale = static_cast<Type>(1.0 / tan(RADIANS_PER_DEGREE * fov / 2));
const Type xScale = yScale / aspect;
const Type difference = zfar - znear;
matrix = {
xScale, 0, 0, 0,
0, yScale, 0, 0,
0, 0, -(zfar + znear) / difference, -2 * zfar * znear / difference,
0, 0, -1, 0
};
}