【问题标题】:Unable to Draw 3D (Frustum) on top of 2D (Ortho) in OpenGL无法在 OpenGL 中的 2D(正交)之上绘制 3D(平截头体)
【发布时间】:2011-07-16 18:15:20
【问题描述】:

我正在尝试在背景图像(正交投影)上使用 Frustum 投影渲染一些网格。无论我做什么,背景图像都会一直在场景顶部(隐藏网格)。

我尝试了一个小测试 - 当我用相同的投影矩阵渲染它们时 以正确的顺序 - 背景图像位于网格后面。

这些是投影矩阵和深度缓冲区初始化:

glEnable(GL_DEPTH_TEST);
glClearDepthf( 1.0f );
glDepthFunc( GL_LEQUAL );
glDepthMask (GL_TRUE);

EGLConfig eglconfig;
EGLint const attrib_list[] = {
    EGL_DEPTH_SIZE, 16,
    EGL_NONE
};
EGLint numreturned;
CHECK(eglChooseConfig(esContext.eglDisplay, attrib_list, &eglconfig, 1, &numreturned) != EGL_FALSE);

float fieldOfView = 60.0;
float znear = 0.1f;
float zfar = 100000;
float size = (float)(znear * tanf((fieldOfView * M_PI /180.0f) / 2.0f)); 

m_orthoProjMatrix.loadOrtho(0, 
                            screenWidth, 
                            0, 
                            screenHeight, 
                            znear, 
                            zfar);

m_frustProjMatrix.loadFrustum(-size, 
                               size, 
                              -size / (screenWidth / screenHeight), 
                               size / (screenWidth / screenHeight), 
                               znear, 
                               zfar);

我正在清理缓冲区: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

最后一件事.. 当我禁用 GL_DEPTH_TEST 时,网格被绘制在背景图像的前面,因为首先调用背景..

我不知道是深度缓冲区还是投影矩阵导致了这个问题。 screenWidth=960 和 screenHeight = 640 的矩阵的值:

Orthographic Proj Matrix:
0.00208 0.00000 0.00000 -1.00000
0.00000 0.00313 0.00000 -1.00000
0.00000 0.00000 0.00000 -1.00000
0.00000 0.00000 0.00000  1.00000

Frustum Proj Matrix:
1.73205 0.00000  0.00000  0.00000
0.00000 2.59808  0.00000  0.00000
0.00000 0.00000 -1.00000 -0.20000
0.00000 0.00000 -1.00000  0.00000

Camera Settings:
Vector3 pos(0,10,50);
Vector3 at(0,0,0);
Vector3 up(0,1,0);
LookAt(pos,at,up);

Scene Settings:
Vector3 BackgroundImagePosition (0,0, -430);
Vector3 SomeMesh(0,0,0);

我做错了什么? 阿米尔。

编辑: 这就是我使用正交投影绘制图像的方式:

GLfloat verts[] = { 
image->x + image->width  , image->y                , image->z,
image->x + image->width  , image->y + image->height, image->z,
image->x                 , image->y + image->height, image->z,
image->x                 , image->y                , image->z};
Matrix4s mv(m_camera->getCameraViewMatrix());
Matrix4f proj(ResManPtr->getOrthoProjMatrix() * mv);
glUniformMatrix4fv(prog->getUniformLocation("u_projMatrix"), 1, GL_FALSE, &(*proj));
glActiveTexture(GL_TEXTURE0);
image->tex->bind();
glUniform1i(prog->getUniformLocation("s_texture"), 0);
glEnableVertexAttribArray(prog->getAttribLocation("a_position")); 
glVertexAttribPointer(prog->getAttribLocation("a_position"), 3, GL_FLOAT, GL_FALSE, 0, verts); 
glEnableVertexAttribArray(prog->getAttribLocation("a_texCoord"));
glVertexAttribPointer(prog->getAttribLocation("a_texCoord"), 2, GL_FLOAT, GL_FALSE, 0, m_texcoord);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

这就是我使用平截头体投影绘制网格的方式:

Matrix4f mv(world->getCamera()->getCameraViewMatrix());
const btVector3& dir = getDirection();
Scalar xzAngle = atan2s(dir.x(), dir.z()) - (Scalar)M_PI_2;
btVector3 origin = getGhostObject()->getWorldTransform().getOrigin();
mv.applyTranslate(origin.x(), origin.y() - m_width/2, origin.z());
mv.applyRotateY(xzAngle);    
GLProgramPtr prog = ResManPtr->getProgramMap()[Consts::DEFAULT_PROGRAM_KEY];
Matrix4f proj(ResManPtr->getFrustProjMatrix() * mv);
glUniformMatrix4fv(prog->getUniformLocation("u_projMatrix"), 1, GL_FALSE, &(*proj));
glActiveTexture(GL_TEXTURE0);
m_texture->bind();  
glUniform1i(prog->getUniformLocation("s_texture") , 0);
m_model->render(frame_number);

