Error Correction
generate-msdf and generate-mtsdf finish with an error correction pass, on by default:
(sdf:generate-msdf contours width height) ; corrected
(sdf:generate-msdf contours width height :error-correction nil) ; as computed
The problem
Each texel of an MSDF can be right on its own, with a median that is the correct distance, while the GPU's bilinear interpolation between two texels is wrong. Where neighboring texels disagree about which channel is the median, the interpolated channels can produce a median that crosses 0.5 where no edge is. The result is a speck, notch or line in the drawn shape, usually near corners, where edges of different colors come close, or where two contours pass near each other.
What the pass does
The pass is a port of msdfgen's MSDFErrorCorrection in its default configuration, edge priority with exact distance checks at edges:
- Protect corners. The four texels around every corner, where the edges on either side share only one channel, keep their channels, since they are what makes the corner sharp.
- Protect edges. For each pair of neighboring texels, horizontal, vertical and diagonal, that lie on either side of an edge, a texel is protected if a channel other than its median is what places the edge between them.
- Find artifacts. For every texel, interpolate towards each of its eight neighbors, bilinearly along the diagonals, and look at the points where two channels are equal, which is where the median can turn. If the interpolated median there falls outside what a distance can do between the two texels, or changes sign where both texels agree, the texel causes an artifact. Protected texels count only sign changes.
- Confirm at edges. Sign changes at protected texels that could not be decided from the field alone are checked against the shape's own distance: the texel is marked only if flattening it brings the interpolated median closer to the true value.
- Flatten. Every marked texel has all three channels set to its median.
Flattening a texel turns it into a plain SDF texel there: still correct, but it no longer helps keep a corner sharp. The pass never changes a texel's median, and never touches the alpha channel of an MTSDF.
On the five-pointed star of Recipes at 32 by 32 texels, it changes 36 of the field's 3072 values.
Checked against msdfgen
When the pass was ported, it was run beside msdfgen on 18 glyphs from DejaVu Sans and URW Bookman, and corrected exactly the same texels. The test suite keeps whole corrected fields from msdfgen, for four straight-edged stars, two of them twisted so that both corner protection and the distance check matter, and requires cl-sdf's output to match within 1/10000 of a texel. See Development.
When to turn it off
Leave it on unless you have a reason:
- You run your own correction, or want to compare with and without.
- You are studying the raw multi-channel distances.
- Generation time matters more than the occasional artifact. The pass adds a fifth to a half to an MSDF's generation time; see Accuracy and Performance.
What it cannot fix
Features thinner than about a texel, and shapes whose edges come within a texel of each other, cannot be represented by any distance field. Error correction removes many of the artifacts this causes, by turning the texels there into plain SDF texels, which round or merge the features instead. A larger field is the cure.