博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
OpenGL11-绘制汉字最高效方法(使用Freetype)(代码已更新)
阅读量:4659 次
发布时间:2019-06-09

本文共 5695 字,大约阅读时间需要 18 分钟。

 

视频教程请关注 http://edu.csdn.net/lecturer/lecturer_detail?lecturer_id=440

 

 

OpenGL本身并没有绘制文字的功能,他只是一个三维绘图的API集和,很多东西都要

自己动手才可以实现。OpenGL绘制文字,网络上已经有很多成熟的方式方法,我这里给

大家介绍的是我使用的方式,从绘制的效率上来说,速度上从已经达到我个人水平的最大值。

如果你有更好的方式,请联系我。

  首先介绍下网络上的一些绘制方式。

  一、将要绘制的文字按照每一个字生成一个小纹理的方式,然后再用将纹理贴到网格

的表面,绘制出来,例如:“博客园-你好”,则会生成6个小纹理,然后生成网格,将纹理

贴到网格的表面。优点:每一个字的大小颜色都可选择。缺点:文字多了以后,频繁的切换

纹理造成效率低下。OSG中使用了这种方式,效率极差,尤其是在文字更新的情况下。

  二、直接将随绘制的文本字符串生成一个纹理数据(而不是一个文字一个纹理),这样

做效率上比第一种要好很多,缺点就是更新的时候要重新构建一个新的纹理。速度上有很大

损失。两种方式的原理图如下:

  三、将所绘制的文字都放到一个较大的纹理上去,然后再纹理上做索引,当绘制的时候,

去查表。在将纹理贴到网格上绘制出来,这种方式,速度很快,很多游戏引擎都在使用这种

方式,存在的问题绘制的文字多了以后速度会变慢,占用大量的cpu时间,当然对于小的应

用已经足够了,今天我提出的方式也是基于这样方式的,只是我在索引上最了一些改进,改

进之后的算法,将不再进行查表操作,而是直接索引,一定程度上降低了cpu消耗,提搞了

效率。纹理图片如下示意图:

  

图片存的数据上也很重要,结合OpenGL,采用GL_ALPHA的上存储,这样可以大大

降低图片所占用的显存空间,从而提高效率。

下面定义一个文字所存储的信息,如下所示:

class   Character{public:    Character()    {        x0          =   0;        y0          =   0;        x1          =   0;        y1          =   0;    }    /**    *   存储当前字符在纹理上的坐标位置    */    unsigned short   x0;    unsigned short   y0;    unsigned short   x1;    unsigned short   y1;};

 为了快速索引,减少查找的过程,我么要结合字体本上来做一些处理,我们知道一个汉字要占用2个字节

两个字节所能表示的范围是0-65535,就是6万多个汉字,那么我们就声明一个这么大的数组来存储字符的

信息:

代码如下:

Character   g_charMap[1<<16];

当我们要绘制一个文字的时候,可以直接通过下标就可以直接定位到该字对应的信息了,例如我们绘制'中'

就可以直接获取其在图片上的内容了:

Character   getCharacter(wchar_t ch){    return g_charMap[ch]; }

然后这样也存在一个问题,即一张多大的纹理才可以容纳这么多的字符呢?如果是一般的应用,我们可以忽略

这个问题,中国常用的汉字只有3000多个,假设是一个汉字占16*16的空间,那么一个1024*1024的纹理

所能容纳的字符有 1024/16 * 1024/16 = 4096个,足够满足正常的需要,如果你是想做一个通用的,没有

瑕疵的应用,我们就要修改我们的设计方式,我能一切从速度优先的方式考虑,我们在上面的Character类中

增加一个字段描述字符所在的纹理句柄,如下:

