ImageVerifierCode 换一换
格式:DOCX , 页数:16 ,大小:25.42KB ,
资源ID:812953      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bingdoc.com/d-812953.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(OpenGL 纹理的使用入门Word格式文档下载.docx)为本站会员(b****1)主动上传,冰点文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰点文库(发送邮件至service@bingdoc.com或直接QQ联系客服),我们立即给予删除!

OpenGL 纹理的使用入门Word格式文档下载.docx

1、另外,无论旧版本还是新版本,都限制了纹理大小的最大值,例如,某OpenGL实现可能要求纹理最大不能超过1024*1024。可以使用如下的代码来获得OpenGL所支持的最大纹理:GLintmax;glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);这样max的值就是当前OpenGL实现中所支持的最大纹理。在很长一段时间内,很多图形程序都喜欢使用256*256大小的纹理,不仅因为256是2的整数次方,也因为某些硬件可以使用8位的整数来表示纹理坐标,2的8次方正好是256,这一巧妙的组合为处理纹理坐标时的硬件优化创造了一些不错的条件。第六个参数是纹理边框的大小,我们没有

2、使用纹理边框,因此这里设置为零。最后三个参数与glDrawPixels函数的最后三个参数的使用方法相同,其含义可以参考glReadPixels的最后三个参数。大家可以复习一下第10课的相关内容,这里不再重复。举个例子,如果有一幅大小为width*height,格式为Windows系统中使用最普遍的24位BGR,保存在pixels中的像素图象。则把这样一幅图象载入为纹理可使用以下代码:glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);注意,载入纹理的过程可能

3、比较慢,原因是纹理数据通常比较大,例如一幅512*512的BGR格式的图象,大小为0.75M。把这些像素数据从主内存传送到专门的图形硬件,这个过程中还可能需要把程序中所指定的像素格式转化为图形硬件所能识别的格式(或最能发挥图形硬件性能的格式),这些操作都需要较多时间。2、纹理坐标我们先来回忆一下之前学过的一点内容:当我们绘制一个三角形时,只需要指定三个顶点的颜色。三角形中其它各点的颜色不需要我们指定,这些点的颜色是OpenGL自己通过计算得到的。在我们学习OpneGL光照时,法线向量、材质的指定,都是只需要在顶点处指定一下就可以了,其它地方的法线向量和材质都是OpenGL自己通过计算去获得。纹

4、理的使用方法也与此类似。只要指定每一个顶点在纹理图象中所对应的像素位置,OpenGL就会自动计算顶点以外的其它点在纹理图象中所对应的像素位置。这听起来比较令人迷惑。我们可以这样类比一下:在绘制一条线段时,我们设置其中一个端点为红色,另一个端点为绿色,则OpenGL会自动计算线段中其它各像素的颜色,如果是使用glShadeMode(GL_SMOOTH);,则最终会形成一种渐变的效果(例如线段中点,就是红色和绿色的中间色)。类似的,在绘制一条线段时,我们设置其中一个端点使用“纹理图象中最左下角的颜色”作为它的颜色,另一个端点使用“纹理图象中最右上角的颜色”作为它的颜色,则OpenGL会自动在纹理图

5、象中选择合适位置的颜色,填充到线段的各个像素(例如线段中点,可能就是选择纹理图象中央的那个像素的颜色)。我们在类比时,使用了“纹理图象中最左下角的颜色”这种说法。但这种说法在很多时候不够精确,我们需要一种精确的方式来表示我们究竟使用纹理中的哪个像素。纹理坐标也就是因为这样的要求而产生的。以二维纹理为例,规定纹理最左下角的坐标为(0, 0),最右上角的坐标为(1, 1),于是纹理中的每一个像素的位置都可以用两个浮点数来表示(三维纹理会用三个浮点数表示,一维纹理则只用一个即可)。使用glTexCoord*系列函数来指定纹理坐标。这些函数的用法与使用glVertex*系列函数来指定顶点坐标十分相似。

