Cir*_*四事件 55
为什么这很难
流行的字体格式如TrueType和OpenType是矢量轮廓格式:它们使用贝塞尔曲线来定义字母的边界.

图像来源.
将这些格式转换为像素数组(光栅化)过于具体,超出了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字体,使其成为最优雅的解决方案.
https://github.com/rougier/freetype-gl
是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(打包问题,一些上游),但它变得更好截至16.10.
没有一个很好的安装方法:https://github.com/rougier/freetype-gl/issues/115
像这个演示生成美丽的输出:
libdgx https://github.com/libgdx/libgdx/tree/1.9.2/extensions/gdx-freetype
示例/教程:
其他字体光栅化器
那些似乎不如FreeType好,但可能更轻量级:
Anton的OpenGL 4教程示例26"位图字体"
该字体由作者手动创建并存储在单个.png文件中.字母以图像形式存储在图像内.
这种方法当然不是很普遍,你会遇到国际化的困难.
建立:
make -f Makefile.linux64
Run Code Online (Sandbox Code Playgroud)
输出预览:
opengl-tutorial第11章"2D字体"
纹理是从DDS文件生成的.
该教程解释了如何使用CBFG和Paint.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渲染字体和文本?
相关主题
在普通的OpenGL中绘制文本不是一个向前的任务.您可能应该查看用于执行此操作的库(通过使用库或作为示例实现).
一些好的起点可能是GLFont,OpenGL字体调查和Nehe位图字体教程(Windows).
请注意,位图不是字体调查中提到的在OpenGL中实现文本的唯一方法.

使用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)
| 归档时间: |
|
| 查看次数: |
112246 次 |
| 最近记录: |