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

C++ 如何仅使用OpenGL方法绘制文本?,c++,c,opengl,graphics,C++,C,Opengl,Graphics,我没有选择使用OpenGL方法(即glxxx()methods)。我只需要使用gl方法绘制文本。阅读红皮书后,我了解到只有通过glBitmap()方法才能实现。如果这是唯一可能的方法,那么任何人都可以帮助我获得所有字符的像素阵列信息。还有其他方法可以绘制文本吗?介绍了如何使用各种技术在OpenGL中渲染文本 仅使用opengl时,有几种方法: 使用glBitmap 使用纹理 使用显示列表 在纯OpenGL中绘制文本不是一项艰巨的任务。您可能应该看看实现这一点的库(通过使用库或作为示例实现) 一

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

介绍了如何使用各种技术在OpenGL中渲染文本

仅使用opengl时,有几种方法:

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

    • 在纯OpenGL中绘制文本不是一项艰巨的任务。您可能应该看看实现这一点的库(通过使用库或作为示例实现)

      一些好的起点可能是,和


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

      我认为在OpenGL中绘制文本的最佳解决方案是纹理字体,我使用它们已经很长时间了。它们灵活、快速、美观(有些后部例外)。我使用特殊的程序将字体文件(.ttf)转换为纹理,纹理保存到一些内部“字体”格式的文件中(我开发的格式和程序基于此,尽管我的版本与最初支持Unicode的版本相差甚远等等)。启动主应用程序时,字体将从此“内部”格式加载。查看上面的链接了解更多信息

      使用这种方法,主应用程序不使用任何特殊的库,比如FreeType,这对我来说也是不可取的。正在使用标准OpenGL函数绘制文本。

      使用
      glutStrokeCharacter(GLUT\u STROKE\u 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;
      }
      
      #包括
      #包括
      #包括
      #包括
      #包括
      GLfloat向上滚动速度=-10.0;
      浮动视图=20.0;
      char quote[6][80];
      int numberOfQuotes=0,i;
      //*********************************************
      //*glutIdleFunc(时间刻度)*
      //*********************************************
      void timeTick(void)
      {
      如果(向上滚动速度<-600)
      视图-=0.000011;
      如果(视图<0){view=20;UpwardsScrollVelocity=-10.0;}
      //出口(0);
      向上滚动速度-=0.015;
      再发现();
      }
      //*********************************************
      //*printToConsoleWindow()*
      //*********************************************
      作废printToConsoleWindow()
      {
      int l,lenghOfQuote,i;
      
      对于(l=0;l加载具有字符作为纹理的图像,并根据所需的字符绘制该纹理的一部分。您可以使用绘制程序创建该纹理,对其进行硬编码,或使用窗口组件绘制图像,并检索该图像以获得系统字体的精确副本

      不需要使用Glut或任何其他扩展,只需要基本的OpenGL可操作性。它完成了任务,更不用说几十年来专业程序员在非常成功的游戏和其他应用程序中都是这样做的。

      为什么很难

      常用的字体格式(如和)是矢量轮廓格式:它们用于定义字母的边界

      将这些格式转换为像素数组(光栅化)过于具体,超出了OpenGL的范围,特别是因为OpenGL没有非直原语(例如,请参阅)

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

      然后OpenGL知道如何通过纹理很好地处理像素阵列

      纹理图谱

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

      更有效的方法是对计划使用的所有字符进行光栅化,并将它们填充到单个纹理上

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

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

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

      我怀疑将角色放置优化为最小纹理问题是一个NP难问题,请参见:

      在web开发中,同样的技术用于同时传输几个小图像(如图标),但在那里它被称为“CSS精灵”:用于隐藏网络的延迟,而不是CPU/GPU通信的延迟

      非CPU光栅方法

      还有一些方法不使用CPU光栅来创建纹理

      CPU rastering很简单,因为它尽可能少地使用GPU,但我们也开始考虑是否有可能进一步提高GPU的效率

      解释其他现有技术:

      • tesselation:将字体转换为小三角形。GPU非常擅长绘制三角形。缺点:
        • 生成一组三角形
        • O(n logn)三角形的CPU计算
      • 计算着色器上的曲线。Blinn Loop在2005年发表的一篇论文将此方法应用到地图上。缺点:复杂。请参阅:
      • 直接硬件实现,如。缺点:由于某些原因,没有广泛实现。请参阅:
      透视三维几何体内部的字体

      使用透视(与正交HUD相比)渲染3D几何体内部的字体要复杂得多,因为透视可以使角色的一部分更靠近屏幕,而比另一部分更大,从而使统一的CPU离散化(例如光栅、镶嵌)在靠近的部分看起来很糟糕
      make -f Makefile.linux64