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

sat*_*h v 37 c c++ opengl graphics

我没有选择使用OpenGL方法(即glxxx()方法).我只需要使用gl方法绘制文本.读完红皮书后,我明白只有通过这种glBitmap()方法才有可能.如果这是唯一可行的方法,那么任何人都可以帮助我获取所有字符的像素数组信息.有没有其他方式来绘制文字?

Cir*_*四事件 55

理论

为什么这很难

流行的字体格式如TrueTypeOpenType是矢量轮廓格式:它们使用贝塞尔曲线来定义字母的边界.

图像来源.

将这些格式转换为像素数组(光栅化)过于具体,超出了OpenGL的范围,特别是因为OpenGl没有非直线基元(例如,参见为什么OpenGL中没有圆形或椭圆形基元?)

最简单的方法是首先在CPU上使用光栅字体,然后将像素数组作为纹理提供给OpenGL.

然后OpenGL知道如何通过纹理很好地处理像素数组.

纹理图集

我们可以为每个帧设置光栅字符并重新创建纹理,但这不是非常有效,特别是如果字符具有固定大小.

更有效的方法是对您计划使用的所有字符进行栅格化,并将它们塞在单个纹理上.

然后将其传输到GPU一次,并使用自定义uv坐标的纹理来选择正确的字符.

这种方法称为纹理图集,它不仅可以用于纹理,还可以用于其他重复使用的纹理,如2D游戏中的图块或Web UI图标.

完整纹理的维基百科图片本身取自freetype-gl,说明了这一点:

我怀疑优化字符放置到最小的纹理问题是一个NP难问题,请参阅:可以使用什么算法将不同大小的矩形打包成最小的矩形,以一种相当优化的方式?

在Web开发中使用相同的技术同时传输几个小图像(如图标),但它被称为"CSS Sprites":https://css-tricks.com/css-sprites/并用于隐藏网络的延迟而不是CPU/GPU通信的延迟.

非CPU栅格方法

还存在不将CPU栅格用于纹理的方法.

CPU rarstering很简单,因为它尽可能少地使用GPU,但我们也开始考虑是否可以进一步使用GPU效率.

此FOSDEM 2014视频介绍了其他现有技术:

具有透视的3D几何体内的字体

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

在此输入图像描述

距离场是现在流行的技术之一.

实现

以下示例均在Ubuntu 15.10上进行了测试.

因为这是一个复杂的问题,如前所述,大多数示例都很大,并且会破坏这个答案的30k char限制,所以只需克隆相应的Git存储库进行编译.

但它们都是完全开源的,所以你可以只使用RTFS.

FreeType解决方案

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

示例/教程:

其他字体光栅化器

那些似乎不如FreeType好,但可能更轻量级:

Anton的OpenGL 4教程示例26"位图字体"

该字体由作者手动创建并存储在单个.png文件中.字母以图像形式存储在图像内.

这种方法当然不是很普遍,你会遇到国际化的困难.

建立:

make -f Makefile.linux64
Run Code Online (Sandbox Code Playgroud)

输出预览:

在此输入图像描述

opengl-tutorial第11章"2D字体"

纹理是从DDS文件生成的.

该教程解释了如何使用CBFGPaint.Net创建DDS文件.

输出预览:

在此输入图像描述

出于某种原因,Suzanne对我来说不见了,但时间计数器工作正常:https://github.com/opengl-tutorials/ogl/issues/15

FreeGLUT

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

OpenGLText

https://github.com/tlorach/OpenGLText

TrueType栅格.由NVIDIA员工.旨在实现可重用性.尚未尝试过.

ARM Mali GLES SDK示例

http://malideveloper.arm.com/resources/sample-code/simple-text-rendering/似乎编码PNG上的所有字符,并从那里剪切它们.

SDL_ttf

在此输入图像描述

资料来源:https://github.com/cirosantilli/cpp-cheat/blob/d36527fe4977bb9ef4b885b1ec92bd0cd3444a98/sdl/ttf.c

生活在SDL的单独树中,并且可以轻松集成.

但是,不提供纹理图集实现,因此性能将受到限制:如何有效地使用SDL2渲染字体和文本?

相关主题


lar*_*moa 8

在普通的OpenGL中绘制文本不是一个向前的任务.您可能应该查看用于执行此操作的库(通过使用库或作为示例实现).

一些好的起点可能是GLFont,OpenGL字体调查Nehe位图字体教程(Windows).

请注意,位图不是字体调查中提到的在OpenGL中实现文本的唯一方法.


Sof*_*ner 8

在此输入图像描述

使用glutStrokeCharacter(GLUT_STROKE_ROMAN, myCharString).

一个例子:一个STAR WARS SCROLLER.

#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;
}
Run Code Online (Sandbox Code Playgroud)

  • glutStrokeCharacter不是opengl函数 (48认同)
  • 它符合glxxx()OP要求虽然:) (18认同)

BЈо*_*вић 6

本文介绍如何使用各种技术在OpenGL中呈现文本.

只使用opengl,有几种方法:

  • 使用glBitmap
  • 使用纹理
  • 使用显示列表


归档时间:

查看次数:

112246 次

最近记录:

6 年,7 月 前