OpenGL ES详解——文字渲染

Android视频录制如何用OpenGL实时叠加水印:从EGL到Shader全流程 在移动端音视频开发中,视频录制是常见需求,而叠加动态水印、时间戳或滤镜则对实时渲染提出更高要求。传统方案多采用MediaRecorder或MediaCodec配合后处理,往往面临二次转码导致的画质损失与等待耗时。理解图形渲染管线与编码器的协作是解决问题的关键,其中EGL作为OpenGL与窗口系统的桥梁,负责将GPU渲染结果直接输送给视频编码器,实现零拷贝的实时合成。Shader编程则让每一帧的水印、特效在编码前精准绘入,既保证画质无损,又带来灵活的动态效果。该技术广泛应用于短视频拍摄、直播推流、录屏教学等场 阅读详情
AI摘要

本文探讨了在图形计算领域使用OpenGL绘制文字的方法。介绍了经典的位图字体渲染方式,其易实现但不够灵活;着重讲解了现代的FreeType库渲染技术,它能加载TrueType字体,灵活可缩放。还提及了未来可结合两种方法,以及解决FreeType字体放大锯齿等问题的技术。

目录

一、文字渲染

二、经典文字渲染:位图字体

1.概念

2.优缺点

三、现代文字渲染:FreeType

1.着色器

2.渲染一行文字

四、关于未来


一、文字渲染

当你在图形计算领域冒险到了一定阶段以后你可能会想使用OpenGL来绘制文字。然而,可能与你想象的并不一样,使用像OpenGL这样的底层库来把文字渲染到屏幕上并不是一件简单的事情。如果你你只需要绘制128种字符,那么事情可能会简单一些。但是当我们要绘制的字符有着不同的宽、高和边距;如果你使用的语言中不止包含128个字符;当你要绘制音乐符、数学符号;以及考虑把如何处理文本自动转行等等情况考虑进来的时候…事情马上就会变得复杂得多,你甚至觉得这些工作并不属于像OpenGL这样的底层图形库该讨论的范畴。

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

开发者最常用的一种方式是将字符纹理绘制到矩形方块上。绘制这些纹理方块其实并不是很复杂,然而检索要绘制的文字的纹理却变成了一项挑战性的工作。本教程将探索多种文字渲染的实现方法,并且着重对更加现代而且灵活的渲染技术(使用FreeType库)进行讲解。

二、经典文字渲染:位图字体

1.概念

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

上图展示了我们如何从一张位图字体的纹理中通过对字形的合理取样(通过小心地选择字形的纹理坐标)来实现绘制文字“OpenGL”到2D方块中的原理。通过对OpenGL启用混合并让位图字体的纹理背景保持透明,这样就能实现使用OpenGL绘制你想要文字到屏幕的功能。上图的这张位图字体是使用Codehead的位图字体生成器生成的。

2.优缺点

使用这种途径来绘制文字有许多优势也有很多缺点。首先,它相对来说很容易实现,并且因为位图字体被预渲染好,使得这种方法效率很高。然而,这种途径并不够灵活。当你想要使用不同的字体时,你不得不重新生成位图字体,以及你的程序会被限制在一个固定的分辨率:如果你对这些文字进行放大的话你会看到文字的像素边缘。此外,这种方式仅局限于用来绘制很少的字符,如果你想让它来扩展支持Unicode文字的话就很不现实了。

这种绘制文字的方式曾经得益于它的高速和可移植性而非常流行,然而现在已经存在更加灵活的方式了。其中一个是我们即将展开讨论的使用FreeType库来加载TrueType字体的方式。

三、现代文字渲染:FreeType

FreeType是一个能够用于加载字体并将他们渲染到位图以及提供多种字体相关的操作的软件开发库。它是一个非常受欢迎的跨平台字体库,被用于 Mac OSX、Java、PlayStation主机、Linux、Android等。FreeType的真正吸引力在于它能够加载TrueType字体。

TrueType字体不采用像素或其他不可缩放的方式来定义,而是一些通过数学公式(曲线的组合)。这些字形,类似于矢量图像,可以根据你需要的字体大小来生成像素图像。通过使用TrueType字体可以轻易呈现不同大小的字符符号并且没有任何质量损失。

FreeType可以在他们的官方网站中下载到。你可以选择自己编译他们提供的源代码或者使用他们已编译好的针对你的平台的链接库。请确认你将freetype.lib添加到你项目的链接库中,同时你还要添加它的头文件目录到项目的搜索目录中。

