Mark Coniglio
Mark Coniglio

Reputation: 401

OpenGL: Dark Halos Around Blurred Text

I'm rendering green text, some of which is is blurred, with an onto a solid blue background. The transparency functions are working as expected, but I get a dark "halo" in the blurred area of the text. I've spent days reading articles and trying different solutions, but to no avail.

The foreground image is filled with pure green (0,0,1) and the alpha channel is where the text -- and transparency -- are defined.

My problem can easily be demonstrated by visiting the site http://www.andersriggelsen.dk/glblendfunc.php and entering these two Image URLs:

foreground: http://troikatronix.com/files/text320x240.png

background: http://troikatronix.com/files/solid-blue.png

This picture shows the setup and the resulting image with the dark halo.

transparency problem example

To try to get to the bottom of this, I wrote a debug function to read back the back buffer after each layer was rendered. Numerically, the math all comes out right.

For instance, if I render a solid part of the premultiplied source image at 10%, (e.g., source is rgba[0, 0, 255, 255] before premultiplication with 10%) and use glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA) it goes like this

bkg = rgba[0, 0, 255, 255]
src = rgba[0, 25, 0, 25]
result = rgba[0, 25, 230, 255]

But when you see that, you basically get a darkened blue and see no green, as demonstrated by this image

darkened blue text

So what am I doing wrong? Or is this some kind of gamma/color matching problem, where an increase in green is not as visible as a decrease in blue?

Upvotes: 3

Views: 332

Answers (1)

geometrian
geometrian

Reputation: 15387

This is a simple perceptual problem, and it is related to gamma.

Starting from this cropped output:
original
If you split the channels, you get (red, green, blue):
red green blue
Monitors, including the sRGB LCD monitor you're almost certainly looking at, do gamma scaling on pixel valuesnote 1.

Here's a graph of an approximation of the sRGB gamma functionnote 2: gamma correction; source: Wikimedia

When we're looking at the blue background (value 0,0,255=>0,0,1), we get an output of 0,0,1. Similarly, when we're looking at the completely green inside of the letter, we get an apparent brightness of 0,1,0note 3.

Now think about what happens to a point on the edge. Let's say it's basically right in the middle 0,127,128~=>0.0,0.5,0.5. Using the graph, this gives us an output apparent intensity of 0.00,0.218,0.218. Our perception of pixels' luminance is additive across channels, so we get an overall brightness of 0.436.

This is noticeably darker than either the inside or outside of the letter--and you perceive it as a dark band!


note 1Why? It has the effect of making the change from e.g. 200 to 201 much larger in terms of actual brightness than the change from e.g. 5 to 6. We do that because human contrast perception is basically a function of the percentage difference. To preserve apparently even contrast, brightness must be nonlinear.
note 2It's a little different in reality, but this is basically right. Specifically, the exponent is really 2.4, and it becomes linear close to 0.0 for numerical reasons. Sometimes there are further corrections to make it C1 continuous.
note 3The different color channels are also scaled to give similar apparent brightness.

Upvotes: 3

Related Questions