《OpenGL纹理贴图.pdf》由会员分享,可在线阅读,更多相关《OpenGL纹理贴图.pdf(15页珍藏版)》请在三一文库上搜索。
1、1.6纹理贴图 在三维图形中,纹理映射( Texture Mapping)的方法运用得很广,尤其描述 具有真实感的物体。 比如绘制一面砖墙, 就可以用一幅真实的砖墙图像或照片作 为纹理贴到一个矩形上, 这样,一面逼真的砖墙就画好了。 如果不用纹理映射的 方法,则墙上的每一块砖都必须作为一个独立的多边形来画。另外,纹理映射能 够保证在变换多边形时, 多边形上的纹理图案也随之变化。例如,以透视投影方 式观察墙面时,离视点远的砖块的尺寸就会缩小,而离视点较近的就会大些。 此外,纹理映射也常常运用在其他一些领域,如飞行仿真中常把一大片植被的图 像映射到一些大多边形上用以表示地面,或用大理石、 木材、布
2、匹等自然物质的 图像作为纹理映射到多边形上表示相应的物体。 纹理映射有许多种情况。 例如,任意一块纹理可以映射到平面或曲面上,且 对光亮的物体进行纹理映射, 其表面可以映射出周围环境的景象;纹理还可按不 同的方式映射到曲面上,一是可以直接画上去(或称移画印花法),二是可以调 整曲面颜色或把纹理颜色与曲面颜色混合;纹理不仅可以是二维的, 也可以是一 维或其它维的。 我们这里重点研究二维纹理贴在三维物体表面上的方法。2D 纹理就是一张 平面图片,它是由平面上的像素点(称纹素Texel)组成,因此每个点的在纹理 内部只有二位的相对坐标(贴在物体上后就有三维的实际坐标了)。 定义 1、修改 TITLE
3、 #define TITLE “5DGS 2D Texture Mapping!“ / 定义窗口标题 2、定义常量 #define MAXTEXTURE 2 / 定义最大的纹理数目 (new) 定义需要开辟的纹理空间为2,每个空间存储一个二维纹理。 3、定义全局变量 GLfloat angle; / 控制物体的旋转角度 GLuint textureMAXTEXTURE; / 纹理数组,保存纹理名称 angle用来控制坐标系的旋转角度。textureMAXTEXTURE 为纹理数组,保 存 MAXTEXTURE 个纹理的名称。 增加 MAXTEXTURE的值可以允许存储更多 的纹理。 4、#in
4、clude 对图像文件的处理需要的库函数 载入图片: LoadImage() AUX_RGBImageRec *LoadImage(char *Filename)/ 加载一个图片 (new) FILE *File = NULL; / 文件句柄 if (!Filename) / 确保文件名已经提供 return NULL; / 如果没有则返回 NULL File = fopen(Filename,“r“); / 检查文件是否存在 if (File) / 文件存在吗? fclose(File); / 关闭 File 文件句柄 return auxDIBImageLoad(Filename); /
5、载入图片并返回其指针 return NULL; / 如果加载错误则返回NULL 1、AUX_RGBImageRec : AUX_RGBImageRec 类型是一个 RGB 图像结构类型。该结构定义了三个成 员: sizeX 图像的宽度; sizeY 图像的高度; data; 图形所包含的数据,其实也就是该图形在内存中的像素数据的一 个指针。 AUX_RGBImageRec 类型的变量描述了一幅图像的特征。 LoadImage()函数功能是载入BMP 图片( BMP 是 Bitmap 的缩写,后缀名 是.BMP。它是微软公司为 Windows 环境设置的标准图像格式, 在 Windows 环境
6、下运行的所有图像处理软件都支持这种格式)。 2、auxDIBImageLoad() glaux.h 库文件中的 auxDIBImageLoad 函数,其实它是一个宏,函数原型为 auxRGBImageLoadW(LPCWSTR)或者 auxRGBImageLoadA(LPCSTR),可以在该 库文件中找到它的定义,宏auxDIBImageLoad 实现的功能就是:根据指定的位 图名称,将该位图的信息加载到内存中,以便用来创建成为纹理。 参数为图片名 称,其返回值是指向图像文件的指针。 3、FILE 文件结构体 FILE 缓冲文件系统为每个正使用的文件在内存开辟文件信息区 文件信息用系统定义的名
7、为FILE 的结构体描述 FILE 定义在 stdio.h 中: typedef struct int _fd; /文件号 int _cleft; /缓冲区中剩下的字符数 int _mode; /文件操作方式 char *_next; /文件当前读写位置 char *_buff; /文件缓冲区位置 FILE; 文件打开函数 fopen fopen函数用来打开一个文件,其调用的一般形式为:文件指针名=fopen(文 件名,使用文件方式 ) 其中, “文件指针名”必须是被说明为 FILE 类型的指针变 量, “文件名”是被打开文件的文件名。 “使用文件方式”是指文件的类型和操作要 求。 “文件名”
8、是字符串常量或字符串数组。 使用文件方式如下: 1)“r“或“rt“: 正文文件只读方式打开。 文件不存在,则打开失败 (顺序读 )“w“ 或“wt“: 正文文件只写方式打开。若文件不存在,则建立文件;若文件存在,则删除文件 内容,重建空文件(顺序写) ; (截取文件长度为0) 。使用 fopen 时,但凡含r 字母的打开方式,一定要加判断,文件是否打开成功,否则程序不会报告错误, 会运行下去。 2) “a“或“at“:正文文件添加方式。文件不存在,则建立文件(顺序添加写 ) 3) “r+“或“rt+“: 正文文件读写打开,文件不存在,则打开失败(顺序读 /写、 随机读 /写,含改写与添加 )
9、; 4) “w+“或“w+“: 正文文件读写方式打开,文件不存在,则建立文件;否则 截取文件长度为 0(顺序读 /写,随机读 /写,对写入的内容可以读或改写或添加) 文件关闭fclose(FILE *fp) 一般地, fclose(fp)与 fopen应配对使用,特别是含有写方式的文件,若不关 闭会造成文件数据丢失。fcloseall(void):关闭当前所有打开的文件。 创建纹理: LoadTexture() 1、状态变量 state 用来判断纹理加载是否成功,成功为true,失败为 false BOOL LoadTextureGL(void) / 加载图片并转换为纹理 (new) BOOL
10、 State = FALSE; / 状态指示 2、为纹理分配空间 为纹理分配 MAXTEXTURE个 AUX_RGBImageRec 结构大小的临时空间 AUX_RGBImageRec *TextureImageMAXTEXTURE; / 为纹理开辟存储空间 memset(TextureImage, 0, sizeof(void *)*MAXTEXTURE); / 清除图像记录,确保其内容为空并使指针指向NULL void *memset(void *s, int c, size_t n); memset: 作用是在一段内存块中填充某个给定的值,它对较大的结构体或数 组进行清零操作的一种最快方
11、法。 3、调用 LoadImage()函数加载 Data 目录下的图片 。如果加载成功,将 state 置为 TRUE。 if (TextureImage0 = LoadImage(“Data/Egypt.bmp“) /加载纹理图片 / 设置状态变量为 TRUE 4、调用 glGenTextures glGenTextures 为 每 个 纹 理 产 生 唯 一 的 名 字 标 识 , 并 存 于 纹 理 数 组 textureMAXTEXTURE 中。 glGenTextures(MAXTEXTURE, / 返回唯一的纹理名字来标识纹理,保存在 texture 中 glGenTextures
12、(GLsizei n, GLuint *textures)函数说明 n: 用来生成纹理名字的数量 textures:存储纹理名称数组的第一个元素指针 5、glBindTexture() glBindTexture()函数将纹理同GL_TEXTURE_2D 绑定。 glBindTexture 函 数 for (int loop=0; loopsizeX, TextureImageloop-sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImageloop-data); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN
13、_FILTER, GL_LINEAR); / 线形滤波 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, L_LINEAR); glBindTexture 函数实现了将调用glGenTextures函数生成的纹理的名字绑定 到对应的目标纹理上。该函数的声明如下所示: void glBindTexture( GLenum target, GLuint texture ); target 纹 理 被 绑 定 的 目 标 , 它 只 能 取 值GL_TEXTURE_1D或 者 GL_TEXTURE_2D ; texture 纹理的名称,并且,该
14、纹理的名称在当前的应用中不能被再次 使用。 6、glTeximage2D() :生成 2D 纹理图像 for (int loop=0; loopsizeX, TextureImageloop-sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImageloop-data); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); / 线形滤波 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, L_LINEAR); glTexIm
15、age2D(GL_TEXTURE_2D, / 此纹理是一个 2D 纹理 0, /代表图像的细节的级别 , 默认为 0 即可 3, /颜色成分 R(红色分量 )、G(绿色分量 )、B(蓝色分量 )三部分,若为 4 则是 R(红色分量 )、G(绿色分量 )、B(蓝色分量 )、Alpha TextureImage0-sizeX, /纹理的宽度 TextureImage0-sizeY, /纹理的高度 0, /边框的值 GL_RGB, /OpenGL 图像数据格式,由红、绿、蓝三色数据组成 GL_UNSIGNED_BYTE, /图像的数据类型是无符号字节类型 TextureImage0-data); /
16、OpenGL 纹理数据的来源 ,此例中指向存 放在 TextureImage0记录中的数据 glTexImage2D函数 调用 glTexImage2D函数,用来指定二维纹理图像。 该函数的声明如下所示: void glTexImage2D( GLenum target, GLint level, GLint components, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels ); 函数参数的含义: target 指定目标纹理,必须为GL_TEXTUR
17、E_2D ; level 指定图像级别的编号, 0 表示基本图像,其它可以参考MSDN; components 纹理中颜色组件的编号,可是是1 或 2 或 3 或 4; width 纹理图像的宽度; height 纹理图像的高度; border 纹理图像的边框宽度,必须是0 或 1; format 指定像素数据的格式, 一共有 9 个取值:GL_COLOR_INDEX 、 GL_RED 、 GL_GREEN 、GL_BLUE 、 GL_ALPHA 、GL_RGB 、 GL_RGBA 、 GL_BGR_EXT、GL_BGRA_EXT、GL_LUMINANCE、 GL_LUMINANCE_ALPH
18、A ,具体含义可以参考MSDN; type 像素数据的数据类型,取值可以为GL_UNSIGNED_BYTE, GL_BYTE, GL_BITMAP, GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, GL_INT, and GL_FLOAT ; pixels 内存中像素数据的指针。 7、glTexParameteri(): 指定纹理滤波方式 for (int loop=0; loopsizeX, TextureImageloop-sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImageloop-data); gl
19、TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); / 线形滤波 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, L_LINEAR); glTexParameteri函数或者 glTexParameterf函数用来设置纹理参数, 声明如下 所示: void glTexParameterf( GLenum target, GLenum pname, GLfloat param ); void glTexParameteri( GLenum target, GLen
20、um pname, GLint param ); 函数参数的含义: target 目标纹理,必须为GL_TEXTURE_1D 或 GL_TEXTURE_2D ; pname 用来设置纹理映射过程中像素映射的问题等,取值可以为: GL_TEXTURE_MIN_FILTER、GL_TEXTURE_MAG_FILTER、 GL_TEXTURE_WRAP_S 、 GL_TEXTURE_WRAP_T , 详细含义可以查看MSDN; param 实际上就是 pname的值,可以参考 MSDN。 另外,该类函数还有两个: void glTexParameterfv( GLenum target, GLenu
21、m pname, const GLfloat *params ); void glTexParameteriv( GLenum target, GLenum pname, const GLint *params ); 上述程序中调用如下: glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR) ; 功能就是实现线形滤波的功能, 当纹理映射到图形表面以后, 如果因为其它 条件的设置导致纹理不能更好地显
22、示的时候,进行过滤,按照指定的方式进行显 示,可能会过滤掉显示不正常的纹理像素。 8、释放临时空间 纹理创建完毕后,释放用来存放图片数据的临时空间,返回状态变量state 。 for (int loop=0; loopdata) / 纹理图像是否存在 free(TextureImageloop-data); / 释放纹理存储空间 free(TextureImageloop); / 释放图像结构 return State; / 返回 State 在 Initialize()里载入纹理 在 Initialize() 里添加 LoadGLTexture()载入纹理。 用 glEnable(GL_TE
23、XTURE-2D) 来开启 2D 纹理映射。禁用 2D 纹理映射可用 glDisable(GL_TEXTURE-2D) 。 482行: if (!LoadTextureGL() / 调用 LoadTextureGL()函数 return FALSE; / 如果纹理加载错误则返回FALSE glEnable(GL_TEXTURE_2D); / 开启 2D 纹理映射 第一个纹理矩形 纹理映射的过程是在DrawGLScene函数中实现的,也就是在绘制图形的过 程中,直接进行纹理映射,或者称为,为指定的平面贴纹理, / 绘制四边形并贴图 glBindTexture(GL_TEXTURE_2D, tex
24、ture0); / 选择并绑定第一张纹理 glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f);glVertex3f(-1.5f,-1.0f, 0.0f); / 纹理和底面四边形的左下顶点(正视) glTexCoord2f(1.0f, 0.0f);glVertex3f( 1.5f,-1.0f, 0.0f); / 纹理和底面四边形的右下顶点 glTexCoord2f(1.0f, 1.0f);glVertex3f( 1.5f, 1.0f, 0.0f); / 纹理和底面四边形的右上顶点 glTexCoord2f(0.0f, 1.0f);glVertex3f(-1.5
25、f, 1.0f, 0.0f); / 纹理和底面四边形的左上顶点 glEnd(); 通过前面的过程, 已经将位图加载并创建和加载纹理成功,纹理数组已经存 在于内存之中,调用上述函数实现纹理映射,即,从内存中取出指定的纹理,将 其映射到立方体的指定的面上。 上述函数中调用了glTexCoord2f 函数,设置纹理坐标, 该函数的声明如下所 示: void glTexCoord2f( GLfloat s, GLfloat t ); glTexCoord2f 的第一个参数是 X 坐标, 当 s=0.0f 时是纹理的左侧,s=0.5f 时 是纹理的中点,s=1.0f 时是纹理的右侧。 glTexCoor
26、d2f 的第二个参数是 Y 坐标, t=0.0f 是纹理的底部, t=0.5f 是纹理的中点,t=1.0f 是纹理的顶部。 glTexCoord2f(0.0f, 0.0f);表示将纹理 texture0的左下角坐标 (0.0f, 0.0f)映射到 立方体前面那个面的顶点(-1.0f, -1.0f, 1.0)上; glTexCoord2f(1.0f, 0.0f);表示将纹理 texture0的右下角坐标 (1.0f, 0.0f)映射到 立方体前面那个面的顶点(1.0f, -1.0f, 1.0f)上; glTexCoord2f(1.0f, 1.0f);表示将纹理 texture0的右上角坐标 (1
27、.0f, 1.0f)映射到 立方体前面那个面的顶点(1.0f, 1.0f, 1.0f)上; glTexCoord2f(0.0f, 1.0f);表示将纹理 texture0的左上角坐标 (0.0f, 1.0f)映射到 立方体前面那个面的顶点(-1.0f, 1.0f, 1.0f)上。 这样,纹理 texture0就被映射到了立方体前面那个面上。 纹理金字塔 在金字塔的各个三角形侧面贴上相同的纹理。在纹理上截取一个三角形区 域,作为三角形侧面的贴图。对应规则如下: 三角形的左下顶点纹理的左下角图素(0.0,0.0) ; 三角形的右下顶点纹理的左下角图素(1.0,0.0) ; 三角形的上顶点纹理顶部的
28、中点图素(0.5,1.0) ; / 绘制旋转的金字塔 glLoadIdentity(); / 重置当前矩阵 glTranslatef(2.0f, 0.0f, -8.0f); / 右移 2.0f,并移入屏幕 8.0f glRotatef(angle, 0.0f, 1.0f, 0.0f); / 绕 Y 轴旋转 angle度 angle += 1.0f; / 增加逆时针旋转角度 glBindTexture(GL_TEXTURE_2D, texture1); / 选择并绑定第二张纹理 glBegin(GL_TRIANGLES); / 开始绘制金字塔各面的三角形 / 前面 glTexCoord2f(0.
29、5f, 1.0f); glVertex3f( 0.0f, 1.0f, 0.0f); / 上顶点(正视) glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,-1.0f, 1.0f); / 左下顶点 glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,-1.0f, 1.0f); / 右下顶点 / 右侧面 glTexCoord2f(0.5f, 1.0f); glVertex3f( 0.0f, 1.0f, 0.0f); / 上顶点(正视) glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f,-1.0
30、f, 1.0f); / 左下顶点 glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,-1.0f,-1.0f); / 右下顶点 / 背面 glTexCoord2f(0.5f, 1.0f); glVertex3f( 0.0f, 1.0f, 0.0f); / 上顶点(正视) glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f,-1.0f,-1.0f); / 左下顶点 glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f,-1.0f,-1.0f); / 右下顶点 / 左侧面 glTexCoord2f(
31、0.5f, 1.0f); glVertex3f( 0.0f, 1.0f, 0.0f); / 上顶点(正视) glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,-1.0f,-1.0f); / 左下顶点 glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f,-1.0f, 1.0f); / 右下顶点 glEnd(); / 底面 glBegin(GL_QUADS); / 绘制底面四边形 glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,-1.0f,-1.0f); / 左下顶点(正视) glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,-1.0f,-1.0f); / 右下顶点 glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,-1.0f, 1.0f); / 右上顶点 glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,-1.0f, 1.0f); / 左上顶点 glEnd(); / 金字塔绘制结束
链接地址:https://www.31doc.com/p-5334620.html