我对字体渲染很陌生,我正在尝试使用 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
}
Run Code Online (Sandbox Code Playgroud)
也许我完全误解了 SDF 的想法,但我的想法是我可以给 freetype 一个 ttf 文件,并使用 FT_RENDER_MODE_SDF 它应该生成一个带有符号距离的缓冲区。但 FT_Render_Glyph 返回错误 (19),恰好是“无法渲染此字形格式”。
小智 8
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( ... );
...
}
Run Code Online (Sandbox Code Playgroud)
渲染文本时,你必须告诉 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
Run Code Online (Sandbox Code Playgroud)
如果您想将文本作为对象放置在场景中的世界空间中,那么在顶点着色器中您可以使用:
gl_Position = uVp * uModel * vec4(vertex.xy, 0.0, 1.0); // uVp is "projection * view" on the CPU side
Run Code Online (Sandbox Code Playgroud)
但是,这有点超出了您的问题范围。通过将相机围绕文本旋转,可以更轻松地从各个角度检查文本。确保glDisable(GL_CULL_FACE)在绘制字形之前运行,以禁用背面剔除,以便它们从两侧都可见。
至于片段着色器我建议你看这个视频。
最低限度是:
void main()
{
float glyphShape = texture(uGlyphTexture, TexCoords).r;
if (glyphShape < 0.5)
discard;
oFragColor = vec4(uTextColor, 1.0);
}
Run Code Online (Sandbox Code Playgroud)
结果:
我认为他们之间有很大的区别,你不觉得吗?
玩得开心!