Custom Z Buffer Rules

Is it possible to define a custom z buffer rule? I’ve been working with transparent polygons and I want it to be so that if a face is to be rendered behind a transparent one, (look in the alpha channel and z buffer) then blend the two pixels.

I’m afraid I cannot face sort these polygons.

Am I missing something critical here?

Is it possible to define a custom z buffer rule? I’ve been working with transparent polygons and I want it to be so that if a face is to be rendered behind a transparent one, (look in the alpha channel and z buffer) then blend the two pixels.

Wouldn’t that be the same is just turning the depth test off? And how do you defined what being “behind a transparent one” means? The depth buffer only stores the closest depth value; it has no knowledge of what might have been under it beforehand. And the color buffer only stores a single color.

I’m afraid I cannot face sort these polygons.

Then you’ve got problems. You can look into some order-independent transparency routines (Google search that term) if you truly can’t do any sorting. But otherwise, there’s nothing you can do. That’s the nature of using a rasterizer.

But the fact that there’s blending going on at all means there has to be an alpha value of some sort right? If not, where does GL_SRC_ALPHA come from in glBlendFunc()?

if(z < existing z)
{
draw pixel
}
else
{
if(existing alpha < 1)
{
blend anyway
}
else
{
dont draw the pixel
}
}

Would this not work?

if(z < existing z)
{
draw pixel
}
else

Consider drawing glass nearer the camera than a brick wall.
Already, something simple has failed your test as the glass must blend the background and not cover it.

Besides that, there is no way to implement what you are describing.

But the fact that there’s blending going on at all means there has to be an alpha value of some sort right?

Yes, but having an alpha value doesn’t mean anything. The problem is that the math doesn’t work.

OK, let’s say you draw the background. The background is (0, 0, 0).

Now, you draw some translucent foreground. It has a color of (1, 1, 1), and is 50% opaque. So now the framebuffer has the color (0.5, 0.5, 0.5).

Then, you come along and want to draw something inbetween the translucent foreground and the background. This object is red: (1, 0, 0). It is opaque.

The correct answer, the answer you would reasonably expect, is (1, 0.5, 0.5).

The problem is that blending only has the current fragment color (1, 0, 0) and the destination framebuffer color (0.5, 0.5, 0.5) to work with. There is no blending operation that can take these two colors and produce the right answer. Even having the destination alpha be 0.5 and the source alpha be 1.0 doesn’t help.

Now, imagine that you have multiple transparent surfaces. Say, 3 layers, all composited together. What happens if you try to render a surface between them? Well, you can’t. You cannot isolate the original transparent surface colors; they have all been composited into a single color value. Without being able to do that, you simply cannot put something between them.

The solution is to render them in order. Render all of the opaque objects first, then render each of the translucent ones in order from back to front.

Would this not work?

No, it wouldn’t.

The color in the framebuffer is a composite color, based on what may have been multiple blending operations.

You want to sort your polygons into a BSP tree. Job done.

As already mentioned, Order Independent Transparency (OIT) is the way to go. There was the old nvidia demo that doesn’t use shaders but I had written a shader version.

Man, is it sweet seeing it work for the first time.
Not having to care about order or where and when it is rendered is nice. The output is always correct.

It would work in most cases, but it may still fail (consider two intersecting transparent [sets of] triangles).

Doing it per fragment is the way to go (GL4 provides a nice way to do so).