纹理映射
纹理映射最简单的形式是将一幅图像贴到物体的表面,就像在罐子表面贴标签或广告版上贴图片一样,该图像可以是从文件读入的图像,也可以是程序内部定义的图像,还可以是从颜色缓存中复制得到的图像。
纹理图就像是一张查找表,当表面上一点被渲染时,从该表中查找与此点对应的信息。
1.定义纹理
定义一维纹理
纹理只在某一方向上变化,而在另一个方向上没有变化,相当于高度为1的二维纹理
使用glTexImage1D()函数定义一维纹理
函数原型
void glTexImage1D( GLenum target, GLint internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixel)
glTexImage1D()函数参数说明
target 必须设置为GL_TEXTURE_1D
level 是使用多重纹理映射时的分辨率级数,若只有一个分辨率,该值为0
internalFormat 表明纹理映射方式,取值为1~4之间的整数值,指定颜色成分的数量,或者是38个符号常量之一
width 给定纹理尺寸,必须是2的幂次方2m(m为非负整数,如果有边界width 为2m+2b )
border指定边界宽度b(为0或1)
format 指定纹理的数据格式(如前,纹素的数据格式)
type 指定纹理的数据类型(见本页备注)
pixel为纹理图像数组的指针,指定纹理图像及其边界
定义二维纹理
使用glTexImage2D()函数定义二维纹理
void glTexImage2D( GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixel)
参数说明
target 必须设置为GL_TEXTURE_2D
width和 height 给定二维纹理的尺寸,必须为2m+2b( width和 height可分别对应不同的m值)
width和 height为0,纹理映射无效
#include <GL/gl.h>
#include <GL/glut.h>
#include <stdio.h>
#include <stdlib.h>
static GLfloat step = 0.0f; //旋转角度
static GLfloat xPosition;
#define checkImageWidth 64
#define checkImageHeight 64
static GLubyte checkImage[checkImageHeight][checkImageWidth][4];
void makeStripeImage(void)
{
int i, j, c;
for (i = 0; i < checkImageHeight; i++) {
for (j = 0; j < checkImageWidth; j++) {
c = ((((i&0x8)==0)^((j&0x8))==0))*255;
checkImage[i][j][0] = (GLubyte) c;
checkImage[i][j][1] = (GLubyte) c;
checkImage[i][j][2] = (GLubyte) c;
checkImage[i][j][3] = (GLubyte) 255;
}
}
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glPushMatrix();
glTranslated(0.0,0.0,xPosition-5.0f);
glRotatef(step, 0.0f, 0.0f, 1.0f); //旋转
//打开二维纹理
glEnable(GL_TEXTURE_2D);
//读取和定义球的纹理
makeStripeImage();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, checkImageWidth, checkImageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, checkImage);
//生成球面纹理坐标
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
//启动环境纹理贴图:
glEnable(GL_TEXTURE_GEN_S);
//绘制犹他壶
glutSolidTeapot(2.0);
glPopMatrix();
glutSwapBuffers();
}
void resize(int width, int height)
{
float ar = (float) width / (float) height;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(75, ar, ar, 21);
glMatrixMode(GL_MODELVIEW);
}
void SpecialKeys(int key, int x, int y)
{
if(key == GLUT_KEY_UP)
step -= 1.0f;
if(key == GLUT_KEY_DOWN)
step += 1.0f;
if(key == GLUT_KEY_LEFT)
xPosition += 0.1f;
if(key == GLUT_KEY_RIGHT)
xPosition -= 0.1f;
step = (GLfloat)((int)step % 360);
glutPostRedisplay();
}
void SetupRC()
{
glClearColor(0.0f, 0.0f, 0.0f,1.0f);
glEnable(GL_DEPTH_TEST);
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowPosition(200, 100);
glutInitWindowSize(800, 600);
glutCreateWindow("OpenGL Examples!");
glutSpecialFunc(SpecialKeys);
glutDisplayFunc(&display);
glutReshapeFunc(resize);
SetupRC();
glutMainLoop();
return 0;
}
定义三维纹理
使用glTexImage3D()函数定义三维纹理
void glTexImage3D(GLenum target, GLint internalFormat, GLsizei width, GLsizei height , GLsizei depth, GLint border, GLenum format ,GLenum type, const GLvoid *texels)
参数说明
target 必须设置为GL_TEXTURE_3D
width 、 height 、depth给定三维纹理的尺寸,必须为2m+2b(三个参数可分别对应不同的m值)
texels为三维纹理图像数组的指针
2.纹理的创建
①直接创建法:利用函数直接设置各像素点的RGB值,只能生成简单的有一定规律的纹理图像
②从帧缓存中读取:将纹理从当前GL_READ_BUFFER中读出来,并将像素放入纹理内存,调用函数glCopyTexImage1D()、 glCopyTexImage2D()
③调用库函数读取外部文件
OpenGL提供函数auxDIBImageLoad()函数读取纹理图像
函数原型
AUX_RGBImageRec auxDIBImageLoad (LPCTSTR filename);
参数说明
filename是纹理图像文件的名称。
该函数可以读取bmp格式的文件。
AUX_RGBImageRec是一个定义纹理数据的结构
typedef struct _AUX_RGBImageRec
{
GLint sizeX, sizeY;
unsigned char *data;
} AUX_RGBImageRec;
其中三个成员变量是sizeX、sizeY和data, sizeX和sizeY是纹理的宽和高,data存储具体的纹理数据
环境模式
替换GL_REPLACE
将纹理作为不透明图像覆盖到物体表面(纹理单元值替换几何图形的片段值)
贴花 GL_DECAL
仅用于RGB和RGBA两种内部格式,物体表面颜色和纹理颜色混合的比例由纹理的Alpha值确定
调整GL_MODULATE
用纹理图像的颜色调整片段的颜色和或颜色比例,综合光照和纹理的效果(纹理单元的颜色值与几何图形的片段颜色值相乘)
融合GL_BLEND
使用指定的颜色,响应光照条件(纹理单元的颜色值与纹理环境颜色值混合)
设置纹理环境函数
void glTexEnv{if}(GLenum target, GLenum pname, TYPE param);
void glTexEnv{if}v(GLenum target, GLenum pname, TYPE *param);
参数说明
target变量必须为GL_TEXTURE_ENV; pname和 param的对应取值
3.激活纹理映射
使用glEnable()和glDisable()函数打开和关闭纹理
glEnable(GL_TEXTURE_1D ); //打开一维纹理
glEnable(GL_TEXTURE_2D); //打开二维纹理
glEnable(GL_TEXTURE_3D); //打开三维纹理
…
glDisable(GL_TEXTURE_1D); //关闭一维纹理
glDisable(GL_TEXTURE_2D); //关闭二维纹理
glDisable(GL_TEXTURE_3D ); //关闭三维纹理
4.计算纹理坐标
调用glTexCoord*()函数指定纹理坐标
函数原型
void glTexCoord{1234}{sifd}(TYPE coords);
void glTexCoord{1234}v{sifd}(TYPE coords);
参数说明
纹理坐标可由s,t,r,q表示,对应几何坐标x,y,z,w。一维纹理只使用s坐标,二维纹理使用s,t坐标。纹理坐标的 范围通常在[0,1],也可以使用该范围以外的值;
参数coords即为纹理坐标数组;
glTexCoord()函数指定的纹理坐标对应其后glVertex*()函数指定的顶点。
glTexCoord*()函数应用实例
glBegin(GL_QUADS);
glTexCoord2d(0.0, 0.0); glVertex3f(-5.0, -5.0, 0.0);
glTexCoord2d(1.0, 0.0); glVertex3f(5.0, -5.0, 0.0);
glTexCoord2d(1.0, 1.0); glVertex3f(5.0, 5.0, 0.0);
glTexCoord2d(0.0, 1.0); glVertex3f(-5.0, 5.0, 0.0);
glEnd();
5.自动计算纹理坐标
调用glTexGen*()函数
void glTexGen{ifd}(GLenum coord, GLenum pname, TYPE param);
void glTexGen{ifd}v(GLenum coord, GLenum pname, TYPE *param);
参数说明
coord必须为GL_S,GL_T,GL_R,GL_Q分别表示生成的是s,t,r,q坐标;
pname可设置为GL_TEXTURE_GEN_MODE、GL_OBJECT_PLANE 或GL_EYE_PLANE
param相对于 pname为GL_TEXTURE_GEN_MODE时,可以取GL_OBJECT_LINEAR(物体线性)、GL_EYE_LINEAR(视觉线性)、GL_SPHERE_MAP(球体贴图);
相对于 pname为GL_OBJECT_PLANE 或GL_EYE_PLANE时, param为一个参数数组,用以指定纹理生成
6.生成纹理名称
void glGenTextures(GLsizei n, Gluint *textureNames);
提供n个当前未被使用的纹理名称
纹理名称可以是任何非0的无符号整数
返回在由textureNames所指定的数组中
GLboolean glIsTexture(Gluint textureName);
确定纹理名称textureName是否已被使用
若纹理名称textureName已经被glGenTextures()返回,但是还没有被绑定,会返回GL_FALSE
如果纹理名称textureName已经被绑定,还未被删除,则返回GL_TRUE
7.绑定纹理
void glBindTexture(GLenum target, Gluint textureName);
创建纹理对象,并使用纹理对象
当绑定了一个纹理对象textureName时,该纹理对象被创建,并且接下来的所有的纹理设置和操作函数调用都是针对该纹理对象的
当重新绑定纹理对象textureName时,其数据成为当前的纹理状态
多重纹理应该为每个level的纹理创建一个纹理对象
8.删除纹理对象
void glDeleteTextures (GLsizei n, const Gluint *textureNames);
删除textureNames数组所指定的所有纹理对象
OpenGL对场景中的纹理提供了控制函数
对纹理进行缩放
在某一坐标方向上重复或箝位纹理
纹理控制函数glTexParameter*()
函数原型
void glTexParameter{if}{v}(GLenum target, GLenum pname, TYPE param);
参数说明
target 为GL_TEXTURE_1D、 GL_TEXTURE_2D或GL_TEXTURE_3D
控制函数glTexParameter*()中参数pname和param的对应关系
9.放大和缩小纹理
OpenGL采用滤波方法对纹理进行缩放
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
GL_TEXTURE_MAG_FILTER 放大纹理滤波
GL_TEXTURE_MIN_FILTER 缩小纹理滤波
GL_NEAREST 表示选择最接近像素中心的纹素进行放大或缩小;
GL_LINEAR 表示选择距离像素中心最近的22维纹素数组加权平均后进行放大或缩小;
GL_TEXTURE_MIN_FILTER 缩小纹理滤波的其他参数