Unable to Draw 3D (Frustum) on top of 2D (Ortho) in OpenGL

I'm trying to render some meshes with Frustum projection on top of a background image (orthographic projection). No matter what I do, the background image keeps being on top of the scene (hiding the meshes).

I've tried a little test - when I've rendered them both with the same projection matrix the were in the right order - the background image was behind the meshes.

These are the projection matrices and the Depth-Buffer init:

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);

I'm cleaning the buffers with: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

One last thing.. When I disable GL_DEPTH_TEST, the meshes are being drawn in front of the background image because the background is being called first..

I can't tell which, the Depth-Buffer or the Projection matrices, causing this problem.. The values of the matrices with screenWidth=960 and 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);

What am i doing wrong? Amir.

Edit: This how i'm drawing the images with the orthographic projection:

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);

and this is how I'm drawing the meshes with the frustum projection:

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);

If I understand correctly, you want to do the following separate things :

  • Draw a fullscreen quad with a texture on it
  • Do something so that this quad is not taken into account in the z-buffer
  • Afterwards, draw a mesh ( with whatever projection, view and model matrices you want) on top of it.
  • "When I disable GL_DEPTH_TEST, the meshes are being drawn in front of the background image because the background is being called first.." -> I take it that you can draw both your fullscreen quad and our mesh separately. So VBO setup, matrices, textures and stuff are all good. It's only point #2 that misses.

  • Solution 1 :
  • Clear everything for a new frame, just as usual. Z-buffer will be 1.0 everywhere

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    

    Draw the background. Your color buffer is OK, but it suck because the z-buffer will contain the depth of your quad, let's say 0.5. So when you will render your mesh, you will have to be lucky enough so that the new depth values are smaller than 0.5, or the depth test will fail. But we can do something about it : simply clear the z-buffer again to 1.0 :

    glClear(GL_DEPTH_BUFFER_BIT);
    

    Now, draw the other mesh as usual. The ModelViewProjection matrix has changed, but OpenGL doesn't know that : all it know is that depth is 1.0 everywhere. So the depth test will always succeed for your mesh. You will thus see your mesh where it shoud be, with correct z-values, and the background quad everywhere else.

  • Solution 2
  • Here, you prevent depth values from beeing updated when the fullscreen quad is drawn.

    Disable writes on the depth buffer :

    glDepthMask(GL_FALSE);
    

    Draw the background. Color buffer will be OK, and z-buffer will still contain 1.0 everywhere, as set by glClear() a few lines above.

    Now re-enable writes on the depth buffer :

    glDepthMask(GL_TRUE);
    

    Draw the other mesh. As before, z-buffer will be 1.0 everywhere, just as if you had just called glClear(), so if your mesh is in the frustum (it obviously has to be), its z will be, say, 0.5, and it will be drawn.

  • Solution 3
  • Simply draw your background far away from the camera, near the far clipping plane. ( ie with a big Z component ). Its z-component will be 0.9999 or something like that, and just as before, mesh will render allright.

    I really, really can't explain in more details. Sorry if it's still not clear, I tried to reformulate each idea in several ways, can't do anything more.

    链接地址: http://www.djcxy.com/p/33968.html

    上一篇: 带有OpenGL性能问题的全屏幕背景纹理(iPad)

    下一篇: 无法在OpenGL中的2D(Ortho)上绘制3D(Frustum)