一、简介
由于OpenGL本身并没有定义如何渲染文字到屏幕,也没有用于表示文字的基本图形,我们必须自己定义一套全新的方式才能让OpenGL来绘制文字。目前一些技术包括:通过GL_LINES来绘制字形、创建文字的3D网格、将带有文字的纹理渲染到一个2D方块中。

二、文字渲染
在早期渲染文字时,选择你应用程序的字体(或者创建你自己的字体)来绘制文字是通过将所有用到的文字加载在一张大纹理图中来实现的。这张纹理贴图我们把它叫做位图字体(Bitmap Font),它包含了所有我们想要使用的字符。这些字符被称为字形(Glyph)。每个字形根据他们的编号被放到位图字体中的确切位置,在渲染这些字形的时候根据这些排列规则将他们取出并贴到指定的2D方块中。

现代文字渲染:FreeType
FreeType是一个能够用于加载字体并将他们渲染到位图以及提供多种字体相关的操作的软件开发库。它是一个非常受欢迎的跨平台字体库,被用于 Mac OSX、Java、PlayStation主机、Linux、Android等。FreeType的真正吸引力在于它能够加载TrueType字体。
TrueType字体不采用像素或其他不可缩放的方式来定义,而是一些通过数学公式(曲线的组合)。这些字形,类似于矢量图像,可以根据你需要的字体大小来生成像素图像。通过使用TrueType字体可以轻易呈现不同大小的字符符号并且没有任何质量损失。
#include <ft2build.h>
#include FT_FREETYPE_H
FreeType要做的事就是加载TrueType字体并为每一个字形生成位图和几个度量值。我们可以取出它生成的位图作为字形的纹理,将这些度量值用作字形纹理的位置、偏移等描述。
要加载一个字体,我们需要做的是初始化FreeType并且将这个字体加载为FreeType称之为面(Face)的东西。这里为我们加载一个从Windows/Fonts目录中拷贝来的TrueType字体文件arial.ttf。
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/arial.ttf”, 0, &face))
std::cout << “ERROR::FREETYPE: Failed to load font” << std::endl;
这些FreeType函数在出现错误的情况下返回一个非零整数值。
一旦我们加载字体面完成,我们还要定义文字大小,这表示着我们要从字体面中生成多大的字形:
FT_Set_Pixel_Sizes(face, 0, 48);
此函数设置了字体面的宽度和高度,将宽度值设为0表示我们要从字体面通过给出的高度中动态计算出字形的宽度。
一个字体面中包含了所有字形的集合。我们可以通过调用FT_Load_Char函数来激活当前要表示的字形。这里我们选在加载字母字形’X’:
if (FT_Load_Char(face, ‘X’, FT_LOAD_RENDER))
std::cout << “ERROR::FREETYTPE: Failed to load Glyph” << std::endl;
通过将FT_LOAD_RENDER设为一个加载标识,我们告诉FreeType去创建一个8位的灰度位图,我们可以通过face->glyph->bitmap来取得这个位图。

着色器:
我们需要使用下面的顶点着色器来渲染字形:

#version 330 core
layout (location = 0) in vec4 vertex; // <vec2 pos, vec2 tex>
out vec2 TexCoords;
uniform mat4 projection;
void main()
{
gl_Position = projection * vec4(vertex.xy, 0.0, 1.0);
TexCoords = vertex.zw;
}
我们将位置和纹理纹理坐标的数据合起来存在一个vec4中。顶点着色器将会将位置坐标与投影矩阵相乘,并将纹理坐标转发给片段着色器:
#version 330 core
in vec2 TexCoords;
out vec4 color;
uniform sampler2D text;
uniform vec3 textColor;
void main()
{
vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);
color = vec4(textColor, 1.0) * sampled;
}
片段着色器有两个uniform变量:一个是单颜色通道的字形位图纹理,另一个是文字的颜色,我们可以同调整它来改变最终输出的字体颜色。我们首先从位图纹理中采样,由于纹理数据中仅存储着红色分量,我们就通过r分量来作为取样颜色的aplpha值。结果值是一个字形背景为纯透明,而字符部分为不透明的白色的颜色。我们将此颜色与字体颜色uniform值相乘就得到了要输出的字符颜色了。
当然我们必需开启混合才能让这一切行之有效:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
至于投影矩阵我们将使用一个正交投影矩阵。对于文字渲染我们通常都不需要进行透视,使用正交投影也能保证我们所有的顶点坐标设置有效:
glm::mat4 projection = glm::ortho(0.0f, 800.0f, 0.0f, 600.0f);
我们设置投影矩阵的底部参数为0.0f并将顶部参数设置为窗口的高度。这样做的结果是我们可以通过设置0.0f~600.0f的纵坐标来表示顶点在窗口中的垂直位置。这意味着现在点(0.0,0.0)表示左下角而不再是窗口正中间。
最后要做的事是创建一个VBO和VAO用来渲染方块。现在我们分配足够的内存来初始化VBO然后在我们渲染字符的时候再来更新VBO的内存。
GLuint VAO, VBO;
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);

