OpenGL进行文字显示的方法.docx
- 文档编号:12267866
- 上传时间:2023-04-17
- 格式:DOCX
- 页数:20
- 大小:44.77KB
OpenGL进行文字显示的方法.docx
《OpenGL进行文字显示的方法.docx》由会员分享,可在线阅读,更多相关《OpenGL进行文字显示的方法.docx(20页珍藏版)》请在冰豆网上搜索。
OpenGL进行文字显示的方法
任何一个DEMO、仿真项目、游戏,都少不了文字这种媒体。
这不可不说是对图形视觉媒体的补充——我们还有一些无法超越文字来向观众表达的心事,或是补充说明,或是感悟,或是感激。
—— ZwqXin.
一般的文字不属于图形渲染部分,而属于用户界面部分,这在游戏引擎中看或许一目了然,但是在底层的图形渲染API——OPENGL或D3D中,文字的显示“并不是必须”,但它是多么深深地被需要着口牙。
所以,把字体设置、文字显示作为一种图形学技术而非单纯的完全我属或他属,我是这么想的。
(同样,拾取也算是这样吧?
[乱弹OpenGL选择-拾取机制Ⅰ])
本文来源于 ZwqXin (.zwqxin./),请注明
原文地址:
.zwqxin./archives/opengl/opengl-font-setting-showing.html
怎么表达文字呢?
在OpenGL中,我们没有什么现成的东西可用,但确实有办法让我们“得到这种技术”。
让我最记忆深刻的是NEHE的两三篇教程(貌似都是十几课吧),讲述的就是今天的这个主题。
可以到NEHE或者在DANCINGWIND的中文翻译(见[搜集的优良OpenGL教程])看看~。
而我所知道的这三种方法,前两种应该就是来自那里吧(记得~~),当时要努力完成课程DEMO,于是胡胡混混地就把相应的那两三课学了,而且把它的文字显示方法应用到自己的程序中(还经历了一段艰辛的探索史...连我当时的MyFont类也记录了这份小辛酸,现在看来,是因为当时的知识水平不够理解吧)。
然后后来又一个课程DEMO,老师后来觉得我应该“写中文”,于是我又去探索中文字体显示方法了,并在一个开源DEMO中找到,分析代码段后就拿来主义了,至昨不曾好好考究——这就是我所知的第三种方法。
三种方法都是三步曲:
在初始化的时候“创建字体”[Build],在渲染阶段“应用字体”(显示文字)[Print],在程序结束或不再需要文字显示的时候“销毁字体”[kill]。
其中前两步比较重要,着重讨论讨论哈~
1.常规的屏幕字体打印(NormalFont)
应用得比较广,大名鼎鼎的AZURE以前的DEMO就是用这个的。
NEHE教程中作为首次出现的字体显示方法,介绍应该比较全面,大家想仔细了解的话请务必从上面网址进入学习(当然还有因为我理解不透不敢乱讲的缘由)。
1. /////////一般的英语字体打印
2.void MyFont:
:
BuildGLFont(int fontHeight)
3.{
4. HDC hDC =:
:
GetDC(HWND_DESKTOP); //////就是这里搞晕了半晚
5.
6. int tFontHeight = -1 * fontHeight;
7.
8. NormalFontBase = glGenLists(96); // Storage For 96 Characters
9. HFONT font = CreateFont( -tFontHeight, // Height Of Font
10. 0, // Width Of Font
11. 0, // Angle Of Escapement
12. 0, // Orientation Angle
13. FW_BOLD, // Font Weight
14. TRUE, // Italic
15. FALSE, // Underline
16. FALSE, // Strikeout
17. ANSI_CHARSET, // Character Set Identifier
18. OUT_TT_PRECIS, // Output Precision
19. CLIP_DEFAULT_PRECIS, // Clipping Precision
20. ANTIALIASED_QUALITY, // Output Quality
21. FF_DONTCARE|DEFAULT_PITCH, // Family And Pitch
22. "Georgia"); // Font Name
23.
24. HFONT oldfont = (HFONT)SelectObject(hDC, font); // Selects The Font We Want
25.
26. wglUseFontBitmaps(hDC, 32, 96, NormalFontBase); // Builds 96 Characters Starting At Character 32
27.
28. SelectObject(hDC, oldfont); // Selects The Font We Want to return to
29. DeleteObject(font); // Delete The Font
30.
31. SetBkMode(hDC,TRANSPARENT);
32.
33. NormalFont = true;
34.}
其中bUild的时候首先用到的是GDI的CreateFont函数创建字体——这应该是比较常用的方法,设置了关于字体的一切并选入字体后,有一步重要的操作:
wglUseFontBitmaps。
1.
2.wglUseFontBitmap
3.为当前选中的GDI字体创建一组OpenGL显示列表位图字体
4.BOOL wglUseFontBitmap(HDC hDC, DWORD dwFirst, DWORD dwCount, DWORD dwListBase);
5.
6.参数
7.hDC
8.设备环境句柄
9.
10.dwFirst
11.用于创建显示列表字体的第一个字符的ASCII值
12.
13.dwCount
14.字符数
15.
16.dwListBase
17.第一个显示列表的名称
18.
19.返回值
20.成功返回TRUE,否则返回FALSE
21.
输入为DC,32,96以及创建的96个新显示列表的base列表。
函数绘制从ASCII码为32-128的字符进入显示列表,依赖OPENGL显示列表的高速显示能力(直接从硬件拿存储区),可以方便进行字符的切换。
在Print过程中,调用glCallLists就能调动起这些列表了,但是怎么决定具体要“调动”哪些字母呢(96个之中)?
1.void MyFont:
:
PrintGLText(GLint x, GLint y, const char *string, ...)
2. char text[256];
3. va_list pArguments;
4.
5. if (string == NULL)
6. return;
7.
8. va_start(pArguments, string);
9. vsprintf(text, string, pArguments);
10. va_end(pArguments);
11.
12.
13. glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT | GL_ENABLE_BIT | GL_LIGHTING_BIT);
14. glDisable(GL_DEPTH_TEST);
15. glDisable(GL_LIGHTING);
16. glDisable(GL_TEXTURE_2D);
17. glColor4f(mColor[0], mColor[1], mColor[2], mColor[3]);
18.
19. glWindowPos2i(x, y);
20.
21. glListBase(NormalFontBase - 32);
22. glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
23. glPopAttrib();
24.}
首先看函数形式——printf形式,若想有个详细了解,可到这里看看。
简单来说,就是C时代的可变参数列。
va_start-vsprintf-(va_arg)-va_end这套机制就是为了把可变参数列的容,通过va_list (char*指针)一个一个从栈中取出来赋予他者——我们的glCallLists所要接受的所有“具体字符”,通过base为基础的索引快速寻觅而取得对应ASCII字符的字体信息(实际是位图字体),并依照期望使其形成为“具体字符串”印入屏幕。
另外着重介绍的是我所添加的两个优化——它们贯穿三种文字显示方法之中。
其一是glPushAttrib,它与glPopAttrib配合,保证了其之间的OPENGL状态设置的独立性,使其不影响该代码逻辑的前后的具体渲染状态。
当然参数取GL_ALL_ATTRIB_BITS是保险点,但只要你弄清楚自己的需要,像上面这样给予特定的状态作为参数效率会更高。
恩,颜色,光照,深度测试,混合……选择与当前方法最匹配的状态而没有对状态机的后顾之忧,如同文字本身一样——作为对象完全独立于图形渲染“模块”。
另一是glWindowPos2i(x, y),按《OpenGL编程指南》第8章所说,它取代我们以前用的glRasterPos2i,不再让作为描绘对象的物体承受模型-视图-投影变换之苦[乱弹OpenGL中的矩阵变换(上)],而是直接独立到OPENGL世界的出口——屏幕坐标系,如GDI般用窗口坐标(根据屏幕像素数)来描述文字的起点位置。
这同样是赋予文字的独立性,而且意义重大——可知道,当时我用glRasterPos2i多么狼狈,好难才让文字不在场景“里面”乱窜。
在具体应用中,在初始化调用BuildGLFont.,在渲染阶段调用PrintGLText。
譬如:
1.//CMAINFRAME
2.MyFont mFont;
3.
4.//初始化:
5.mFont.BuildGLFont(25);//25是字体字高,控制字体大小
6.
7.//渲染阶段(RenderGLScene)
8.
9.mFont.PrintGLText(530, 710, ".Zwqxin. - My 3D Graphics");
10.
11.//将在坐标X = 530, Y =710位置开始绘制文字。
对1024*768大小的渲染窗口中,即在右上角
注意,OpenGL窗口坐标系的原点在窗口的左下角,横坐标为X,竖坐标为Y,最大值在右上角。
(同见[乱弹OpenGL选择-拾取机制Ⅱ])
浏览一下效果,第一行就是了,因为我默认用的是Georgia字体(应该一般人电脑都有),所以很漂亮
接下来会谈及其余两种方法,并比较之。
真正的纹理文字是怎样弄的呢?
怎样让中文字体乖乖显示?
什么时候用哪种方法?
我集成的MyFont类是怎样个怪样?
听下回分解:
在OpenGL上设置字体和显示文字(下)
本文来源于 ZwqXin (.zwqxin./),请注明
原文地址:
.zwqxin./archives/opengl/opengl-font-setting-showing.html
Tags:
OpenGL 代码 工具类 C
分类:
OpenGL技术 |评论:
1|引用:
0|浏览:
7399
«水效果Ⅰ-水池在OpenGL上设置字体和显示文字(下)»
分享到新浪微博QQ空间腾讯微博人人网豆瓣0
∙点击这里获取该日志的TrackBack引用地址
∙相关文章:
∙乱弹OpenGL选择-拾取机制(下) (2009-6-1423:
3:
8)
乱弹OpenGL选择-拾取机制(上) (2009-6-1316:
54:
2)
子类调用父类的纯虚函数之问题 (2009-6-823:
18:
32)
视锥类CFrustum.zwqxinver (2009-6-222:
39:
52)
标准MFC在OpenGL (2009-5-3117:
46:
47)
QuickSort快速排序的实现 (2009-5-61:
21:
55)
全屏反锯齿-多重采样Ⅱ (2009-5-319:
50:
7)
全屏反锯齿-多重采样Ⅰ (2009-5-216:
21:
56)
图像处理里的空间域滤波 (2009-4-2723:
53:
18)
一年前,首次献给OpenGL之夜.雷达追踪 (2009-4-522:
18:
52)
在OpenGL上设置字体和显示文字(下)
2009-8-610:
22:
27|发布:
zwqxin
本篇紧随上篇,继续说一下鄙人所了解的在OpenGL进行文字显示的方法,也方便不知从哪个次元来到这里的学习者提供一点这方面的信息。
上一篇见:
[在OpenGL上设置字体和显示文字(上)]——ZwqXin.
本文来源于 ZwqXin (.zwqxin./),请注明
原文地址:
.zwqxin./archives/opengl/opengl-font-setting-showing-2.html
2.纹理字体
最近接触Irrlicht引擎,里面的GUI模块涉及的字体设置就是用了这种纹理字体的方法。
事实上,上篇的方法最后多少了涉及到了位图字体,但是这里所说的,是直接从一“写着各个英文字符和其他常用字符”的纹理上,按对此纹理上的图案“结构”的先验知识而获取字符对应的“纹理部分”,显示到屏幕上。
换句话来说,这就是真正的纹理贴图了,因此必须结合一特定设计的“字体纹理”。
要显示一个字符,需要你绘制一个一定大小的矩形(这个长度值相当于之前的字体高度——它控制最后出来的文字的大小),然后找到你所需字符在该纹理上的纹理坐标,作为索引检索出纹理上的对应字符部分的小纹理,贴到该矩形上。
1.
2.//////////从字体集纹理中取出的字符
3.void MyFont:
:
BuildTextureFont(GLuint fonttex, int fontHeight, int screenWidth, int screenHeight)
4.{
5. TextureFontFont = fonttex;
6.
7. float cx; // Holds Our X Character Coord
8. float cy; // Holds Our Y Character Coord
9.
10. glEnable(GL_TEXTURE_2D);
11.
12. TextureFontBase = glGenLists(256); // Creating 256 Display Lists
13.
14. glBindTexture(GL_TEXTURE_2D, TextureFontFont); // Select Our Font Texture
15.
16. for(int loop=0; loop<256; loop++) // Loop Through All 256 Lists
17. {
18. cx=float(loop%16)/16.0f; // X Position Of Current Character
19. cy=float(loop/16)/16.0f; // Y Position Of Current Character
20.
21. glNewList(TextureFontBase + loop, GL_COMPILE); // Start Building A List
22. glBegin(GL_QUADS); // Use A Quad For Each Character
23. glTexCoord2f(cx,1-cy-0.0625f); // Texture Coord (Bottom Left)
24. glVertex2i(0,0); // Vertex Coord (Bottom Left)
25. glTexCoord2f(cx+0.0625f,1-cy-0.0625f); // Texture Coord (Bottom Right)
26. glVertex2i(fontHeight, 0); // Vertex Coord (Bottom Right)
27. glTexCoord2f(cx+0.0625f,1-cy); // Texture Coord (Top Right)
28. glVertex2i(fontHeight,fontHeight); // Vertex Coord (Top Right)
29. glTexCoord2f(cx,1-cy); // Texture Coord (Top Left)
30. glVertex2i(0, fontHeight); // Vertex Coord (Top Left)
31. glEnd(); // Done Building Our Quad (Character)
32. glTranslated(fontHeight,0,0); // Move To The Right Of The Character
33. glEndList(); // Done Building The Display List
34. } // Loop Until All 256 Are Built
35.
36. glDisable(GL_TEXTURE_2D);
37.
38. ScreenWidth = screenWidth;
39. ScreenHeight = screenHeight;
40.
41. TextureFont = true;
42.}
这在BUILD阶段就做的必要是没有的,但是一次过导入纹理中256个字符,生成256个小纹理,并在每帧都选择对应的纹理索引检索纹理,且每个字符如此——这样的重复不变而低效的事情,还是由OpenGL的显示列表技术来做比较好——一次过在初始化时做好,放入显示列表。
在PRINT阶段只要调用显示列表就好。
关于显示列表,eastcowboy在他的OPENGL入门学习中详细提及过,有兴趣的朋友可看看他的文章:
OpenGL入门学习——第八课-使用显示列表 。
比起最时兴的VBO,显示列表在重复劳动上还是有一定优势的额~
最后的结果是按glTranslated进行排列的256个具有纹理字符的矩形。
为什么要得到渲染窗口的大小呢?
因为这些矩形要保证在屏幕最前方,就应该让它突破矩阵变换啊。
在上篇[在OpenGL上设置字体和显示文字(上)]也提过glWindowPos2i(x,y),但这里对实际的矩形它不是很适用。
因此我还是选择原来的路子,来给予文字以独立于图形的属性——在屏幕最前而位置只由屏幕坐标XY决定。
方法就是,或许很多人也熟悉的,glOrtho正交投影变换。
因此,屏幕大小(这里指渲染窗口的大小)是需要的。
1.
2.void MyFont:
:
PrintTextureText(GLint x, GLint y, char *string, int TextureSet)
3.{
4. if (TextureSet > 1)TextureSet = 1;
5. if (TextureSet < 0)TextureSet = 0;
6.
7. glPushAttrib(GL_CURRENT_BIT | GL_LIGHTING_BIT | GL_ENABLE_BIT| GL_LIST_BIT);
8. glDisable(GL_LIGHTING);
9.
10. glEnable(GL_TEXTURE_2D);
11. glBindText
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- OpenGL 进行 文字 显示 方法