In the previous post I introduced my summer project, to render labels on maps. As part of this, I want to be able to draw outlines, halos, and drop shadows. Signed distance field[1] fonts are well suited for this. The basic use is to consider the signed distances -1 to 0 to be “inside” (filled) and signed distances 0 to +1 to be “outside” (transparent).
To draw an outline, we can add another range, maybe 0.0 to +0.2:
While “pixel peeping” the quality of the outlines, I noticed a little bit of black interior color leaking outside the white outline:
What could be causing this? I looked through the code but nothing was obvious.
To troubleshoot/debug, I need to make the problem happen reliably. Once I can reproduce it, I can start generating hypotheses and then testing them.
So the first step is to make sure this problem happened on initial run, and not only after changing anything interactively. I made sure the d got rendered in that spot and that the black color leak was there.
The next step is to come up with a hypothesis. I thought that the rendering of black pixels was extending past the rendering of white pixels.
The next step is to come up with a test to disprove or prove the hypothesis. If the black pixels were rendering outside the outline, one way to see this would be to change the colors. I changed the black pixels to yellow, and to my surprise, yellow did not go outside the outline. I should’ve changed the outline color too, to make it more visible, but in this screenshot we can see that what’s outside the outline is still black, not yellow:
This means my hypothesis was wrong. That’s ok. Debugging may take several hypotheses and tests. But what could cause black pixels outside a sprite, when none of the sprite colors were black?
This is when I remembered articles I read from Tom Forsyth[2], John Carmack[3], Eric Haines[4], and others say that I should be using premultiplied alpha to avoid black fringing around sprites. Do I really need that? I don’t have sprite graphics here. But that became my next hypothesis. How can I test it? By changing the blending. This fixed the problem:
I think most people would be happy with fixing the bug, but I call this only a partial success. I fixed it but don’t understand why my previous code was broken. And sadly, I hadn’t checked in the buggy version, so I can’t easily go back and study the cause. Without understanding the cause, I may end up making the same mistake again in a future project. If I run into this bug again I will want to study it more closely.
This was one of many bugs and mysteries I encountered in this project.