chlumsky / msdfgen Goto Github PK
View Code? Open in Web Editor NEWMulti-channel signed distance field generator
License: MIT License
Multi-channel signed distance field generator
License: MIT License
I've been reading through your paper in an attempt to integrate multi-channel SDFs into a C++ font handling library I wrote; and came across a small discrepancy between the paper and your code.
In the file edge-segments.cpp, function SignedDistance QuadraticSegment::signedDistance(Point2 origin, double ¶m) const, you have:
Vector2 qa = p[0]-origin;
Vector2 ab = p[1]-p[0];
Vector2 br = p[0]+p[2]-p[1]-p[1];
double a = dotProduct(br, br);
double b = 3*dotProduct(ab, br);
double c = 2*dotProduct(ab, ab)+dotProduct(qa, br);
double d = dotProduct(qa, ab);
This slightly different from the equations in your paper on page 16, notably 2.31 and 2.38. If I'm reading the paper right what you should have is:
Vector2 qa = origin-p[0];
double c = 2*dotProduct(ab, ab)-dotProduct(br, qa);
double d = -dotProduct(qa, ab);
Now the negation of qa (from p - p0 to p0 - p) is balanced by the negations in c and d. So the end result is mathematically identical. I'm wondering, was this intentional? Is there some reason for this change that I'm not seeing?
Hello-
It is great that the releases include a compiled Windows executable. As a feature request, can the documentation be extended to include instructions for how to compile the comprehensive standalone console program on other distributions. The naive g++ -o ms main.cpp
does not work on MacOS. There is a precompiled executable for MacOS, but it does not appear to be a recent version. Thanks for a terrific program.
Generated SDF flips depending on TTF/OTF file.
For example, in 'Times New Roman.ttf' (coming with OSX), SDF is generated for outer direction
while in 'NotoSansCJKjp-Bold.otf' (https://www.google.com/get/noto/), it's generated to inner direction.
Need to check a winding direction for a robust SDF generation?
Hello,
I am testing your library. And when I generate the Bitmap< FloatRGB > data using generateMSDF and look at the values in the bitmap, I see both positive and negative values. The lower the pixel range, the closer they are to 0. And if the pixel range is high, the absolute values of the colors are also high. But there are always both positive and negative values.
The code I am using (angleThreshold, edgeThreshold and range are changeable using keyboard):
// create shape
msdfgen::Shape shape;
bool status = msdfgen::loadGlyph( shape, this->font, int( c ), nullptr );
if( !status )
cout << "msdfgen::loadGlyph failed" << endl;
// process shape
shape.normalize();
msdfgen::edgeColoringSimple( shape, this->angleThreshold );
if( !shape.validate() )
cout << "shape validation failed" << endl;
//
int bitmap_width = 128;
int bitmap_height = 128;
// rasterize shape
double shape_l, shape_b, shape_r, shape_t;
shape.bounds( shape_l, shape_b, shape_r, shape_t );
double shape_width = shape_r-shape_l;
double shape_height = shape_t-shape_b;
double scale;
msdfgen::Vector2 translate;
if( shape_width * bitmap_height < shape_height * bitmap_width )
{
translate.set( 0.5 * ( bitmap_width / bitmap_height * shape_height - shape_width ) - shape_l, 0.0 - shape_b );
scale = bitmap_height / shape_height;
}
else
{
translate.set( 0.0 - shape_l, 0.5 * ( bitmap_height / bitmap_width * shape_width - shape_height ) - shape_b );
scale = bitmap_width / shape_width;
}
msdfgen::Bitmap< msdfgen::FloatRGB > bitmap( bitmap_width, bitmap_height );
msdfgen::generateMSDF( bitmap, shape, this->range, msdfgen::Vector2( scale, scale ), translate, this->edgeThreshold );
//msdfgen::generateMSDF_legacy( bitmap, shape, this->range, msdfgen::Vector2( scale, scale ), translate, this->edgeThreshold );
// convert it to pixels
for( int x = 0; x < bitmap_width; x++ )
for( int y = 0; y < bitmap_height; y++ )
{
msdfgen::FloatRGB rgb = bitmap( x, y );
cout << ": "<<rgb.r<<" "<<rgb.g<<" "<<rgb.b<< endl;
}
Sample of produced output (range around 4):
: -19.3036 -19.3036 8.32928
: -19.473 -19.473 7.8819
: -19.6425 -19.6425 7.43451
: -19.812 -19.812 6.98712
: -19.9814 -19.9814 6.53973
: -20.1509 -20.1509 6.09235
: -20.3203 -20.3203 5.64496
: -20.4898 -20.4898 5.19757
: -20.6593 -20.6593 4.75018
: -20.8287 -20.8287 4.3028
: -20.9982 -20.9982 3.85541
: -21.1677 -21.1677 3.40802
: -21.3371 -21.3371 2.96063
: -21.5066 -21.5066 2.51324
: -21.676 -21.676 2.06586
: -21.8455 -21.8455 1.61847
: -22.015 -22.015 1.17108
: -22.1844 -22.1844 0.723694
: -1.07684 -1.07684 0.723694
: -1.2463 -1.2463 1.17108
: -1.41576 -1.41576 1.61847
: -1.58523 -1.58523 2.06586
: -1.75469 -1.75469 2.51324
: -1.92415 -1.92415 2.96063
: -2.09361 -2.09361 3.40802
: -2.26307 -2.26307 3.85541
: -2.43253 -2.43253 4.3028
: -2.602 -2.602 4.75018
: -2.77146 -2.77146 5.19757
: -2.94092 -2.94092 5.64496
: -3.11038 -3.11038 6.09235
: -3.27984 -3.27984 6.53973
: -3.4493 -3.4493 6.98712
: -3.61877 -3.61877 7.43451
: -3.78823 -3.78823 7.8819
: -3.95769 -3.95769 8.32928
: -4.12715 -4.12715 8.77667
: -4.29661 -4.29661 9.22406
: -4.46607 -4.46607 9.67145
: -4.63554 -4.63554 10.1188
: -4.805 -4.805 10.5662
: -4.97446 -4.97446 11.0136
: -5.14392 -5.14392 11.461
: -5.31338 -5.31338 11.9084
: -5.48284 -5.48284 12.3558
: -5.65231 -5.65231 12.8032
: -5.82177 -5.82177 13.2505
Thank you for any advices.
JK
Hi Chlumsky,
I created a (roughly) 64x64 glyph texture using the Showcard Gothic font and noticed that, when rendering at large sizes, the inner curve of the R is made from straight edges, instead of a nice curve. The same is not true for the outer curves of the R. Other glyphs show similar problems.
When examining the font file, it's clear that the font is using a smooth curve. I tried increasing MSDFGEN_CUBIC_SEARCH_STEPS
to 40, but that did not do anything.
Do you have any idea what might cause this?
To preserve sharp corners, the edge colors must be assigned according to these simple rules:
The program uses a very simple heuristic, which performs the edge coloring according to these rules in an arbitrary way, but there are usually many possible ways to do this, and depending on the complex interactions of unrelated edges which lie close together, the visual result may differ greatly.
This is definitely something to be investigated, and I will probably at least add an "edge coloring seed" parameter, which will allow users to test different pseudorandom variants of edge coloring.
Thank you very much for publishing your code ! I'm eager to read your paper.
I've tried to play a bit with the program and I'm trying to to reproduce your fir figure (capital 'A' / Arial font) but the output is not so good. I've been using:
./msdfgen msdf -font Arial.ttf '0x41' -o msdf.png -size 16 16 -pxrange 2 -autoframe -testrender render.png 256 256
and I get:
Any idea what is wrong in my command line ?
Hey,
I have a problem when trying to convert SVGs into distance fields with your project.
Very often, the corner or "end points" of the SVG paths are bleeding out into the distance field, as if the shape intersected itself at that point.
The source SVG file can be found here: http://tiny.cc/3524iy
See the following simple shape as an example:
The problem, as you can see, is the hole in the lower left corner, which will be rendered filled as the shape itself.
No matter what options I use, the result it always the same. Could you please tell me what the problem is and how I could mitigate it?
Making the corner "smooth" by moving the fourth control point of the bezier curve around creates a good result, but it also substitutes the sharp corner with a round one:
Trying to process this font FandolKai.zip produces a lot of artifacts. Here is one example I studied more carefully
- char #36864
- char #36873
Hi Chlumsky,
I noticed some aliasing artifacts when rendering fonts using msdfgen. By changing the shader a bit, I was able to improve the rendering quality:
float sigDist = median( sample.r, sample.g, sample.b );
float w = fwidth( sigDist );
float opacity = smoothstep( 0.5 - w, 0.5 + w, sigDist );
Especially note the capitals "A" and "W".
Thanks for sharing your hard work on SDF text rendering with the open source community!
I'm integrating msdfgen in our content generation pipeline. It looks great, but I'm having troubles finding the offsets to the baseline and the left most pixel that belongs to the glyph.
I know the translation and scaling msdfgen applied to center the glyph with the autoframe feature. I can undo these but (obviously) that doesn't put the glyph on the baseline yet. If I use FreeType to render a glyph I get an x and y offset. How do I get the equivalent data from msdfgen?
Do you have an example where you layout a sentence using info from msdfgen?
Currently, the closest edge segment to a point in the distance field is found with a brute force approach, comparing distances of all edges. For use in runtime glyph map generation, it is necessary to make this process more efficient. If an efficient closest edge lookup is implemented, it will not be a problem to integrate with my method of multi-channel distance field generation.
Problem definition:
Implement a data structure that holds a set of edge segments (line segments, quadratic and cubic Bรฉzier curves), some of which may share an endpoint, but generally do not form closed paths, and that supports efficient lookup of the closest edge segment (in terms of absolute euclidean distance) to a given point in the plane.
For the distance, the computation implemented in EdgeSegment::signedDistance
can be used (the absolute value of the result).
Note that if a common endpoint of two edges is the closest point, it must either produce both, or correctly choose the edge that is considered closer by the same logic used in my SignedDistance class.
Any suggestions on how to implement this are welcome.
Hi! thanks for your awesome MSDF generator, im so happy you solved that :)
One note on your GLSL though, i got really ugly results using fwidth(sigDist) as AA especially at small font sizes.
I'm currently using a scale of this value:
Thanks again
The library headers are currently in the project, but should probably be removed in favor of the package location facilities provided by CMake (it can automatically create the proper CXX flags to locate the exact includes). It's not super urgent as FT doesn't change that frequently, but it could introduce compilation errors later on due to header/library mismatch.
Just spent a while debugging nondeterministic results from Shape::bounds()
, it could be improved with:
void Shape::bounds(double &l, double &b, double &r, double &t) const {
l = b = LARGE_VALUE;
r = t = -LARGE_VALUE;
for (std::vector<Contour>::const_iterator contour = contours.begin(); contour != contours.end(); ++contour)
contour->bounds(l, b, r, t);
}
msdfgen allows the creation of a single texture per character or vector each time.
What about creating a texture map of all chars in a font?
In terms of packing, should every char be in a full square area or is it possible to have more packed elements ?
The program does not support shapes whose edge segments intersect each other. Unfortunatelly, I have found that some font glyphs, especially those with accents, are defined like this.
This could be solved either by preprocessing the shape to eliminate such occurences, or perhaps by generating multiple distance fields for non-intersecting components (contours), and combining them in a certain way. The latter solution should be sufficient for the accents.
Couple of issues I'm running into while processing some font glyphs - any workarounds appreciated.
First one is, the bottom part of the Q is inverted:
I've tried -keeporder and -reverseorder .. I saw something about a -seed parameter but I can't find any proper info about it so I'm not sure if I can use that to get around this?
The other one is just the overlap on this "D" is a bit funky:
I'm guessing that one is pretty hard to fix but worth reporting.
Both are using -autoframe
The font I'm using is "Most Wasted": http://www.dafont.com/mostwasted.font
please see a problem and a solution in this #19
Could you give me a description to retrieve right values for scale and translate value in msdfgen::generateMSDF() ?
For example, given Bitmap is set up with a size of 16x24,
what is a recommended method to retrieve the scale and translate values to make the glyph located at the center of the area with the size?
I'd love to use MSDF fonts (btw, kudos and thanks for the program/library) but font outlining is a must for the project I'd be using them.
Unfortunately the shaders I've seen with SDF outlines are very weak: artifacts and swiggly lines, specially when having to use pronunciated outlines.
So my idea is using two MSDF fonts instead of one: one for the outline (a "fatter" version of the font) and the usual font. Print first the outline and then the normal font (or maybe using two textures in the shader and do it in one pass)
And here comes the question: Is it possible/easy to create a fatter version of the font with msdfgen without the obvious loss of quality the MSDF outline shaders present? Could somebody give some pointers on what should be modified in the code to obtain that?
Thanks!
A minor thing, but this line of code in edge-coloring.cpp:
contour->edges[(corner+i)%m]->color = (colors+1)[int(3+2.875*i/(m-1)-1.4375+.5)-3];
is complex and hard to understand. I believe, if I've done the simplification correctly, this turns into:
contour->edges[(corner+i)%m]->color = colors[int(2.875*i/(m-1) + 0.0625];
The intent appears to split the colors into three groups, index 0, 1, and 2, about evenly divided among those groups. Adding a comment here as to intent would also be nice.
Hi, we are using your converter and it's great so far. One report we received was that zlib1.dll is missing, and it turns out freetype6.dll requires it. We decided to remove both by using a static version of freetype.lib (in the patch file if you want to use it) or just including zlib1.dll should be enough.
(The static version is still smaller)
the latest version (8b2d463) has a rendering error when rendering this svg path.
compiler: gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
command line: ./msdfgen -svg shape.svg
the cyan bar on the far right shouldn't be there.
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 64 64"
version="1.1"
width="64"
height="64">
<path
d="m 51.118496,55.684596 0,-8.665695 -15.010504,0 q -3.077468,5.123513 -8.82417,8.792201 -5.746698,3.668689 -11.587606,4.933753 -0.628056,-2.783142 -3.203078,-4.048209 5.52688,-0.632532 10.457108,-3.257541 4.93023,-2.625009 8.007698,-6.420204 l -9.54643,0 q -2.889052,0 -5.840909,0.126505 0.125607,-1.581331 0,-3.225916 2.951857,0.189762 5.840909,0.189762 l 11.4934,0 q 0.942081,-1.834344 1.318913,-3.731942 l -14.947701,0 q 0.753668,-7.147617 0,-14.295233 l 34.982645,0 q -0.753666,7.147616 -0.0628,14.295233 l -15.638559,0 q -0.314026,1.897598 -1.004887,3.731942 l 17.773946,0 0,12.081369 q 0,1.897598 -1.758553,3.352424 -2.763441,2.150609 -9.169599,2.087355 0.690862,-2.909649 -1.381719,-5.123512 1.884163,0.189758 4.741813,0.221385 2.857649,0.03163 3.10887,-0.221385 0.251222,-0.253014 0.251222,-0.822292 z M 26.687173,17.289874 q 0,-1.707837 -0.125608,-3.225915 l -13.126341,0 0.0628,26.439857 q 0.0628,12.08137 -7.2226217,18.090431 Q 4.9564898,56.443634 2.5070771,55.747848 5.772959,53.85025 7.4059026,50.497829 9.5412869,46.070101 9.2900656,40.503816 l -0.062803,-29.349506 19.5325009,0 0,-2.2138648 q 0,-4.3012187 -0.188418,-8.60243962 2.323803,0.25301302 4.647604,0 Q 33.093342,2.8048823 33.030533,5.271759 l 15.136117,0 q 2.951857,0 5.903714,-0.1265065 -0.188416,1.6445841 0,3.2259145 Q 51.118507,8.2446605 48.16665,8.2446605 l -15.19892,0 0,2.9096495 27.885622,0 0.628057,3.415674 q -0.251223,-0.379519 -0.502444,-0.06325 -1.1305,2.150609 -1.884165,4.617485 l -3.893939,-1.58133 1.381721,-3.478929 -25.62463,0 q -0.125607,1.391573 -0.0628,2.972902 l 14.068425,-0.75904 q 2.700634,-0.189758 5.401268,-0.44277 -0.125607,1.454823 0.125607,2.909649 -2.700634,0.06326 -5.401269,0.18976 l -14.13122,0.759032 q 0.43964,1.707837 1.94697,1.707837 l 16.517836,0 q 1.821358,0 2.260997,-0.885544 l 0.942081,-2.150612 q 1.758555,1.138559 3.768328,1.96085 l -1.884163,3.289171 q -0.628054,1.391571 -2.700633,1.391571 l -18.967252,0 q -2.512219,0 -4.145161,-1.359946 -1.632941,-1.359945 -1.946968,-3.700315 l -6.029325,0.316267 q -2.700635,0.126506 -5.401271,0.442773 0.0628,-1.454826 -0.125607,-2.909649 2.700636,-0.06326 5.338464,-0.18976 z m 12.058647,14.991021 11.304986,0 0,-3.542183 -11.304986,0 0,3.542183 z m -4.207965,0 0,-3.542183 -11.053762,0 0,3.542183 11.053762,0 z m 4.207965,2.656636 0,2.783142 11.242179,0 0,-2.783142 -11.242179,0 z m -4.207965,0 -11.053762,0 0,2.783142 11.053762,0 0,-2.783142 z m 26.943544,-20.367547 0,0.126507 0,-0.126507 z"
style="fill:#000000" />
</svg>
Forgive my ignorance, but I'm not sure I quite undrestand how to integrate the SDFs on the OpenGL. Currently, I have bitmap font engine that renders text from bitmap glyphs generated by freetype. The fragment shader looks like this:
uniform sampler2D bitmap;
in vec2 texC;
in vec4 color;
out vec4 fragColor;
void main(void)
{
fragColor = texture(tex_bitmap, texC) * vec4(color);
}
It enabes alpha blending and uses triangle vertices as a primitive. Pretty standard stuff.
I tried replacing that shader with your example shader (setting bgColor to the background color and replacing fgColor with color), but all that I see are white squares.
I replaced the standard bitmap atlas with a bitmap atlas generated using your tool to create 64x64 (auto framed) glyphs.
I'm also confused as to how to render the text at a given size (16 pt, 14 pt, etc.). Is it just a question of scaling the mvp matrix in the vertex shader to get the size that I want?
Any information you could provide as to how things should look on the OpenGL side would be super appreciated.
Hi,
could you add a little description, what the output from "-printmetrics" means? Are the values in pixels or Glyph units? What does "bounds" exactly mean? (In my case bounds contains a negative value, which irritates me). What is range?
Basically, my characters are too far apart, when I try to render them as an actual text and im trying to figure out, what Im doing wrong here.
Thanks for your work!
Would you like to add more error handling for return values from calls of the function "fprintf"?
Hello,
all fonts I'm trying (tried 6 so far) are having an artifact on the side that touches bottom-left (it's hard to explain but easy to see). Also the output.png file does not cover the full PNG, but 1/4 of the image, which seems weird although I only have the example.bat defineshape as reference.
The commandline I'm using is, in example,: msdfgen.exe -font arial.ttf 65 -testrender render.png 1024 1024
I've tried binaries 1.4, 1.5 and compiled the https://github.com/ckohnert/msdfgen fork. All give me this problem.
In example, J is verdana, C is ConsolasBold, A is Arial (for arial the problem is minimal , at the bottom left, but still is there).
Any ideas?
Thanks!
Hi, i found there is no x64 lib for FreeType, can we add it?
in your docs there is a phrase To start using the program immediately, there is a Windows binary available for download in the "Releases" section. Please can you explain where it ("Releases" section) is located?
I noticed that the pseudo distance field produces noticeable discontinuities at edges that point towards smooth curves. The issue is probably caused by the call of distanceToPseudoDistance
afterwards because at the point where the distance fields of the sharp corner and the curve touch each other, only their regular signed distances are equal. Only on the side closer to the sharp corner, the distance field is modified by distanceToPseudoDistance
changing the value on one side. This creates this discontinuity.
I tried fixing this by moving the call to distanceToPseudoDistance
inside the inner loop to create the pseudo distance field everywhere instead just for the closest segment. Unfortunately this made things a lot worse and I am not really sure yet why.
An image of a distance field: (Arial)
This is a problem for us because we want to apply shader effects to the rendered font. For that we need proper distance information far away from the glyph itself.
Hello I am stuck on trying to get this library working, which thank you for writing this library. However getting proper metrics and scaling using the c++ api provided has proved difficult. Can you tell me how I would scale the bitmaps or get proper metrics for rendering?
The include directories are not set up correctly in the default project/solution.
1>c:\depo\common\tools\msdfgen-master\lib\tinyxml2.cpp(24): fatal error C1083: Cannot open include file: 'tinyxml2.h': No such file or directory
1> lodepng.cpp
1>c:\depo\common\tools\msdfgen-master\lib\lodepng.cpp(31): fatal error C1083: Cannot open include file: 'lodepng.h': No such file or directory
1> save-png.cpp
1>c:\depo\common\tools\msdfgen-master\ext\save-png.cpp(5): fatal error C1083: Cannot open include file: 'lodepng.h': No such file or directory
1> import-svg.cpp
1>c:\depo\common\tools\msdfgen-master\ext\import-svg.cpp(5): fatal error C1083: Cannot open include file: 'tinyxml2.h': No such file or directory
1> import-font.cpp
1>c:\depo\common\tools\msdfgen-master\ext\import-font.cpp(6): fatal error C1083: Cannot open include file: 'ft2build.h': No such file or directory
It seems I am unable to feed an SVG file with the proper specs. Would you happen to have an example we can use for comparison?
Edit: A description of how a proper SVG output is obtained in the first place would also be very useful. Inkscape? Illustrator? My attempts at creating the simplest shapes have failed so far. I'm actually having more success creating a dummy TTF file with the vector shapes and then feeding that TTF to msdfgen with the -font option :)
The error detection/correction of the multi-channel distance field is based on identification of "fronts of discontinuity" in the distance field, but they may not be correctly detected if they are too close to an edge to be sufficiently "pronounced", and the change in the distance field seems completely smooth. This may cause visual artifacts in rare cases, where distance field resolution is insufficient.
The problem can be reproduced like this:
msdfgen.exe -font FreeSansBold.ttf 'A' -size 16 16 -autoframe
I have an idea how to fix this by generating a gradient vector field of the signed distances, and using that in the error detection.
When I try to run msdfgen on the 'o' character (111) with the Proxima Nova font, msdfgen fails with "Failed to load glyph from font file."
Other glyphs from the font work fine, as do other fonts.
I love the work you've done on this project, and would love to use it for rendering text in my game, but the the nature of the GPL makes me wary to do so. In particular, I want to support dynamic glyph generation, which involves integrating some of the code you've written, but GPL licensing means that this library wouldn't be a good fit for me.
I think that licensing the code under a less restrictive license, such as MIT or FreeBSD license would allow more people to try out this cool rendering technique. Both the MIT and FreeBSD licenses are GPL compatible and Open Source Initiative approved, so there shouldn't be any loss of freedom.
I expect that exception handling is usually supported by a C++ program. I wonder why your function "main" does not contain corresponding try and catch instructions so far.
How do you think about recommendations by Matthew Wilson in an article?
Would you like to adjust the implementation if you consider effects for uncaught/unhandled exceptions like they are described by Danny Kalev?
I'm running into pretty severe quality issues when trying to generate MSDFs for various glyphs in popular fonts (such as Google's Roboto). Here is for instance the glyph 'A' rendered at 64x64 from a 16x16 MSDF (generated using -size 16 16 -pxrange 1 -autoframe
):
Using a larger pxrange makes the problem even worse. Generating larger MSDFs wouldn't be much of an issue if minification worked well.
I have found that the fwidth() GLSL call is only supported on newer computers. Old PC's with intel graphics cards and similar simply fails to load the GLSL shader because of that function usage despite it being available since GLSL since v1.10.
Use of the fwidth() function also doesn't seem to work when compiling OpenGL projects with the ANGLE project (angleproject.org)
Is there a more portable way to get this information?
Was hoping I could avoid resorting to manual derivative calculations by doing several texture lookups.
This zip file contains an example svg that results in a weird output. The svg is produced by exporting from a photoshop file shape I made.
HealthIcon.zip
First off, the svg can't be parsed without my pull request: #55
Once done, this is how my Unreal Engine material renders it.
This is the output produced by msdfgen when I use the sdf flag. Not what I'd expect.
There may be some weirdness in my shape data. I'll look at trying to fix the shape later.
The dependency on FreeType(hosted on sourceforge ugh), which appears to have last been compiled on windows 10 years ago is slightly annoying:/
Does stb_truetype have the capabilities to replace the use of FreeType here?
Is there any interest in adding a C API? I'm working on an engine written in C that uses this library and have a rudimentary C API for msdfgen in a fork. If there's interest, I could clean it up and open up a PR.
Hey,
This is just a request for more details of how the font effects (outline, soft shadow, thickness) could be implemented in glsl.
I tried to do the outline as follows:
fragColor = mix(fragColor, outlineColor, float(abs(sigDist) < 0.1));
but it's not antialiased in that case of course
hi, how can I generate msdf/sdf from PNG files?
please comment on this,
I modified the original msdf glsl shader (https://github.com/Chlumsky/msdfgen) [left] to archive font subpixel rendering effect.[right]
the original look like this :
#ifdef GL_OES_standard_derivatives
#extension GL_OES_standard_derivatives : enable
#endif
precision mediump float;
varying vec2 v_texCoord;
uniform sampler2D s_texture; //msdf texture
uniform vec4 bgColor;
uniform vec4 fgColor;
float median(float r, float g, float b) {
return max(min(r, g), min(max(r, g), b));
}
void main() {
vec4 sample = texture2D(s_texture, v_texCoord);
float sigDist = median(sample[0], sample[1], sample[2]) - 0.5;
float opacity = clamp(sigDist/fwidth(sigDist) + 0.5, 0.0, 1.0);
gl_FragColor = mix(bgColor, fgColor, opacity);//original
}
I modified it to this :
#ifdef GL_OES_standard_derivatives
#extension GL_OES_standard_derivatives : enable
#endif
precision mediump float;
varying vec2 v_texCoord;
uniform sampler2D s_texture; //msdf texture
uniform vec4 bgColor;
uniform vec4 fgColor;
float median(float r, float g, float b) {
return max(min(r, g), min(max(r, g), b));
}
void main() {
vec4 sample = texture2D(s_texture, v_texCoord);
float sigDist = median(sample[0], sample[1], sample[2]) - 0.5;
float opacity = clamp(sigDist/fwidth(sigDist) + 0.5, 0.0, 1.0);
//gl_FragColor = mix(bgColor, fgColor, opacity);//original
float ddx= dFdx(sigDist);
if(opacity == 1.0){
//100%
gl_FragColor = mix(bgColor, fgColor, opacity);//original
}else if(opacity< (1.0/3.0)){
if(ddx>0.0){
//uphill
float c_r = bgColor[0];
float c_g = bgColor[1];
float c_b = (mix(bgColor[2],fgColor[2], opacity));
gl_FragColor = mix(bgColor, vec4(c_r,c_g,c_b,1.0), opacity);
}else{//downhill
float c_r = (mix(bgColor[0],fgColor[0], opacity));
float c_g = bgColor[1];
float c_b = bgColor[2];
gl_FragColor = mix(bgColor, vec4(c_r,c_g,c_b,1.0), opacity);
}
}else if(opacity< (2.0/3.0)){
if(ddx>0.0){
//uphill
float c_r = bgColor[0];
float c_g = (mix(bgColor[1],fgColor[1], opacity));
float c_b = (mix(bgColor[2],fgColor[2], 1.0));
gl_FragColor = mix(bgColor, vec4(c_r,c_g,c_b,1.0), opacity);
}else{//downhill
float c_r = (mix(bgColor[0],fgColor[0], 1.0));
float c_g = (mix(bgColor[1],fgColor[1], opacity));
float c_b = bgColor[2];
gl_FragColor = mix(bgColor, vec4(c_r,c_g,c_b,1.0), opacity);
}
}else{
if(ddx>0.0){
//uphill
float c_r = (mix(bgColor[0],fgColor[0], opacity));
float c_g = (mix(bgColor[1],fgColor[1], 1.0));
float c_b = (mix(bgColor[2],fgColor[2], 1.0));
gl_FragColor = mix(bgColor, vec4(c_r,c_g,c_b,1.0), opacity);
}else{ //downhill
float c_r = (mix(bgColor[0],fgColor[0], 1.0));
float c_g = (mix(bgColor[1],fgColor[1], 1.0));
float c_b = (mix(bgColor[2],fgColor[2], opacity));
gl_FragColor = mix(bgColor, vec4(c_r,c_g,c_b,1.0), opacity);
}
}
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.