每个2D方块需要6个顶点,每个顶点又是由一个4维向量(一个纹理坐标和一个顶点坐标)组成,因此我们将VBO的内存分配为6*4个float的大小。由于我们会在绘制字符时更新这断内存,所以我们将内存类型设置为GL_DYNAMIC_DRAW。

OpenGL文字渲染相关推荐

  1. OpenGL text rendering文字渲染的实例

    OpenGL text rendering文字渲染 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <iostream> #inclu ...

  2. OpenGL基础55:文字渲染

    一.FreeType库 FreeType是一个能够提供多种字体相关的操作的软件开发库,往往使用它来做最简单的文字渲染: OpenGL环境配置(超全整合版)FreeType库可以从这篇文章中的链接中下载 ...

  3. OpenGL进阶(二十一) - 文字渲染

    经典文字渲染:位图字体 在早期渲染文字时,选择你应用程序的字体(或者创建你自己的字体)来绘制文字是通过将所有用到的文字加载在一张大纹理图中来实现的.这张纹理贴图我们把它叫做位图字体(Bitmap Fo ...

  4. Qt移动应用开发(八):实现跨平台的QML和OpenGL混合渲染

    Qt移动应用开发(八):实现跨平台的QML和OpenGL混合渲染 上一篇文章讲到了利用C++这个桥梁,我们实现了QML和Java的交互.Qt 5大力推崇的QML/JS开发,让轻量.高速开发的QML/J ...

  5. Android OpenGL ES 渲染文本

    1 前言 先来个灵魂拷问:为什么要研究OpenGL渲染文本? 用Android的canvas,不是更香吗?! 这就看应用场景了,一个纯粹的UI界面,确实不需要用到OpenGL,但是,复杂一些的,例如弹 ...

  6. qt android opengl,案例:实现Qt和OpenGL混合渲染 | 求索阁

    Qt自有一个绘图的引擎,这个引擎的核心就是QPainter,我们知道QPainter在渲染二维图形和文字有很大的优势,而OpenGL是当前流行的三维渲染器,怎样才能将两者结合起来,制作更为丰富的应用程 ...

  7. OpenGL 四边形渲染的实例

    OpenGL 四边形渲染 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <vmath.h> #include <string& ...

  8. OpenGL 分层渲染Layered Rendering的实例

    OpenGL 分层渲染Layered Rendering 先上图,再解答. 完整主要的源代码 源代码剖析 先上图,再解答. 完整主要的源代码 #include <string> #incl ...

  9. OpenGL地形渲染

    OpenGL地形渲染 先上图,再解答. 一:正常显示 二:按下w键 三 :按下空格键 完整主要的源代码 源代码剖析 先上图,再解答. 一:正常显示 二:按下w键 三 :按下空格键

最新文章

  1. dnslog在mysql在linux_DNSlog实现Mysql注入
  2. 【PC工具】更新速度最快最好用的文件内容搜索工具:searchmyfiles
  3. CobaltStrike使用
  4. springmvc请求返回一个字符_SpringMVC系列之Web利器SpringMVC
  5. androidstudio build tools安装_Android Studio4.0 安装及配置
  6. idea连接不了5.6mysql_IDEA无法连接mysql数据库的6种解决方法大全
  7. Kubernetes之Pod生命周期详解
  8. start.bat怎么启动java项目_部署java项目为服务,设置开机自启动
  9. ASCII对应码表(键值)
  10. vs各个版本的编译器号
  11. 华为数通笔记-DHCPv6原理与实验
  12. Windows使用cwRsync实现服务器文件同步到Linux服务器
  13. 库乐队历史版本怎么下载_ios库乐队旧版本下载
  14. 堆外缓存是什么? OHC 堆外缓存使用简介
  15. python request下载文件时、显示进度以及网速_实时网速显示_实例_python
  16. Android studio 入门笔记
  17. python将excel时间_Python学习笔记(一)Python时间戳与Excel的日期
  18. 用 Python 写了一个表白神器,照片隐藏表白话语!
  19. poj Best Cow Line
  20. Huawei EROFS 初探

热门文章

  1. C++的学习心得和知识总结(十七)|Visual Studios 2019配置游戏开发引擎HGE1.8教程
  2. FSSC22000认证辅导,GFSI旨在维持食品安全管理方案的基准审核流程,以实现食品安全标准的统一
  3. python做斐波那契数列通项公式_python实现斐波那契数列
  4. Linux下的ip命令
  5. 开源无国界:CSDN董事长蒋涛、GitHub副总裁Thomas Dohmke对话实录
  6. 游戏策划学习第二十七天
  7. Raspberry Pi 4B树莓派 | #入门教程09# 树莓派广角摄像头使用教程
  8. 猩便利蒋一新:即时便利零售的核心是数据化
  9. oracle select max min 优化,select max(),min()为什么要全表扫描?
  10. 使用Git将项目上传到gitlab详解(windows)