然后请确认包含合适的头文件:

#include <ft2build.h>
#include FT_FREETYPE_H  

由于FreeType开发得比较早(至少在我写这篇文章以前就已经开发好了),你不能将它们的头文件放到一个新的目录下,它们应该保存在你包含目录的根目录下。通过使用像 #include <FreeType/ft2build.h> 这样的方式导入FreeType可能会出现各种头文件冲突的问题。

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来取得这个位图。

使用FreeType加载的字形位图并不像我们使用位图字体那样持有相同的尺寸大小。使用FreeType生产的字形位图的大小是恰好能包含这个字形的尺寸。例如生产用于表示’.’的位图的尺寸要比表示’X’的小得多。因此,FreeType在加载字形的时候还生产了几个度量值来描述生成的字形位图的大小和位置。下图展示了FreeType的所有度量值的涵义。

每一个字形都放在一个水平的基线(Baseline)上,上图中被描黑的水平箭头表示该字形的基线。这条基线类似于拼音四格线中的第二根水平线,一些字形被放在基线以上(如’x’或’a’),而另一些则会超过基线以下(如’g’或’p’)。FreeType的这些度量值中包含了字形在相对于基线上的偏移量用来描述字形相对于此基线的位置,字形的大小,以及与下一个字符之间的距离。下面列出了我们在渲染字形时所需要的度量值的属性:

属性获取方式生成位图描述
widthface->glyph->bitmap.width宽度,单位:像素
heightface->glyph->bitmap.rows高度,单位:像素
 bearingX face->glyph->bitmap_left水平位置(相对于起点origin),单位:像素
bearingY face->glyph->bitmap_top垂直位置(相对于基线Baseline),单位:像素
 advanceface->glyph->advance.x起点到下一个字形的起点间的距离(单位:1/64像素)

在我们想要渲染字符到屏幕的时候就能根据这些度量值来生成对应字形的纹理了,然而每次渲染都这样做显然不是高效的。我们应该将这些生成的数据储存在应用程序中,在渲染过程中再去取。方便起见,我们需要定义一个用来储存这些属性的结构体,并创建一个字符表来存储这些字形属性。

struct Character {
    GLuint     TextureID;  // 字形纹理ID
    glm::ivec2 Size;       // 字形大大小
    glm::ivec2 Bearing;    // 字形基于基线和起点的位置
    GLuint     Advance;    // 起点到下一个字形起点的距离
};

std::map<GLchar, Character> Characters;

本教程本着让一切简单的目的,我们只生成表示128个ASCII字符的字符表。并为每一个字符储存纹理和一些度量值。这样,所有需要的字符就被存下来备用了。

glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //禁用byte-alignment限制
for (GLubyte c = 0; c < 128; c++)
{
    // 加载字符的字形 
    if (FT_Load_Char(face, c, FT_LOAD_RENDER))
    {
        std::cout << "ERROR::FREETYTPE: Failed to load Glyph" << std::endl;
        continue;
    }
    // 生成字形纹理
    GLuint texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexImage2D(
        GL_TEXTURE_2D,
        0,
        GL_RED,
        face->glyph->bitmap.width,
        face->glyph->bitmap.rows,
        0,
        GL_RED,
        GL_UNSIGNED_BYTE,
        face->glyph->bitmap.buffer
    );
    //设置纹理选项
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    // 将字符存储到字符表中备用
    Character character = {
        texture, 
        glm::ivec2(face->glyph->bitmap.width, face->glyph->bitmap.rows),
        glm::ivec2(face->glyph->bitmap_left, face->glyph->bitmap_top),
        face->glyph->advance.x
    };
    Characters.insert(std::pair<GLchar, Character>(c, character));
}

在这个for循环中我们将所有ASCII中的128个字符设置合适的字形。为每一个字符创建纹理并存储它们的部分度量值。有趣的是我们这里将纹理的格式设置为GL_RED。通过字形生成的位图是8位灰度图,他的每一个颜色表示为一个字节。因此我们需要将每一位都作为纹理的颜色值。我们通过创建每一个字节表示一个颜色的红色分量(颜色分量的第一个字节)来创建字形纹理。我们想用一个字节来表示纹理颜色,这需要提前通知OpenGL

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);   

