如何只使用OpenGL方法绘制文本?

58wvjzkj  于 2022-11-04  发布在  其他
关注(0)|答案(6)|浏览(179)

我没有使用OpenGL方法的选项(即glxxx()方法)。我只需要使用gl方法绘制文本。在阅读红皮书后,我了解到只有通过glBitmap()方法才有可能。如果这是唯一可能的方法,那么谁能帮助我获得所有字符的像素阵列信息。还有其他方法可以绘制文本吗?

gblwokeq

gblwokeq1#

理论
"为什么很难"
TrueTypeOpenType等常用字体格式是矢量轮廓格式:它们使用Bezier curves来定义字母的边界。

Image source
将这些格式转换为像素阵列(光栅化)过于具体,超出了OpenGL的范围,特别是因为OpenGl没有非直线图元(例如,请参见Why is there no circle or ellipse primitive in OpenGL?
最简单的方法是首先在CPU上光栅化字体,然后将像素阵列作为纹理提供给OpenGL。
OpenGL知道如何通过纹理很好地处理像素阵列。

纹理图册

我们可以为每一帧光栅化字符,并重新创建纹理,但这不是很有效,特别是如果字符具有固定大小。
更有效的方法是光栅化您计划使用的所有角色,并将它们填充在单个纹理上。
然后将其传输到GPU一次,并使用它的纹理与自定义的紫外线坐标来选择正确的字符。
这种方法被称为texture atlas,它不仅可以用于纹理,还可以用于其他重复使用的纹理,如2D游戏中的瓷砖或Web UI图标。
完整纹理的维基百科图片(取自freetype-gl)很好地说明了这一点:

我怀疑优化字符放置到最小的纹理问题是一个NP难问题,请参见:What algorithm can be used for packing rectangles of different sizes into the smallest rectangle possible in a fairly optimal way?
同样的技术也被用于Web开发中,一次传输几个小图像(如图标),但在那里它被称为“CSS Sprites”:https://css-tricks.com/css-sprites/,用于隐藏网络延迟,而不是CPU / GPU通信延迟。

非CPU栅格方法

也存在不使用CPU光栅来纹理的方法。
CPU光栅化很简单,因为它尽可能少地使用GPU,但我们也开始考虑是否有可能进一步使用GPU效率。
This FOSDEM 2014 video解释了其他现有技术:

在3D几何体内部渲染字体(与正交HUD相比)要复杂得多,因为透视可能会使角色的一部分更靠近屏幕,并且比另一部分更大,从而使统一的CPU离散化(例如光栅、镶嵌)在靠近的部分上看起来很糟糕。这实际上是一个活跃的研究主题:

https://www.youtube.com/watch?v=1b5hIMqz_wM由马丁唐纳德(2020)是一个不错的视频评论它,它似乎给予了一些更具体的使用建议以及。

  • 距离场 * 是现在流行的技术之一。

实施

下面的例子都是在Ubuntu 15.10上测试的。
正如前面所讨论的,这是一个复杂的问题,大多数例子都很大,并且会超出这个答案的30 k字符限制,所以只需克隆相应的Git仓库进行编译。
然而,它们都是完全开源的,所以您可以只使用RTFS。

FreeType解决方案

FreeType看起来像是主流的开源字体光栅化库,因此它允许我们使用TrueType和OpenType字体,使其成为最优雅的解决方案。

是一组示例OpenGL和freetype,但或多或少地演变成一个库,这样做,并公开了一个体面的API。
在任何情况下,通过复制粘贴一些源代码,应该已经可以将其集成到您的项目中。
它提供了现成的纹理贴图集和距离场技术。
演示位于:https://github.com/rougier/freetype-gl/tree/master/demos
没有Debian软件包,在Ubuntu 15.10上编译很痛苦:https://github.com/rougier/freetype-gl/issues/82#issuecomment-216025527( Package 问题,一些上游),但它得到了更好的16.10。
没有很好的安装方法:https://github.com/rougier/freetype-gl/issues/115显示器
生成如下所示的漂亮输出:

  • 库文件系统

示例/教程:

它们看起来不如FreeType好,但可能更轻量级:

字体由作者手动创建并存储在一个.png文件中。字母以数组形式存储在图像中。
这种方法当然不是很通用,而且在国际化方面也会遇到困难。
构建方式:

make -f Makefile.linux64

输出预览:
x1c4d 1x指令集

opengl教程第11章“二维字体”

纹理是从DDS files生成的。
本教程介绍了如何使用CBFGPaint.Net创建DDS文件。
输出预览:

由于某种原因,苏珊娜对我来说是失踪了,但计时器工作正常:https://github.com/opengl-tutorials/ogl/issues/15显示器

免费GLUT

GLUT有glutStrokeCharacter,FreeGLUT是开源的... https://github.com/dcnieho/FreeGLUT/blob/FG_3_0_0/src/fg_font.c#L255

OpenGL文本

https://github.com/tlorach/OpenGLText显示器
TrueType光栅。由NVIDIA员工开发。旨在实现可重用性。还没有尝试过。

ARM Mali GLES软件开发工具包示例

http://malideveloper.arm.com/resources/sample-code/simple-text-rendering/似乎对PNG上的所有字符进行了编码,并将其从PNG上剪切下来。

SDL_ttf


指令集
来源:https://github.com/cirosantilli/cpp-cheat/blob/d36527fe4977bb9ef4b885b1ec92bd0cd3444a98/sdl/ttf.c
与SDL位于不同的树形结构中,可轻松整合。
但是,不提供纹理贴图集实现,因此性能将受到限制:How to render fonts and text with SDL2 efficiently?显示器

相关线程

js81xvg6

js81xvg62#

在普通OpenGL中绘制文本并不是一个简单的任务。你可能应该看看库来完成这个任务(通过使用库或作为示例实现)。
一些好的起点可以是GLFontOpenGL Font SurveyNeHe Tutorial for Bitmap Fonts (Windows)
请注意,位图并不是字体调查中提到的在OpenGL中实现文本的唯一方式。

91zkwejq

91zkwejq3#

This article描述如何使用各种技术在OpenGL中渲染文本。
仅用opengl,有几种方法:

  • 使用glBitmap
  • 使用材质
  • 使用显示列表
nwlqm0z1

nwlqm0z14#

使用glutStrokeCharacter(GLUT_STROKE_ROMAN, myCharString)
一个例子:一个星星大战卷轴。


# include <windows.h>

# include <string.h>

# include <GL\glut.h>

# include <iostream.h>

# include <fstream.h>

GLfloat UpwardsScrollVelocity = -10.0;
float view=20.0;

char quote[6][80];
int numberOfQuotes=0,i;

//*********************************************
//*  glutIdleFunc(timeTick);                  *
//*********************************************

void timeTick(void)
{
    if (UpwardsScrollVelocity< -600)
        view-=0.000011;
    if(view < 0) {view=20; UpwardsScrollVelocity = -10.0;}
    //  exit(0);
    UpwardsScrollVelocity -= 0.015;
  glutPostRedisplay();

}

//*********************************************
//* printToConsoleWindow()                *
//*********************************************

void printToConsoleWindow()
{
    int l,lenghOfQuote, i;

    for(  l=0;l<numberOfQuotes;l++)
    {
        lenghOfQuote = (int)strlen(quote[l]);

        for (i = 0; i < lenghOfQuote; i++)
        {
          //cout<<quote[l][i];
        }
          //out<<endl;
    }

}

//*********************************************
//* RenderToDisplay()                       *
//*********************************************

void RenderToDisplay()
{
    int l,lenghOfQuote, i;

    glTranslatef(0.0, -100, UpwardsScrollVelocity);
    glRotatef(-20, 1.0, 0.0, 0.0);
    glScalef(0.1, 0.1, 0.1);

    for(  l=0;l<numberOfQuotes;l++)
    {
        lenghOfQuote = (int)strlen(quote[l]);
        glPushMatrix();
        glTranslatef(-(lenghOfQuote*37), -(l*200), 0.0);
        for (i = 0; i < lenghOfQuote; i++)
        {
            glColor3f((UpwardsScrollVelocity/10)+300+(l*10),(UpwardsScrollVelocity/10)+300+(l*10),0.0);
            glutStrokeCharacter(GLUT_STROKE_ROMAN, quote[l][i]);
        }
        glPopMatrix();
    }

}
//*********************************************
//* glutDisplayFunc(myDisplayFunction);       *
//*********************************************

void myDisplayFunction(void)
{
  glClear(GL_COLOR_BUFFER_BIT);
  glLoadIdentity();
  gluLookAt(0.0, 30.0, 100.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
  RenderToDisplay();
  glutSwapBuffers();
}
//*********************************************
//* glutReshapeFunc(reshape);               *
//*********************************************

void reshape(int w, int h)
{
  glViewport(0, 0, w, h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(60, 1.0, 1.0, 3200);
  glMatrixMode(GL_MODELVIEW);
}

//*********************************************
//* int main()                                *
//*********************************************

int main()
{
    strcpy(quote[0],"Luke, I am your father!.");
    strcpy(quote[1],"Obi-Wan has taught you well. ");
    strcpy(quote[2],"The force is strong with this one. ");
    strcpy(quote[3],"Alert all commands. Calculate every possible destination along their last known trajectory. ");
    strcpy(quote[4],"The force is with you, young Skywalker, but you are not a Jedi yet.");
    numberOfQuotes=5;

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(800, 400);
    glutCreateWindow("StarWars scroller");
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glLineWidth(3);

    glutDisplayFunc(myDisplayFunction);
    glutReshapeFunc(reshape);
    glutIdleFunc(timeTick);
    glutMainLoop();

    return 0;
}
jfgube3f

jfgube3f5#

加载一个带有字符的图像作为纹理,并根据需要的字符绘制纹理的一部分。您可以使用绘图程序创建纹理,对其进行硬编码或使用窗口组件绘制图像,然后检索该图像以获得系统字体的精确副本。
不需要使用Glut或任何其他扩展,只是基本的OpenGL可操作性。它完成了工作,更不用说它已经这样做了几十年的专业程序员在非常成功的游戏和其他应用程序。

5n0oy7gb

5n0oy7gb6#

我认为在OpenGL中绘制文本的最佳解决方案是纹理字体,我使用它们很长时间了。它们灵活、快速、美观(与一些后方例外)。我使用特殊的程序转换字体文件(例如.ttf)到纹理,保存为某种内部“字体”格式的文件(我已经开发了基于http://content.gpwiki.org/index.php/OpenGL:Tutorials:Font_System的格式和程序,虽然我的版本与最初支持Unicode等的版本相差很远)。字体是从此'内部'格式加载有关详细信息,请查看上面链接
使用这种方法,主应用程序不使用任何特殊的库,如FreeType,这对我来说也是不可取的。

相关问题