Perspective projection and view matrix: Both depth buffer and triangle face orientation are reversed in OpenGL(透视投影和视图矩阵:深度缓冲区和三角形面方向在 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);上午[14] = 1;返回A;}
AV4X4FLOAT formViewModelMatrix(AV4FLOAT pos,AV4FLOAT target,AV4FLOAT up){AV4X4FLOAT M;AV4X4FLOAT R;AV4FLOAT你;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;//由于我们重载mult运算符的方式,与您期望的相反!M.display();R.display();返回 M*R;}
这就是我在我的绘图程序中所说的.
glMatrixMode(GL_PROJECTION);glLoadMatrixf(projMatrix.m);glMatrixMode(GL_MODELVIEW);glLoadMatrixf(viewModelMatrix.m);
一些其他信息,
是的,我启用了深度测试!
投影矩阵的计算存在一些问题.你必须像这样调整你的代码:
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);上午[14] = - 1.0;返回A;}
透视投影矩阵如下所示:
r = 右,l = 左,b = 底部,t = 顶部,n = 近,f = 远2*n/(r-l) 0 0 00 2*n/(t-b) 0 0(r+l)/(r-l) (t+b)/(t-b) -(f+n)/(f-n) -10 0 -2*f*n/(f-n) 0
如下:
aspect = w/htanFov = 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 以下代码与 gluLookAt
或 glm::lookAt
的作用相同:
使用 TVec3 = std::array<浮动,3>;使用 TVec4 = std::array<浮动,4>;使用 TMat44 = std::array;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] };}浮动点(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] - 目标[0], pos[1] - 目标[1], pos[2] - 目标[2] };归一化( mz );TVec3 my = { up[0], up[1], up[2] };TVec3 mx = Cross(my, mz);归一化(mx);我的 = 交叉(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{ 点(mx, pos), 点(my, pos), -Dot(mz, pos), 1.0f }};返回 v;}
像这样调整你的代码:
AV4X4FLOAT formViewModelMatrix(AV4FLOAT pos,AV4FLOAT target,AV4FLOAT up){AV4FLOAT mz;mz.x = pos.x - 目标.x;mz.y = pos.y - target.y;mz.z = pos.z - target.z;mz.w = 1.0f;mz.normalize();AV4FLOAT 我的;my.x = up.x;my.y = up.y;my.z = up.z;我的.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;我的.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[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;米[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;返回米}
进一步查看以下问题的答案:
- 如何在现代 OpenGL 中使用片段着色器中的 gl_FragCoord.z 线性渲染深度?
- 如何在给定视图空间深度值和 ndc xy 的情况下恢复视图空间位置
- 变换模型矩阵
- 自定义视图矩阵的拉伸问题
I am having trouble with my scene in OpenGL. Objects that are supposed to be further away are drawn closer etc AND front facing triangles are being culled instead of back facing ones. They are drawn in the correct orientation as it is a package I have used before. I am convinced that it is something to do with my projection or veiwModel matrix. I can not see anything wrong with these though!
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;
}
This is what I call in my drawing routine.
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(projMatrix.m);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(viewModelMatrix.m);
Some otherinfo,
Yes, I have enabled depth testing!
解决方案 There are some issues with in the calculation of the projection matrix. You have to adapt your code like this:
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;
}
The Perspective Projection Matrix looks like this:
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
it follows:
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
The following function will calculate the same projection matrix as gluPerspective
or glm::perspective
does:
#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 }
};
}
On the viewport the X-axis points to the left, the Y-axis up and the Z-axis out of the view (Note in a right hand system the Z-Axis is the cross product of the X-Axis and the Y-Axis).
The following code does the same as gluLookAt
or glm::lookAt
does:
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;
}
Adapt your code like this:
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
}
See further the answers to the following question:
- How to render depth linearly in modern OpenGL with gl_FragCoord.z in fragment shader?
- How to recover view space position given view space depth value and ndc xy
- Transform the modelMatrix
- Stretching Issue with Custom View Matrix
这篇关于透视投影和视图矩阵:深度缓冲区和三角形面方向在 OpenGL 中反转的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:透视投影和视图矩阵:深度缓冲区和三角形面方向在 OpenGL 中反转
基础教程推荐
- 如何使图像调整大小以在 Qt 中缩放? 2021-01-01
- Windows Media Foundation 录制音频 2021-01-01
- 使用从字符串中提取的参数调用函数 2022-01-01
- 如何在不破坏 vtbl 的情况下做相当于 memset(this, ...) 的操作? 2022-01-01
- 管理共享内存应该分配多少内存?(助推) 2022-12-07
- 为 C/C++ 中的项目的 makefile 生成依赖项 2022-01-01
- 在 C++ 中循环遍历所有 Lua 全局变量 2021-01-01
- 从 std::cin 读取密码 2021-01-01
- 如何“在 Finder 中显示"或“在资源管理器中显 2021-01-01
- 为什么语句不能出现在命名空间范围内? 2021-01-01