Semi-transparent cutouts

Hi everyone!

I am trying to render textured quads in a 3D scene to draw some texts.

The bitmaps I’m using behaves as alpha maps, with A=0 for the backgound, A=1 for the glyphs and in-between values at the boundaries between the glyphs and the background.

Since those texts are actually part of the scene and could be arbitrarily placed in the 3D space I think I need to draw them with depth testing enabled and alpha clipping to prevent the “transparent” portions of the quads from occluding what’s behind them.

The problem is that I don’t know how to blend the semitransparent pixels of the textured quads with the rest of the scene:

setting an alpha treshold such that only 100% opaque pixels are drawn would result in jagged edges while lowering the threshold and enabling blending (add, SrcA, 1-SrcA) gives me unpleasant outlines around the texts.

What options do I have? Should I draw those entities with 2 passes (one for the fully opauqe part of the quad and one for the semitransparent part after all the opaque entities have been drawn)?

Is there any reference / article about the topic? How has the same problem been solved for foliage/grass rendering in videogames?

1 Like

Use Premultiplied Alpha.

Links:

A few past forum threads where folks have hit this before:

Thanks @Dark_Photon,
I’m afraid I didn’t provide a clear explanation of the problem, which is not (I think) related to blended color computation itself:

The problem is that I need to draw those texts “inside the scene” and since they are fully opaque I need to draw them with depth testing and writing enabled.
They are fully-opaque except for some portions near the edges of the glyphs where they are semi-transparent, to achieve a smoother look.
I also need to perform alpha clipping on the quad, the problem is that if I clip all the fragments with A<1 the smoother look of the text is ignored, if I use a lower threshold (and enable blending) the edges get blended with whatever was previously drawn but (obviously) not with what comes next.

EXAMPLE:
I have a textured quad (text image with alpha) and a cube. I draw the quad with alpha clipping and blending, the semitransparent edges gets correctly blended with the background. Then I draw the cube but it’s behind the text. Now the semitransparent edges of the text show a correct blending with the background but not the cube (while they should since the cube is behind the text).

Then they’re not “fully-opaque,” are they? An object either is opaque or it isn’t. If it’s only partially opaque, then it’s not opaque.

You have to do blending if you want this to work.

You are right, however I don’t know how to do that.
I can’t disable depth writing and draw my texts with blending (also, they are arbitrarily oriented so a simple back to front sorting wouldn’t work), and I also can’t keep writing and testing depth while drawing them (see example above, the text, background and cube scenario).

This is an example alpha map.
I think that rendering quads with depth test/write and alpha clipping with A=1 as threshold and then draw the not-fully-opaque pixels with blending and no depth write after all the opaque objects and the background have been drawn would give the correct result (except for the order of the blending).

However, I’d like if there are other (simpler) ways to achieve the same.

It’s text; you can figure out a back-to-front order of the quads. It’s not trivial, but so long as they don’t intersect, you can do it.

And unless overlapping, transformed text is super-important to your application, I wouldn’t bother trying to sort all of the text quads from every line of text at once. Order the quads in each line of text separately (that should be pretty simple; you either render them left to right or right to left), then figure out an overall order for all lines of text.

I don’t see why not. Draw all opaque objects first, then draw the transparent ones with depth testing but not depth writing.

But that’s the thing that prevents you from just doing blending from the start, right? So you haven’t actually found a solution, just a different way to express the problem.

Thanks, I guess sorting is another option to solve my problem.

But texts are not transparent in this case, they have fully-opaque sections and semitransparent ones, so I can’t accept to just blend a text over another that was closer to the camera (assuming no view direction sorting).

I don’t follow you. With the approach I described I’ll split the text into 2 parts: opaque and transparent.
So I’m allowing blending errors only in the transparent part (a few pixels compared to the opaque part), while I’d get errors potentially everywhere if I do blending from the start. Am I missing something?

That’s what “being transparent” is. You cannot treat an object as partially opaque. It either is opaque in its entirety or it must be treated as transparent.

Yes, you will get bad results if you start with bad assumptions.

Transparency requires sorting. Well, there are order-independent transparency techniques, but they’re really not worthwhile for drawing a bunch of text quads.

