freetype中文字符渲染
效果图:

代码只是对freetype api的简单使用,只是用来验证参考的:
#include <QString>
#include <iostream>
#include <map>
#include <string>
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <freetype/ftglyph.h> .
#include "Shader.h"
const GLuint WIDTH = 800, HEIGHT = 600;
struct Character {
GLuint TextureID;
glm::ivec2 Size;
glm::ivec2 Bearing;
GLuint Advance;
};
std::map<GLshort, Character> Characters;
GLuint VAO, VBO;
void RenderText(Shader &shader, const QString& text, GLfloat x, GLfloat y, GLfloat scale, glm::vec3 color);
int main(int argc, char *argv[])
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);
glfwMakeContextCurrent(window);
glewExperimental = GL_TRUE;
glewInit();
glViewport(0, 0, WIDTH, HEIGHT);
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Shader shader("shaders/text.vs", "shaders/text.frag");
glm::mat4 projection = glm::ortho(0.0f, static_cast<GLfloat>(WIDTH), 0.0f, static_cast<GLfloat>(HEIGHT));
shader.Use();
glUniformMatrix4fv(glGetUniformLocation(shader.getProgram(), "projection"), 1, GL_FALSE, glm::value_ptr(projection));
FT_Library ft;
if (FT_Init_FreeType(&ft))
std::cout << "ERROR::FREETYPE: Could not init FreeType Library" << std::endl;
FT_Face face;
if (FT_New_Face(ft, "fonts/FZSTK.TTF", 0, &face))
std::cout << "ERROR::FREETYPE: Failed to load font" << std::endl;
if (FT_Select_Charmap(face, ft_encoding_unicode))
std::cout << "ERROR::FT_Select_Charmap" << std::endl;
FT_Set_Pixel_Sizes(face, 0, 48);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
int charUnicode = 0x6211;
int index = FT_Get_Char_Index(face,charUnicode);
FT_Load_Glyph(face,index, FT_LOAD_RENDER);
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RED,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_RED,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Character character = {
texture,
glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top),
face->glyph->advance.x
};
Characters.insert(std::pair<GLshort, Character>(charUnicode, character));
charUnicode = 21644;
index = FT_Get_Char_Index(face,charUnicode);
FT_Load_Glyph(face,index, FT_LOAD_RENDER);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RED,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_RED,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Character character1 = {
texture,
glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top),
face->glyph->advance.x
};
Characters.insert(std::pair<GLshort, Character>(charUnicode, character1));
for (GLubyte c = 0; c < 128; c++)
{
if (FT_Load_Char(face, c, FT_LOAD_RENDER))
{
std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl;
continue;
}
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RED,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_RED,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Character character = {
texture,
glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top),
face->glyph->advance.x
};
Characters.insert(std::pair<GLshort, Character>(c, character));
}
glBindTexture(GL_TEXTURE_2D, 0);
FT_Done_Face(face);
FT_Done_FreeType(ft);
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
while (!glfwWindowShouldClose(window))
{
glfwPollEvents();
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
RenderText(shader, "我This 和eeis sample text", 25.0f, 25.0f, 1.0f, glm::vec3(0.5, 0.8f, 0.2f));
RenderText(shader, "(C) LearnOpenGL.com", 540.0f, 570.0f, 0.5f, glm::vec3(0.3, 0.7f, 0.9f));
glfwSwapBuffers(window);
}
glfwTerminate();
return 0;
}
void RenderText(Shader &shader, const QString& text, GLfloat x, GLfloat y, GLfloat scale, glm::vec3 color)
{
shader.Use();
glUniform3f(glGetUniformLocation(shader.getProgram(), "textColor"), color.x, color.y, color.z);
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(VAO);
int nCount = text.count();
for(int i = 0 ; i < nCount ; i++)
{
QChar cha = text.at(i);
ushort uni = cha.unicode();
Character ch;
if(uni >= 0x4E00 && uni <= 0x9FA5)
{
if(Characters.find(uni)!=Characters.end())
{
}else{
std::cout<<"unicode:"<<uni<<std::endl;
continue;
}
}
ch = Characters[uni];
GLfloat xpos = x + ch.Bearing.x * scale;
GLfloat ypos = y - (ch.Size.y - ch.Bearing.y) * scale;
GLfloat w = ch.Size.x * scale;
GLfloat h = ch.Size.y * scale;
GLfloat vertices[6][4] = {
{ xpos, ypos + h, 0.0, 0.0 },
{ xpos, ypos, 0.0, 1.0 },
{ xpos + w, ypos, 1.0, 1.0 },
{ xpos, ypos + h, 0.0, 0.0 },
{ xpos + w, ypos, 1.0, 1.0 },
{ xpos + w, ypos + h, 1.0, 0.0 }
};
glBindTexture(GL_TEXTURE_2D, ch.TextureID);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 6);
x += (ch.Advance >> 6) * scale;
}
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}参考:文字渲染
参考:Text Rendering
参考:GLSL Font
参考:FreeType-2.9.1 API参考
参考:I. Simple Glyph Loading
参考:eetype不能显示字母、数字、标点符号,可以显示汉字是怎么回事?
参考:OpenGL显示文字--显示汉字
参考:OpenGL渲染绘制中文字符
参考:opengl绘制汉字
参考:OpenGL显示字体
参考:OpenGL点阵字体绘制终极解决方案!哈!
参考:OpenGL 图形库的使用(四十六)—— 实战之文本渲染Text Rendering
参考:OpenGL 绘制简单的英文字符
参考:glProject
参考:透過 FreeType 繪製 Unicode ASCII Art
参考:利用freetype显示unicode字符
参考:freetype_test.cpp
参考:游戏如何处理渲染亚洲unicode文本?
参考:freetype-gl
参考:利用freetype显示unicode字符
参考:第二人生的源码分析(五十八)使用FreeType字体
参考:fatal_font.cpp
参考:OpenGL显示unicode编码的三维汉字的方法
参考:Qt中获取字符串中的汉字
参考:将freetype位图复制到opengl纹理的问题
参考:Glyph Hell
参考:Problem with GLEW on Windows when building a static library within another project
参考:【OpenGL】使用FreeType库加载字体并在GL中绘制文字
参考:freetype库实现文字显示
参考:利用freetype显示中文字符
参考:使用freetype来显示中文汉字和英文字符
第二阶段:
汉字那么多,康熙字典有3万印象中是这个数量级,常用汉字3000多,还有繁体简体的,怎么高效的渲染呢?
将所绘制的文字都放到一个较大的纹理上去,然后再纹理上做索引,当绘制的时候,去查表。在将纹理贴到网格上绘制出来.
表中可以先包含3000个常用字,然后没出现的动态注册添加到大纹理中去
参考:[置顶]OpenGL11-绘制汉字最高效方法(使用Freetype)(代码已更新)
参考:OpenGL11-绘制汉字最高效方法(使用Freetype)(代码已更新)
参考:[置顶]OpenGL11-绘制汉字最高效方法(使用Freetype)(代码已更新)
参考:python+freetype+opencv 图片中文(汉字)显示 详细图文教程和项目完整源代码
参考:FreeType使用的总结
参考:让irrlicht支持中文输入和输出
参考:让OGRE支持中文(二)
参考:Step 2 — managing glyphs
参考:freetype2 中文显示
参考:在OpenGL繪製中文字
参考:第二部分 管理字形
参考:freetype显示带有空格时,下一行的内容就不能显示了
参考:修改cocos2dx-3.0有些字体描边偏移的问题
参考:FT_LOAD_FLAGS
后记:
打算让rtcw/quake系列的游戏也支持中文渲染,从上面的文章已经有了思路,可是还是想不好到底怎么修改,游戏渲染部分的代码还是要细细看明白才能找到正确的切入点;
网上看到ET支持unicode渲染,测试了一下

ET中的思路和原来ascii的渲染逻辑所以整体结构改变不是很大,但毕竟达到了效果 可以参考
- 点赞
- 收藏
- 关注作者
评论(0)