第十一课:2D文本
来源:互联网 发布:搭建免费网络直播系统 编辑:程序博客网 时间:2024/06/08 14:19
转载自:http://www.opengl-tutorial.org/cn/intermediate-tutorials/tutorial-11-2d-text/
第十一课:2D文本
本课将学习如何在三维场景之上绘制二维文本。本例是一个简单的计时器:
API
我们将实现这些简单的接口(位于common/text2D.h):
1 void initText2D(const char * texturePath);2 void printText2D(const char * text, int x, int y, int size);3 void cleanupText2D();
为了让代码在640*480和1080p分辨率下都能正常工作,x和y的范围分别设为[0-800]和[0-600]。顶点着色器将根据实际屏幕大小做对它做调整。
完整的实现代码请参阅common/text2D.cpp。
纹理
initText2D只是简单地读取一个纹理和一些着色器,并无特别之处。不过这张纹理却不普通,来看看:
该纹理由CBFG生成。 CBFG是一种由字体生成纹理的工具。然后把纹理加载到Paint.NET(红色背景仅为了方便观察,其实是透明的)。
printText2D负责生成一个矩形,并正确计算出该矩形的屏幕位置和纹理坐标(译注:取字符的过程就像从报纸上剪字一样)。
绘制
首先,填充这些缓冲:
1 std::vector vertices;2 std::vector UVs;
然后为文本中的每个字符计算其四边形包围盒的顶点坐标,然后添加(组成这个四边形的)两个三角形:
1 for ( unsigned int i=0 ; i<length ; i++ ){ 2 3 glm::vec2 vertex_up_left = glm::vec2( x+i*size , y+size ); 4 glm::vec2 vertex_up_right = glm::vec2( x+i*size+size, y+size ); 5 glm::vec2 vertex_down_right = glm::vec2( x+i*size+size, y ); 6 glm::vec2 vertex_down_left = glm::vec2( x+i*size , y ); 7 8 vertices.push_back(vertex_up_left ); 9 vertices.push_back(vertex_down_left );10 vertices.push_back(vertex_up_right );11 12 vertices.push_back(vertex_down_right);13 vertices.push_back(vertex_up_right);14 vertices.push_back(vertex_down_left);
最后计算UV坐标。左上角坐标的计算方式如下:
1 char character = text[i];2 float uv_x = (character%16)/16.0f;3 float uv_y = (character/16)/16.0f;
这样做是可行的(只能说基本上行得通,详见下文),因为A的ASCII码为65。 65%16 = 1,因此A位于第1列(列号从0开始)。
65/16 = 4,因此A位于第4行(这是整数除法,所以结果不是想象中的4.0625)
两者都除以16.0使之符合OpenGL的[0.0 - 1.0]纹理坐标范围。
现在只需对顶点重复相同的操作:
1 glm::vec2 uv_up_left = glm::vec2( uv_x , 1.0f - uv_y ); 2 glm::vec2 uv_up_right = glm::vec2( uv_x+1.0f/16.0f, 1.0f - uv_y ); 3 glm::vec2 uv_down_right = glm::vec2( uv_x+1.0f/16.0f, 1.0f - (uv_y + 1.0f/16.0f) ); 4 glm::vec2 uv_down_left = glm::vec2( uv_x , 1.0f - (uv_y + 1.0f/16.0f) ); 5 6 UVs.push_back(uv_up_left ); 7 UVs.push_back(uv_down_left ); 8 UVs.push_back(uv_up_right ); 9 10 UVs.push_back(uv_down_right);11 UVs.push_back(uv_up_right);12 UVs.push_back(uv_down_left);13 }
其余的操作和往常一样:绑定缓冲,填充,选择着色器程序,绑定纹理,开启、绑定、配置顶点属性,开启混合,调用glDrawArrays
。恭喜恭喜,大功告成喽!
有一点非常重要:这些坐标位于[0,800][0,600]范围内。也就是说,这里不需要矩阵。顶点着色器只需简单换算就可以把这些坐标转换到[-1,1][-1,1]范围内(也可以在C++代码中完成这一步)。
1 void main(){ 2 3 // Output position of the vertex, in clip space 4 // map [0..800][0..600] to [-1..1][-1..1] 5 vec2 vertexPosition_homoneneousspace = vertexPosition_screenspace - vec2(400,300); // [0..800][0..600] -> [-400..400][-300..300] 6 vertexPosition_homoneneousspace /= vec2(400,300); 7 gl_Position = vec4(vertexPosition_homoneneousspace,0,1); 8 9 // UV of the vertex. No special space for this one.10 UV = vertexUV;11 }
片段着色器的工作量也很少:
1 void main(){2 color = texture( myTextureSampler, UV );3 }
顺便说一下,这些代码只能处理拉丁字符,请勿将其应用到工程中。否则您的产品在印度、中国、日本(甚至德国,因为纹理上没有ß这个字母)就难以出售了。这张纹理是我用法语字符集生成的,在法国使用没有问题(注意 é, à, ç等字母)。修改其他教程的代码时请注意库的版本。其他教程大多使用OpenGL 2,和本教程不兼容。不幸的是我不知道有什么库能较好地处理UTF-8字符集。
另外,建议您阅读Joel Spolsky写的The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!) by Joel Spolsky.
如果您需要处理大量的文本,可以参考这篇Valve的文章。
- 第十一课:2D文本
- OpenGL3.0教程 第十一课:2D文本
- 第十一章 图像之2D(2)
- 第十一章 图像之2D(1)SpriteBatch
- Quartz 2D 参考-文本
- Quartz 2D 参考-文本
- Quartz 2D 参考-文本
- Quartz 2D 参考-文本
- Quartz 2D 自定义富文本控件
- cocos 2d x 创建文本按钮
- sun在线教材之-java 2d 文本指南-第二课 绘制艺术字
- 第十一课 数组
- 第十一课 jQuery part1
- 第十一课 jQuery part1
- Java第十一课
- C语言第十一课
- 【第十一课】异常---StringEquals
- 【第十一课】异常---toString
- 笔记:textarea cols,rows属性和宽度高度关系
- 你不知道的Linux Kernel——Linux内核的工作原理
- Docker Swarm学习教程
- innobackupex mysql备份及恢复(全量和增量)
- UML中的四种关系
- 第十一课:2D文本
- CSS 那么多属性,而且每个属性都有多个值怎么记?
- app 原形设计常用工具总结
- CSRF漏洞简介
- 开发调试方法总结
- DPI、PPI、DP、PX 的详细计算方法及算法来源是什么?
- 算法导论之堆的应用---优先队列
- 正则匹配公式大全
- 设备描述表之映射模式介绍