|
@@ -10,12 +10,13 @@ to reproduce sharp corners almost perfectly by utilizing all three color channel
|
|
|
|
|
|
The following comparison demonstrates the improvement in image quality.
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
|
|
|
- To learn more about this method, you can read my [Master's thesis](https://github.com/Chlumsky/msdfgen/files/3050967/thesis.pdf).
|
|
|
-- Check what's new in the [changelog](CHANGELOG.md).
|
|
|
+- Check out my [MSDF-Atlas-Gen](https://github.com/Chlumsky/msdf-atlas-gen) if you want to generate entire glyph atlases for text rendering.
|
|
|
+- See what's new in the [changelog](CHANGELOG.md).
|
|
|
|
|
|
## Getting started
|
|
|
|
|
@@ -143,13 +144,12 @@ Using a multi-channel distance field generated by this program is similarly simp
|
|
|
The only additional operation is computing the **median** of the three channels inside the fragment shader,
|
|
|
right after sampling the distance field. This signed distance value can then be used the same way as usual.
|
|
|
|
|
|
-The following is an example GLSL fragment shader including anti-aliasing:
|
|
|
+The following is an example GLSL fragment shader with anti-aliasing:
|
|
|
|
|
|
```glsl
|
|
|
-in vec2 pos;
|
|
|
+in vec2 texCoord;
|
|
|
out vec4 color;
|
|
|
uniform sampler2D msdf;
|
|
|
-uniform float pxRange;
|
|
|
uniform vec4 bgColor;
|
|
|
uniform vec4 fgColor;
|
|
|
|
|
@@ -158,16 +158,35 @@ float median(float r, float g, float b) {
|
|
|
}
|
|
|
|
|
|
void main() {
|
|
|
- vec2 msdfUnit = pxRange/vec2(textureSize(msdf, 0));
|
|
|
- vec3 sample = texture(msdf, pos).rgb;
|
|
|
- float sigDist = median(sample.r, sample.g, sample.b) - 0.5;
|
|
|
- sigDist *= dot(msdfUnit, 0.5/fwidth(pos));
|
|
|
- float opacity = clamp(sigDist + 0.5, 0.0, 1.0);
|
|
|
+ vec3 msd = texture(msdf, texCoord).rgb;
|
|
|
+ float sd = median(msd.r, msd.g, msd.b);
|
|
|
+ float screenPxDistance = screenPxRange()*(sd - 0.5);
|
|
|
+ float opacity = clamp(screenPxDistance + 0.5, 0.0, 1.0);
|
|
|
color = mix(bgColor, fgColor, opacity);
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-**Note:** This is an example shader only and probably is not optimal for your use case! Please do not blindly copy & paste.
|
|
|
+Here, `screenPxRange()` represents the distance field range in output screen pixels. For example, if the pixel range was set to 2
|
|
|
+when generating a 32x32 distance field, and it is used to draw a quad that is 72x72 pixels on the screen,
|
|
|
+it should return 4.5 (because 72/32 * 2 = 4.5).
|
|
|
+**For 2D rendering, this can generally be replaced by a precomputed uniform value.**
|
|
|
+
|
|
|
+For rendering in a **3D perspective only**, where the texture scale varies across the screen,
|
|
|
+you may want to implement this function with fragment derivatives in the following way.
|
|
|
+I would suggest precomputing `unitRange` as a uniform variable instead of `pxRange` for better performance.
|
|
|
+
|
|
|
+```glsl
|
|
|
+uniform float pxRange; // set to distance field's pixel range
|
|
|
+
|
|
|
+float screenPxRange() {
|
|
|
+ vec2 unitRange = vec2(pxRange)/vec2(textureSize(msdf, 0));
|
|
|
+ vec2 screenTexSize = vec2(1.0)/fwidth(texCoord);
|
|
|
+ return max(0.5*dot(unitRange, screenTexSize), 1.0);
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+`screenPxRange()` must never be lower than 1. If it is lower than 2, there is a high probability that the anti-aliasing will fail
|
|
|
+and you may want to re-generate your distance field with a wider range.
|
|
|
|
|
|
## Shape description syntax
|
|
|
|