【问题讨论】:

  • 到目前为止,您只显示了初始值。但是要知道哪里出了问题,我需要查看实际的绘图代码。
  • @datenwolf - 我已经添加了绘图代码:)
  • 由于 znear, zfar 对于两个绘图通道都相等,并且在每个通道中都使用深度测试,因此您必须清除绘图通道之间的深度缓冲区 => 请参阅@Calvin1602 给出的答案的解决方案 1

标签: opengl-es opengl-es-2.0 orthographic frustum projection-matrix


【解决方案1】:

如果我理解正确,你想做以下单独的事情:

  • 绘制一个带有纹理的全屏四边形
  • 做一些事情,使这个四边形不被考虑到 z 缓冲区中
  • 然后,在其上绘制一个网格(使用您想要的任何投影、视图和模型矩阵)。

“当我禁用 GL_DEPTH_TEST 时,网格将被绘制在背景图像的前面,因为首先调用背景..” -> 我认为您可以分别绘制全屏四边形和我们的网格。所以 VBO 设置、矩阵、纹理和其他东西都很好。只有第 2 点遗漏了。

  • 解决方案 1:

像往常一样为新框架清除所有内容。 Z-buffer 在任何地方都是 1.0

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

绘制背景。您的颜色缓冲区还可以,但它很糟糕,因为 z 缓冲区将包含您的四边形的深度,比如说 0.5。因此,当您渲染网格时,您必须足够幸运,新的深度值小于 0.5,否则深度测试将失败。但我们可以做点什么:只需将 z-buffer 再次清除为 1.0:

glClear(GL_DEPTH_BUFFER_BIT);

现在,像往常一样绘制另一个网格。 ModelViewProjection 矩阵已经改变,但 OpenGL 不知道:它所知道的只是深度在任何地方都是 1.0。因此,深度测试对于您的网格将始终成功。因此,您将在应有的位置看到网格,具有正确的 z 值,以及其他任何地方的背景四边形。

  • 解决方案 2

在这里,您可以防止在绘制全屏四边形时更新深度值。

禁用对深度缓冲区的写入:

glDepthMask(GL_FALSE);

绘制背景。颜色缓冲区没问题,z-buffer 仍然会在所有地方都包含 1.0,正如上面几行 glClear() 设置的那样。

现在重新启用对深度缓冲区的写入:

glDepthMask(GL_TRUE);

绘制另一个网格。和以前一样,z-buffer 到处都是 1.0,就好像你刚刚调用了 glClear(),所以如果你的网格在平截头体中(它显然必须是),它的 z 将是 0.5,它会画出来。

  • 解决方案 3

只需将您的背景画得远离相机,靠近远剪裁平面。 (即具有大 Z 分量)。它的 z-component 将是 0.9999 或类似的值,就像以前一样,mesh 会渲染得很好。

我真的,真的无法更详细地解释。抱歉,如果仍然不清楚,我尝试以多种方式重新表述每个想法,无法再做任何事情。

【讨论】:

  • 实际上,解决方案#3 的性能应该稍好一些,因为它避免了一个昂贵的 glClear 按帧。但是,是的,这非常简单。
  • 首先,感谢您的评论。我真正的问题是我真的需要深度......现在它只是背景......但很快它就会在网格上出现广告牌......它用于我的横向滚动地图引擎......
  • 您将使用所有 3 种方法获得网格的深度(或者 z-buffer 无法正常工作并且您会看到伪影)。如果背景必须具有精确的深度,请选择解决方案 3,或使用 glClearDepth(float)。
  • 解决方案 1 和 2 不使用 dept.. 一切都将绘制在它之上,无论它是什么 z.. 解决方案 3 不起作用..
  • 能否请您更新您的问题并准确解释您要做什么?因为解决方案 1 和 2 确实使用了深度,所以我不再理解您的问题。解决方案 3 应该可以工作,你绘制全屏四边形的代码是什么?
猜你喜欢
  • 2021-11-25
  • 2015-12-18
  • 1970-01-01
  • 1970-01-01
  • 2021-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多