I have a game. and I want to make a text. so I decided to use the SDF approach. but when I scale the text, the text is rounded at the corners. After research, I found the msdf (https://github.com/Chlumsky/msdfgen). This is the way I'm trying to display text.
I am generating a 96x96 png image for the letters "g", " V " and "A".
This was the command I ended up using:
./msdfgen msdf -font Arial.ttf 'g' -size 96 96 -pxrange 12 -scale 2 -o a.png -translate 3 20
I got the images and store the images in an array of 2D textures
Then I do the Kerning. I used FreeType to provide the kerning (8px size).
I then rendered each character with a sprite/plane and set it’s width and height to the character size provided to FreeType in the kerning section above.
My shaders
vertex
#version 430 core
layout(location = 0) in vec2 position;
layout(location = 1) in vec2 texCoord;
layout(location = 2) in float layer;
out vec2 uv;
out float layer_get;
void main()
{
gl_Position = vec4(position, 0.0, 1.0);
uv = texCoord;
layer_get = layer;
}
fragment
#version 430 core
out vec4 color_output;
in vec2 uv;
layout (binding=0) uniform sampler2DArray textureArray;
in float layer_get;
float median(float r, float g, float b) {
return max(min(r, g), min(max(r, g), b));
}
void main()
{
vec3 flipped_texCoords = vec3(uv.x, 1.0 - uv.y, layer_get);
vec2 pos = flipped_texCoords.xy;
vec3 distance = texture(textureArray, flipped_texCoords).rgb;
ivec2 sz = textureSize(textureArray, 0).xy;
float dx = dFdx(pos.x) * sz.x;
float dy = dFdy(pos.y) * sz.y;
float sigDist = median(distance.r, distance.g, distance.b);
float w = fwidth(sigDist);
float opacity = smoothstep(0.5 - w, 0.5 + w, sigDist);
color_output = vec4(0.0,0.0,0.0, opacity);
}
example in this thread.
My result
It looks absolutely not natural.
To give you a feel of how I calculated the squares, I disable blending to see what the actual rendered squares look like:
Kerning (I think I'm doing something wrong in that phrase).
fn kerning(text: &Vec<&str>, face: FontFace) -> Vec<f32> {
let mut vec: Vec<f32> = Vec::new();
let mut x = 0.0;
let scale_factor = 26.0 / 8.0; // Initially calculated as 8px, then I try to scale to 26px
for (i, l) in text.iter().enumerate() {
let res = face.chars.get(&l.to_string()).unwrap();
let xpos = x + res.bearX as f32 * scale_factor;
/*
I know that the OpenGL coordinate system is different from the coordinate system I'm used to.this function just makes a square starting from the top left corner
*/
vec.append(&mut make_square_px(
res.width as f32 * scale_factor,
res.height as f32 * scale_factor,
x, // X
0.0, // Y i am not calculating the baseline
300.0, // Screen width
300.0, // Screen height
i as f32, // layer
));
// Now advance cursors for next glyph
x += ((res.advance as f32 / 64.0) * scale_factor);
}
vec
}
My knowledge of OpenGL is small . so I hope someone will help me solve this problem.