【问题标题】:use of texture arrays with freetype in opengl在opengl中使用带有freetype的纹理数组
【发布时间】:2016-05-19 15:13:03
【问题描述】:

阅读并运行以下教程 (http://learnopengl.com/code_viewer.php?code=in-practice/text_rendering) 后,我学会了如何在 OpenGL 中使用 freetype 渲染文本。我现在想知道是否可以避免为每个字形调用 glDrawArrays。因此,我对 VBO 进行了一些修改,以将其用于整个字符串而不是一个字形。作为第一步,我使用了字符串“AA”,并且由于两个字形相同,它们也共享相同的纹理。因此,运行以下代码不是问题:

glGenVertexArrays(1, & textVAO);
glBindVertexArray(textVAO);
glGenBuffers(1, &textVBO);
glBindBuffer(GL_ARRAY_BUFFER,textVBO);
glBufferData(GL_ARRAY_BUFFER, 24* 2* sizeof(float), NULL, GL_DYNAMIC_DRAW);
glVertexPointer( 4, GL_FLOAT, 0, NULL);

接着是:

textShader.Use();
glm::vec3 color;
color = glm::vec3(1.0, 0.7f, 0.9f);
glUniform3f(glGetUniformLocation(textShader.Program, "textColor"), color.x, color.y, color.z);
glBindVertexArray(textVAO);
glActiveTexture(GL_TEXTURE0);
int k=0;
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;
    V.block(0,k,24,1) << 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;
    k++;
    x += ( (ch.Advance >> 6) * scale);
}
glBindTexture(GL_TEXTURE_2D,66);

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

glBindBuffer(GL_ARRAY_BUFFER,textVBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, 24* 2* sizeof(float), V.data());
glDrawArrays(GL_TRIANGLES,0,4*3);
glBindTexture(GL_TEXTURE_2D,0);
glDisableClientState(GL_VERTEX_ARRAY);
glUseProgramObjectARB(0);

我希望能够在屏幕上渲染“AB”或“ZW”,因此我现在尝试将 GL_TEXTURE_2D_ARRAY 与 glTexImage3D 和 glTexSubImage3D 一起使用。再次为简化起见,我使用“AA”以使字形具有相同的宽度和高度。所以我加了

GLuint textureArray;
glEnable(GL_TEXTURE_2D_ARRAY);
glGenTextures(1, &textureArray);
glBindTexture(GL_TEXTURE_2D_ARRAY, textureArray);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, 4, 30, 35, 2, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);

到前面的代码的第一部分和第二部分变成了:

textShader.Use();
glm::vec3 color;
color = glm::vec3(1.0, 0.7f, 0.9f);
glUniform3f(glGetUniformLocation(textShader.Program, "textColor"), color.x, color.y, color.z);
glBindVertexArray(textVAO);
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glEnable(GL_TEXTURE_2D_ARRAY);
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;
    V.block(0,k,24,1) << 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;
    glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, k, 30,35, 1, GL_RED, GL_UNSIGNED_BYTE, ch.pointeur);
    k++;
    x += ( (ch.Advance >> 6) * scale);
    }
glBindTexture(GL_TEXTURE_2D_ARRAY,textureArray);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER,textVBO);
glBufferSubData(GL_ARRAY_BUFFER, 0, 24* 2* sizeof(float), V.data());
glDrawArrays(GL_TRIANGLES,0,4*3);
glBindTexture(GL_TEXTURE_2D,0);
glDisableClientState(GL_VERTEX_ARRAY);
glUseProgramObjectARB(0);

代码编译,但屏幕上没有任何内容。所以我想知道我是否正确使用了 GL_TEXTURE_2D_ARRAY 以及是否必须对着色器进行“数组版本”。我正在使用 OpenGL 4.5,谢谢。

【问题讨论】:

    标签: opengl textures freetype


    【解决方案1】:

    有(至少)两个问题。

    首先,您使用的是固定功能管道,它不能与数组纹理一起使用。访问东西的纹理环境不知道如何处理它们。如果你想使用数组纹理,你必须使用着色器。

    其次,即使你使用了着色器,你也做错了。再说一次,你被教程错误地教导了(在这种情况下,它教导了如此糟糕的做法,以至于它正在积极地损害 OpenGL 用户)。您将每个字形放在其自己的数组层中。嗯,很多 OpenGL 实现 only support 256 array layers,如果你想包含非英文文本,这不是很多字形。

    进行字形渲染的正确方法是构建字形的纹理图集,而不是使用每个纹理的字形(就像糟糕的教程那样)或每个数组层的字形(就像你做的那样)。您将多个字形放置在单个 2D 纹理的不同位置,然后使用纹理坐标来选择要使用的字形。这将允许您通过一次绘制调用提交整个文本块。

    如今,2D 纹理大小可以超过 16K 像素。即使只有 4096x4096 纹理,您也可以将超过 1600 个 32x32 字形放入其中。

    【讨论】:

    • 作为本教程的作者,我想表达一些见解:我同意将所有字形打包到一个纹理中绝对是最好的性能。我在本教程中采用按字形方法的原因是,对于字形渲染的新手来说,它更容易理解。如果我还要花时间描述如何打包字形并使用不同的 UV 坐标以不同方式渲染每个字形,那么教程将是庞大且更难理解的。本教程最后对此进行了说明,并建议读者自行解决。
    • @JoeyDewd:我理解并欣赏在决定教什么和不教什么的艰难平衡行为。但是,纹理图集是图形开发人员的基本和重要技能。它们在整个图形中用于各种事物,但对于新的图形程序员来说,大多数用途都是发明。您没有渲染足够复杂的场景以使性能差异变得清晰。相比之下,文本渲染为引入纹理图集的概念提供了完美的机会。我仍然说不在这里介绍它对您的读者有害。
    • 我同意,理想情况下,我应该有 3 个单独的教程:一个用于纹理图集,一个用于 FreeType,另一个用于按顺序使用 FreeType 生成纹理图集(以及可选的一个用于有符号距离场渲染)。我已经在我的待办事项清单上记下了这一切。
    • 谢谢! Joey 向我介绍了 opengl 中的 freetype,Nicol 为我提供了遵循的方法。我想避免“边做边学”,但是教程很容易获得……而且要找出最合适的理论背景并不容易。我现在已经使用了纹理图集并且它可以工作,至少对它自己来说是这样。
    【解决方案2】:

    我发现另一个教程分为两部分,第一部分(在教学上与 Joey 的教程非常相似)为每个字形调用 gldraw,第二部分解释如何在一次调用中绘制整个字符串。这是第二部分的链接。可以下载完整的代码(向下滚动页面)。谢谢!

    https://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_Text_Rendering_02

    【讨论】:

    • 只是为了澄清那些现在来这里的人,这是讨论纹理图集的教程。这是要遵循的。谢谢乔纳森。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-03
    • 1970-01-01
    • 1970-01-01
    • 2021-01-15
    • 1970-01-01
    • 1970-01-01
    • 2013-09-09
    相关资源
    最近更新 更多