Lighthouse3d.com >> GLUT Tutorial >> Fonts >> Bitmap Fonts and Orthogonal Projections

一般用法下,位图字体只能以二维的形式显示信息给用户.例如,一个简单的例子,我们想显示应用程序每秒的帧数.这些信息可以驻留在同一个位置,即使用户移动镜头.除此之外,用二维的正交投影比透视投影更容易计算这些位置,因为我们可以指定用像素表示该位置.

实现的基本模式是以之前的方式绘制世界,用透视投影,然后切换到正交投影来绘制文本.执行完最后一步之后我们要恢复到原来的视角,这样下一帧就会正确显示.

接下来我们演示一个渲染函数的模板来大道该效果:

void renderScene() {

// do everything we need to render the world as usual
... setOrthographicProjection(); glPushMatrix();
glLoadIdentity();
renderBitmapString(,,GLUT_BITMAP_HELVETICA_18,"Lighthouse3D");
glPopMatrix(); restorePerspectiveProjection(); glutSwapBuffers();
}

上面有两个新函数: setOrthograpicProjection and restorePerspectiveProjection.第一个函数始于转换矩阵模式到GL_PROJECTION,意味着我们在镜头下工作.然后我们保存之前的设置,在这个例子中是引用自其它某处定义好的透视投影.然后我们用glLoadIdentity函数重置矩阵,并用gluOrtho函数定义一个正交投影.

该函数的参数是表示从x到y轴的范围.然后转换沿着y轴滑动,正值是向下,翻译成原型是到左上角.这样使输出文本到屏幕坐标更简单.

变量w和h在其它地方计算好(见之前changeSize函数).

void setOrthographicProjection() {

    // switch to projection mode
glMatrixMode(GL_PROJECTION); // save previous matrix which contains the
//settings for the perspective projection
glPushMatrix(); // reset matrix
glLoadIdentity(); // set a 2D orthographic projection
gluOrtho2D(, w, , h); // invert the y axis, down is positive
glScalef(, -, ); // mover the origin from the bottom left corner
// to the upper left corner
glTranslatef(, -h, ); // switch back to modelview mode
glMatrixMode(GL_MODELVIEW);
}

一个演示正交投影的快速方法如下.方法是设置投影而无需测量和翻译.

void setOrthographicProjection() {

    // switch to projection mode
glMatrixMode(GL_PROJECTION); // save previous matrix which contains the
//settings for the perspective projection
glPushMatrix(); // reset matrix
glLoadIdentity(); // set a 2D orthographic projection
gluOrtho2D(, w, h, ); // switch back to modelview mode
glMatrixMode(GL_MODELVIEW);
}

该函数非常简单.当我们在设置正交投影前保存透视投影的设置的时候,我们需要做的只是更改矩阵模式到GL_PROJECTION,然后弹出矩阵.然后恢复设置,最后更改矩阵模式回GL_MODELVIEW.

void restorePerspectiveProjection() {

    glMatrixMode(GL_PROJECTION);
// restore previous projection matrix
glPopMatrix(); // get back to modelview mode
glMatrixMode(GL_MODELVIEW);
}

上面这个renderBitmapString函数,上一节介绍过,会连续写入字符,不包含额外的空间,除了文本本身带有空格字符外.为了添加额外的空间,我们必须保持跟踪当然的栅格位置,这样才可以添加额外的空间到x坐标.至少有两种不同的方法来保持跟踪栅格位置.一种是在绘制完一张位图之后计算当前的栅格位置.另一种是专注于请求OpenGL的关于当前栅格位置的状态机器.

第一种方法需要我们知道字符的维度.最大的高度一直保持为一个特殊字体的常量,在多数字体中宽度是可以任意变更的.幸运的是GLUT提供了一个函数来返回字宽.glutBitmapWidth原型如下:

int glutBitmapWidth(void *font, int character);

font - GLUT中的预定义字体之一,见上一节中列出的可选值

character - 我们想要知道字宽的字符

所以,例如我们需要一个函数来写入一个固定每个字符所占像素量的字符串,我们可以如下实现:

void renderSpacedBitmapString(

            float x,
float y,
int spacing,
void *font,
char *string) { char *c;
int x1=x; for (c=string; *c != '\0'; c++) { glRasterPos2f(x1,y);
glutBitmapCharacter(font, *c);
x1 = x1 + glutBitmapWidth(font,*c) + spacing;
}
}

如果我们想要绘制垂直的文本,可以如下实现:

void renderVerticalBitmapString(

            float x,
float y,
int bitmapHeight,
void *font,
char *string) { char *c;
int i; for (c=string,i=; *c != '\0'; i++,c++) { glRasterPos2f(x, y+bitmapHeight*i);
glutBitmapCharacter(font, *c);
}
}

