OpenGL ES 文字渲染 - 揭秘图形世界的文字奥妙
2023-11-26 18:27:57
在音视频或 OpenGL ES 中,文字渲染是一个高频使用的功能,比如制作一些酷炫的 UI、为视频添加水印、设置特殊字体等等。实际上 OpenGL ES 并没有定义渲染文字的方式,所以我们最能想到的办法是:将文字转化为纹理,然后利用 OpenGL ES 的纹理渲染机制将文字显示出来。
这种方法虽然可行,但存在两个问题:
- 首先,文字转化为纹理需要一个额外的步骤,增加了开发的复杂度。
- 其次,当文字内容需要频繁改变时,这种方法的性能开销会很大。
为了解决这些问题,OpenGL ES 提供了另外一种渲染文字的方法:使用着色器。
着色器是一种可被 GPU 并行执行的程序,它可以用来处理顶点数据、片元数据等。我们可以编写一个顶点着色器来生成文字的顶点数据,然后编写一个片元着色器来将这些顶点数据转换为最终的片元颜色。
这种方法的优点是:
- 减少了开发的复杂度。
- 提高了性能。
但是,使用着色器来渲染文字也存在一个问题:着色器的开发难度较高。
为了降低开发难度,我们可以使用一些现成的着色器库来渲染文字。比如,我们可以使用 stb_truetype 库来生成文字的顶点数据,然后使用 stb_truetype 的着色器来将这些顶点数据转换为最终的片元颜色。
使用 stb_truetype 库来渲染文字非常简单,我们只需几行代码即可完成。
#include <glad/glad.h>
#include <stdlib.h>
#include <stdio.h>
#include " stb_truetype.h"
int main() {
// 初始化 GLAD
if (!gladLoadGL()) {
fprintf(stderr, "Failed to initialize GLAD\n");
return 1;
}
// 创建顶点数组对象和顶点缓冲对象
GLuint vao, vbo;
glGenVertexArrays(1, & vao);
glGenBuffers(1, & vbo);
// 绑定顶点数组对象和顶点缓冲对象
glBindVertexArray( vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
// 生成文字的顶点数据
stb_truetype_vertex *vertices;
int num_vertices;
if (! stb_truetype_make_shape_from_font(&vertices, &num_vertices,
"DejaVuSans.ttf", 100, 'a', 'z')) {
fprintf(stderr, "Failed to generate text vertices\n");
return 1;
}
// 将顶点数据复制到顶点缓冲对象中
glBufferData(GL_ARRAY_BUFFER, num_vertices * sizeof( stb_truetype_vertex), vertices, GL_STATIC_DRAW);
// 设置顶点属性指针
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof( stb_truetype_vertex), (void*)offsetof( stb_truetype_vertex, x));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof( stb_truetype_vertex), (void*)offsetof( stb_truetype_vertex, y));
glEnableVertexAttribArray(1);
// 加载着色器
GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
const char *vertex_shader_source = ...
const char *fragment_shader_source = ...
glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
glCompileShader(vertex_shader);
glCompileShader(fragment_shader);
GLuint program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
// 渲染文字
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
glBindVertexArray( vao);
glDrawArrays(GL_TRIANGLES, 0, num_vertices);
// 删除着色器、顶点数组对象和顶点缓冲对象
glDeleteProgram(program);
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
glDeleteVertexArrays(1, & vao);
glDeleteBuffers(1, & vbo);
return 0;
}
这段代码首先加载了必要的库,然后创建了顶点数组对象和顶点缓冲对象。接下来,它调用 stb_truetype 库来生成文字的顶点数据,并将这些顶点数据复制到顶点缓冲对象中。
接下来,它设置了顶点属性指针,然后加载了着色器。最后,它渲染了文字,并删除了着色器、顶点数组对象和顶点缓冲对象。
这种方法非常简单,而且性能也非常好。但是,它只能渲染单色的文字。如果我们需要渲染彩色文字,我们需要使用另外一种方法。
我们可以使用纹理来渲染彩色文字。这种方法的原理是:将文字转化为纹理,然后将纹理贴到一个几何体上。
这种方法的优点是:
- 我们可以渲染彩色文字。
- 我们可以使用各种各样的字体。
但是,这种方法的缺点是:
- 开发复杂度更高。
- 性能开销更大。
无论您选择哪种方法,OpenGL ES 都可以帮助您轻松实现令人惊叹的文字效果。