4

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);
Amir
  • 349
  • 6
  • 13
  • So far you've shown only the initial values. But to tell what's going wrong, I need to see the actual drawing code. – datenwolf Mar 16 '11 at 16:55
  • @datenwolf - I've added the drawing code :) – Amir Mar 17 '11 at 16:30
  • 1
    Since znear, zfar are equal for both drawing passes and use depth testing in each of them you must clear the depth buffer between drawing passes => See solution 1 of the answer given by @Calvin1602 – datenwolf Mar 17 '11 at 20:10

1 Answers1

6

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. ( i.e 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.

Calvin1602
  • 9,413
  • 2
  • 44
  • 55
  • Actually, solution #3 should perform slightly better since it avoids one expensive glClear by frame. But yeah it's very straightforwad. – Calvin1602 Mar 16 '11 at 17:27
  • First of all, thank you for you comment. My real problem is that i really need the depth... right now its just the background.. but soon its gonna have billboards over the meshes.. its for my Side-Scrolling Map Engine.. – Amir Mar 16 '11 at 19:28
  • You will get the depth of the mesh with all 3 methods (or z-buffer wouldn't work correctly and you'd see artefacts). If background must have precise depth, go for solution 3, or use glClearDepth(float). – Calvin1602 Mar 16 '11 at 19:34
  • Solution 1 and 2 doesn't use dept.. everything will be drawn on top of it regardless of it's z.. Solution 3 doesn't work.. – Amir Mar 16 '11 at 19:54
  • Could you please update your question and explain exactly what you're trying to do ? Because Solution 1 and 2 DO use depth, and I don't understand your question anymore. Solution 3 should work, what's your code for drawing the fullscreen quad ? – Calvin1602 Mar 17 '11 at 08:37
  • @Calvin1602 updated :).. when i disable or clear the depth buffer, anything that will be drawn afterwards will be drawn on top.. solution 3 simply doesn't work.. i've tried to increase the image's z component but the image gets to the far-plane and clips.. – Amir Mar 17 '11 at 16:38
  • @Amir : "when i disable or clear the depth buffer, anything that will be drawn afterwards will be drawn on top.." -> isn't that _precisely_ the point of a background image ?? Notice that in my solutions, the depth buffer is not cleared _after_ drawing the meshes, but _before_. – Calvin1602 Mar 17 '11 at 17:06
  • @Amir : what do you call a "background image" ? maybe the confusion comes from here. For me, it's the image with the trees in http://dorando.emuverse.com/images/super-mario-bros-3.e_01.png – Calvin1602 Mar 17 '11 at 17:09
  • @Calvin1602 : bg image is the ortho projected rectangle at the background, like the image with the trees. The thing is that i want to draw images in front of the meshes as well. Anyway, It says [here](http://newsgroups.derkeiler.com/Archive/Comp/comp.graphics.algorithms/2006-02/msg00051.html) that the solution is very complicated.. the z component of the ortho projected is linear while frustum isn't, and this is why it so hard to align them. – Amir Mar 17 '11 at 17:53
  • @Calvin1602 : I didn't quite get it.. it means that solution 3# should work.. but i've tested it and it's not. The other solutions are just workarounds. I think that I'll just stick with orthographic projection.. the game is 2.5D after all.. – Amir Mar 17 '11 at 17:53
  • @Amir : updated answer. Link irrelevant to your problem. Check your code ! – Calvin1602 Mar 17 '11 at 20:11