OpenGL要求所有的纹理颜色都必须是4字节队列,这样纹理的内存大小就一定是4字节的整数倍。通常这并不会出现什么问题,因为通常的纹理都有4或者4的整数倍的储存大小,但是现在我们只用一位来表示每一个像素颜色,此时的纹理可能有任意内存长度。通过将纹理解压参数设为1,这样才能确保不会有内存对齐的解析问题。

当你处理完字形后同样不要忘记清理FreeType的资源。

FT_Done_Face(face);
FT_Done_FreeType(ft);

1.着色器

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

#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

2.渲染一行文字

要渲染一个字符,我们从之前创建的字符表中取出一个字符结构体,根据字符的度量值来计算方块的大小。根据方块的大小我们就能计算出6个描述方块的顶点,并使用glBufferSubData函数将其更新到VBO所在的内存中。

我们创建一个函数用来渲染一行文字:

void RenderText(Shader &s, std::string text, GLfloat x, GLfloat y, GLfloat scale, glm::vec3 color)
{
    // 激活合适的渲染状态
    s.Use();
    glUniform3f(glGetUniformLocation(s.Program, "textColor"), color.x, color.y, color.z);
    glActiveTexture(GL_TEXTURE0);
    glBindVertexArray(VAO);

    // 对文本中的所有字符迭代
    std::string::const_iterator c;
    for (c = text.begin(); c != text.end(); c++)
    {
        Character ch = Characters[*c];

        GLfloat xpos = x + ch.Bearing.x * scale;
        GLfloat ypos = y - (ch.Size.y - ch.Bearing.y) * scale;

        GLfloat w = ch.Size.x * scale;
        GLfloat h = ch.Size.y * scale;
        // 当前字符的VBO
        GLfloat vertices[6][4] = {
            { xpos,     ypos + h,   0.0, 0.0 },            
            { xpos,     ypos,       0.0, 1.0 },
            { xpos + w, ypos,       1.0, 1.0 },

            { xpos,     ypos + h,   0.0, 0.0 },
            { xpos + w, ypos,       1.0, 1.0 },
            { xpos + w, ypos + h,   1.0, 0.0 }           
        };
  // 在方块上绘制字形纹理
        glBindTexture(GL_TEXTURE_2D, ch.textureID);
        // 更新当前字符的VBO
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); 
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        // 绘制方块
        glDrawArrays(GL_TRIANGLES, 0, 6);
        // 更新位置到下一个字形的原点,注意单位是1/64像素
        x += (ch.Advance >> 6) * scale; //(2^6 = 64)
    }
    glBindVertexArray(0);
    glBindTexture(GL_TEXTURE_2D, 0);
}

这个函数的内容注释的比较详细了:我们首先计算出方块的起点坐标(即xpos和ypos)和它的大小(即w和h),并为该方块生成6个顶点;注意我们在缩放的同时会将部分度量值也进行缩放。接着我们更新方块的VBO、绑定字形纹理来渲染它。

其中这行代码需要加倍留意:

GLfloat ypos = y - (ch.Size.y - ch.Bearing.y);   

一些字符(诸如’p’或’q’)需要被渲染到基线以下,因此字形方块也应该讲y位置往下调整。调整的量就是便是字形度量值中字形的高度和BearingY的差:

要计算这段偏移量的距离,我们需要指出是字形在基线以下的部分最底断到基线的距离。在上图中这段距离用红色双向箭头标出。如你所见,在字形度量值中,我们可以通过用字形的高度减去bearingY来计算这段向量的长度。这段距离有可能是0.0f(如’x’字符) ,或是超出基线底部的距离的长度(如’g’或’j’)。

如果你每件事都做对了,那么你现在已经可以使用下面的句子成功地渲染字符串了:

RenderText(shader, "This is sample text", 25.0f, 25.0f, 1.0f, glm::vec3(0.5, 0.8f, 0.2f));
RenderText(shader, "(C) LearnOpenGL.com", 540.0f, 570.0f, 0.5f, glm::vec3(0.3, 0.7f, 0.9f));

渲染效果看上去像这样:

通过关闭字形纹理的绑定,能够给你对文字方块的顶点计算更好的理解,它看上去像这样:

