如何在 freetype 中使用 FT_RENDER_MODE_SDF?

How to use FT_RENDER_MODE_SDF in freetype?

我对字体渲染很陌生,我正在尝试使用 freetype 生成带符号的距离场,以便它可以在 OpenGL 的片段着色器中使用。这是我试过的代码:

           error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
           if (error)
           {
              // Handle error
           }
 
           
           error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_SDF);
           if (error)
           {
              // Handle error
           }

也许我完全误解了 SDF 的概念,但我的想法是我可以给 freetype 一个 ttf 文件,并且 FT_RENDER_MODE_SDF 它应该产生一个带符号距离的缓冲区。但是 FT_Render_Glyph returns 一个错误 (19) 恰好是“无法呈现此字形格式”。

SDF 支持已于 2020 年底添加,并在 2021 年下半年添加了一个新模块,因此请确保您拥有比该版本更新的版本。例如,2.6 早于 2.12.0(撰写本文时最新版本)。

说完这些,让我们开始吧。

我假设您已经完成了 LearnOpenGL 的字体渲染教程,并且您可以在屏幕上成功渲染文本。你应该有这样的东西 (注意新增内容):

glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // Disable byte-alignment restriction

FT_GlyphSlot slot = face->glyph; // <-- This is new

for (unsigned char c = 0; c < 128; c++)
{
    // Load character glyph 
    if (FT_Load_Char(face, c, FT_LOAD_RENDER))
    {
        // error message
        continue;
    }

    FT_Render_Glyph(slot, FT_RENDER_MODE_SDF); // <-- And this is new

    // Generate texture
    GLuint texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexImage2D( ... );
    ...
}

渲染文本时,必须告诉OpenGL不要将四边形的片段写入深度缓冲区,否则相邻的字形会重叠并开始闪烁:

glDepthMask(GL_FALSE); // Don't write into the depth buffer
RenderText(pTextShader, text, 25.0f, 25.0f, 1.0f, glm::vec3(0.5, 0.8f, 0.2f));
glDepthMask(GL_TRUE); // Re-enable writing to the depth buffer

如果您想将文本作为对象放置在场景中,在 world-space 中,那么在顶点着色器中您可以使用:

gl_Position = uVp * uModel * vec4(vertex.xy, 0.0, 1.0); // uVp is "projection * view" on the CPU side

但是,这有点超出您的问题范围。通过将相机环绕在文本周围,它只是让从各个角度检查文本变得更加容易。确保在绘制字形之前 运行 glDisable(GL_CULL_FACE) 禁用背面剔除,因此它们从两侧都可见。

关于片段着色器我建议你看一下this video

最低限度为:

void main()
{    
    float glyphShape = texture(uGlyphTexture, TexCoords).r;

    if (glyphShape < 0.5)
        discard;

    oFragColor = vec4(uTextColor, 1.0);
}

结果:

我认为它们之间有非常明显的区别,你不觉得吗?

玩得开心!