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

2021-12-19 00:00:00 opengl c graphics c++

我只能选择使用 OpenGL 方法(即 glxxx() 方法).我只需要使用 gl 方法绘制文本.看了红皮书才明白,只有通过glBitmap()方法才有可能.如果这是唯一可能的方法,那么任何人都可以帮助我处理所有字符的像素阵列信息.有没有其他方法可以绘制文字?

解决方案

理论

为什么难

流行的字体格式,如 .

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

在 Web 开发中使用相同的技术一次传输多个小图像(如图标),但在那里称为CSS Sprites":

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

实施

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

因为如前所述,这是一个复杂的问题,大多数示例都很大,并且会超出此答案的 30k 字符限制,因此只需克隆相应的 Git 存储库即可编译.

不过,它们都是完全开源的,因此您可以只使用 RTFS.

FreeType 解决方案

  • libdgx

    opengl-tutorial 第 11 章二维字体"

    • 教程:

      由于某种原因苏珊娜对我来说不见了,但时间计数器工作正常:

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

      与 SDL 位于单独的树中,并且易于集成.

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

      相关主题

      • 如何为 GUI 进行 OpenGL 实时文本渲染?
      • 文本/字体渲染OpenGLES 2(iOS - CoreText?)- 选项和最佳实践?

      I don't have the option to use but OpenGL methods (that is glxxx() methods). I need to draw text using gl methods only. After reading the red book, I understand that it is possible only through the glBitmap() method. If this is the only possible way, then can any one help me with the pixel array information for all the characters. Is there is any other way to draw text?

      解决方案

      Theory

      Why it is hard

      Popular font formats like TrueType and OpenType are vector outline formats: they use Bezier curves to define the boundary of the letter.

      Image source.

      Transforming those formats into arrays of pixels (rasterization) is too specific and out of OpenGL's scope, specially because OpenGl does not have non-straight primitives (e.g. see Why is there no circle or ellipse primitive in OpenGL?)

      The easiest approach is to first raster fonts ourselves on the CPU, and then give the array of pixels to OpenGL as a texture.

      OpenGL then knows how to deal with arrays of pixels through textures very well.

      Texture atlas

      We could raster characters for every frame and re-create the textures, but that is not very efficient, specially if characters have a fixed size.

      The more efficient approach is to raster all characters you plan on using and cram them on a single texture.

      And then transfer that to the GPU once, and use it texture with custom uv coordinates to choose the right character.

      This approach is called a texture atlas and it can be used not only for textures but also other repeatedly used textures, like tiles in a 2D game or web UI icons.

      The Wikipedia picture of the full texture, which is itself taken from freetype-gl, illustrates this well:

      I suspect that optimizing character placement to the smallest texture problem is an NP-hard problem, see: What algorithm can be used for packing rectangles of different sizes into the smallest rectangle possible in a fairly optimal way?

      The same technique is used in web development to transmit several small images (like icons) at once, but there it is called "CSS Sprites": https://css-tricks.com/css-sprites/ and are used to hide the latency of the network instead of that of the CPU / GPU communication.

      Non-CPU raster methods

      There also exist methods which don't use the CPU raster to textures.

      CPU rastering is simple because it uses the GPU as little as possible, but we also start thinking if it would be possible to use the GPU efficiency further.

      This FOSDEM 2014 video explains other existing techniques:

      • tesselation: convert the font to tiny triangles. The GPU is then really good at drawing triangles. Downsides:
        • generates a bunch of triangles
        • O(n log n) CPU calculation of the triangles
      • calculate curves on shaders. A 2005 paper by Blinn-Loop put this method on the map. Downside: complex. See: Resolution independent cubic bezier drawing on GPU (Blinn/Loop)
      • direct hardware implementations like OpenVG. Downside: not very widely implemented for some reason. See:
        • OpenGL, OpenVG. Draw text?
        • OpenVG implementation?

      Fonts inside of the 3D geometry with perspective

      Rendering fonts inside of the 3D geometry with perspective (compared to an orthogonal HUD) is much more complicated, because perspective could make one part of the character much closer to the screen and larger than the other, making an uniform CPU discretization (e.g. raster, tesselation) look bad on the close part. This is actually an active research topic:

      • What is state-of-the-art for text rendering in OpenGL as of version 4.1?
      • http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf

      Distance fields are one of the popular techniques now.

      Implementations

      The examples that follow were all tested on Ubuntu 15.10.

      Because this is a complex problem as discussed previously, most examples are large, and would blow up the 30k char limit of this answer, so just clone the respective Git repositories to compile.

      They are all fully open source however, so you can just RTFS.

      FreeType solutions

      FreeType looks like the dominant open source font rasterization library, so it would allow us to use TrueType and OpenType fonts, making it the most elegant solution.

      • https://github.com/rougier/freetype-gl

        Was a set of examples OpenGL and freetype, but is more or less evolving into a library that does it and exposes a decent API.

        In any case, it should already be possible to integrate it on your project by copy pasting some source code.

        It provides both texture atlas and distance field techniques out of the box.

        Demos under: https://github.com/rougier/freetype-gl/tree/master/demos

        Does not have a Debian package, and it a pain to compile on Ubuntu 15.10: https://github.com/rougier/freetype-gl/issues/82#issuecomment-216025527 (packaging issues, some upstream), but it got better as of 16.10.

        Does not have a nice installation method: https://github.com/rougier/freetype-gl/issues/115

        Generates beautiful outputs like this demo:

      • libdgx https://github.com/libgdx/libgdx/tree/1.9.2/extensions/gdx-freetype

      Examples / tutorials:

      • a NEHE tutorial: http://nehe.gamedev.net/tutorial/freetype_fonts_in_opengl/24001/
      • http://learnopengl.com/#!In-Practice/Text-Rendering mentions it, but I could not find runnable source code
      • SO questions:
        • OpenGL font rendering using Freetype2
        • Text not rendering correctly - OpenGL using FreeType2

      Other font rasterizers

      Those seem less good than FreeType, but may be more lightweight:

      • https://github.com/nothings/stb/blob/master/stb_truetype.h
      • http://www.angelcode.com/products/bmfont/

      Anton's OpenGL 4 Tutorials example 26 "Bitmap fonts"

      • tutorial: http://antongerdelan.net/opengl/
      • source: https://github.com/capnramses/antons_opengl_tutorials_book/blob/9a117a649ae4d21d68d2b75af5232021f5957aac/26_bitmap_fonts/main.cpp

      The font was created by the author manually and stored in a single .png file. Letters are stored in an array form inside the image.

      This method is of course not very general, and you would have difficulties with internationalization.

      Build with:

      make -f Makefile.linux64
      

      Output preview:

      opengl-tutorial chapter 11 "2D fonts"

      • tutorial: http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-11-2d-text/
      • source: https://github.com/opengl-tutorials/ogl/blob/71cad106cefef671907ba7791b28b19fa2cc034d/tutorial11_2d_fonts/tutorial11.cpp

      Textures are generated from DDS files.

      The tutorial explains how the DDS files were created, using CBFG and Paint.Net.

      Output preview:

      For some reason Suzanne is missing for me, but the time counter works fine: https://github.com/opengl-tutorials/ogl/issues/15

      FreeGLUT

      GLUT has glutStrokeCharacter and FreeGLUT is open source... https://github.com/dcnieho/FreeGLUT/blob/FG_3_0_0/src/fg_font.c#L255

      OpenGLText

      https://github.com/tlorach/OpenGLText

      TrueType raster. By NVIDIA employee. Aims for reusability. Haven't tried it yet.

      ARM Mali GLES SDK Sample

      http://malideveloper.arm.com/resources/sample-code/simple-text-rendering/ seems to encode all characters on a PNG, and cut them from there.

      SDL_ttf

      Source: https://github.com/cirosantilli/cpp-cheat/blob/d36527fe4977bb9ef4b885b1ec92bd0cd3444a98/sdl/ttf.c

      Lives in a separate tree to SDL, and integrates easily.

      Does not provide a texture atlas implementation however, so performance will be limited: How to render fonts and text with SDL2 efficiently?

      Related threads

      • How to do OpenGL live text-rendering for a GUI?
      • Text/font rendering in OpenGLES 2 (iOS - CoreText?) - options and best practice?
  • 相关文章