6、例如:glTexCoord2f(0.0f, 0.0f);指定使用(0, 0)纹理坐标。通常,每个顶点使用不同的纹理,于是下面这样形式的代码是比较常见的。glBegin( /* . */ ); glTexCoord2f( /* . */ ); glVertex3f( /* . */ ); /* . */glEnd();当我们用一个坐标表示顶点在三维空间的位置时,可以使用glRotate*等函数来对坐标进行转换。纹理坐标也可以进行这种转换。只要使用glMatrixMode(GL_TEXTURE);,就可以切换到纹理矩阵(另外还有透视矩阵GL_PROJECTION和模型视图矩阵GL_MODELVIE

7、W,详细情况在第五课有讲述),然后glRotate*,glScale*,glTranslate*等操作矩阵的函数就可以用来处理“对纹理坐标进行转换”的工作了。在简单应用中,可能不会对矩阵进行任何变换,这样考虑问题会比较简单。3、纹理参数到这里,入门所需要掌握的所有难点都被我们掌握了。但是,我们的知识仍然是不够的,如果仅利用现有的知识去使用纹理的话,你可能会发现纹理完全不起作用。这是因为在使用纹理前还有某些参数是必须设置的。使用glTexParameter*系列函数来设置纹理参数。通常需要设置下面四个参数:GL_TEXTURE_MAG_FILTER:指当纹理图象被使用到一个大于它的形状上时(即:

8、有可能纹理图象中的一个像素会被应用到实际绘制时的多个像素。例如将一幅256*256的纹理图象应用到一个512*512的正方形),应该如何处理。可选择的设置有GL_NEAREST和GL_LINEAR,前者表示“使用纹理中坐标最接近的一个像素的颜色作为需要绘制的像素颜色”,后者表示“使用纹理中坐标最接近的若干个颜色,通过加权平均算法得到需要绘制的像素颜色”。前者只经过简单比较,需要运算较少,可能速度较快,后者需要经过加权平均计算,其中涉及除法运算,可能速度较慢(但如果有专门的处理硬件,也可能两者速度相同)。从视觉效果上看,前者效果较差,在一些情况下锯齿现象明显,后者效果会较好(但如果纹理图象本身比

9、较大,则两者在视觉效果上就会比较接近)。GL_TEXTURE_MIN_FILTER:指当纹理图象被使用到一个小于(或等于)它的形状上时(即有可能纹理图象中的多个像素被应用到实际绘制时的一个像素。例如将一幅256*256的纹理图象应用到一个128*128的正方形),应该如何处理。可选择的设置有GL_NEAREST,GL_LINEAR,GL_NEAREST_MIPMAP_NEAREST,GL_NEAREST_MIPMAP_LINEAR,GL_LINEAR_MIPMAP_NEAREST和GL_LINEAR_MIPMAP_LINEAR。其中后四个涉及到mipmap,现在暂时不需要了解。前两个选项则和G

10、L_TEXTURE_MAG_FILTER中的类似。此参数似乎是必须设置的(在我的计算机上,不设置此参数将得到错误的显示结果,但我目前并没有找到根据)。GL_TEXTURE_WRAP_S:指当纹理坐标的第一维坐标值大于1.0或小于0.0时,应该如何处理。基本的选项有GL_CLAMP和GL_REPEAT,前者表示“截断”,即超过1.0的按1.0处理,不足0.0的按0.0处理。后者表示“重复”,即对坐标值加上一个合适的整数(可以是正数或负数),得到一个在0.0, 1.0范围内的值,然后用这个值作为新的纹理坐标。某二维纹理,在绘制某形状时,一像素需要得到纹理中坐标为(3.5, 0.5)的像素的颜色,其

11、中第一维的坐标值3.5超过了1.0,则在GL_CLAMP方式中将被转化为(1.0, 0.5),在GL_REPEAT方式中将被转化为(0.5, 0.5)。在后来的OpenGL版本中,又增加了新的处理方式,这里不做介绍。如果不指定这个参数,则默认为GL_REPEAT。GL_TEXTURE_WRAP_T:指当纹理坐标的第二维坐标值大于1.0或小于0.0时,应该如何处理。选项与GL_TEXTURE_WRAP_S类似,不再重复。设置参数的代码如下所示:glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);4、纹理对象前面已经提到过,载入

12、一幅纹理所需要的时间是比较多的。因此应该尽量减少载入纹理的次数。如果只有一幅纹理,则应该在第一次绘制前就载入它,以后就不需要再次载入了。这点与glDrawPixels函数很不相同。每次使用glDrawPixels函数,都需要把像素数据重新载入一次,因此用glDrawPixels函数来反复绘制图象的效率是较低的(如果只绘制一次,则不会有此问题),使用纹理来反复绘制图象是可取的做法。但是,在每次绘制时要使用两幅或更多幅的纹理时,这个办法就行不通了。你可能会编写下面的代码:glTexImage2D( /* . */ ); / 载入第一幅纹理/ 使用第一幅纹理 / 载入第二幅纹理/ 使用第二幅纹理/

