实验四 纹理映射实验
实验项目性质:设计性实验
所属课程名称:计算机图形学A
实验计划学时:3学时
一、实验目的和要求
掌握纹理映射的基本原理,利用VC++ OpenGL实现纹理映射技术。
二、实验原理
纹理映射是真实感图形制作的一个重要部分,运用纹理映射可以方面地制作真实感图形,而不必花更多的时间去考虑物体的表面纹理。如一张木制桌子其表面的木纹是不规范的,看上去又是那么自然,如果在图形制作中不用纹理映射,那么只是这张桌面纹理的设计,就要花费很大精力,而且设计结果也未必能像现实中那么自然。如果运用纹理映射就非常方便,可以用扫描仪将这样的一张桌子扫成一个位图。然后的具体的操作中,只需把桌面形状用多边形画出来,把桌面纹理贴上去就可以了。
另外,纹理映射能够在多边形进行变换时仍保证纹理的图案与多边形保持一致性。例如,以透视投影方式观察墙面时,远端的砖会变小,而近处的砖就会大一些。
此外,纹理映射也可以用于其他方面。例如,使用一大片植被的图像映射到一些连续的多边形上,以模拟地貌,或者以大理石、木纹等自然物质的图像作为纹理映射到相应的多边形上,作为物体的真实表面。
在OpenGL中提供了一系列完整的纹理操作函数,用户可以用它们构造理想的物体表面,可以对光照物体进行处理,使其映射出所处环境的景象,可以用不同方式应用到曲面上,而且可以随几何物体的几何属性变换而变化,从而使制作的三维场景和三维物体更真实更自然。
在OpenGL中要实现纹理映射,需要经历创建纹理、指定纹理应用方式、启用纹理映射、使用纹理坐标和几何坐标绘制场景几个过程。
用于指定一维、二维和三维纹理的函数分别为:
Void glTexImage1D(GLenum target, Glint level, Glint components, GLsizei width, Glint border, GLenum format, GLenum type, const GLvoid *texels);
Void glTexImage2D(GLenum target, Glint level, Glint components, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *texels);
Void glTexImage3D(GLenum target, Glint level, Glint components, GLsizei width, GLsizei height, GLsizei depth, Glint border, GLenum format, GLenum type, const GLvoid *texels);
其中,参数target取值一般为GL_TEXTURE_1D, GL_TEXTURE_2D和GL_TEXTURE_3D,分别与一维、二维和三维的纹理相对应。参数Level表示纹理多分辨率层数,通常取值为0,表示只有一种分辨率。参数components的可能取值为1~4的整数以及多种符号常量(如GL_RGBA),表示纹理元素中存储的哪些分量(RGBA颜色、深度等)在纹理映射中被使用,1表示使用R颜色分量,2表示使用R和A颜色分量,3表示使用RGB颜色分量,4表示使用RGBA颜色分量。参数width,height,depth分别指定纹理的宽度、高度、深度。参数format和type表示给出的图像数据的数据格式和数据类型,这两个参数的取值都是符号常量(比如format指定为GL_RGBA,type指定为GL_UNSIGNED_BYTE,参数texels指向内存中指定的纹理图像数据。
比如:glTexImage2D(GL_TEXTURE_2D, 0, 3, 64, 64, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
在定义了纹理之后,需要启用纹理的函数:
glEnable(GL_TEXTURE_1D);
glEnable(GL_TEXTURE_2D);
glEnable(GL_TEXTURE_3D);
在启用纹理之后,需要建立物体表面上点与纹理空间的对应关系,即在绘制基本图元时,在glVertex函数调用之前调用glTexCoord函数,明确指定当前顶点所对应的纹理坐标,例如:
glBegin(GL_TRIANGLES);
glTexCoord2f(0.0, 0.0); glVertex2f(0.0, 0.0);
glTexCoord2f(1.0, 1.0); glVertex2f(15.0, 15.0);
glTexCoord2f(1.0, 0.0); glVertex2f(30.0, 0.0);
glEnd();
其图元内部点的纹理坐标利用顶点处的纹理坐标采用线性插值的方法计算出来。
在OpenGL中,纹理坐标的范围被指定在[0,1]之间,而在使用映射函数进行纹理坐标计算时,有可能得到不在[0,1]之间的坐标。此时OpenGL有两种处理方式,一种是截断,另一种是重复,它们被称为环绕模式。在截断模式(GL_CLAMP)中,将大于1.0的纹理坐标设置为1.0,将小于0.0的纹理坐标设置为0.0。在重复模式(GL_REPEAT)中,如果纹理坐标不在[0,1]之间,则将纹理坐标值的整数部分舍弃,只使用小数部分,这样使纹理图像在物体表面重复出现。例如,使用下面的函数:
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
分别指定二维纹理中s坐标采用截断或重复处理方式。
另外,在变换和纹理映射后,屏幕上的一个像素可能对应纹理元素的一小部分(放大),也可能对应大量的处理元素(缩小)。在OpenGL中,允许指定多种方式来决定如何完成像素与纹理元素对应的计算方法(滤波)。比如,下面的函数可以指定放大和缩小的滤波方法:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
其中,glTexParameteri函数的第一个参数指定使用的是一维、二维或三维纹理;第二个参数为GL_TEXTURE_MAG_FILTER或GL_TEXTURE_MIN_FILTER,指出要指定缩小还是放大滤波算法;最后一个参数指定滤波的方法。
定义纹理参数和指定纹理的函数可以放在init函数中,也可以放在main函数中。
三、实验内容
在OpenGL中纹理映射所使用的纹理数据,既可以是程序生成的一组数据,也可以从外部文件中直接读取。
- 利用直接创建纹理的方法生成二维纹理并映射到四边形上。
二维纹理生成代码:
void makeImage(void)
{
int i, j, r,g,b;
for (i = 0; i < ImageWidth; i++)
{
for (j = 0; j < ImageHeight; j++)
{
r=(i*j)%255;
g=(4*i)%255;
b=(4*j)%255;
Image[i][j][0] = (GLubyte) r;
Image[i][j][1] = (GLubyte) g;
Image[i][j][2] = (GLubyte) b;
}
}
}
- 从外部文件中直接读取纹理实现正方体每个面的纹理映射,并使正方体转动。整个过程需要三个步骤:创建纹理对象并绑定纹理、启用纹理映射和使用纹理坐标和几何坐标绘制,下面我们主要对创建纹理和绑定纹理这一过程进行阐述,并给出参考代码。
1)创建纹理对象并绑定纹理
纹理创建即在内存中创建保存纹理数据的数组,一般是先读入一个图像文件,将图像文件的RGBA信息存入我们创建的纹理空间中,当然图像的位图不同,创建的纹理空间结构也会有所不同。为了更加简单易懂地实现这个过程,我们使用未压缩的纹理。
代码:
GLuint texture[1]; //创建一个纹理空间
AUX_RGBImageRec *LoadBMP(CHAR *Filename) //载入位图图像
{
FILE *File=NULL; //文件句柄
if(!Filename) //确保文件名已提供
{
return NULL;
}
File=fopen(Filename, "r"); //尝试打开文件
if(File)
{
fclose(File); //关闭文件
return auxDIBImageLoadA(Filename); //载入位图并返回指针
}
return NULL; //如果载入失败,返回NULL
}
int LoadGLTextures() //载入位图并转换成纹理
{
int Status=FALSE; //状态指示器
AUX_RGBImageRec *TextureImage[1]; //创建纹理的存储空间
memset(TextureImage, 0, sizeof(void *)*1);//初始化
//载入位图,检查有无错误,如果位图没找到则退出
if(TextureImage[0]=LoadBMP("data.bmp"))
{
Status=TRUE;
//使用来自位图数据生成的纹理
glBindTexture(GL_TEXTURE_2D, 0);
//指定二维纹理
glTexImage2D(GL_TEXTURE_2D,0,3,TextureImage[0]->sizeX,TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
if(TextureImage[0]) //纹理是否存在
{
if(TextureImage[0]->data) //纹理图像是否存在
{
free(TextureImage[0]->data); //释放纹理图像占用的内存
}
free(TextureImage[0]); //释放图像结构
}
return Status; //返回Status
}
2)启用纹理映射操作,初始化相关参数
3)使用纹理坐标和几何坐标绘制
- 实现立方体六个面加不同纹理的效果。
应用纹理对象:
Gluint my_texture=1;
glBindTexture(GL_TEXTURE_2D, my_texture);
- 给实验二绘制的桌子加上纹理。
选做:1)利用纹理坐标给曲面加上纹理(球面、茶壶)
GLfloat planes[] = { 0.5,0.0,0.0,0.5 };
GLfloat planet[] = { 0.0,0.5,0.0,0.5 };
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glTexGenfv(GL_S, GL_OBJECT_LINEAR, planes);
glTexGenfv(GL_T, GL_OBJECT_LINEAR, planet);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
2)利用OpenGL函数实现球面环境映射效果:
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
四、实验设计思路
1.根据示例进行修改代码
2.创建一个正方体,使用给定的代码加载纹理图片,使用glTexCoord2f(); glVertex3f();函数使得纹理的坐标与正方体的四边形顶点每个面进行对应,再利用glBindTexture()函数赋予每个面的贴图。
3.与2对应,将每个面使用glBindTexture()函数进行赋予不同的贴图。
4.将实验二中的椅子进行赋予纹理,与上述方式相似,利用给定代码加载纹理图片,从而进行模型纹理的映射。
5.与4同样的方式,主要是构建茶壶模型,以及纹理坐标和点的对应。
五、实验代码
1.
// texture2.cpp : 定义控制台应用程序的入口点。 // //#include "stdafx.h" #include <GL/glut.h> #include <stdlib.h> #include <stdio.h> // 创建棋盘格子纹理图样 #define checkImageWidth 128 #define checkImageHeight 128 static GLubyte checkImage[checkImageHeight][checkImageWidth][4]; #ifdef GL_VERSION_1_1 static GLuint texName; #endif void makeCheckImage(void) { int i, j, r, g, b; for (i = 0; i < checkImageWidth; i++) { for (j = 0; j < checkImageHeight; j++) { r = (i * j) % 255; g = (4 * i) % 255; b = (4 * j) % 255; checkImage[i][j][0] = (GLubyte)r; checkImage[i][j][1] = (GLubyte)g; checkImage[i][j][2] = (GLubyte)b; } } } void init(void) { glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_FLAT); glEnable(GL_DEPTH_TEST); makeCheckImage(); // glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 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, 4, checkImageWidth, checkImageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, checkImage); } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_TEXTURE_2D); glBegin(GL_QUADS); glColor3f(1.0, 1.0, 0.0); glTexCoord2f(0.0, 0.0); glVertex3f(-2.0, -1.0, 0.0); glTexCoord2f(0.0, 1.0); glVertex3f(-2.0, 1.0, 0.0); glTexCoord2f(1.0, 1.0); glVertex3f(0.0, 1.0, 0.0); glTexCoord2f(1.0, 0.0); glVertex3f(0.0, -1.0, 0.0); glTexCoord2f(0.0, 0.0); glVertex3f(1.0, -1.0, 0.0); glTexCoord2f(0.0, 2.0); glVertex3f(1.0, 1.0, 0.0); glTexCoord2f(2.0, 2.0); glVertex3f(2.41421, 1.0, -1.41421); glTexCoord2f(2.0, 0.0); glVertex3f(2.41421, -1.0, -1.41421); glEnd(); glFlush(); } void reshape(int w, int h) { glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0, (GLfloat)w / (GLfloat)h, 1.0, 30.0); // glOrtho(-3, 3, -2, 2, 0,10); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0, 0.0, -3.6); } void keyboard(unsigned char key, int x, int y) { switch (key) { case 's': glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glutPostRedisplay(); break; case 'S': glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glutPostRedisplay(); break; case 't': glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glutPostRedisplay(); break; case 'T': glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glutPostRedisplay(); break; case 27: exit(0); break; default: break; } } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(250, 250); glutInitWindowPosition(100, 100); glutCreateWindow(argv[0]); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMainLoop(); return 0; }
2.
#include <GL/glut.h> #include <GL/glaux.h> #include <stdio.h> #include <stdlib.h> #include <windows.h> #pragma comment(lib, "openGL32.lib") #pragma comment(lib, "glu32.lib") #pragma comment(lib, "glaux.lib") #pragma comment( lib,"openGL32.lib" ) GLuint texture[1];//创建纹理空间 GLfloat xRot, yRot, zRot;//控制正方体的旋转 //载入位图图像 AUX_RGBImageRec* LoadBMP(CHAR* Filename) { //载入位图图像 FILE* File = NULL; //文件句柄 if (!Filename) { //确保文件名已提供 return NULL; } File = fopen(Filename, "r"); //尝试打开文件 if (File) { fclose(File); //关闭文件 return auxDIBImageLoadA(Filename); //载入位图并返回指针 } return NULL; //如果载入失败,返回NULL } int LoadGLTextures() //载入位图并转换成纹理 { int Status = FALSE; //状态指示器 AUX_RGBImageRec* TextureImage[1]; //创建纹理的存储空间 memset(TextureImage, 0, sizeof(void*) * 1);//初始化 //载入位图,检查有无错误,如果位图没找到则退出 if (TextureImage[0] = LoadBMP((CHAR*)"texture6.bmp")) { Status = TRUE; //使用来自位图数据生成的纹理 glBindTexture(GL_TEXTURE_2D, 0); //指定二维纹理 glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } if (TextureImage[0]) //纹理是否存在 { if (TextureImage[0]->data) //纹理图像是否存在 { free(TextureImage[0]->data); //释放纹理图像占用的内存 } free(TextureImage[0]); //释放图像结构 } return Status; //返回Status } int InitGL(GLvoid) { if (!LoadGLTextures()) { //调用纹理载入子例程 return FALSE; } glEnable(GL_TEXTURE_2D); //启用纹理映射 glShadeModel(GL_SMOOTH); //启用阴影平滑 glClearColor(0.0f, 0.0f, 0.0f, 0.5f); //黑色背景 glClearDepth(1.0f); //设置深度缓存 glEnable(GL_DEPTH_TEST); //启用深度测试 return TRUE; } void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslatef(0.0f, 0.0f, -5.0f); glRotatef(xRot, 1.0f, 0.0f, 0.0f); glRotatef(yRot, 0.0f, 1.0f, 0.0f); glRotatef(zRot, 0.0f, 0.0f, 1.0f); //绘制正方体,贴上纹理并使之转动 glBindTexture(GL_TEXTURE_2D, texture[0]); //选择纹理 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(); glBindTexture(GL_TEXTURE_2D, texture[0]); glBegin(GL_QUADS); //后 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); glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, -1.0f, -1.0f); glEnd(); glBindTexture(GL_TEXTURE_2D, texture[0]); glBegin(GL_QUADS); // 上 glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.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(1.0f, 1.0f); glVertex3f(1.0f, 1.0f, -1.0f); glEnd(); glBindTexture(GL_TEXTURE_2D, texture[0]); glBegin(GL_QUADS); //下 glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, -1.0f, -1.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(); glBindTexture(GL_TEXTURE_2D, texture[0]); glBegin(GL_QUADS); //右 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); glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, -1.0f, 1.0f); glEnd(); glBindTexture(GL_TEXTURE_2D, texture[0]); 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(); glutPostRedisplay(); glutSwapBuffers(); } void reshape(int w, int h) { if (0 == h) h = 1; glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0f, (GLfloat)w / (GLfloat)h, 1, 100); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void spinDisplay(void) { xRot += 0.2f; yRot += 0.2f; glutPostRedisplay(); } void mouse(int button, int state, int x, int y) //鼠标监听 { switch (button) { case GLUT_LEFT_BUTTON: if (state == GLUT_DOWN) glutIdleFunc(spinDisplay); //设备空闲时调用的函数 break; case GLUT_MIDDLE_BUTTON: case GLUT_RIGHT_BUTTON: if (state == GLUT_DOWN) glutIdleFunc(NULL); break; default: break; } } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); glutInitWindowSize(400, 400); glutInitWindowPosition(100, 100); glutCreateWindow("Texture Map"); InitGL(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMouseFunc(mouse);//鼠标监听 glutMainLoop(); return 0; }
3.
#include <GL/glut.h> #include <GL/glaux.h> #include <stdio.h> #include <stdlib.h> #include <windows.h> #pragma comment(lib, "openGL32.lib") #pragma comment(lib, "glu32.lib") #pragma comment(lib, "glaux.lib") #pragma comment( lib,"openGL32.lib" ) GLuint texture[1];//创建纹理空间 GLfloat xRot, yRot, zRot;//控制正方体的旋转 //载入位图图像 AUX_RGBImageRec* LoadBMP(CHAR* Filename) { //载入位图图像 FILE* File = NULL; //文件句柄 if (!Filename) { //确保文件名已提供 return NULL; } File = fopen(Filename, "r"); //尝试打开文件 if (File) { fclose(File); //关闭文件 return auxDIBImageLoadA(Filename); //载入位图并返回指针 } return NULL; //如果载入失败,返回NULL } //int LoadGLTextures() //载入位图并转换成纹理 //{ // int Status = FALSE; //状态指示器 // AUX_RGBImageRec* TextureImage[1]; //创建纹理的存储空间 // memset(TextureImage, 0, sizeof(void*) * 1);//初始化 ////载入位图,检查有无错误,如果位图没找到则退出 // if (TextureImage[0] = LoadBMP((CHAR*)"texture6.bmp")) // { // Status = TRUE; // //使用来自位图数据生成的纹理 // glBindTexture(GL_TEXTURE_2D, 0); // //指定二维纹理 // glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // } // // if (TextureImage[0]) //纹理是否存在 // { // if (TextureImage[0]->data) //纹理图像是否存在 // { // free(TextureImage[0]->data); //释放纹理图像占用的内存 // } // free(TextureImage[0]); //释放图像结构 // } // return Status; //返回Status //} int LoadGLTextures() //载入位图并转换成纹理 { int Status = FALSE; //状态指示器 AUX_RGBImageRec* TextureImage[6]; //创建纹理的存储空间 memset(TextureImage, 0, sizeof(void*) * 6);//初始化 //载入位图,检查有无错误,如果位图没找到则退出 char* image[] = { (char*)"texture1.bmp", (char*)"texture2.bmp", (char*)"texture3.bmp", (char*)"texture4.bmp", (char*)"texture5.bmp", (char*)"texture6.bmp", }; for (int i = 0; i < 6; i++) { if (TextureImage[i] = LoadBMP(image[i])) { Status = TRUE; glGenTextures(1, &texture[i]); //使用来自位图数据生成的纹理 glBindTexture(GL_TEXTURE_2D, texture[i]); //指定二维纹理 glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[i]->sizeX, TextureImage[i]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[i]->data); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } if (i == 5) { printf("cecewce"); } if (TextureImage[i]) //纹理是否存在 { if (TextureImage[i]->data) //纹理图像是否存在 { printf("纹理存在"); free(TextureImage[i]->data); //释放纹理图像占用的内存 } free(TextureImage[i]); //释放图像结构 } } return Status; //返回Status } int InitGL(GLvoid) { if (!LoadGLTextures()) { //调用纹理载入子例程 return FALSE; } glEnable(GL_TEXTURE_2D); //启用纹理映射 glShadeModel(GL_SMOOTH); //启用阴影平滑 glClearColor(0.0f, 0.0f, 0.0f, 0.5f); //黑色背景 glClearDepth(1.0f); //设置深度缓存 glEnable(GL_DEPTH_TEST); //启用深度测试 return TRUE; } void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslatef(0.0f, 0.0f, -5.0f); glRotatef(xRot, 1.0f, 0.0f, 0.0f); glRotatef(yRot, 0.0f, 1.0f, 0.0f); glRotatef(zRot, 0.0f, 0.0f, 1.0f); //绘制正方体,贴上纹理并使之转动 glBindTexture(GL_TEXTURE_2D, texture[0]); //选择纹理 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(); glBindTexture(GL_TEXTURE_2D, texture[1]); glBegin(GL_QUADS); //后 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); glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, -1.0f, -1.0f); glEnd(); glBindTexture(GL_TEXTURE_2D, texture[4]); glBegin(GL_QUADS); // 上 glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.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(1.0f, 1.0f); glVertex3f(1.0f, 1.0f, -1.0f); glEnd(); glBindTexture(GL_TEXTURE_2D, texture[3]); glBegin(GL_QUADS); //下 glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, -1.0f, -1.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(); glBindTexture(GL_TEXTURE_2D, texture[4]); glBegin(GL_QUADS); //右 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); glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, -1.0f, 1.0f); glEnd(); glBindTexture(GL_TEXTURE_2D, texture[5]); 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(); glutPostRedisplay(); glutSwapBuffers(); } void reshape(int w, int h) { if (0 == h) h = 1; glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0f, (GLfloat)w / (GLfloat)h, 1, 100); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void spinDisplay(void) { xRot += 0.2f; yRot += 0.2f; glutPostRedisplay(); } void mouse(int button, int state, int x, int y) //鼠标监听 { switch (button) { case GLUT_LEFT_BUTTON: if (state == GLUT_DOWN) glutIdleFunc(spinDisplay); //设备空闲时调用的函数 break; case GLUT_MIDDLE_BUTTON: case GLUT_RIGHT_BUTTON: if (state == GLUT_DOWN) glutIdleFunc(NULL); break; default: break; } } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); glutInitWindowSize(400, 400); glutInitWindowPosition(100, 100); glutCreateWindow("Texture Map"); InitGL(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMouseFunc(mouse);//鼠标监听 glutMainLoop(); return 0; }
4.
#define _CRT_SECURE_NO_WARNINGS #include <GL/glut.h> #include <stdlib.h> #include<GL/glaux.h> #include<stdio.h> float size = 0.25; //缩放 float fRotate = 0; float fScale = 1.0f; // set inital scale value to 1.0f float x = 1, y = 0, z = 0; static GLfloat spin = 0.0; static GLfloat i = 0.0; // 初始化材质特性、 光源、 光照模型和深度缓冲区 GLuint texture[1]; //创建一个纹理空间 AUX_RGBImageRec* LoadBMP(CHAR* Filename) //载入位图图像 { FILE* File = NULL; //文件句柄 if (!Filename) //确保文件名已提供 { return NULL; } File = fopen(Filename, "r"); //尝试打开文件 if (File) { fclose(File); //关闭文件 return auxDIBImageLoadA(Filename); //载入位图并返回指针 } return NULL; //如果载入失败,返回NULL } int LoadGLTextures() //载入位图并转换成纹理 { int Status = FALSE; //状态指示器 AUX_RGBImageRec* TextureImage[1]; //创建纹理的存储空间 memset(TextureImage, 0, sizeof(void*) * 1);//初始化 //载入位图,检查有无错误,如果位图没找到则退出 if (TextureImage[0] = LoadBMP((CHAR*)"texture.bmp")) { Status = TRUE; //使用来自位图数据生成的纹理 glBindTexture(GL_TEXTURE_2D, 0); //指定二维纹理 glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } if (TextureImage[0]) //纹理是否存在 { if (TextureImage[0]->data) //纹理图像是否存在 { free(TextureImage[0]->data); //释放纹理图像占用的内存 } free(TextureImage[0]); //释放图像结构 } return Status; //返回Status } void myinit(void) { glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST); GLfloat mat_ambient[] = { 0.2, 0.2, 0.2, 1.0 }; GLfloat mat_diffuse[] = { 0.8, 0.8, 0.8, 1.0 }; GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat mat_shininess[] = { 50.0 }; GLfloat light0_ambient[] = { 0.2, 0.2, 0.2, 1.0 }; GLfloat light0_diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat light0_specular[] = { 0.0, 1.0, 1.0, 1.0 }; GLfloat light0_position[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat light1_ambient[] = { 0.2, 0.2, 0.2, 1.0 };//环境光 GLfloat light1_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };//漫反射 GLfloat light1_specular[] = { 0.0, 0.0, 1.0, 1.0 };//镜面反射 GLfloat light1_position[] = { 0.0, -1.5, -4.0, 1.0 }; GLfloat spot_direction[] = { 0.0, 1.5, -6.0 }; glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, light0_specular); glLightfv(GL_LIGHT0, GL_POSITION, light0_position); glLightfv(GL_LIGHT1, GL_AMBIENT, light1_ambient); glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse); glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular); glLightfv(GL_LIGHT1, GL_POSITION, light1_position); glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, spot_direction); glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 30.0); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_LIGHT1); glDepthFunc(GL_LESS); glEnable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); LoadGLTextures(); GLfloat planes[] = { 0.5,0.0,0.0,0.5 }; GLfloat planet[] = { 0.0,0.5,0.0,0.5 }; glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); glTexGenfv(GL_S, GL_OBJECT_LINEAR, planes); glTexGenfv(GL_T, GL_OBJECT_LINEAR, planet); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); } void Draw_Leg() // This function draws one of the table leg { //绘制一个桌子腿 glPushMatrix(); glScalef(1.0f, 1.0f, 3.0f); glutSolidCube(1.0 * size); glPopMatrix(); } void Draw_Table() // This function draws a Table { glPushMatrix(); //将当前矩阵保存入堆栈顶(保存当前矩阵)。 glScalef(5.0f, 4.0f, 1.0f); //缩放函数 glColor3f(1.0, 0.0, 1.0); glutSolidCube(1 * size); //绘制线立方体 glPopMatrix(); //pop出来 glPushMatrix(); //将当前矩阵保存入堆栈顶(保存当前矩阵)。 glScalef(4.0f, 1.0f, 4.0f); //缩放函数 glTranslatef(0.0 * size, 1.5 * size, 0.5 * size); glColor3f(0.0, 0.0, 1.0); glutSolidCube(1 * size); //绘制线立方体 glPopMatrix(); //pop出来 glPushMatrix(); //左下角的柱子 glTranslatef(-1.5 * size, -1 * size, -1.5 * size); //尺寸是相对于中心的坐标原点,按照实验指导上的大小进行的 Draw_Leg(); glPopMatrix(); glPushMatrix(); //右下角的柱子 glTranslatef(1.5 * size, -1 * size, -1.5 * size); Draw_Leg(); glPopMatrix(); glPushMatrix(); //右上角的柱子 glTranslatef(1.5 * size, 1 * size, -1.5 * size); Draw_Leg(); glPopMatrix(); glPushMatrix(); //左上角的柱子 glTranslatef(-1.5 * size, 1 * size, -1.5 * size); Draw_Leg(); glPopMatrix(); } void display(void) { GLfloat position[] = { 0.0, -1.5, -4.0, 1.0 }; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glTranslatef(0.0f, 0.0f, -6.0f); // Place the triangle at Center glRotatef(fRotate, 1, 0, 0); // Rotate around Y axis Draw_Table(); // Draw triangle glPopMatrix(); fRotate += 0.05; glutSwapBuffers(); //交换双缓存 glFlush(); } void myReshape(int width, int height) { glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void keyboard(unsigned char key, int x, int y) { switch (key) { case'x': exit(0); break; default: break; } } void spinDisplay(void) { spin = spin + 0.02; if (spin > 360.0) spin = spin - 360.0; glutPostRedisplay(); } void mouse(int button, int state, int x, int y) { switch (button) { case GLUT_LEFT_BUTTON: if (state == GLUT_DOWN) glutIdleFunc(spinDisplay); //设 备空闲时调用的函数 break; case GLUT_MIDDLE_BUTTON: case GLUT_RIGHT_BUTTON: if (state == GLUT_DOWN) glutIdleFunc(NULL); break; default: break; } } //主函数, 初始化窗口大小、RGBA 显示模式和处理输入事件 int main(int argc, char* argv[]) { glutInit(&argc, argv); //glutIni tDi splayMode (GLUT. SINGLE| GLUT_ RGB); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); //使用双缓存模式 glutInitWindowSize(640, 480); glutInitWindowPosition(0, 0); glutCreateWindow("位置光源和多光源演示"); glutReshapeFunc(myReshape); glutDisplayFunc(display); myinit(); glutMouseFunc(mouse); glutKeyboardFunc(keyboard); glutMainLoop(); return 0; }
5.
#define _CRT_SECURE_NO_WARNINGS #include <GL/glut.h> #include<GL/glaux.h> #include<stdio.h> static GLfloat theta[] = { 0.0,0.0,0.0 }; static GLint axis = 2; GLuint texture[1]; //创建一个纹理空间 AUX_RGBImageRec* LoadBMP(CHAR* Filename) //载入位图图像 { FILE* File = NULL; //文件句柄 if (!Filename) //确保文件名已提供 { return NULL; } File = fopen(Filename, "r"); //尝试打开文件 if (File) { fclose(File); //关闭文件 return auxDIBImageLoadA(Filename); //载入位图并返回指针 } return NULL; //如果载入失败,返回NULL } int LoadGLTextures() //载入位图并转换成纹理 { int Status = FALSE; //状态指示器 AUX_RGBImageRec* TextureImage[1]; //创建纹理的存储空间 memset(TextureImage, 0, sizeof(void*) * 1);//初始化 //载入位图,检查有无错误,如果位图没找到则退出 if (TextureImage[0] = LoadBMP((CHAR*)"texture3.bmp")) { Status = TRUE; //使用来自位图数据生成的纹理 glBindTexture(GL_TEXTURE_2D, 0); //指定二维纹理 glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } if (TextureImage[0]) //纹理是否存在 { if (TextureImage[0]->data) //纹理图像是否存在 { free(TextureImage[0]->data); //释放纹理图像占用的内存 } free(TextureImage[0]); //释放图像结构 } return Status; //返回Status } void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glRotatef(theta[0], 1.0, 0.0, 0.0); glRotatef(theta[1], 0.0, 1.0, 0.0); glRotatef(theta[2], 0.0, 0.0, 1.0); glutSolidTeapot(1.0); // glutSolidCube(3.0); // glutSolidSphere(1.0, 50, 50); glutSwapBuffers(); } void spinCube() { theta[axis] += 0.05; if (theta[axis] > 360.0) theta[axis] -= 360.0; glutPostRedisplay(); } void mouse(int btn, int state, int x, int y) { if (btn == GLUT_LEFT_BUTTON && state == GLUT_DOWN) axis = 0; if (btn == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) axis = 1; if (btn == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) axis = 2; } void myReshape(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-2.0, 2.0, -2.0 * (GLfloat)h / (GLfloat)w, 2.0 * (GLfloat)h / (GLfloat)w, -10.0, 10.0); else glOrtho(-2.0 * (GLfloat)w / (GLfloat)h, 2.0 * (GLfloat)w / (GLfloat)h, -2.0, 2.0, -10.0, 10.0); glMatrixMode(GL_MODELVIEW); } void key(unsigned char k, int x, int y) { if (k == '1') glutIdleFunc(spinCube); if (k == '2') glutIdleFunc(NULL); if (k == 'q') exit(0); } void Init() { glClearColor(1.0, 1.0, 1.0, 1.0); glEnable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); glShadeModel(GL_SMOOTH); LoadGLTextures(); GLfloat planes[] = { 0.5,0.0,0.0,0.5 }; GLfloat planet[] = { 0.0,0.5,0.0,0.5 }; glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); glTexGenfv(GL_S, GL_OBJECT_LINEAR, planes); glTexGenfv(GL_T, GL_OBJECT_LINEAR, planet); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(500, 500); glutCreateWindow("colorcube"); glutReshapeFunc(myReshape); glutDisplayFunc(display); glutIdleFunc(spinCube); glutMouseFunc(mouse); Init(); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glutKeyboardFunc(key); glutMainLoop(); }
六、实验结果与心得
编辑编辑
编辑编辑
编辑
此次实验,对三维立体图形纹理映射,使得物体更加具有真实感,通过贴图进行纹理的映射,通过坐标进行面的纹理赋予。通过本次实验,学习了图形学中的纹理映射,收获颇多,对今后本课程的学习有了较大的帮助。