The solution is to enable depth-buffering but make the depth buffer read-only while drawing the
translucent objects. First you draw all the opaque objects, with the depth buffer in normal operation.
Then, you preserve these depth values by making the depth buffer read-only. When the translucent
objects are drawn, their depth values are still compared to the values established by the opaque objects,
so they aren't drawn if they're behind the opaque ones. If they're closer to the viewpoint, however, they
don't eliminate the opaque objects, since the depth-buffer values can't change. Instead, they're blended
with the opaque objects. To control whether the depth buffer is writable, use glDepthMask(); if you
pass GL_FALSE as the argument, the buffer becomes read-only, whereas GL_TRUE restores the
normal, writable operation.
void GLWidget::paintGL() {
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gluLookAt(0, 0, 8, 0, 0, 0, 0, 1, 0);
glPushMatrix();
{
glColor3f(1.0, 0.0f, 0.0f);
glTranslatef(0.0f, 0.0f, -1.0f);
this->drawCube(1.0f, 1.0f, 1.0f, 0.1f);
}
glPopMatrix();
glPushMatrix();
{
glColor3f(0.0, 0.0f, 1.0f);
glTranslatef(0.60f, 0.0f, -0.5f);
this->drawCube(1.0f, 1.0f, 1.0f, 0.1f);
}
glPopMatrix();
glPushMatrix();
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthMask(GL_FALSE);
glColor4f(0.0, 1.0f, 0.0f, 0.5f);
glTranslatef(0.20f, 0.0f, 0.0f);
this->drawCube(0.60f, 1.0f, 1.0f, 0.1f);
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
}
glPopMatrix();
}
void GLWidget::drawCube(GLfloat len, GLfloat xFactor, GLfloat yFactor,
GLfloat zFactor) {
GLfloat x = len * xFactor / 2;
GLfloat y = len * yFactor / 2;
GLfloat z = len * zFactor / 2;
// GLfloat p0[3] = { -x, -y, -z };
// GLfloat p1[3] = { x, -y, -z };
// GLfloat p2[3] = { x, y, -z };
// GLfloat p3[3] = { -x, y, -z };
// GLfloat p4[3] = { -x, -y, z };
// GLfloat p5[3] = { x, -y, z };
// GLfloat p6[3] = { x, y, z };
// GLfloat p7[3] = { -x, y, z };
glBegin(GL_QUADS);
{
// Draw left surface.
glNormal3f(-1.0f, 0.0f, 0.0f);
glVertex3f(-x, y, -z);
glVertex3f(-x, -y, -z);
glVertex3f(-x, -y, z);
glVertex3f(-x, y, z);
// Draw front surface.
glNormal3f(0.0f, 0.0f, 1.0f);
glVertex3f(-x, -y, z);
glVertex3f(x, -y, z);
glVertex3f(x, y, z);
glVertex3f(-x, y, z);
// Draw right surface.
glNormal3f(1.0f, 0.0f, 0.0f);
glVertex3f(x, -y, z);
glVertex3f(x, -y, -z);
glVertex3f(x, y, -z);
glVertex3f(x, y, z);
// Draw back surface.
glNormal3f(0.0f, 0.0f, -1.0f);
glVertex3f(x, y, -z);
glVertex3f(x, -y, -z);
glVertex3f(-x, -y, -z);
glVertex3f(-x, y, -z);
// Draw top surface.
glNormal3f(0.0f, 1.0f, 0.0f);
glVertex3f(x, y, z);
glVertex3f(x, y, -z);
glVertex3f(-x, y, -z);
glVertex3f(-x, y, z);
// Draw bottom surface.
glNormal3f(0.0f, -1.0f, 0.0f);
glVertex3f(-x, -y, -z);
glVertex3f(x, -y, -z);
glVertex3f(x, -y, z);
glVertex3f(-x, -y, z);
}
glEnd();
// glBegin(GL_QUADS);
// {
// // Draw left surface.
// glNormal3f(-1.0f, 0.0f, 0.0f);
// glVertex3fv(p3);
// glVertex3fv(p0);
// glVertex3fv(p4);
// glVertex3fv(p7);
//
// // Draw front surface.
// glNormal3f(0.0f, 0.0f, 1.0f);
// glVertex3fv(p4);
// glVertex3fv(p5);
// glVertex3fv(p6);
// glVertex3fv(p7);
//
// // Draw right surface.
// glNormal3f(1.0f, 0.0f, 0.0f);
// glVertex3fv(p5);
// glVertex3fv(p1);
// glVertex3fv(p2);
// glVertex3fv(p6);
//
// // Draw back surface.
// glNormal3f(0.0f, 0.0f, -1.0f);
// glVertex3fv(p2);
// glVertex3fv(p1);
// glVertex3fv(p0);
// glVertex3fv(p3);
//
// // Draw top surface.
// glNormal3f(0.0f, 1.0f, 0.0f);
// glVertex3fv(p6);
// glVertex3fv(p2);
// glVertex3fv(p3);
// glVertex3fv(p7);
//
// // Draw bottom surface.
// glNormal3f(0.0f, -1.0f, 0.0f);
// glVertex3fv(p0);
// glVertex3fv(p1);
// glVertex3fv(p5);
// glVertex3fv(p4);
// }
// glEnd();
}