可以看出,对应’p’和’(‘等字形的方块明显向下偏移了一些,通过这些你就能清楚地看到那条传说中的基线了。

四、关于未来

本教程演示了如何使用FreeType绘制TrueType文字。这种方式灵活、可缩放并支持多种字符编码。然而,你的应用程序可能并不需要这么强大的功能,性能更好的点阵字体也许是更可取的。当然你可以结合这两种方法通过动态生成位图字体中所有字符字形。这节省了从大量的纹理渲染器开关和基于每个字形紧密包装可以节省相当的一些性能。

另一个使用FreeType字体的问题是字形纹理是对应着一个固定的字体大小的,因此直接对其放大就会出现锯齿边缘。此外,对字形进行旋转还会使它们看上去变得模糊。通过将每个像素设为最近的字形轮廓的像素,而不是直接设为实际栅格化的像素,可以减轻这些问题。这项技术被称为有向距离场(Signed Distance Fields),Valve在几年前发表过一篇了论文,探讨了他们通过这项技术来获得好得惊人的3D渲染效果。

参考文章

文字渲染 - LearnOpenGL-CN

opengl es2.0 使用字符偏移图渲染文字 使用文字偏移图提升opengl es 2.0 文字渲染效率 阅读详情

相关推荐

从零讲解 iOS OpenGL ES 的纹理渲染

本文主要介绍,如何使用 OpenGL ES 来渲染一张图片。内容包括:基础概念的讲解,如何使用 GLKit 来渲染纹理,如何使用 GLSL 编写的着色器来渲染纹理。 前言 OpenGL(Open Graphics Library)是 Khronos Group (一个图形软硬件行业协会,该协会主要关注图形和多媒体方面的开放标准)开发维护的一个规范,它是硬件无关的。它主要为我们定义了用来操作图形和图片的一系列函数的 API,OpenGL 本身并非 API。 **OpenGL ES(OpenGL for Em.

原来是泽镜的博客 870

OpenGL -文字

OpenGL 文字

weixin_45054115的博客 3386

OpenGL 简单实现中文字体渲染

为了方便起见,我们将采用 bitmap 字体的方式进行渲染。FreeType 能够读取常见字体文件(如 .ttf)并生成字形轮廓,这与 OpenGL 的二维矢量图形不兼容。这个函数将会返回一个 Bitmap 字体的指针,可以在 OpenGL 中使用此指针进行 TextView 的渲染。以上代码展示了如何将 Bitmap 字体渲染出来,并在渲染时通过偏移量对字符进行平移,从而实现字符间距的调整。由于 FreeType 不是 OpenGL 的标准库,需要先行安装。渲染 Bitmap 字体。

CyberSphinx的博客 739

OpenGL显示文字

阅读这篇文章前,可以先看一下这个文字显示系列的其他文章,了解一些字符编码,字体相关的知识:https://blog.youkuaiyun.com/wlk1229/article/category/9008450 显示文字 OpenGL提供的是图形API,本身并不提供文字处理方面的接口,如果想要显示文字就需要先将文字转化成图片,然后渲染图片。 Char Map Char Map是最简单的方式,首先...

Wlk1229 1万+

OpenGL 绘制文本(QPainter)

OpenGL 绘制文本(QPainter)

dayuhaitang1的博客 1456

Qt OpenGL(三十二)——Qt OpenGL 核心模式-文字

在Qt中使用OpenGL绘制文字,我们可以通过Qt提供的QPainter类来实现在OpenGLWidget界面上绘制我们需要的文字,这也是实现这个功能需求的一种方法。本文原创作者:冯一川(ifeng12358@163.com),未经作者授权同意,请勿转载。

ifeng12358的博客 1895

NDK_OpenGLES_3_0文字渲染:FreeType库集成与中文字体显示优化终极指南

在Android OpenGL ES 3.0开发中,文字渲染一直是一个技术难点。本教程将为你详细解析NDK_OpenGLES_3_0项目如何通过FreeType库实现高质量的文字渲染,特别是针对中文字体的显示优化。OpenGL ES 3.0文字渲染与FreeType库集成是移动端图形开发的重要技能,掌握这项技术能让你在应用中实现美观的文本显示效果。 ## 📚 为什么需要FreeType库进行文

gitblog_00525的博客 391

OpenGL ES 文字渲染方式有几种?

在音视频或 OpenGL 开发中,文字渲染是一个高频使用的功能,比如制作一些酷炫的字幕、为视频添加水印、设置特殊字体等等。实际上 OpenGL 并没有定义渲染文字的方式,所以我们最能想到的办法是:将带有文字的图像上传到纹理,然后进行纹理贴图。本文分别介绍下在应用层和 C++ 层常用的文字渲染方式。

字节流动 9944

Android音视频开发实战:基于FFmpeg、OpenGL ES与RTMP的全栈解析

这篇文章介绍了一个Android平台的全栈多媒体开发项目WyFFmpeg,该项目整合了FFmpeg编解码、OpenGL ES渲染、H.264/H.265解析和RTMP推流等核心技术。项目包含7个模块:ffmpegplay(音视频处理)、glplay(OpenGL渲染)、h264(H.264解析)、h265(H.265解析与转码)、rtmplive(RTMP推流)等。文章详细解析了各模块的架构设计和关键技术实现,包括JNI动态注册、FFmpeg音视频处理流程、OpenGL ES渲染管线、H.264/H.265

wangyongyao1989的博客 232

OpenGL ES 文字渲染进阶--渲染中文字体

每个 2D 方块需要 6 个顶点,每个顶点又是由一个 4 维向量(一个纹理坐标和一个顶点坐标)组成,因此我们将VBO 的内存分配为 6*4 个 float 的大小。片段着色器有两个 uniform 变量:一个是单颜色通道的字形位图纹理,另一个是文字的颜色,我们可以同调整它来改变最终输出的字体颜色。使用 FreeType 渲染中文和英文字符在流程上基本一致,都是根据字符的编码值来加载位图,然后上传纹理。,它小巧、高效、高度可定制,主要用于加载字体并将其渲染到位图,支持多种字体的相关操作。

字节流动 9994

IMGUI+GLFW+WebGL+WASM:C++桌面工具浏览器移植指南

在跨平台应用开发中,如何复用现有C++图形界面代码是常见痛点。即时模式GUI(如Dear ImGui)通过每帧生成绘制指令,天然适配浏览器底层的WebGL渲染模型。借助Emscripten工具链,将GLFW窗口事件映射到canvas,再通过WASM提供运行时,即可将桌面版的IMGUI工具几乎原样搬进网页。这种方式避免了重写前端UI的工作量,同时保留了C++侧的业务逻辑。文章从实时渲染原理出发,讲解IMGUI与WebGL的契合点,梳理Emscripten编译、字体嵌入、输入焦点、高分屏适配等关键环节,并给出实

weixin_33154775的博客 281

Opengl ES之文字渲染

Opengl ES之EGL环境搭建Opengl ES之着色器Opengl ES之三角形绘制Opengl ES之四边形绘制Opengl ES之纹理贴图Opengl ES之VBO和VAOOpengl ES之EBOOpengl ES之FBOOpengl ES之PBOOpengl ES之YUV数据渲染YUV转RGB的一些理论知识Opengl ES之RGB转NV21Opengl ES之踩坑记Opengl ES之矩阵变换(上)Opengl ES之矩阵变换(下)Opengl ES之水印贴图。

u012944685的专栏 1292

基于Kubernetes的ML平台架构设计

本文在Kubernetes开源组件的基础上,对ML平台各部分组件的作用进行了介绍,并且进行了组件选型,初步设计了ML平台的技术架构。

2401_83124266的博客 2052

Android OpenGL ES 渲染文本

介绍如何用OpenGLES 渲染文字。

newchenxf的专栏 6958

flowable表中文注释-表结构-主要表结构字段注释-sql脚本

flowable表结构中文注释,主要表结构字段注释,sql执行脚本,包含MySQL版和Oracle版sql脚本。

bushinakeshu的博客 1068

MaxEnt物种分布预测中的常见误区与优化技巧:如何提高模型准确率

本文深入探讨了MaxEnt物种分布预测模型从基础应用到精准预测的进阶实践。针对模型准确率提升,文章系统分析了环境变量筛选、模型参数调优、结果批判性解读等核心环节的常见误区,并提供了基于生态位模型原理的深度优化技巧,帮助研究者产出更可靠、可解释的预测结果。

weixin_29219539的博客 594

android opengl es 文字,OpenGL ES2.0实现文字绘制Android

OpenGL ES2.0是无法直接绘制文字的,我采用的方法是将文字转为Bitmap,然后以图贴的方式进行渲染。看到网上也有人是将文字生成点,一个个进行绘制的,个人觉得这种方法还是挺麻烦的。文章分为两部分,一部分是在canvas中绘图转Bitmap,第二部分是贴图纹理绘制。文字转Bitmap这部分比较麻烦,网上介绍的canvas.drawText()的资料太多,看了都让人一头雾水,我也看了一天才明白...

weixin_39736606的博客 1106

sldd数据字典导出为excel

sldd导出为excel

zpfjf的博客 2237

OpenGL ES实现实时文本渲染

本文介绍基于OpenGL ES和FreeType实现高性能实时文本渲染的技术方案,涵盖字形光栅化、纹理图集打包、GPU着色器绘制及VBO增量更新等核心环节,适用于游戏、AR/VR等对性能敏感的应用场景。

weixin_31860973的博客 972

STM32入门教程:人脸识别

STM32CubeMX配置 打开STM32CubeMX,创建一个新的工程,并选择你使用的STM32系列和具体型号。根据摄像头模块的规格,将摄像头的输出引脚连接到相应的STM32引脚上。人脸识别是一种非常常见的人工智能应用,它可以通过摄像头捕捉到的图像,识别出图像中的人脸并进行相关的分析和处理。在本教程中,我们将使用STM32开发板和相关传感器,通过指导你搭建一个基于STM32的简单人脸识别系统,并编写相应的代码来实现该功能。另外,为了达到更好的人脸识别效果,可能需要使用更高性能的处理器和更复杂的算法。

吃不胖. 374

第02章:HSA-Runtime架构概览

摘要: 本章深入解析HSA Runtime的三层架构设计,包括公共API层(C语言接口)、核心实现层(C++业务逻辑)和驱动抽象层(硬件交互)。重点介绍了Runtime的核心组件(Agent、Queue、Signal、Memory)及其关系,以及初始化流程、配置选项和调试功能。通过学习,读者将掌握HSA Runtime的整体架构,为后续模块学习奠定基础。

图形/计算GPU的驱动与虚拟化技术分享园地 2915

opengl es2.0 渲染文字

这篇文章是我写在公司项目组的博客下的. 在OpenGL 家族中是没有提供直接渲染文字的接口,所以我们要在opengl中显示文字,就需要借助于其他的三方库或者自己解析绘制文字,然后使用opengl中的绘制接口去渲染出文字 这里我使用的freetype这个三方库· FreeType 2.0 FreeType是一个完全开源的、可扩展、可定制且可移植的字体引擎,它提供True

tlglove326的博客 6043

Qt5+Ros+GUI界面

在之前建立的工程的基础上添加一个gui界面。 在ros包中新建一个文件夹,名字叫gui 右击gui文件夹添加一个文件,选择Qt->Qt设计师界面类 选择MainWindow 选择下一步 最后在gui中生成三个文件 mainwindow.cpp、mainwindow.h、mainwindow.ui 但此时,这些新创建的文件和原本的ros工程还没建立任何关系,只是目录下多出了几个文件而已...

二毛的博客 8843

一对一源码,OpenGL ES 文字渲染

一对一源码,OpenGL ES 文字渲染实现的相关代码 基于 Canvas 绘制生成 Bitmap 在应用层实现文字渲染主要是利用 Canvas 将文本绘制成 Bitmap ,然后生成一张小图,然后在渲染的时候进行贴图。 在实际的生产环境中,一般会将这张小图转换成灰度图,减少不必要的数据拷贝和内存占用,然后在渲染的时候可以为灰度图上色,作为字体的颜色。 // 创建一个 bitmap Bitmap bitmap = Bitmap.createBitmap(width, hight, Bitmap.Confi

云豹网络科技 457

YOLO26轻量化科研实践:PartialConv驱动CSPCPC模块,让模型参数量直降1000W且精度不减

在目录下,新建AddModules文件夹,将cspcpc.py放入其中。

m0_71589036的博客 166

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

android opengl es 位图字体

<br />一:先总结下今天遇到的问题<br />(1)opengl如何绘制字符串<br />最终参考了以下网址<br />http://xmchang.bokee.com/6922990.html<br />(2)关于坐标问题<br />参考<br />http://blog.youkuaiyun.com/cjkwin/archive/2010/11/17/6016224.aspx<br />以前没有重视这个问题,今天好好看了下,发现各坐标应如下图所示<br />a:vertex即正文体顶点坐标<br /> <br

Simdanfeg的专栏 7909

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

上一篇: Android opengl 绘制矩形,宽高相同,不能显示为正方形,是怎么回事
下一篇: OpenGL ES详解——YUV数据渲染
闲暇部落
博客等级 码龄12年 2775粉丝 215原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

闲暇部落

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值