变量bitmapHeight可以很容易计算得出,因为我们知道每个字体的最大高度,就是字体名的最后那串数字.例如GLUT_BITMAP_TIMES_ROMAN_10是占10个像素的高度.

最后一件事是,GLUT提供了另外一个函数来处理位图字体,就是glutBitMapLength函数,它可以以像素为单位计算一个字符串的长度.函数的返回值是字符串中字符的宽度总和.原型如下:

int glutBitmapLength(void *font, char *string);

font -  GLUT中的预定义字体之一,见上一节中列出的可选值

string - 我们想要知道字宽的字符串

[译]GLUT教程 - 位图和正交投影视图的更多相关文章

  1. [译]GLUT教程 - 位图字体

    Lighthouse3d.com >> GLUT Tutorial >> Fonts >> Bitmap Fonts 位图字体一般是二维字体.虽然我们会把它放到三维 ...

  2. [译]GLUT教程(目录)

    http://www.lighthouse3d.com/tutorials/glut-tutorial/ GLUT是OpenGL Utility Toolkit的意思.作者Mark J. Kilgar ...

  3. [译]GLUT教程 - 整合代码5

    Lighthouse3d.com >> GLUT Tutorial >> Extras >> The Code So Far V 该代码与位图字体的代码类似.区别是 ...

  4. [译]GLUT教程 - 渲染到子窗体

    Lighthouse3d.com >> GLUT Tutorial >> Subwindows >> Rendering to Subwindows 先回顾一下之前 ...

  5. [译]GLUT教程 - 整合代码6

    Lighthouse3d.com >> GLUT Tutorial >> Extras >> The Code So Far VI 下面代码以窗体模式启动.你可以在 ...

  6. [译]GLUT教程 - 游戏模式

    Lighthouse3d.com >> GLUT Tutorial >> Extras >> Game Mode 根据GLUT官网的说明,GLUT的游戏模式是为开启 ...

  7. [译]GLUT教程 - 笔划字体

    Lighthouse3d.com >> GLUT Tutorial >> Fonts >> Stroke Fonts 笔划字体是用线条生成的.跟位图字体相反,笔划字 ...

  8. [译]GLUT教程 - 整合代码4

    Lighthouse3d.com >> GLUT Tutorial >> Pop-up Menus >> The Code So Far IV 以下代码使用了位图字 ...

  9. [译]GLUT教程 - glutPostRedisplay函数

    Lighthouse3d.com >> GLUT Tutorial >> Avoiding the Idle Func >> glutPostRedisplay 直 ...

随机推荐

  1. vue插槽slot的理解与使用

    一.个人理解及插槽的使用场景 刚开始看教程我的疑惑是为什么要用插槽,它的使用场景是什么,很多解释都是“父组件向子组件传递dom时会用到插槽”,这并不能很好的解决我的疑惑.既然你用了子组件,你为什么要给 ...

  2. poj3415(后缀数组)

    poj3415 题意 给定两个字符串,给出长度 \(m\) ,问这两个字符串有多少对长度大于等于 \(m\) 且完全相同的子串. 分析 首先连接两个字符串 A B,中间用一个特殊符号分割开. 按照 \ ...

  3. C# Json格式字符串

    转自:http://www.cnblogs.com/unintersky/p/3884712.html 将Json字符串转化成格式化表示的方法: 字符串反序列化为对象-->对象再序列化为字符串 ...

  4. 快速搭建一个restful风格的springboot项目

    1.创建一个工程. 2.引入pom.xml依赖,如下 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi ...

  5. perl一次读取多行文本的策略

    在处理文本时,经常遇到这种情况:就是我们须要把两行文本做一个比較,然后选择性输出. 而在while(<FILEHAND>){do something}程序块中默认仅仅能一次读取一行.笔者在 ...

  6. python xml与字典的相互转换

    def trans_xml_to_dict(xml): """ 将微信支付交互返回的 XML 格式数据转化为 Python Dict 对象 :param xml: 原始 ...

  7. ES6中的Map集合(与java里类似)

    Set类型可以用来处理列表中的值,但是不适用于处理键值对这样的信息结构.ES6也添加了Map集合来解决类似的问题 一.Map集合 JS的对象(Object),本质上是键值对的集合(Hash结构),但是 ...

  8. log4j教程 8、日志格式化

    Apache log4j 提供了各种布局对象,每一个对象都可以根据各种布局格式记录数据.另外,也可以创建一个布局对象格式化测井数据中的特定应用的方法. 所有的布局对象 - Appender对象收到 L ...

  9. java、freemarker保留两位小数

    一.Java保留2位小数 double acc = 22.4322; String accX = String.format("%.2f", acc); 二.freemarker保 ...

  10. Spring 配置多个数据源,并实现动态切换

    1.配置两个不同的数据源,如下 <!-- 数据源配置1 --> <bean id="testDataSource1" class="com.alibab ...