Weird model behaviour when trying to draw an object semi transparent (glDepthMask set to false)

Hey guys!

I am trying to render a transparent cube with a glowing question mark inside kind of like the item boxes in mariokart.

The question mark looks great (drawn using an fbo to add blooming):
image
…and so does the cube.

But when trying to draw the cube with a semi transparent texture (50%) the cube looks weird:
image

I’ve been told that the easiest and best way to draw transparent object is to:

  1. disable depth buffer writes (glDepthMask(false))
  2. enable alpha blending (SRC_ALPHA, ONE_MINUS_SRC_ALPHA)
  3. draw the back faces of the object (glCullFace(GL_FRONT)
  4. draw the front faces of the object (glCullFace(GL_BACK)

I draw the whole “mystery cube” last in the rendering cycle. I first draw the backfaces than the question mark and then the frontfaces.

The problem is that whenever I disable depthtesting or set glDepthMask to false (which I believe I have to do in order for the cube to become transparent) the cube looks weird as mentioned above.

These are the OpenGL settings I use when drawing the cube:

public void useProgramFront() {
    // Depth testing
    glEnable(GL_DEPTH_TEST); // CAREFUL: disable while rendering gui (so that two gui objects with transparency can be placed on top of each other)
    glDepthMask(false);

    // Scissoring
    glEnable(GL_SCISSOR_TEST);

    // Culling
    glCullFace(GL_FRONT);
    glEnable(GL_CULL_FACE);

    // Blending
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND); // CAREFUL: disable when not rendering gui

    // Set the current OpenGL shader program to this program
    glUseProgram(program);
}

public void useProgramBack() {
    // Depth testing
    glEnable(GL_DEPTH_TEST); // CAREFUL: disable while rendering gui (so that two gui objects with transparency can be placed on top of each other)
    glDepthMask(false);

    // Scissoring
    glEnable(GL_SCISSOR_TEST);

    // Culling
    glCullFace(GL_BACK);
    glEnable(GL_CULL_FACE);

    // Blending
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND); // CAREFUL: disable when not rendering gui

    // Set the current OpenGL shader program to this program
    glUseProgram(program);
}

I would greatly appreciate any help!

The depth mask shouldn’t matter here, because you shouldn’t be drawing anything behind the cube after drawing the cube.

From the image, it looks as if the vertex colours are wrong. What results do you get if you disable blending (but leave everything else unchanged)?

1 Like

Thanks for answering so quickly!

With blending disabled I get similar results:
image

Only the colours are a bit brighter which makes sense to me.

The cube looks totally fine when I enable depthtesting (and don’t disable gldepthmask):
image

I also tried the texture (which really is just one colour 64x64) on other models and I would always get the same result. The model renders fine until I start setting gldepthmask to false (or disable depthtesting)
With glDepthMask set to false all of my models look strange (random parts that shouldn’t be visible become visible) but I thought that that would be normal. Am I wrong?

I suspect that the face orientation is inconsistent, i.e. the faces which OpenGL considers to be front-facing (by default, those with counter-clockwise winding in screen space) aren’t necessarily front facing. So you’re drawing them in the wrong order. If they’re consistently reversed, then glFrontFace(GL_CW) should fix that. Otherwise, you’ll need to re-order the indices (if you’re using glDrawElements) or the vertices themselves (if you’re using glDrawArrays).

1 Like

Since I’m loading the cube model from an obj file that I exported in blender I would have a hard time reordering the indices.

I tried loading the cube into (please don’t judge me) Paint3D. You seem to be right, the model acts weird there as well.

So I guess my problem is “solved” for now. Thanks a lot for helping me. (again)

Although this might seem like a rather trivial problem, I would not have been able to solve this without you, since under normal conditions (no transparency) the model works fine and I was absolutely sure that this is me failing the transparency part.

It’s not that hard, although it’s not trivial either. For any closed surface, each edge occurs exactly twice. If the winding is consistent, the two occurrences will have opposing directions. I.e. if you have an edge from A to B then the other edge must be from B to A.

To make use of this fact, iterate over the faces, constructing sets of connected faces (i.e. every face in the set shares an edge with some other face). For each face, iterate over its edges, and check whether any set already includes that edge, and whether it’s the same direction or the opposite direction (for a closed surface, you can’t have more than one set which already includes any single edge). You might have a face with multiple edges included in different sets, in which case you need to merge the sets, possibly inverting the winding of faces in one of them to maintain consistency. At the end, you’ll have a single set containing all of the faces with consistent winding (however, the winding could be either CW or CCW).

If the surface is known to be convex, you can avoid some of the complexity and get a pre-determined winding order by first calculating a centroid (just the mean of all of the vertices), then for each face calculating the face normal and checking the side of the face on which the centroid lies. As the normal direction is determined by the winding order, forcing the centroid to be on a specific side ensures a specific winding order.

But if you’re generating the mesh yourself, it might be easier to just fix the original mesh. In Blender, this may be as simple as going into Edit mode and pressing Ctrl+N (“Make Normals Consistent”). If that doesn’t work, try removing duplicate vertices first.