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)