13、当纹理的数量增加时,这段代码会变得更加复杂。在绘制动画时,由于每秒钟需要将画面绘制数十次,因此如果使用上面的代码,就会反复载入纹理,这对计算机是非常大的负担,以目前的个人计算机配置来说,根本就无法让动画能够流畅的运行。因此,需要有一种机制,能够在不同的纹理之间进行快速的切换。纹理对象正是这样一种机制。我们可以把每一幅纹理(包括纹理的像素数据、纹理大小等信息,也包括了前面所讲的纹理参数)放到一个纹理对象中,通过创建多个纹理对象来达到同时保存多幅纹理的目的。这样一来,在第一次使用纹理前,把所有的纹理都载入,然后在绘制时只需要指明究竟使用哪一个纹理对象就可以了。使用纹理对象和使用显示列表有相似之处:

14、使用一个正整数来作为纹理对象的编号。在使用前,可以调用glGenTextures来分配纹理对象。该函数有两种比较常见的用法:GLuint texture_ID;glGenTextures(1, &texture_ID); / 分配一个纹理对象的编号或者:GLuint texture_ID_list5;glGenTextures(5, texture_ID_list); / 分配5个纹理对象的编号零是一个特殊的纹理对象编号,表示“默认的纹理对象”,在分配正确的情况下,glGenTextures不会分配这个编号。与glGenTextures对应的是glDeleteTextures,用于销毁一个纹理

15、对象。在分配了纹理对象编号后,使用glBindTexture函数来指定“当前所使用的纹理对象”。然后就可以使用glTexImage*系列函数来指定纹理像素、使用glTexParameter*系列函数来指定纹理参数、使用glTexCoord*系列函数来指定纹理坐标了。如果不使用glBindTexture函数,那么glTexImage*、glTexParameter*、glTexCoord*系列函数默认在一个编号为0的纹理对象上进行操作。glBindTexture函数有两个参数,第一个参数是需要使用纹理的目标,因为我们现在只学习二维纹理,所以指定为GL_TEXTURE_2D,第二个参数是所使用的纹

16、理的编号。使用多个纹理对象,就可以使OpenGL同时保存多个纹理。在使用时只需要调用glBindTexture函数,在不同纹理之间进行切换,而不需要反复载入纹理,因此动画的绘制速度会有非常明显的提升。典型的代码如下所示:/ 在程序开始时:分配好纹理编号,并载入纹理glGenTextures( /* . */ );glBindTexture(GL_TEXTURE_2D, texture_ID_1);/ 载入第一幅纹理glBindTexture(GL_TEXTURE_2D, texture_ID_2);/ 载入第二幅纹理/ 在绘制时,切换并使用纹理,不需要再进行载入 / 指定第一幅纹理 / 指定第

17、二幅纹理提示:纹理对象是从OpenGL 1.1版开始才有的,最旧版本的OpenGL 1.0并没有处理纹理对象的功能。不过,我想各位的机器不会是比OpenGL 1.1更低的版本(Windows 95就自带了OpenGL 1.1版本,遗憾的是,Microsoft对OpenGL的支持并不积极,Windows XP也还采用1.1版本。据说Vista使用的是OpenGL 1.4版。当然了,如果安装显卡驱动的话,现在的主流显卡一般都附带了适用于该显卡的OpenGL 1.4版或更高版本),所以这个问题也就不算是问题了。5、示例程序纹理入门所需要掌握的知识点就介绍到这里了。但是如果不实际动手操作的话,也是不可

18、能真正掌握的。下面我们来看看本课开头的那个纹理效果是如何实现的吧。因为代码比较长,我把它拆分成了三段,大家如果要编译的话,应该把三段代码按顺序连在一起编译。如果要运行的话,除了要保证有一个名称为dummy.bmp,图象大小为1*1的24位BMP文件,还要把本课开始的两幅纹理图片保存到正确位置(一幅名叫ground.bmp,另一幅名叫wall.bmp。我为了节省网络空间,把两幅图片都转成jpg格式了,读者把图片保存到本地后,需要把它们再转化为BMP格式。可以使用Windows XP带的画图程序中的“另存为”功能完成这一转换)。第一段代码如下。其中的主体grab函数,是我们在第十课介绍过的,这里仅

