赞
踩
http://staff.ustc.edu.cn/~lgliu/Resources/CG/What_is_CG.htm
一、建模
1.计算机辅助设计(CAD)中主流方法是采用NURBS(非均匀有理B-样条、Bezier曲线曲面)方法。
2.细分曲面造型方法,作为一种离散迭代的曲面构造方法,其构造过程朴素简单以及实现容易。
3.利用软件直接手工建模。现在主流的商业化的三维建模软件有Autodesk 3D Max和 Maya。
n.三维几何模型的构建过程中,还会涉及到很多需要处理的几何问题,比如数据去噪(denoising or smoothing)、补洞(repairing)、简化(simplification)、层次细节(level of detail)、参数化(parameterization)、变形(deformation or editing)、分割(segmentation)、形状分析及检索(shape analysis and retrieval)等。这些问题构成“数字几何处理”的主要研究内容。
二、渲染
有了三维模型或场景,怎么把这些三维几何模型画出来,产生令人赏心悦目的真实感图像?这就是传统的计算机图形学的核心任务。
因此,如何充分利用GPU的计算特性,结合分布式的集群技术,从而来构造低功耗的渲染服务是发展趋势之一。
三、动画
动画是采用连续播放静止图像的方法产生物体运动的效果。
四、人机交互
人通过一定的交互方式,让计算机完成任务。
五、其他内容
虚拟现实,可视化,计算机艺术等。
一、数学
包括:微积分、线性代数、矩阵计算、微分几何、数值计算和分析、计算方法、偏微分方程、微分方程数值解、最优解、概率、统计、计算几何等。
研究过程中若遇到什么数学知识再去学相关的知识,学习起来会更有兴趣,掌握起来会更快更扎实;学习数学要结合图形,即“数形结合”,需要有图形的想象能力;
二、编程
掌握C++编程语言和面向对象编程思想
三、其他
英语基础要好,因为需要大量阅读英文文献和进行英文论文的写作;英文的听说能力也要好些,因为要跟国际学者交流讨论;
计算机图形学中的很多算法是真实物理世界的模拟,因此,如果你要进行基于物理的建模和仿真,一些物理知识和理论也需要的,比如力学(动力学,运动学,流体力学)和光学等;
四、教材
最好的学习方法就是在使用中学习。因此,计算机图形学的学习和研究提供了你学习其他相关知识的好的过程。
计算机图形学的内容远比教材中或你想象中的内容多得多。
Open Graphics Library 开放图形库,是用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序编程接口(API)。常用于CAD、虚拟现实、科学可视化程序和电子游戏开发。
OpenGL被设计为只有输出的,所以它只提供渲染功能。核心API没有窗口系统、音频、打印、键盘/鼠标或其他输入设备的概念。
在图形绘制中,有许多状态量需要管理,如果线条的颜色,线条的粗细,是否打开纹理映射和是否打开光照等。采用状态机机制,对状态量进行管理,即,一个状态量被设置后,将对随后的所有绘制指令生效,直到它被再次设置为止。
OpenGL语法遵循以下规则:
绘制二维图形,并设置其绘制属性:颜色、线型。填充模式等。
绘制过程:场景定义,观察定义;
glViewport();
glMatrixMode(GL_PROJECTION);
初始化变换:glLoadIdentity()
glPerspective()
gluLookAt()
glMatrixMode(GL_MODELVIEW);
初始化变换:glLoadIdentity()
glRotatef()
glCallList(object)
几何变换是OpenGL绘制流水线中模型变换的核心内容,常被用于构造需要绘制的场景。
平移、旋转、缩放和斜切都是几何变换的例子。
平移:x' = x + a; y' = y + b; z' = z +c; 缩放:x' = ax; y' = by; z' = cz; 斜切:x' = x + ay; y' = y; 旋转:x' = xcos@ - ysin@; y' = xsin@ + ycos@; z' = z;
观察变换:相机被放置在坐标系原点,而相机的朝向和-z方向重合,相机的向上方向和y轴重合。在这个坐标框架下,裁剪和投影的过程将大大简化。
投影变换:gluPerspective(45.0f, 1.0f*w/h, 1.0f, 100.0f);glOrtho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 20.0f);
创建光源,照亮场景中的材质物体。
使用OpenGL纹理函数在多边形上贴纹理,自动生成纹理坐标,以及如何在同一张多边形表面同事使用多张纹理。
unsigned char* LoadBitmapFile(char* filename, BITMAPINFOHEADER* bitmapinfoHeader);//自定义函数 BITMAPINFOHEADER bitmapinfoHeader; //bitmap信息头 unsigned char* bitmapData;//纹理数据 bitmapData = NULL; bitmapData = LoadBitmapFile("world.bmp", &bitmapinfoHeader);//读取文件数据 unsigned int texture[2]; glGenTextures(2, texture);//可以一次生成多个纹理标识符 glBindTexture(GL_TEXTURE_2D, texture[0]);//指定当前使用的纹理,余下操作将只作用与该纹理 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);//放大:当像素比对应纹理上的像素texel小;(GL_NEAREST没有过滤,点采样,取最近的texel值;GL_LINEAR双线性插值) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);//缩小:当像素比对应纹理上的像素大;(前两+;GL_NEAREST_MIPMAP_NEAREST取最接近的mipmap的值;GL_LINEAR_MIPMAP_LINEAR三线性插值) //下面将从bitmap文件中读取的图像文件交给OpenGL纹理,纹理数据在OpenGL内部保存,也可能保存在显卡上。 glTexImage2D(GL_TEXTURE_2D, 0, //mipmap层次,通常为0,表示最上层 GL_RGB, //希望有红绿蓝数据 bitmapInfoHeader.biWidth,//纹理宽度,必须是2^n,若有边框+2 bitmapInfoHeader.biWidth,//纹理高度,必须是2^n,若有边框+2 0, //边框:0=无边框;1=有边框 GL_RGB,//bitmap数据格式 GL_UNSIGNED_BYTE,//每个颜色数据的类型 bitmapData); //bitmap数据指针 //如果使用了mipmap,则需要对每个mipmap都调用一次上面的函数,并相应地改变mipmap的层次数。 glEnable(GL_TEXTURE_2D);//绘制前需要打开纹理映射 //---------------------------------------------------------- //下面的代码创建一个四边形,并将该四边形的顶点与纹理的角点建立关联 glBindTexture(GL_TEXTURE_2D, texture[1];//从已装载纹理中选择当前纹理 glColor3f(1.0f, 1.0f, 1.0f);//将当前颜色设置为白色 //绘制四边形,并为每个顶点设定纹理坐标 glBegin(GL_QUADS); glTexCoord2i(1, 1); glVertex3i(1,1,0); glTexCoord2i(1, 0); glVertex3i(1,-1,0); glTexCoord2i(0, 0); glVertex3i(-1,-1,0); glTexCoord2i(0, 1); glVertex3i(-1,1,0); glEnd(); //纹理坐标:X:0~1;Y:0~1, 左下角(0, 0) //四边形顶点:X:-1~1;Y-1~1;Z:-1~1, 左下角(-1,-1,-1)
//调用glTexGen(),并使用函数glEnable()打开了模式GL_TEXTURE_GEN_S和GL_TEXTURE_GEN_T;
planeCoefficients = [1, 0, 0, 0];
glTexGen(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glTexGen(GL_S, GL_OBJECT_PLANE, planCoefficients);
glEnable(GL_TEXTURE_GEN_S);
glBegin(GL_QUADS);
glVertex3f(-3.25, -1, 0);
glVertex3f(-1.25, -1, 0);
glVertex3f(-1.25, 1, 0);
glVertex3f(-3.25, 1, 0);
glEnd();
//用于控制纹理坐标生成的方式:void glTexGeni(GLenum coord, GLenum pname, GLdouble, param);
//coord:指定一类纹理坐标,必须为GL_S,GL_T,GL_R,GL_Q之一
//pname:必须是GL_TEXTURE_GEN_MODE
//param:纹理生成参数,必须为GL_OBJECT_LINEAR,GL_EYE_LINEAR,GL_SPHERE_MAP之一;前两个都是按照顶点到一个平面的距离产生纹理坐标
1.平面定义:AX+BY+CZ+D=0;点[x,y,z]是否落在该平面;向量[A,B,C]是该平面的法向量,即决定了平面的朝向;系数D控制该平面到原点的距离;如果[A,B,C]是一个单位向量,则D等于平面到原点的距离;
2.纹理坐标生成模式:GL_OBJECT_LINEAR; glTexGenfv(GL_S, GL_OBJECT_PLANE, planeCoefficients); 纹理坐标S=AX+BY+CZ+D,这里的[x,y,z]为顶点的坐标值,通过函数glVertex()传递;可以通过给系数乘以不同的比例来控制纹理重复出现的频率(即对纹理进行缩放);
3.纹理坐标生成模式:GL_EYE_LINEAR; glTexGenfv(GL_S, GL_EYE_PLANE, planeCoefficients); GL_OBJECT_LINEAR模式计算的纹理坐标只和函数glVertex()传递的值的相关,不会通过变换改变物体或相机发生变化。而GL_EYE_LINEAR模式使用经过了所有ModelView变换后的顶点位置产生纹理坐标,即它们使用顶点在平面上的坐标产生纹理坐标。
4.二维纹理自动生成:上个实例中,始终只对纹理坐标S进行了生成。事实上,OpenGL支持对纹理坐标S和T的同时自动生成。例如,可以对纹理坐标T使用不同的平面方程调用函数glTexGen():
SplaneCoefficients=[1,0,0,0];
glTexGeni(GL_S,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR);
glTexGenfv(GL_S,GL_EYE_PLANE,SplaneCoefficients);
glTexGenfv(GL_S,GL_OBJECT_PLANE,SplaneCoefficients);
TplaneCoefficients=[0,1,0,0];
glTexGeni(GL_T,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR);
glTexGenfv(GL_T,GL_EYE_PLANE,TplaneCoefficients);
glTexGenfv(GL_T,GL_OBJECT_PLANE,TplaneCoefficients);
5.球形映射:环境纹理的一种,常被用于模拟反射的表面。在OpenGL中可以通过纹理坐标自动生成GL_SPHERE_MAP来进行控制。在这种模式下,并没有其他的参数:glTexGeni(GL_S, GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP); 在球形映射中,将使用从视点到观察点的向量作为参考,并将它相对于模型表面法向量进行反射,得到的反射向量将用于从纹理中查询颜色。该纹理嘉定提供了周围被反射环境的360度全方位包围。
多重纹理是否被支持
constGLubyte *extensions = glGetString(GL_EXTENSIONS);
bool multiTexturingSupported = strstr((const char*)extensions, "GL_ARB_multitexture") != NULL;
初始化相关函数
glMultiTexCoord1fARB = (PFENGLMULTITEXCOORD1FARBPROC) wglGetProcAddress("glMutiTexCoord1fARB");
glMutiTexCoord2fARB = (PFENGLMULTITEXCOORD2FARBPROC) wglGetProcAddress("glMutiTexCoord2fARB");
glMutiTexCoord3fARB = (PFENGLMULTITEXCOORD3FARBPROC) wglGetProcAddress("glMutiTexCoord3fARB");
glMutiTexCoord4fARB = (PFENGLMULTITEXCOORD4FARBPROC) wglGetProcAddress("glMutiTexCoord4fARB");
glActiveTextureARB = (PFENGLACTIVETEXTUREARBPROC)wglGetProcAddress("glActiveTextureARB");
glClientActiveTextureARB = (PFENGLCLIENTACTIVETEXTUREARBPROC)wglGetProcAddress("glClientActiveTextureARB");
2.OpenGL扩展:
3.多重纹理扩展:允许使用超过一个纹理单元。一个纹理单元可以用来保存纹理坐标、纹理过滤方式、纹理环境状态、纹理坐标自动生成方式等。对每个纹理单元可以对应于一张不同的纹理。多重纹理功能非常强大,允许在一次绘制时使用多张纹理。当物体复杂时,使用多次绘制来实现同样的效果将耗时更多。
4.纹理单元:开发者可以控制当前使用哪个纹理单元。一个纹理单元通过OpenGL常量GL_TEXTUREi_ARB来访问。该常量为一个0到31之间的整数。因此,最多的纹理单元数为32,但并不是所有的显卡都能支持这么多纹理单元(例如,很多显卡只支持8个纹理单元)。
//为了查询可使用的纹理单元数,可以使用函数glGetIntegerv(),并使用参数GL_MAX_TEXTURE_UINTS_ARB;
GLint maxTextureUnits = 0;
glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &maxTextureUnits);
//为了激活一个纹理单元,可以将它的常量作为参数调用函数glActiveTextureARB();
glActiveTextureARB(GL_TEXTUREi_ARB);
//则当前的纹理单元为GL_TEXTUREi_ARB, 直到重新调用这个函数激活另一个纹理单元;
5.使用多重纹理:
//在激活了纹理单元后,对于纹理的操作和使用一个纹理类似绑定纹理,指定纹理过滤方式。唯一的不同在于指定顶点的纹理坐标,现在需要使用函数glMultiTexCoord** ARB() glMultiTexCoord**ARB(GL_TEXTUREi_ARB, ...); //其中,参数...为纹理坐标 //演示使用两张纹理来绘制一个方块,并且更改不同的模式,使用一张纹理或使用多重纹理。 if (mode == 0){ glActiveTextureARB(GL_TEXTURE0_ARB); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture[0]); }else{ if (mode == 1) { glActiveTextureARB(GL_TEXTURE0_ARB); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture[1]); }else{ glActiveTextureARB(GL_TEXTURE0_ARB); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture[0]); glActiveTextureARB(GL_TEXTURE1_ARB); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture[1]); } //将当前颜色设置为白色 if (b['r']) glColor3f(1.0f, 0.0f, 0.0f); else glColor3f(1.0f, 1.0f, 1.0f); //绘制四边形 //并为每个顶点设定纹理坐标 glBegin(GL_QUADS); glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0, 1); glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0, 1); glVertex3i(1, 1, 0); glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0, 0); glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0, 0); glVertex3i(1, -1, 0); glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 1, 0); glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1, 0); glVertex3i(-1, -1, 0); glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 1, 1); glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 1, 1); glVertex3i(-1, 1, 0); glEnd(); //恢复纹理状态 glActiveTextureARB(GL_TEXTURE1_ARB); glDisable(GL_TEXTURE_2D); glActiveTextureARB(GL_TEXTURE1_ARB); }
前面已经介绍了如何使用OPENGL的API进行图形绘制,但他们的效率存在问题。本章重点介绍OPENGL提供的顶点数组、显示列表和顶点顶点缓冲对象等三种渲染加速技术,并讨论他们的优缺点以及如何根据应用场景的不同进行选择。
使用顶点数组三步:
指定将要使用的顶点数据(包含坐标位置、颜色、法向量、纹理坐标和边可见性标记的数组);
将这些顶点数据传输给OPENGL;
用这些顶点数据进行绘制(将这些顶点组装成什么体素).
glVertexPointer(); 指定顶点空间位置
glNormalPointer();指定顶点法向量数组
glColorPointer();指定顶点颜色数组
glIndexPointer();指定颜色索引数组
glTexCoordPointer();指定纹理坐标数组
glEdgeFlagPointer();指定边可见性标记数组
注意这些顶点的属性数组,存放在应用程序中(系统内存),即客户端。而OpenGL在服务端访问他们。这就是为什么对顶点数组需要调用特别的glEnableClientState()和glDisbaleClientState()函数,而不是调用glEnable()和glDisable()函数。
#define X 0.5257311f
#define Z 0.85065080f
GLfloat vertices[][3] = {
{-X, 0.0, Z}, {X, 0.0, Z}, {-X, 0.0, -Z}, {X, 0.0, -Z},
{0.0, Z,X},{0.0,Z,-X},{0.0,-Z,X},{0.0,-Z,-X},
{Z,X,0.0},{-Z,X,0.0},{Z,-X,0.0},{-Z,-X,0.0},
};//多面体的顶点数据
//将使用顶点数组来产生坐标信息
glEnableClientState(GL_VERTEX_ARRAY);
//将顶点数组提交给OPENGL使用
glVertexPointer(3,GL_FLOAT,0,(GLvoid*)vertices);
glBegin(GL_TRANGLES);
//用第1、4、0个坐标数据中的元素画一个三角形
glArrayElement(1);
glArrayElement(4);
glArrayElement(0);
//用第4、9、0个坐标数据中的元素画一个三角形
glArrayElement(4);
glArrayElement(9);
glArrayElement(0);
glEnd();
通过使用下表访问顶点数据,重复的顶点数据被清除了。但是通过上面的硬编码来指定顶点的组合对于大型的程序显然是不合适的。一个较好的方法是将这些下标保存在一个数组中,如下例
GLfloat vertices[][3] = { {-X, 0.0, Z}, {X, 0.0, Z}, {-X, 0.0, -Z}, {X, 0.0, -Z}, {0.0, Z,X},{0.0,Z,-X},{0.0,-Z,X},{0.0,-Z,-X}, {Z,X,0.0},{-Z,X,0.0},{Z,-X,0.0},{-Z,-X,0.0}, };//多面体的顶点数据 //将每个三角形的下标值(3个)保存在数组中,该下标值将用于从顶点数组获取数据。 //同时,在其他的地方...... //将使用顶点数组来产生坐标信息 glEnableClient(GL_VERTEX_ARRAY); //将顶点数组提交给OPENGL使用 glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)vertices); //将下标从数组取出用用于绘制 glBegin(GL_TRIANGLES); for (int i = 0; i< 20; i++) { glArrayElement(triangles[i][0]); glArrayElement(triangles[i][1]); glArrayElement(triangles[i][2]); } glEnd();
//最后,可采用glDrawElements进一步优化
glDrawElements(GL_TRIANGLES, sizeof(triangles)/3, GL_UNSIGNED_INT, triangles);
//数组triangles里每个元素用来访问顶点数组
//这段代码和上面功效相同,且效率更高
#define NEW_LIST 1
//为显示列表定义一个唯一的标识符
//显示列表开始
glNewList(NEW_LIST, GL_COMPILE);//编译(但不立即显示)
//参数二还有哦一个参数GL_COMPILE_AND_EXECUTE
glBegin(...);
...
glEnd();
//许多绘制体素,变换,光照函数
...
glEndList();//显示列表被创建。
//执行显示列表
glCallList(NEW_LIST);
//用glGenBuffersARB()创建一个新的顶点缓冲对象;
//用glBindBuffersARB()绑定一个顶点缓冲对象;
//用glBufferDataARB将顶点数据复制到顶点缓冲对象;
void glGenBuffersARB(GLsize ini,GLuint* ids);//创建缓冲对象个数,保存返回标志符的数组地址;
void glBindBufferARB(GLenum target, GLuint id);//将缓冲对象与对应的ID建立关联,target用来标明该缓冲对象用于保存顶点数组数据还是索引数组数据GL_ARRAY_BUFFER_ARB或GL_ELEMENT_ARRAY_BUFFER_ARB。一旦函数调用后,VBO将缓冲对象初始化为零尺寸,并设置其初始状态,如使用和访问属性等。
void glBufferDataARB(GLenum target, GLsize size, const void* data, GLenum usage);//当缓冲对象初始化后,可以用函数将数据复制到缓冲对象。target取值GL_ARRAY_BUFFER_ARB或GL_ELEMENT_BUFFER_ARB;size是传送数据的字节数;data指向来源数据的数组;usage指明该缓冲对象将如何使用:静态、动态、流或读、复制、绘制。GL_STATIC_DRAW_ARB、GL_DYNAMIC_COPY_ARB、GL_STREAM_READ_ARB(3x3种)。
//静态static指该缓冲对象中的数据将不会修改(指定一次,修改多次);动态dynamic标明该缓冲对象的数据将经常修改(指定多次,修改多次);流stream表明数据每帧都会修改(指定一次,使用一次);
//绘制draw指数据将会送到图形处理器用于绘制。读Read指数据将被客户端读取。复制copy表明数据将同时用于绘制和读取。对VBO来说,只有绘制时有限的,读和复制为其他的扩展保留。
//下面的代码将创建一个存放顶点坐标数据的VBO。注意,可以在数据复制到VBO后,立即将顶点数组的内存释放
GLuint vbold; //VBO标识符
GLfloat* vertices = new GLfloat[vCount*3];//创建一个顶点数组
...
//创建一个新的VBO,并得到它的相关ID
glGenBuffersARB(1, &vboid);
//绑定VBO以使用它的相关ID
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vboid);
//传输数据到该VBO
glBufferDataARB(GL_ARRAY_BUFFER_ARB, dataSize, vertices, GL_STATIC_DRAW_ARB);
//复制数据到VBO后就可以将顶点数据释放了
delete[] vertices;
...
//程序终止时释放该VBO
glDeleteBUffersARB(1, &vboid);
//将顶点缓冲对象绑定到顶点数组和索引数组
glBindBuffersARB(GL_ARRAY_BUFFER_ARB, vboid1);//顶点坐标
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, vboid2);//索引值
//和顶点数据绘制相同,除了指针
glEnableClientState(GL_VERTEX_ARRAY);//激活坐标数组
//最后一个参数是偏移量,而不是指针
glVertexPointer(3, GL_FLOAT, 0, 0);
//用索引画留个四边形
glDrawElements(GL_QUADS, 24, GL_UNSIGNED_BYTE, 0);
glDisableClientState(GL_VERTEX_ARRAY);//关闭顶点数组
//绑定为0,切换到正常的指针操作
glBindBuffersARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
//将缓冲对象绑定为0,则关闭了顶点缓冲对象操作。在使用完顶点缓冲对象后最好将它关闭,这样原来的顶点数组只恨可以被重新激活。
void* glMapBufferARB(GLenum target, GLenum access);用于将缓冲对象映射到客户端内存。
返回一个指向该缓冲的指针,否则返回NULL.
TARGET:
ACCESS:指明对映射的数据做如何操作:读、写、读和写(GL_READ_ONLY_ARB,GL_WRITE_ONLY_ARB,GL_READ_WRITE_ARB).
GLboolean glUnmapBufferARB(GLenum target):
对VBO的数据修改完毕后,必须撤销在客户端程序建立的映射。
如果映射撤销成功,返回TRUE; 返回FALSE时,标明在建立映射时该VBO的内容已损坏
//绑定,然后映射该VBO
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vboid);
float* ptr = (float*)glMapBufferARB(GL_ARRAY_BUFFER_ARB,GL_WRITE_ONLY_ARB);
//如果指针合法,修改VBO内容
if(ptr) {
updateMyVBO(ptr, ...); //修改VBO中的数据
glUmmapBufferARB(GL_ARRAY_BUFFER_ARB);//使用完毕后撤销映射
}
//可以绘制修改后的VBO了
...
OpenGL中,没有内置文字输出函数。
基于文字位图的文字绘制由以下三步:
1.将文字位图装载为OpenGL纹理;LoadBitmapFile
2.为位图中每个字符的绘制生成显示列表;
3.在场景绘制时,调用文字的显示列表显示文字
为每个字符生成显示列表
float cx,cy; //存放当前字符的x,y坐标;
base = glGenList(256); //创建256个显示列表
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。