OpenGL快问快答

OpenGL快问快答

本文内容主要来自对(http://www.opengl.org/wiki/FAQ)的翻译,随机加入了本人的观点。与原文相比,章节未必完整,含义未必雷同,顺序未必一致。仅供参考。

+BIT祝威+悄悄在此留下版了个权的信息说:

名词术语

渲染:等于"画",等于"draw"。

OpenGL是什么?

OpenGL是Open Graphics Library(开源图形库)的缩写。它是一本说明书,是一个PDF文件。它写的是渲染三维图形所使用的API(Application Programming Interface)。OpenGL实现是实现了说明书里定义的那些API的函数库。

简单理解:OpenGL是一个关于C语言函数声明的*.h文件。

普通显卡里都有一个OpenGL实现。犯二显卡里可能没有。所以你才能通过include一个"gl.h"之类的头文件就能编写运行OpenGL程序。OpenGL说明书是平台无关的,所以你写的OpenGL程序能够在多种显卡上运行,并且可能支持以后出现的新型显卡。

OpenGL不是什么?

OpenGL的API只处理渲染什么图形的问题。OpenGL实现处理如何渲染图形的问题。作为OpenGL使用者,我们不学如何渲染图形的问题,只学渲染什么图形的问题。OpenGL里没有处理动画、计时、文件读写、图片格式、GUI这些功能的函数。OpenGL只关心渲染。

GLUT不是OpenGL。GLUT也不是OpenGL的一部分。它是一个库,可以用来创建OpenGL窗口。

OpenGL说明书是谁写的?

OpenGL说明书是OpenGL Architectural Review Board(简称ARB)编写和维护的。

OpenGL是开源的吗?

不。因为OpenGL根本就没有代码,它只是一本说明书。说明书里讲的是程序员可以使用哪些函数,这些函数应该做什么。准确来说,OpenGL是一套理论,一些函数声明,一本开源的说明书,人人都可以免费下载。ISO的标准和说明书就不是免费下载的。

有一个开源的OpenGL实现(估计这是提问者想要的东西),名字是Mesa3D。它自称实现了 OpenGL 3.0GLSL 1.30。反正我没研究过。

在哪儿下载OpenGL?

如"开源"之问,OpenGL不是一个软件产品,它是一本说明书。在苹果电脑上,自动集成了OpenGL的实现。

在Windows系统上,nVidia和AMD/ATI等公司根据OpenGL说明书实现了各自的OpenGL功能。所以说OpenGL功能包含在他们提供的显卡驱动里。

如果你的OpenGL版本不够新,更新显卡驱动就可以了。

程序员编程时需要获取OpenGL函数指针(手动加载自动加载),这可以参考openGL入门

OpenGL有SDK吗?

没有。

不过文档、教程之类的还是有的,比如这里

NVIDIA 和ATI关于OpenGL有各自的SDK,且富含示例代码。

哪些平台支持OpenGL?

Windows:95及其以上。

苹果:所有版本。

Linux:由开源驱动、Mesa库或专有Nvidia驱动提供。

嵌入式系统中通常支持OpenGL ES。但是OpenGL ES是一套不同于传统的OpenGL的API。

+BIT祝威+悄悄在此留下版了个权的信息说:

OpenGL上下文是什么?

(详情参见 OpenGL context

OpenGL能画很大很复杂很绚丽的三维世界,它肯定要用一些变量记录一些状态、编号,把这些状态、编号集合起来,作为一个整体,就是OpenGL上下文。OpenGL看到这些状态、编号,才知道自己应该画什么,所以叫做上下文。

你必须先创建一个OpenGL上下文,之后才能调用OpenGL函数。像下面这样直接调用是不行的:

1 int main(int argc, char **argv)
2 {
3     char *GL_version=(char *)glGetString(GL_VERSION);
4     char *GL_vendor=(char *)glGetString(GL_VENDOR);
5     char *GL_renderer=(char *)glGetString(GL_RENDERER);
6     return 0;
7 }

 

这段代码中,程序员只是想获取OpenGL版本信息,但是失败了。因为这段代码还没有与OpenGL驱动器开始对话。

假如你想问一个人的名字,至少得先找个人在你面前。上面这段代码就等于直接对空气问"what's your name?"。

如果是我,我会想让上帝给我找一个大学生,性别女,爱好男,学习成绩好,性格温和,相貌端庄,无不良嗜好……然后问"你喜欢吃青椒吗?"。

类似地,我想用OpenGL时,我会想让OpenGL驱动器给我分配一块显卡上的内存,指定像素格式、色彩缓存格式、深度缓存、模版缓存、累积缓存、是否启用光照、雾等,然后才能使用上面那段代码。

 

如何实现离屏渲染?

有人想做离屏渲染:渲染的时候不显示窗口。唯一的方法是:像平常一样创建窗口,然后把窗口隐藏起来。你指定像素格式,创建OpenGL上下文,把它置为当前上下文,然后调用OpenGL函数进行渲染。建议你创建一个FBO渲染到FBO上,否则可能会失败。这方面的详情请参考:

    http://www.opengl.org/wiki/Common_Mistakes#The_Pixel_Ownership_Problem

    http://www.opengl.org/wiki/Common_Mistakes#The_Object_Oriented_Language_Problem

    http://www.opengl.org/wiki/Platform_specifics

OpenGL程序在Windows上是如何实现的?

当你编译一个App时,会链接opengl32.dll

当你运行此App,opengl32.dll会被加载并检测是否存在OpenGL驱动器。如果存在,就加载驱动器。例如,ATI的OpenGL驱动器是atioglxx.dll而NVIDIA的是nvoglv32.dll。(这两个文件名可能随版本不同而有所差异。)

opengl32.dll仅直接包含OpenGL 1.1的函数。想使用更高版本里的函数的话,你必须使用 wglGetProcAddress 来手动获取其函数指针。详情在此。有一些辅助库帮你做这件事,被称为 Extension Loading Libraries

重要的是要知道opengl32.dll属于Microsoft。所以不要改动它,不要替换它,也不要在发布你的App时把它加安装包。也不要把nvoglv32.dll(或者其它系统文件)加入安装包。

安装OpenGL驱动是用户的事,不管他们是从哪里(Dell、HP、nVidia、ATI/AMD……)下载。你可以提醒他们,这很正常。

+BIT祝威+悄悄在此留下版了个权的信息说:

我的OpenGL版本是多少?

使用 glGetString,传入参数 GL_VERSION。它会返回一个字符串(可能很长)。

在OpenGL 3.0以上,也可以用 glGetIntegerv(GL_MAJOR_VERSION, *)  和 glGetIntegerv(GL_MINOR_VERSION, *) 。

想获取你的GPU支持的OpenGL最高版本?更新你的显卡驱动即可,OpenGL就在里面。

假如你当前的OpenGL版本是2.0,而你的GPU却不支持更高版本,那么显卡厂商可能就不给你做新的驱动了。

这怎么破?两个办法:买个新显卡,或者使用Mesa3D(纯软件实现的OpenGL,在http://www.mesa3d.org)。不过截止到本文编写时(2015年5月11日),Mesa3D只支持到OpenGL 3.3,而最新的OpenGL说明书已经出到OpenGL 4.5了。

 

为什么我的OpenGL版本只有1.4或者更低?

可能原因有三:

1.    在Windows上,如果你创建OpenGL上下文时使用了未加速的(我也不知道什么叫"加速")像素格式,你就只能得到OpenGL1.1版本。

解决办法是小心选择像素格式,详情参考Platform_specifics:_Windows或自行百度。

2.    另一个原因是你的显卡及其驱动厂商没有提供新版的OpenGL实现。好多显卡厂商都已经关门大吉了,哪有什么售后。

不过,在那些尚未死掉的厂商里,Intel集成显卡最容易出这个问题。对此我们无计可施。NVIDIA 和ATI就很好地支持他们的集成显卡更新。

3.    最后,检查一下你有没有安装显卡驱动吧。

glGetString检测OpenGL版本正常时,你就万事俱备了。

 

glTranslate/glRotate/glScale 有硬件加速吗?

没有。

没有GPU直接支持这三个家伙。他们已经在OpenGL 3.0被标记为弃用了。你应该用你自己的数学库,自己构造矩阵,把矩阵上传到shader这里有几个库你可以试试。

+BIT祝威+悄悄在此留下版了个权的信息说:

现代GPU还支持固定功能管道吗?

(详情参见 Legacy OpenGL

现在GPU不再为管道中的某步计算提供专门的硬件。所有的计算都由shader完成。为了保持兼容性,OpenGL驱动器生成一个特别的shader,这个shader模仿了固定功能管道。

例如渲染一个图元,固定功能管道的方式是在glBegin() 和glEnd() 之间用glVertex3f( , , ),提交各个顶点的位置属性。使用shader的方式时,你必须先在内存中用数组保存所有顶点的属性,然后创建缓存对象,最后用glBufferDataglBufferSubDataglMapBuffer或者glMapBufferRange把数组上传到显卡内存中。这样shader就可以用上传的数据进行渲染了。

 

如何在像素空间渲染?(在屏幕固定位置渲染一个模型)

指定这样一个投影矩阵:

1 glMatrixMode(GL_PROJECTION);
2 glLoadIdentity();
3 glOrtho(0.0, WindowWidth, 0.0, WindowHeight, -1.0, 1.0);
4 //Setup modelview to identity if you don't need GL to move around objects for you
5 glMatrixMode(GL_MODELVIEW);
6 glLoadIdentity();

注意,在glOrtho中Y轴是从下到上的。当然你可以通过交换bottom和top参数来翻转Y轴。你得保证你用正确的顺序(顺时针or逆时针)渲染多边形,不然OpenGL可能会剔除它。保证不了就禁用剔除: glDisable(GL_CULL_FACE); 。

 

怎么画全屏四边形?

经常有人问,怎么画一个四边形,让它覆盖全屏?这需要什么样的投影矩阵?

投影矩阵用单位矩阵就可以了。在老版OpenGL,你可以用

1 glMatrixMode(GL_PROJECTION);
2 glLoadIdentity();
3 glMatrixMode(GL_MODELVIEW);
4 glLoadIdentity();

在使用shader的OpenGL里,GLSL代码甚至不需要矩阵。这样就行:

#version 110
void main()
{
    gl_Position = gl_Vertex; //Just output the incoming vertex
}

当然,这要求四边形的顶点得是:{-1.0, -1.0, 0.0}, {1.0, -1.0, 0.0}, {1.0, 1.0, 0.0}, {-1.0, 1.0, 0.0}。

多索引渲染?

多索引渲染的意思是,每种顶点属性(位置、法向量等)都有自己的索引数组。OpenGL和Direct3D都不支持多索引渲染。

程序员必须自己调整数据格式,使得各种顶点属性的数组长度相同。这样才能使用单一的索引。

使用OBJ文件格式的同学经常问这个问题。

 1 v 1.52284 39.3701 1.01523
 2 v 36.7365 17.6068 1.01523
 3 v 12.4045 17.6068 -32.475
 4 and so on ...
 5 n 0.137265 0.985501 -0.0997287
 6 n 0.894427 0.447214 -8.16501e-08
 7 n 0.276393 0.447214 -0.850651
 8 and so on ...
 9 t 0.6 1
10 t 0.5 0.647584
11 t 0.7 0.647584
12 and so on ...
13 f 102/102/102 84/84/84 158/158/158
14 f 158/158/158 84/84/84 83/83/83
15 f 158/158/158 83/83/83 159/159/159
16 and so on ...

以f开头的行是面(face)。每个顶点都有三个索引,分别是位置、法向量和贴图坐标(v、n和t)。上面的例子里,幸运的是每个{位置, 法向量, 贴图坐标}里的三个分量都是相等的。你得处理它们不相等的情况,比如:

1 f 1/1/1 2/2/2 3/2/2
2 f 5/5/5 6/6/6 3/4/5

这里的3/2/2和3/4/5就是两个不同的顶点。

所以加载OBJ文件后你得做一些后处理。OBJ文件里的顶点位置数、法向量数、贴图坐标数……都要相同。例如,你有10各顶点的位置,那么你必须有10个法向量与之对应。你不能有10个顶点的位置却只有7个法向量。

你有三个选项:

1. 为顶点的每个属性分别分配一个数组。

2. 创建一个数组,交错填入各个属性值。

3. 创建一个数组,依次填入各个属性。(例如,先把所有位置属性放到数组开头,然后放法向量,最后放贴图坐标)。

详情可参考Vertex Specification

+BIT祝威+悄悄在此留下版了个权的信息说:

画立方体

很多人都需要画立方体,所以这个问题值得一提。

从上一个问题我们知道,OpenGL只支持单一索引。

由于立方体的面是平的,我们可以用平面着色来渲染各个面。这意味着每个面都只有1个法向量。但是OpenGL只知道顶点的法向量,面的法向量是通过顶点的法向量计算出来的。那么办法来了:把画立方体的工作看做画6个互不相干的正方形的工作。这就是说要把一个顶点复制2次,变为3个。自己体会。

还有个办法,如下代码所示:

 1 //The following code is for GL 2.0
 2 
 3 //Render face 1
 4 glNormal3fv(mynormal1); //Set your face normal
 5 glBindBuffer(GL_ARRAY_BUFFER, VertexVBOID);
 6 glEnableClientState(GL_VERTEX_ARRAY);
 7 glVertexPointer(3, GL_FLOAT, sizeof(MyVertex), BUFFER_OFFSET(0)); //The starting point of the VBO, for the vertices
 8 glClientActiveTexture(GL_TEXTURE0);
 9 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
10 glTexCoordPointer(2, GL_FLOAT, sizeof(MyVertex), BUFFER_OFFSET(12)); //The starting point of texcoords, 12 bytes away
11 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexVBOID); //Bind the IBO
12 glDrawElements(GL_QUADS, 4, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));
13 
14 //Render face 2
15 glNormal3fv(mynormal2); //Set your face normal
16 //We can just call glDrawElements since the rest of the setup is already done above
17 glDrawElements(GL_QUADS, 4, GL_UNSIGNED_SHORT, BUFFER_OFFSET(16));
18 
19 //.... and render face 3 and 4 and 5 and 6

上述代码中,缺点是渲染1个立方体就需要6次调用 glDrawElements,且使用了被鄙视的 glNormal3fv这个函数。 glNormal3fv不使用VBO里的数据,很low。

但是也有一点好处,绘制1个立方体可以节省3个法向量 * 3个浮点数 * 4字节 * 6 面= 216 字节。

glClear和 glScissor

glScissor 是为数不多的几个影响glClear的函数之一。如果你只想清除画面上某一块区域,就调用 glScissor 和glEnable(GL_SCISSOR_TEST)

如果你忘记用glDisable(GL_SCISSOR_TEST);关闭剪切测试,glClear就可能会出奇奇怪怪的问题。

屏蔽(Masking)

小心使用 glColorMask ,  glStencilMask 和 glDepthMask 。如果你用 glDepthMask(FALSE); 禁掉了深度写入,那么所有对 glClear 的调用都不会清除深度缓存。

+BIT祝威+悄悄在此留下版了个权的信息说:

glGetError (如何检查OpenGL错误?)

(详情参见GL Error Codes

OpenGL保存最近一次的各种类型的错误,每调用一次glGetError() 就返回一个类型的错误代码并清除其记录。如果一个错误记录都没有,就返回 GL_NO_ERROR 。

这个辅助函数可用于查询最近所有命中的错误:

 1 int CheckGLErrors()
 2 {
 3     int errCount = 0;
 4     for(GLenum currError = glGetError(); currError != GL_NO_ERROR; currError = glGetError())
 5     {
 6         //Do something with `currError`.
 7         ++errCount;
 8     }
 9 
10     return errCount;
11 }

这个函数主动轮询错误信息。这会降低性能。所以最好只在debug版的程序里使用。

有个OpenGL扩展(ARB_debug_output)提供另一种机制来进行错误处理,且不需要轮询。开销也很明显,且只在拥有 CONTEXT_DEBUG_BIT_ARB 标记的上下文里才能用。它在OpenGL 4.3里成为了核心特性(KHR_debug),你随时可以用,但是在非debug上下文里不会有实际有效的log信息。

 

我应该用什么3D文件格式?

新手往往对使用哪种3D文件格式感到没底。

OpenGL不加载文件。所以,你可以用任何网格格式。这也意味着你得自己编写格式解析代码,OpenGL不管。

现有的文件格式各具特色。下述格式都可以用Open Asset Import 库解析。

Wavefront.obj

此格式较简单。每个.obj文件描述一个单独的网格。Obj文件可以引用外部的材质文件(存储为.mtl格式,比较少见)。Obj里的网格只能包含位置、法向量和贴图坐标(可有可无)。

Autodesk.3ds

这是二进制的网格格式。包含材质信息,能存储多个命名的网格。

Quake2.md2 and Quake3.md3

也是二进制网格格式。不含材质信息,只存储一个网格。支持关键帧动画,就是说一个单独的网格文件可能含有所有的关键帧及动画数据。

COLLADA

这是基于XML的网格文件格式。什么玩意都能存。它适合用在不同的3D文件格式之间互相转换上。

+BIT祝威+悄悄在此留下版了个权的信息说:

OpenGL有内存泄漏吗?

没有

常常有人认为OpenGL驱动器发生了内存泄漏。他们写下如下的代码:

1 glClear(...);
2 SwapBuffers(...);

然后他们观察到:每次渲染都会使内存占用量增长。

这其实很正常。驱动器可能在另一个线程上进行优化相关的运算,或者在准备缓存数据。具体干什么无法得知,但是内存泄漏是没有的。

也有人使用 glDeleteTextures  或者 glDeleteLists  或者其它的delete函数,然后他们注意到内存占用量没有下降。这是你我无能为力的。内存管理是驱动器自己负责的,它可能不在你调用delete函数时就立即执行释放内存的操作。所以这也不是什么内存泄漏的证据。

+BIT祝威+悄悄在此留下版了个权的信息说:

谁管理内存?OpenGL如何管理内存?

显卡的内存也是有限的。如果你想分配太多缓存对象或者贴图或者其它OpenGL资源,OpenGL驱动器就会把他们存到系统内存里。当你使用他们的时候,驱动器会视情况做数据交换。这显然会降低渲染速度。驱动器本身持有的内存量也是有限的,所以你调用  glGetError() 时可能会得到一个 GL_OUT_OF_MEMORY 。就算还有一些内存可用,如果你申请一个超大的缓存对象,OpenGL驱动器也会给你一个 GL_OUT_OF_MEMORY

内存不足的问题在OpenGL说明书里没有写。因为OpenGL是与系统无关的,它才不管系统设计,不在乎系统有没有显卡,用的是集成显卡还是独立显卡。

 

我应该用显示列表、顶点数组还是顶点缓存对象?

详情参见(Vertex Specification

显示列表顶点数组从最初的OpenGL开始就有。顶点缓存对象在OpenGL 1.5引入。他们都可以渲染图元,但是有很大的区别。

    显示列表里的数据提交到显卡内存后是不能改变的,但渲染速度较快

    多个顶点信息保存在数组里,通过一次API调用就可以完成传送,但是始终保存在App内存中,每次渲染时都要传送到显卡内存。

    顶点缓存对象把顶点信息存储在显卡内存里。这避免了每次渲染都传送顶点数据。且数据是可以更新的。最后,需要调用的API次数也很少

显示列表顶点数组都是OpenGL最古老的特性。现代OpenGL一般都用顶点缓存对象顶点数组对象描述顶点信息。建议你克制使用那些古老的特性。

当且仅当需要维护已有的古老代码且不可能重写渲染系统时,再用显示列表描述静态的顶点信息;如果顶点信息需要更新,就用顶点数组。如果有立即模式(比如glBegin() ),包含的顶点有几百几千,那么用显示列表或顶点数组都可以提升性能。

 

Unresolved External Symbol是什么意思?

新手编译OpenGL程序时可能会遇到这样的错误:

error LNK2001: unresolved external symbol _glBegin

 

你需要告诉编译器它应该搜索哪个库文件。

使用VC++2010时,你可以右击项目,选择'属性'。在属性对话框里,在左侧,打开'配置属性',打开'链接器',点击'输入'。在右侧,有一项'附加依赖'。输入库的名字,用分号隔开。如果是OpenGL,就输入'opengl32.lib',如果是GLU,就输入'glu32.lib'。

你也可以在cpp文件里添加下面两行来达到同一效果。

1 #pragma comment(lib, "opengl32.lib")
2 #pragma comment(lib, "glu32.lib")

不过有的编译器可能不支持#pragma。

我就不一一列举各种IDE的做法了,请自行百度。

如果你使用GCC,在这样编译时:

1 gcc -lGL -lglut myprogram.c -o myprogram

编译器告诉你:

/tmp/ccCQkTKm.o:myprogram.c:function display: error: undefined reference to 'gluLookAt'

这是因为你使用了GLU但是没有链接GLU库,你应该这么写:

1 gcc -lGL -lGLU -lglut myprogram.c -o myprogram
+BIT祝威+悄悄在此留下版了个权的信息说:

Not Declared In This Scope是什么意思?

有时候你会得到这样的编译错误:

GL_TEXTURE_3D was not declared in this scope

 

这是因为编译器找不到 GL_TEXTURE_3D 的声明。

你可能没有include合适的OpenGL头文件。gl.h可能不包含所有的东西。你应该用OpenGL Loading Library;;不然就得用the OpenGL Registry里的glext.h,而且还得手动加载OpenGL函数

OpenGL最多渲染8个光源吗?

以前,OpenGL固定功能管道有个最大光源数的概念。现在,shader根本没有光源的概念,你可以用shader渲染任意数量的光源。

经常有人问为什么管道功能管道最多渲染8个光源。其实并非如此。OpenGL要求的是最少支持8个光源。你的驱动器/GPU可以支持超过8个光源,但是他们一般都限制为8个。原因是有3、4个光源时,再增加光源就对一个照射到一个平面上的光没多少区别了。所以,实际上8是一个足够大的数了。

例如,你设计了一个城市,路上有路灯,那需要的光源肯定海了去了。怎么办?办法是把你的街道划分成小段,使得只有3个光源能影响到这段路里的平面。

例如,你在做一个粒子系统,每个粒子都是一个光源,所以你可能需要1000个光源。对于旧硬件(比如仅支持到OpenGL 1.5的),这太疯狂了。你可以用一个覆盖整个粒子系统范围的光源代替那1000个光源。

如果你实在想要超过8个光源,你可以采用多遍渲染的方式。先开启8个光源,渲染一遍,然后开启混合并使用glBlendFunc(GL_ONE, GL_ONE),然后再渲染一遍。你可能需要把深度测试设置为 GL_LEQUAL 。

现在换个角度看问题。那些古老的游戏使用光源了吗?实际上,没有。很多古老的游戏对静态表面使用灯光贴图。对于运动的物体,程序员自己计算光照或者预计算(即light volume)。

 

能否预编译shader?

OpenGL 4.1增加了预编译shader的功能。你需要为你的显卡/GPU下载专门的shader编译器。这玩意换个GPU可能就不行了;显卡驱动更新后可能也就不行了。这个特性的目的是一次编译后留作以后运行。这避免了每次运行都需要编译、链接的时间。但是,驱动器更新时可能更新shader版本,这会强制你再次编译shader。

如果你发布的App里使用了预编译的shader,你还是得把shader源码也放在安装包里。因为一旦预编译shader无法加载,你只能重新用源码编译一次。

注意,实现这一特性的扩展(ARB_get_program_binary)在4.1之前的硬件就广泛存在了。所以4.x级的硬件不是必须的。

+BIT祝威+悄悄在此留下版了个权的信息说:

如何组织纹理?

这项技术也称为纹理地图集

有的程序员认为,把多个小型2D纹理放到一个大型2D纹理上(1024 x 1024什么的),可以少调用一次 glBindTexture,也许能提升性能。这是个办法,但是你必须小心处理你的模型的纹理坐标。你也要仔细处理纹理滤波,因为线性滤波会导致纹素渗透(texel bleed),即一个模型使用了其它模型的纹理(因为纹素相邻了)

如果所有的2D纹理的大小都相同,你还可以把它们全放到一个3D纹理中。OpenGL 1.3开始支持 GL_TEXTURE_3D。不过在线性滤波时还是会有纹素渗透的问题。在S、T方向上不会有事,有事的是纹理层之间

另一个办法是使用2D纹理数组。OpenGL 3.0开始支持 GL_TEXTURE_2D_ARRAY。这个方法没有纹素渗透的问题,不过也要求所有的2D纹理大小都相同

 

字体渲染和文字渲染

OpenGL是一个底层库,它不处理渲染文字的事。它只渲染点、线、三角形这些。想渲染文字,要么使用第三方库,要么自己做个库。

一种最简单的方法是把字符做成纹理。需要渲染文字的时候就渲染四边形,并把纹理贴上去。

当然,你也可以做一个整句的纹理。

你也可以读取操作系统的字体信息,然后生成纹理。使用方法同上。

Windows提供了一些渲染文字的方法,不过很老了,不建议使用。详情参见(wglUseFontBitmaps)和(wglUseFontOutlines)。

更多内容可参考 http://www.opengl.org/archives/resources/faq/technical/#indx0170

GLU是什么?

GLU是OpenGL utility library 的缩写。它基于老版OpenGL特性,提供一些实用的功能,最著名的例子就是gluLooktAt()gluPerspective(),它们简化了设置视图和投影矩阵的工作。但是,这两个函数都使用老版的特性(矩阵栈等)。这在现代OpenGL程序中不提倡

如果你使用现代OpenGL(3.0及其以上),建议你要么使用非基于OpenGL的第三方库要么自己写这种库,要么就使用OpenGL 3.0以上的核心特性。这里有一些可用的第三方库

如果你仍然打算使用GLU,你要知道Windows提供glu32.dll的是1.2版的GLU。你的编译器需要glu32.lib或glu32.a。最新的GLU是1.3版。你可以下载Mesa3D(http://www.mesa3d.org)提供的完整包。

这个包里有GLU1.3的源码,你得自己编译它。记住,你不能替换Microsoft的glu32.dll,它是系统文件,永远都不要覆盖它。

posted @ 2015-05-11 23:31  BIT祝威  阅读(3381)  评论(1编辑  收藏  举报