Перспективная проекция и матрица вида: как буфер глубины, так и ориентация граней треугольника в OpenGL меняются местами

У меня проблемы с моей сценой в OpenGL. Объекты, которые, как предполагается, находятся дальше, притягиваются ближе и т. Д., А передние треугольники отбраковываются, а не обращенные назад. Они нарисованы в правильной ориентации, так как это пакет, который я использовал раньше. Я убежден, что это как-то связано с моей проекцией или матрицей veiwModel. Я не вижу ничего плохого в этом, хотя!

AV4X4FLOAT formProjMatrix(float FOVangle,float aspect,float nearz,float farz)
{
AV4X4FLOAT A;

A.m[0] = 1/(aspect*tanf(FOVangle/2));
A.m[5] = 1/tanf(FOVangle/2);
A.m[10] = farz/(farz-nearz);
A.m[11] = -nearz*farz/(farz-nearz);
A.m[14] = 1;
return A;
}

AV4X4FLOAT formViewModelMatrix(AV4FLOAT pos,AV4FLOAT target,AV4FLOAT up)
{
AV4X4FLOAT M;
AV4X4FLOAT R;
AV4FLOAT u;
AV4FLOAT v;
AV4FLOAT W;

W.x = -pos.x + target.x;
W.y = -pos.y + target.y;
W.z = -pos.z + target.z;

W.w = 0;
W.normalize();

u.x = up.y*W.z-W.y*up.z;
u.y = -up.x*W.z+W.x*up.z;
u.z = up.x*W.y-W.x*up.y;
u.w = 0;
u.normalize();

v.x = W.y*u.z-u.y*W.z;
v.y = -W.x*u.z+u.x*W.z;
v.z = W.x*u.y-u.x*W.y;
v.w = 0;

M.m[0]  = u.x;  M.m[1]  = u.y;  M.m[2]  = u.z;  M.m[3]  = 0;
M.m[4]  = v.x;  M.m[5]  = v.y;  M.m[6]  = v.z;  M.m[7]  = 0;
M.m[8]  = -W.x; M.m[9]  = -W.y; M.m[10] = -W.z; M.m[11] = 0;
M.m[12] = 0;    M.m[13] = 0;    M.m[14] = 0;    M.m[15] = 1;

R.m[0] = 1;
R.m[5] = 1;
R.m[10] = 1;
R.m[15] = 1;
R.m[12] = -pos.x;
R.m[13] = -pos.y;
R.m[14] = -pos.z;

//the opposite of what you expect because of the way we overload mult operator!
M.display ();
R.display ();
return M*R;
}

Это то, что я называю в своей программе рисования.

glMatrixMode(GL_PROJECTION);
glLoadMatrixf(projMatrix.m);

glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(viewModelMatrix.m);

Некоторая другая информация,

Да, я включил тестирование глубины!

1

Решение

Есть некоторые проблемы при расчете матрицы проекции. Вы должны адаптировать свой код следующим образом:

AV4X4FLOAT formProjMatrix(float FOVangle,float aspect,float nearz,float farz)
{
AV4X4FLOAT A;

A.m[0]  = 1.0 / (aspect*tanf(FOVangle/2));
A.m[5]  = 1.0 / tanf(FOVangle/2);
A.m[10] =  (nearz+farz)/(farz-nearz);
A.m[11] = - 2.0 * nearz*farz/(farz-nearz);
A.m[14] = - 1.0;
return A;
}

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

введите описание изображения здесь

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

следует:

введите описание изображения здесь

aspect = w / h
tanFov = tan( fov_y * 0.5 );

p[0][0] = 2*n/(r-l) = 1.0 / (tanFov * aspect)
p[1][1] = 2*n/(t-b) = 1.0 / tanFov

Следующая функция рассчитает ту же матрицу проекции, что и gluPerspective или же glm::perspective делает:

#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 }
};
}

В области просмотра ось 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;
}

Адаптируйте ваш код так:

AV4X4FLOAT formViewModelMatrix(AV4FLOAT pos,AV4FLOAT target,AV4FLOAT up)
{
AV4FLOAT mz;
mz.x = pos.x - target.x; mz.y = pos.y - target.y; mz.z = pos.z - target.z; mz.w = 1.0f;
mz.normalize();

AV4FLOAT my;
my.x = up.x; my.y = up.y; my.z = up.z; my.w = 1.0f;

AV4FLOAT mx;
mx.x = my.y*mz.z - my.z*mz.y; mx.y = my.z*mz.x - my.x*mz.z; mx.z = my.x*mz.y - my.y*mz.x; mx.w = 1.0f;
mx.normylize();

my.x = mz.y*mx.z - mz.z*mx.y; my.y = mz.z*mx.x - mz.x*mx.z; my.z = mz.x*mx.y - mz.y*mx.x; my.w = 1.0f;

AV4FLOAT t;
t.x = mx.x*pos.x + mx.y*pos.y + mx.z*pos.z;
t.y = my.x*pos.x + my.y*pos.y + my.z*pos.z;
t.z = -(mz.x*pos.x + mz.y*pos.y + mz.z*pos.z);

AV4X4FLOAT m;
m[0]  = mx.x;  m[1]  = my.x;  m[2]  = mz.x;  m[3]  = 0.0f;
m[4]  = mx.y;  m[5]  = my.y;  m[6]  = mz.y;  m[7]  = 0.0f;
m[8]  = mx.z;  m[9]  = my.z;  m[10] = mz.z;  m[11] = 0.0f;
m[12] = t.x;   m[13] = t.y;   m[14] = t.z;   m[15] = 1.0f;

return m
}

Смотрите далее ответы на следующий вопрос:

5

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]