class   Character{public:    Character()    {        x0          =   0;        y0          =   0;        x1          =   0;        y1          =   0;        texId       =   0;    }    unsigned short   x0;    unsigned short   y0;    unsigned short   x1;    unsigned short   y1;    //! 索引纹理,即当前字符所在的纹理    unsigned         texId;};

这样,就可以拜托之前的限制,实现大规模的绘制文字了。

说完了方案,我们还有说下实现方式,说道文字绘制,不得不提的就是FreeType字体库了

几乎所有的三维绘制文字的方式,都采用这个库。下面以代码的方式来介绍他,我们这里

只用到其中很少的一部分(FreeType)相关内容这里不做介绍,有兴趣的同学可以自行了解。

第一步:初始化字体库

FT_Init_FreeType( &_library );

第二步:加载字体

FT_New_Face(_library,_fontFace,0,&_face);

第三步:设置字体大小

FT_Set_Char_Size( _face, fontSize << 6, fontSize << 6, 72, 72);

第四步:获取字体的信息

FT_Load_Glyph( face, FT_Get_Char_Index( face, code ), FT_LOAD_DEFAULT );              FT_Glyph glyph;    FT_Get_Glyph( face->glyph, &glyph );    //Convert the glyph to a bitmap.    FT_Glyph_To_Bitmap( &glyph, ft_render_mode_normal, 0, 1 );    FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;    //This reference will make accessing the bitmap easier    FT_Bitmap& bitmap   =   bitmap_glyph->bitmap;

第五步:将bmp数据写到纹理上

glTexSubImage2D(GL_TEXTURE_2D,0,x,y,width,height,GL_ALPHA,GL_UNSIGNED_BYTE,data);

第六步:生成网格,贴上纹理绘制文字

RESULT  IGraphyDeviceImpl::draw2DText(const wchar_t* text,float x,float y,const Rgba4Byte& color,RectF* pOut){        typedef float   TextVertex[5];    TextVertex  vert[2048 * 6];        float       texWidth    =   (float)_fontDefault._textures._width;    float       texHeight   =   (float)_fontDefault._textures._height;    float       xStart      =   x;    float       yStart      =   y;    float       zStart      =   0;    unsigned    index       =   0;    unsigned    nSize       =   wcslen(text);    float       fHeight     =   0;       for (unsigned i = 0 ;i <  nSize; ++ i )    {        Character*  ch  =   _fontDefault.getCharacter(text[i]);               int         h   =   ch->y1 - ch->y0;        int         w   =   ch->x1 - ch->x0;        /**        *   第一个点        */        vert[index + 0][0]  =   xStart;        vert[index + 0][1]  =   yStart;        vert[index + 0][2]  =   zStart;        vert[index + 0][3]  =   ch->x0/texWidth;        vert[index + 0][4]  =   ch->y0/texHeight;        /**        *   第二个点        */        vert[index + 1][0]  =   xStart;        vert[index + 1][1]  =   yStart + h;        vert[index + 1][2]  =   zStart;        vert[index + 1][3]  =   ch->x0/texWidth;        vert[index + 1][4]  =   ch->y1/texHeight;        /**        *   第二个点        */        vert[index + 2][0]  =   xStart + w;        vert[index + 2][1]  =   yStart + h;        vert[index + 2][2]  =   zStart;        vert[index + 2][3]  =   ch->x1/texWidth;        vert[index + 2][4]  =   ch->y1/texHeight;        /**        *   第二个三角形        */        vert[index + 3][0]  =   xStart;        vert[index + 3][1]  =   yStart;        vert[index + 3][2]  =   zStart;        vert[index + 3][3]  =   ch->x0/texWidth;        vert[index + 3][4]  =   ch->y0/texHeight;        /**        *   第二个点        */        vert[index + 4][0]  =   xStart + w;        vert[index + 4][1]  =   yStart + h;        vert[index + 4][2]  =   zStart;        vert[index + 4][3]  =   ch->x1/texWidth;        vert[index + 4][4]  =   ch->y1/texHeight;        /**        *   第二个点        */        vert[index + 5][0]  =   xStart + w;        vert[index + 5][1]  =   yStart;        vert[index + 5][2]  =   zStart;        vert[index + 5][3]  =   ch->x1/texWidth;        vert[index + 5][4]  =   ch->y0/texHeight;        index   +=  6;        xStart  +=  w;    }    glColor4ub(color._r,color._g,color._b,color._a);    /**    *   对字体使用到的纹理和定点坐标进行排序    */    bindTexture2D(_fontDefault._textures._texture);    CELL::Graphy::VertexDeclaration fontDesc[]    =       {        0,  CELL::Graphy::TYPE_VERTEX,   CELL::Graphy::FORMAT_FLOAT,     3,  0, sizeof(TextVertex),        0,  CELL::Graphy::TYPE_TEXCOORD0,CELL::Graphy::FORMAT_FLOAT,     2,  12, sizeof(TextVertex)    };    drawPrimitiveDirect(fontDesc,2,PT_TRIANGLELIST,vert,0,index);

上面简单的介绍了如何使用FreeType与OpenGL绘制文字,笔者能力所致,说解不到之处,有误之处,敬请谅解,指教。

 

转载于:https://www.cnblogs.com/zhanglitong/p/3206497.html

你可能感兴趣的文章
内存分配失败捕捉 set_new_handler
查看>>
2013年再见,我会永远记住这一年!
查看>>
Unity 游戏框架搭建 (十七) 静态扩展GameObject实现链式编程
查看>>
青蛙学Linux—Ansible中playbook的使用
查看>>
ASP.NET MVC3 URL友好化的重型武器[路由]
查看>>
tiny6410在I2c用户态中的程序设计eeprom
查看>>
canvas制作刮刮乐案例
查看>>
软件工程真的是一门什么用都没有的学科么?
查看>>
笔记_JSON
查看>>
JSOI2018简要题解
查看>>
LODOP在页面让客户选择打印机
查看>>
[不断更新中]模板
查看>>
《团队-排课软件-项目总结》
查看>>
Maven之打包时配置文件替换
查看>>
Python 文件 writelines() 方法
查看>>
hdu 1284
查看>>
atoi 函数
查看>>
SQLserver增删改操作
查看>>
在一些老的浏览器上启用 HTML5 的支持
查看>>
java虚拟机5 字节码
查看>>