Sorting is not optional.

But that’s what your problem is currently. The transparent parts in your pictures are showing errors. Those white outlines in your text are the “transparent parts”.

No. If you blend correctly (that means with sorting back-to-front, rendering transparent objects after non-transparent ones), then it all just works.

leoner, you can try Alpha-to-Coverage for this. It does avoid explicit sorting. But don’t expect perfect edge quality on the translucent edges of your text. For that you’ll want blending. And for that you need sorting.

1 Like

I know this usually is a problem when no sorting is done when the text is 3D and inside the scene insted of in the GUI.

So what you are experiencing is sometimes the text objects blend fine with the background but in some angles they don’t, correct? If so, then it is definitely a sorting issue, you need either to sort each object or draw the text objects at the end of all the other objects (and then only sort the text objects to prevent the weird effect itself)

OR

you can try to check out this technique:

Distance Fields (or Signed Distance Fields) font approach technique, as mentioned here:

Basically not only will this give you a better control over the font’s glyph border, but it will also give out many other set of features such as outlines, shadow, bold, thin (when using gradients).
And as you will be discarding pixels then It won’t be a problem since there won’t be any alpha values to blend with.

Thanks for the suggestion, I’ll consider it.

I understand, however, since I could also have transparent 3D objects (just to say “not quads”) in the same scene along with texts I don’t think that sorting texts would be sufficient. Let’s say I have a text in the center of a transparent torus for example, no matter what order I use to draw with blending, text over torus OR torus over text will result in a noticeable error.
I know this is the same problem I’d have with a transparent cube inside a transparent torus, there’s nothing special about the text being a text, however typically a transparent 3D object will have alpha values not so close to 1 as a text will certainly have for the majority of the pixels it covers.

I’m assuming a blending order error (A over B instead of B over A) is greater the more the pixels are opaque (if Aa==1 and Ba==1 I get the maximum possible error), is this a wrong assumption?

So I thought that limiting this error to the text’s edges would be beneficial.

However, refining my google search I found this article that clearly states the problem I’m referring to and the solution I had in mind: Smooth plant rendering in Overgrowth news - Indie DB
(it also mentions alpha-to-coverage as an option).

I just wanted to know how this problem has been solved in the past, now I also know about alpha to coverage and sorting (which I still don’t get how to combine that with transparent geometry).

I’m really sorry about that, I should have labeled the image. That image is showing a text drawn with blending, alpha clipping and depth testing and writing enabled. The entities are not sorted so the text is drawn and blended over the background, then the blue entity behind it is drawn, leaving those outlines.

You should almost never enable blending and depth writes simultaneously. Depth testing is a binary choice; the current fragment either completely obscures anything drawn behind it or it doesn’t.

When rendering a fragment with partial alpha, anything that will appear behind it must have already been rendered.

If you need to support arbitrary translucent geometry within a scene, the modern approach is to use order-independent transparency techniques such as depth peeling or linked lists of fragments. The legacy approach was to sort translucent geometry (e.g. using BSP trees); but that’s computationally expensive when used with complex geometry.

If you just want anti-aliasing, it’s better to use multi-sampling, alpha-testing and/or alpha-to-coverage.

1 Like

That is why you will need OIT (order independent transparency)

Order-independent transparency (OIT) corrects the display of transparent objects that are drawn out of order.

ezgif-1-09b773d01f

OIT is useful when creating the following:

  • Concave geometry – When you create concave geometry, such as a glass, wine glass, or glass sculpture, some triangles may cover the same pixels and are drawn on top of each other. OIT solves the out-of-order issues that appear from certain angles.
  • Intersecting geometry – When you create intersecting geometry, such as hair planes, some triangles may intersect in separate draws. OIT properly orders the triangles for each pixel.
  • Transparent objects inside transparent objects – This includes liquids inside of glasses, holograms, or x-ray style effects.

To further demonstrate, see the following images.

In such case you should check out depth peeling or, to simplify divide the bigger one (torus) into smaller parts in order to get a better result, but keep in mind that transparency blending is an expensive task when done perfectly, sometimes its better just ignore some smaller issues as you can see in some games.