1
0
mirror of https://github.com/LearnOpenGL-CN/LearnOpenGL-CN.git synced 2025-08-23 12:45:29 +08:00

校对06-02

This commit is contained in:
gjy_管
2015-08-25 18:32:39 +08:00
parent 7f7bafce08
commit 96dd04823d

View File

@@ -4,33 +4,33 @@
---|---
作者 | JoeyDeVries
翻译 | [Geequlim](http://geequlim.com)
校对 | 未校对
校对 | gjy_1992
当你在图形计算领域冒险到了一定阶段以后你可能会想使用OpenGL来绘制文字。然而可能与你想象的并不一样使用像OpenGL这样的底层库来渲染文字到屏幕上并不是一件简单的事情。如果你你只需要绘制128种字符那么事情可能会简单一些。但是当我们要绘制的字符有着不同的宽、高和边距如果你使用的语言中不止包含128个字符当你要绘制音乐符、数学符号以及考虑把如何处理文本自动转行等等情况考虑进来的时候...你甚至觉得这些工作并不属于像OpenGL这样的底层图形库该讨论的范畴。
当你在图形计算领域冒险到了一定阶段以后你可能会想使用OpenGL来绘制文字。然而可能与你想象的并不一样使用像OpenGL这样的底层库来把文字渲染到屏幕上并不是一件简单的事情。如果你你只需要绘制128种字符那么事情可能会简单一些。但是当我们要绘制的字符有着不同的宽、高和边距如果你使用的语言中不止包含128个字符当你要绘制音乐符、数学符号以及考虑把如何处理文本自动转行等等情况考虑进来的时候...事情马上就会变得复杂得多,你甚至觉得这些工作并不属于像OpenGL这样的底层图形库该讨论的范畴。
由于OpenGL本身并没有定义如何渲染文字到屏幕也没有用于表示文字的基本图形我们必学富有创造力才能让OpenGL来绘制文字。目前已经实现的方式包括:通过**`GL_LINES`**来绘制字、创建文字的3D网格、将带有文字的纹理渲染到一个2D方块中。
由于OpenGL本身并没有定义如何渲染文字到屏幕也没有用于表示文字的基本图形我们必须自己定义一套全新的方式才能让OpenGL来绘制文字。目前一些技术包括:通过**`GL_LINES`**来绘制字、创建文字的3D网格、将带有文字的纹理渲染到一个2D方块中。
开发者最常用的一种方式是将字符纹理绘制到矩形方块上。绘制这些纹理方块其实并不是很复杂,然而检索要绘制到方块的纹理却变成了一项挑战性的工作。本教程将探索多种文字渲染的实现方法,并且着重对更加灵活的渲染技术(使用FreeType库)进行讲解。
开发者最常用的一种方式是将字符纹理绘制到矩形方块上。绘制这些纹理方块其实并不是很复杂,然而检索要绘制的文字的纹理却变成了一项挑战性的工作。本教程将探索多种文字渲染的实现方法,并且着重对更加现代而且灵活的渲染技术(使用FreeType库)进行讲解。
## 经典文字渲染:使用位图字体
在早期渲染文字时,选择你应用程序的字体(或者创建你自己的字体)来绘制所有相关的的文字是通过加载在一张包含所有字符纹理的大纹理图来实现的。这张纹理贴图我们把它叫做位图字体(Bitmap Font),它包含了所有我们想要用来表示文字的字符或其他符号。这些字符和符号被称为**字形(glyph)**。每个字形根据他们的含义被放到位图字体中的确切位置在渲染这些字形的时候根据这些排列规则将他们取出并贴到指定的2D方块中。
在早期渲染文字时,选择你应用程序的字体(或者创建你自己的字体)来绘制文字是通过将所有用到的文字加载在一张大纹理图来实现的。这张纹理贴图我们把它叫做位图字体(Bitmap Font),它包含了所有我们想要使用的字符。这些字符被称为**字形(glyph)**。每个字形根据他们的编号被放到位图字体中的确切位置在渲染这些字形的时候根据这些排列规则将他们取出并贴到指定的2D方块中。
![](http://learnopengl.com/img/in-practice/bitmapfont.png)
上图展示了我们如何从一张位图字体的纹理中通过对字形的合理取样(通过小心地选择字形的纹理坐标)来实现绘制文字“OpenGL”到2D方块中的原理。通过对OpenGL启用混合并让位图字体的纹理背景保持透明这样就能实现使用OpenGL绘制你想要文字到屏幕的功能。上图的这张位图字体是使用[Codehead的位图字体生成器](http://www.codehead.co.uk/cbfg/)生成的。
使用这种途径来绘制文字有许多优势也有很多缺点。首先,他的一个优点是这相对来说容易实现,因为位图字体一般都是预先定义好的。然而,这种途径并不够灵活。当你想要使用不同的字体时你不得不修改并重新编译你加载文字的代码;如果你对这些文字进行放大的话你会看到文字的像素边缘此外这种方式仅局限于用来绘制很少的字符如果你想让它来扩展支持Unicode文字的话就很不现实了。
使用这种途径来绘制文字有许多优势也有很多缺点。首先,相对来说容易实现,并且因为位图字体被预渲染好,使得这种方法效率很高。然而,这种途径并不够灵活。当你想要使用不同的字体时你不得不重新生成位图字体,以及你的程序会被限制在一个固定的分辨率:如果你对这些文字进行放大的话你会看到文字的像素边缘此外这种方式仅局限于用来绘制很少的字符如果你想让它来扩展支持Unicode文字的话就很不现实了。
这种绘制文字的方式曾经得益于它的高速和可移植性而非常流行然而现在已经存在更加灵活的方式了。其中一个是我们即将展开讨论的使用FreeType库来加载TrueType字体的方式。
## 现代文字渲染使用FreeType
FreeType是一个能够用于加载字体并将他们渲染到位图提供多种字体相关的操作的软件开发库。它是一个非常受欢迎的字体库,被用于 Mac OSX、Java、PlayStation主机、Linux、Android等。FreeType的真正吸引力在于它能够加载TrueType字体。
FreeType是一个能够用于加载字体并将他们渲染到位图以及提供多种字体相关的操作的软件开发库。它是一个非常受欢迎的跨平台字体库,被用于 Mac OSX、Java、PlayStation主机、Linux、Android等。FreeType的真正吸引力在于它能够加载TrueType字体。
TrueType字体是一些通过数学公式(包含曲线函数等)来定义的字形的集合。这些字形不是使用像素或其他不可缩放的方式定义的,因此他们更加类似于矢量图像,这些点阵化的字体图形可以生成基于你想获得字体高度的样式。通过使用TrueType字体可以轻易呈现不同大小的字符符号并且没有任何质量损失。
TrueType字体不采用像素或其他不可缩放的方式来定义,而是一些通过数学公式(曲线的组合)。这些字形,类似于矢量图像,可以根据你需要的字体大小来生成像素图像。通过使用TrueType字体可以轻易呈现不同大小的字符符号并且没有任何质量损失。
FreeType可以在他们的[官方网站](http://www.freetype.org/)中下载到。你可以选择自己编译他们提供的源代码或者使用他们已编译好的平台链接库。请确认你将freetype.lib添加到你项目的链接库中同时你还要添加它的头文件目录到项目的搜索目录中。
FreeType可以在他们的[官方网站](http://www.freetype.org/)中下载到。你可以选择自己编译他们提供的源代码或者使用他们已编译好的针对你的平台链接库。请确认你将freetype.lib添加到你项目的链接库中同时你还要添加它的头文件目录到项目的搜索目录中。
然后请确认包含合适的头文件:
@@ -75,7 +75,7 @@ if (FT_Load_Char(face, 'X', FT_LOAD_RENDER))
通过将**`FT_LOAD_RENDER`**设为一个加载标识我们告诉FreeType去创建一个8位的灰度位图我们可以通过`face->glyph->bitmap`来取得这个位图。
使用FreeType加载的字形位图并不像我们使用位图字体那样持有相同的尺寸大小。使用FreeType生产的字形位图的大小是恰好能包含这个字形的尺寸。例如生产用于表示'.'的位图的尺寸要比表示'X'的小。因此FreeType在加载字形的时候还生产了几个度量值来描述生成的字形位图的大小和位置。下图展示了FreeType的所有度量值的涵义。
使用FreeType加载的字形位图并不像我们使用位图字体那样持有相同的尺寸大小。使用FreeType生产的字形位图的大小是恰好能包含这个字形的尺寸。例如生产用于表示'.'的位图的尺寸要比表示'X'的小得多。因此FreeType在加载字形的时候还生产了几个度量值来描述生成的字形位图的大小和位置。下图展示了FreeType的所有度量值的涵义。
![](http://learnopengl.com/img/in-practice/glyph.png)
@@ -104,7 +104,7 @@ struct Character {
std::map<GLchar, Character> Characters;
```
本教程本着让一切简单的目的,我们生成表示128个ASCII字符的字符表。并为每一个字符储存纹理和一些度量值。这样所有需要的字符就被存下来备用了。
本教程本着让一切简单的目的,我们生成表示128个ASCII字符的字符表。并为每一个字符储存纹理和一些度量值。这样所有需要的字符就被存下来备用了。
```c++
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //禁用byte-alignment限制
@@ -232,7 +232,7 @@ glBindVertexArray(0);
### 渲染一行文字
要渲染个字符我们从之前创建的字符表中取出一个字符结构体根据字符的度量值来计算方块的大小。根据方块的大小我们就能计算出6个描述方块的顶点并使用`glBufferSubData`函数将其更新到VBO所在内内存中。
要渲染个字符我们从之前创建的字符表中取出一个字符结构体根据字符的度量值来计算方块的大小。根据方块的大小我们就能计算出6个描述方块的顶点并使用`glBufferSubData`函数将其更新到VBO所在内内存中。
我们创建一个函数用来渲染一行文字:
@@ -282,7 +282,7 @@ void RenderText(Shader &s, std::string text, GLfloat x, GLfloat y, GLfloat scale
}
```
这个函数的内容相对来说是自注释型的我们首先计算出方块的起点坐标和它的大小并为该方块生成一个6个顶点注意我们在缩放的同时会将部分度量值也进行缩放。接我们更新方块的VBO、绑定字形纹理来渲染它。
这个函数的内容注释的比较详细了我们首先计算出方块的起点坐标和它的大小并为该方块生成一个6个顶点注意我们在缩放的同时会将部分度量值也进行缩放。接我们更新方块的VBO、绑定字形纹理来渲染它。
其中这行代码需要加倍留意:
@@ -318,6 +318,6 @@ RenderText(shader, "(C) LearnOpenGL.com", 540.0f, 570.0f, 0.5f, glm::vec3(0.3, 0
## 关于未来
本教程演示了如何使用FreeType绘制TrueType文字。这种方式灵活、可缩放并支持多种字符编码。然而对你来说可能是应用程序和表现方面点阵字体可能是更可取的。当然你可以结合这两种方法通过动态生成位图字体中所有字符字形。这节省了从大量的纹理渲染器开关和基于每个字形紧密包装可以节省相当的一些性能。
本教程演示了如何使用FreeType绘制TrueType文字。这种方式灵活、可缩放并支持多种字符编码。然而你的应用程序可能并不需要这么强大的功能,性能更好的点阵字体也许是更可取的。当然你可以结合这两种方法通过动态生成位图字体中所有字符字形。这节省了从大量的纹理渲染器开关和基于每个字形紧密包装可以节省相当的一些性能。
另一个使用FreeType字体的问题是字形纹理是通过字体大小修正的,因此直接对其放大就会出现锯齿边缘。此外,应用旋转到执行上还会使它们看上去变得模糊。通过储存点阵化的像素颜色,储存字形最近的描边的像素可以减轻这些问题。这项技术被称为**signed distance fields**Valve在几年前发表过一篇了[论文](http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf),探讨了他们通过这项技术来得惊人的3D渲染的好效果。
另一个使用FreeType字体的问题是字形纹理是对应着一个固定的字体大小的,因此直接对其放大就会出现锯齿边缘。此外,对字形进行旋转还会使它们看上去变得模糊。可以通过将每个像素设为最近的字形轮廓的像素,而不是直接设为实际栅格化的像素可以减轻这些问题。这项技术被称为**signed distance fields**Valve在几年前发表过一篇了[论文](http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf),探讨了他们通过这项技术来获得好得惊人的3D渲染效果。