19、仅是抄过来用一下,目的是为了将最终效果图保存到一个名字叫grab.bmp的文件中。(当然了,为了保证程序的正确运行,那个大小为1*1的dummy.bmp文件仍然是必要的,参见第十课)#defineWindowWidth 400WindowHeight 400WindowTitleOpenGL纹理测试#includestdio.hstdlib.h/* 函数grab* 抓取窗口中的像素* 假设窗口宽度为WindowWidth,高度为WindowHeight*/BMP_Header_Length 54voidgrab(void) FILE* pDummyFile; pWritingFile; GLu

20、byte* pPixelData; GLubyte BMP_HeaderBMP_Header_Length; GLint i, j; PixelDataLength; / 计算像素数据的实际长度 i = WindowWidth * 3; / 得到每一行的像素数据长度while( i%4 != 0 ) / 补充数据,直到i是的倍数 +i; / 本来还有更快的算法, / 但这里仅追求直观,对速度没有太高要求 PixelDataLength = i * WindowHeight; / 分配内存和打开文件 pPixelData = (GLubyte*)malloc(PixelDataLength);i

21、f( pPixelData = 0 )exit(0); pDummyFile =fopen(dummy.bmp,rb);if( pDummyFile = 0 ) pWritingFile =grab.bmpwbif( pWritingFile = 0 ) / 读取像素 glPixelStorei(GL_UNPACK_ALIGNMENT, 4); glReadPixels(0, 0, WindowWidth, WindowHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, pPixelData); / 把dummy.bmp的文件头复制为新文件的文件头fread(BMP_H

22、eader,sizeof(BMP_Header), 1, pDummyFile);fwrite(BMP_Header,sizeof(BMP_Header), 1, pWritingFile);fseek(pWritingFile, 0x0012, SEEK_SET); i = WindowWidth; j = WindowHeight;fwrite(&i,sizeof(i), 1, pWritingFile);j,sizeof(j), 1, pWritingFile); / 写入像素数据fseek(pWritingFile, 0, SEEK_END);fwrite(pPixelData, Pi

23、xelDataLength, 1, pWritingFile); / 释放内存和关闭文件fclose(pDummyFile);fclose(pWritingFile);free(pPixelData);第二段代码是我们的重点。它包括两个函数。其中power_of_two比较简单,虽然实现手段有点奇特,但也并非无法理解(即使真的无法理解,读者也可以给出自己的解决方案,用一些循环以及多使用一些位操作也没关系。反正,这里不是重点啦)。另一个load_texture函数却是重头戏:打开BMP文件、读取其中的高度和宽度信息、计算像素数据所占的字节数、为像素数据分配空间、读取像素数据、对像素图象进行缩放(

24、如果必要的话)、分配新的纹理编号、填写纹理参数、载入纹理,所有的功能都在同一个函数里面完成了。为了叙述方便,我把所有的解释都放在了注释里。/* 函数power_of_two* 检查一个整数是否为2的整数次方,如果是,返回1,否则返回0* 实际上只要查看其二进制位中有多少个,如果正好有1个,返回1,否则返回0* 在“查看其二进制位中有多少个”时使用了一个小技巧* 使用n &= (n-1)可以使得n中的减少一个(具体原理大家可以自己思考)intpower_of_two(intn)if( n = 0 )return0;(n & (n-1) = 0;/* 函数load_texture* 读取一个BMP

25、文件作为纹理* 如果失败,返回0,如果成功,返回纹理编号GLuint load_texture(constchar* file_name) GLint width, height, total_bytes; GLubyte* pixels = 0; GLuint last_texture_ID, texture_ID = 0; / 打开文件,如果失败,返回 FILE* pFile =fopen(file_name,if( pFile = 0 ) / 读取文件中图象的宽度和高度fseek(pFile, 0x0012, SEEK_SET);fread(&width, 4, 1, pFile);height, 4, 1, pFile);fseek(pFile, BMP_Header_Length, SEEK_SET); / 计算每行像素所占字节数,并根据此数据计算总像素字节数 GLint line_bytes = width * 3;while( line_bytes % 4 ! +line_bytes; total_bytes = line_bytes * height; / 根据总像素字节数分配内存 pixels = (GLubyte*)malloc(total_bytes);if( pixe

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2