freetype中文字符渲染

举报
Amrf 发表于 2018/12/22 00:48:35 2018/12/22
【摘要】 效果图:代码只是对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...

效果图:

image.png

代码只是对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渲染,测试了一下

image.png

ET中的思路和原来ascii的渲染逻辑所以整体结构改变不是很大,但毕竟达到了效果 可以参考

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。