三维图形程序设计1Face三维图形程序设计5三维图形程序设计2Chap5纹理映射Chap4•引例:1、绘制一面砖墙的应用:就可以用一幅真实的砖墙图像或照片作为纹理贴到一个矩形上,这样,一面逼真的砖墙就画好了。如果不用纹理映射的方法,则墙上的每一块砖都必须作为一个独立的多边形来画。2、透视投影方式观察墙面纹理映射能够保证在变换多边形时,多边形上的纹理图案也随之变化。例如,以透视投影方式观察墙面时,离视点远的砖块的尺寸就会缩小,而离视点较近的就会大些。纹理映射•将图像映射到物体模型表面,模拟物体表面细节,称为纹理映射(TextureMapping)stxyz图像:即纹理几何屏幕纹理是什么?纹理是一个数组,其中的数据是颜色、辉度或者颜色和alpha值。纹理数组中的值通常被称为纹理单元(纹素)。纹理映射的步骤?•定义纹理定义纹理的数据,维数,多重性(多分辨率),边界值•指定纹理的映射方式•激活纹理映射glEnable()v.sglDisable()GL_TEXTURE_1DGL_TEXTURE_2DGL_TEXTURE_3D•确定纹理坐标和几何坐标的关系----绘制场景引例:看看教材上一个最简单的纹理映射执行效果:2个位置不同的立方体在其表面贴上一个自生成的贴图引例:看看教材上一个最简单的纹理映射引例:看看教材上一个最简单的纹理映射定义纹理•纹理可以是一维、二维或三维的•多重纹理映射–为纹理定义多种分辨率;–在距离观察位置远时,映射低分辨率的纹理图像;–距离近时,映射高分辨率的纹理图像;•为纹理设置边界–实际应用中需要多种纹理拼接;–为纹理设置边界超出[0.0,1.0]纹理参数范围的边界border,通常为1个像素宽;–通过线性平均,实现纹理图像间的光滑过渡。定义纹理•定义一维纹理–纹理只在某一方向上变化,而在另一个方向上没有变化,相当于高度为1的二维纹理–使用glTexImage1D()函数定义一维纹理函数原型voidglTexImage1D(GLenumtarget,GLintinternalFormat,GLsizeiwidth,GLintborder,GLenumformat,GLenumtype,constGLvoid*pixel)glTexImage1D()函数参数说明target设置为GL_TEXTURE_1Dlevel是使用多重纹理映射时的分辨率级数,若只有一个分辨率,该值为0internalFormat表明纹理映射方式,取值为1~4之间的整数值,或者是38个符号常量之一(实际就是纹理单元中所存储的内容)width给定纹理尺寸,必须是2的幂次方2m(m为非负整数,如果有边界width为2m+b)border指定边界宽度b(为0或1)format指定纹理的数据格式(纹素的数据格式)(_COLOR,_INDEX,_RGB,_RGBA,_RED,_ALPHA…)type指定纹理的数据类型(GL_BYTE,GL_SHORT,GL_INT,GL_FLOAT,GL_UNSIGNED_INT…)pixel为纹理图像数组的指针,指定纹理图像及其边界定义纹理•定义二维纹理–使用glTexImage2D()函数定义二维纹理函数原型voidglTexImage2D(GLenumtarget,GLintinternalFormat,GLsizeiwidth,GLsizeiheigth,GLintborder,GLenumformat,GLenumtype,constGLvoid*pixel)参数说明target设置为GL_TEXTURE_2Dwidth和heigth给定二维纹理的尺寸,必须为2m+2b(width和heigth可分别对应不同的m值)width和heigth为0,纹理映射无效•定义三维纹理常用于医学和地质学应用程序中。在医学应用程序中,三维纹理可以用于表示一系列的CT图像地质程序中,三维纹理可以模拟岩石层定义纹理•定义三维纹理–使用glTexImage3D()函数定义三维纹理函数原型voidglTexImage3D(GLenumtarget,GLintinternalFormat,GLsizeiwidth,GLsizeiheigth,GLsizeidepth,GLintborder,GLenumformat,GLenumtype,constGLvoid*texels)参数说明target必须设置为GL_TEXTURE_3Dwidth、heigth、depth给定三维纹理的尺寸,必须为2m+2b(三个参数可分别对应不同的m值)texels为三维纹理图像数组的指针定义纹理通常在纹理对象的帮助下来使用纹理,因为它可以极大的提高纹理使用的性能。步骤:1、生成纹理对象的名称2、将纹理对象与纹理数据关联(即创建纹理对象)3、检查是否有足够的空间来存储所有纹理对象(可以多个),否则通过设置优先级,来保证最常用的纹理对象驻留在工作集中。4、重新绑定纹理对象,使之成为当前对象。纹理对象操作纹理对象所涉及到的函数(4个)glGenTextures(n,*textureNames);glIsTexture(textureName);glBindTexture(target,textureName);glDeleteTextures(n,*textureNames);纹理对象1、如果名字首次使用,将新建纹理对象2、如果为已经创建的,则使之为当前化3、如果为0,停用纹理对象定义纹理•定义多重纹理映射–事先指定一系列分辨率逐渐减小的纹理图像;–OpenGL会根据所映射的物体尺寸自动选择使用哪个分辨率的纹理图;–需要额外的计算,增加计算时间;–但可避免场景中小物体移动时纹理的闪烁mipmap:为提示纹理映射的质量,通过指定一系列预先经过滤波生成的、分辨率递减的纹理图。优点:根据物体的大小,自动确定将使用哪个纹理图像,避免出现晃动和闪烁现象缺点:增加计算量和纹理所需的存储空间mipmap1、纹理尺寸例:64×162、如何确定在变化中使用哪一级mipmapλ=log2ρ(ρ:缩放因子,λ:mipmap等级)32×816×48×24×12×11×1总结•定义纹理glGenTextures(1,&texName);glBindTextrue(GL_TEXTURE_2D,texName);glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,width,height,0,GL_RGBA,GL_UNSIGNED_BYTE,bmpImage);glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,32,32,0,GL_RGBA,GL_UNSIGNED_BYTE,bmpImage32);glTexImage2D(GL_TEXTURE_2D,1,GL_RGBA,16,16,0,GL_RGBA,GL_UNSIGNED_BYTE,bmpImage16);glTexImage2D(GL_TEXTURE_2D,2,GL_RGBA,8,8,0,GL_RGBA,GL_UNSIGNED_BYTE,bmpImage8);glTexImage2D(GL_TEXTURE_2D,3,GL_RGBA,4,4,0,GL_RGBA,GL_UNSIGNED_BYTE,bmpImage4);glTexImage2D(GL_TEXTURE_2D,4,GL_RGBA,2,2,0,GL_RGBA,GL_UNSIGNED_BYTE,bmpImage2);glTexImage2D(GL_TEXTURE_2D,5,GL_RGBA,1,1,0,GL_RGBA,GL_UNSIGNED_BYTE,bmpImage1);mipmap如何动态控制mipmap的等级λglTexParamteri(GL_TEXTURE_2D,GL_TEXTURE_BASS_LEVEL,2);glTexParamteri(GL_TEXTURE_2D,GL_TEXTURE_MAX_LEVEL,5);glTexParamteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_LOD,1);glTexParamteri(GL_TEXTURE_2D,GL_TEXTURE_MAX_LOD,4);要使用的分辨率最高的纹理的等级要使用的分辨率最低的纹理的等级λ的最小值λ的最大值64×1632×84×1014进一步讨论mipmap除了前面由程序员自行定义各分辨率级的map外,OpenGL还提供由程序自行生成mipmap的函数。使用前提:程序员要提供0级别纹理(即分辨率最高的那一级)使用结果:得到最小直到1×1的mipmapgluBuild1DMipmaps(target,internalFormat,width,format,type,*texels);gluBuild2DMipmaps(target,internalFormat,width,height,format,type,*texels);gluBuild3DMipmaps(target,internalFormat,width,height,depth,format,type,*texels);滤波(过滤)一般来说,纹理图像为正方形或长方形。但当它映射到一个多边形或曲面上并变换到屏幕坐标时,纹理的单个纹素很少对应于屏幕图像上的象素。根据所用变换和所用纹理映射,屏幕上单个象素可以对应于一个纹素的一小部分(即放大)或一大批纹素(即缩小)。下面用函数glTexParameter*()说明放大和缩小的方法:glTexParameter*(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);glTexParameter*(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);三维图形程序设计24只使用一个mipmapGL_NEAREST_MIPMAP_NEARESTGL_LINEAR_MIPMAP_NEAREST使用两个mipmapGL_NEAREST_MIPMAP_LINEARGL_LINEAR_MIPMAP_LINEAR纹理的重复和截取纹理坐标[0,1],超出范围,将进行截取或重复重复可以简单重复,也可以进行镜像边框的处理:如果使用的纹理有边框或者指定了纹理边框的颜色,则是否以及如何使用边框颜色将取决于两者:环绕模式和过滤方法纹理的重复和截取过滤方式为GL_NEAREST:如果环绕模式为GL_GLAMP_TO_BORDER,将使用最近的边框或边框常量颜色过滤方式为GL_LINEAR:1、环绕模式为GL_NEAREST:忽略边框2、环绕模式为GL_CLAMP:将边框用于加权平均3、环绕模式为GL_CLAMP_TO_EDGE:忽略边框4、环绕模式为GL_GLAMP_TO_BORDER:将使用最近的边框或边框常量颜色指定纹理坐标纹理坐标通常可定义成一、二、三或四维形式,称为s,t,r和q坐标,以区别于物体坐标(x,y,z,w)和其他坐标。一维纹理常用s坐标表示,二维纹理常用(s,t)坐标表示,三维坐标用(s,t,r),q坐标象w一样,一般值都设置为1,主要用于建立齐次坐标。OpenGL坐标定义的函数是:voidglTexCoord{1234}{sifd}[v](TYPEcoords);eg:glTexCoord2f(0.0,1.0);glVertex3f(0.0,1.0,-3.0);#includegl\glaux.h#pragmacomment(lib,glaux.lib)AUX_RGBImageRec*LoadBMP(char*Filename){FILE*File=NULL;if(!Filename){returnNULL;}File=fopen(Filename,r);if(File){fclose(File);returnauxDIBImageLoad(Filename);}returnNULL;}提供一种方法:读取外部图像文件TextureImag