OpenGL学习——纹理贴图一

本篇文章为纹理贴图的第一次学习,没太多时间去深入的学,把每个函数都搞得明明白白,所以这里自己的理解写的比较少。别人总结的还蛮好的,所以我主要是总结了几篇其他文章的内容,如果不去深究每个函数,我觉得足以让你明白纹理贴图的一个大致操作流程。

这篇就当做入门的吧,纹理映射还是比较难的,后面肯定会结合着代码再写的。

开篇先放一个大致流程,方便以后快速查看:

启用2D纹理
加载纹理图像(即导入图片)
创建纹理对象
绑定纹理对象
设定纹理过滤的参数
为纹理对象指定纹理图像数据
纹理映射,绘制纹理图像

一、创建纹理对象,并为它指定一个纹理

启用纹理贴图

glEnable(GL_TEXTURE_2D);

定义一个纹理对象编号

static GLuint texName;

创建一个纹理对象,&texName指向纹理索引

glGenTextures(1, &texName);

绑定纹理:改变OpenGL状态,使得后续的纹理操作都对texName指向的2D纹理生效

glBindTexture(GL_TEXTURE_2D, texName);

二、载入纹理,设置纹理参数

  1. 纹理过滤函数

glTexParameteri()

图象从纹理图象空间映射到帧缓冲图象空间(映射需要重新构造纹理图像,这样就会造成应用到多边形上的图像失真),这时就可用glTexParmeteri()函数来确定如何把纹理象素映射成像素。

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

这些参数先不用管,就是说贴图时的各种限制和模式。

以后还会总结的。

  1. 指定纹理贴图与材质的混合模式

glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

材质这个不是太懂。

  1. 为纹理对象指定一个纹理

glTexImage2D (
GLenum target, //指定的目标,可以使用GL_TEXTURE_2D
GLint level, //“多重细节层次”,不考虑多重纹理的话设置为零。
GLint internalformat,//RGB数据存储的格式,比如GL_RGB
GLsizei width,
GLsizei height, //二维纹理像素的宽度和高度。
GLint border, //纹理边框的大小,不使用纹理边框设置为零。
GLenum format, //
GLenum type, //数据格式和数据保存形式。
const GLvoid *pixels //保存了纹理图像的内参块地址。
);

此函数的参数可以像下面这样设置:

glTexImage2D(
GL_TEXTURE_2D,        //target,目标纹理
0, 			          //分辨率级数参数,默认为0
GL_RGBA, 	       	  //纹理单元格式
checkImageWidth,      //纹理图像的宽
checkImageHeight,     //纹理图像的高
0, 			          //纹理图像边框的宽度,0或1
GL_RGBA,              //纹理像素数据的格式
GL_UNSIGNED_BYTE, 	  //像素数据类型
checkImage	          //内存中指向纹理图像的指针
);

三、纹理映射,绘制纹理图像

纹理映射跟颜色的绘制一样,需要指定每一个顶点在纹理图像中所对应的位置,OpenGL会自动计算出顶点之间的其他点在纹理图像中应该对应的位置。这里注意纹理图像的坐标范围是从(0,0)到(1,1),左下角为(0,0),右上角为(1,1)。比如,将图像映射到多个四边形上:

    // 绘制底面以及纹理glBindTexture(GL_TEXTURE_2D, texSea);glBegin(GL_QUADS);glTexCoord2f(0.0f, 0.0f);   //纹理坐标配置函数glVertex3f(-8.0f, -8.0f, 0.0f);glTexCoord2f(0.0f, 3.0f);glVertex3f(-8.0f, 8.0f, 0.0f);glTexCoord2f(3.0f, 3.0f);glVertex3f(8.0f, 8.0f, 0.0f);glTexCoord2f(3.0f, 0.0f);glVertex3f(8.0f, -8.0f, 0.0f);glEnd();

此代码显示3行3列个位图(共9个)(如果坐标是小于1的,那就是正常的映射),坐标可以这样映射:(0.0f, 0.0f)、(0.0f, 3.0f)、(3.0f, 3.0f)、(3.0f, 0.0f)。

glTexCoord2f()主要与glVertex3f()配合使用,glTexCoord2f()是配置纹理坐标,glVertex3f()是配置图形坐标。

四、其他补充

参考文章:
https://blog.csdn.net/dcrmg/article/details/53180369

更详细的解释可以看这篇文章(我以后会再总结):

https://www.cnblogs.com/sunliming/archive/2011/07/17/2108917.html

下面这个代码的原文章有大致这样说明,读取纹理图片到内存时,位图的大小有规定的大小,宽度什么的有些要求,如果长宽有超过当前版本所支持最大长宽数值,还需要对图像进行缩放。这里我们先不管这个格式问题了,给的位图是标准的。

还有代码中关于读取位图的操作,我觉得有点麻烦,我看有些直接使用stb_image.h来加载图像,这个我还没有研究,但肯定比这篇文章的示例代码简单些。

他这个代码是手动分配内存的,就先别管了,重点是看纹理的使用流程。

ps:给的代码放到桌面上运行。
在这里插入图片描述

#define WindowWidth  400
#define WindowHeight 400
#define WindowTitle  "纹理贴图"#include 
#include 
#include 
#define GL_BGR_EXT 0x80E0   //我这个版本找不到这个宏,需要自己定义//定义两个纹理对象编号
GLuint texSea;
GLuint texSky;#define BMP_Header_Length 54  //图像数据在内存块中的偏移量static GLfloat angle = 0.0f;   //旋转角度//读取一个BMP文件作为纹理。如果失败,返回0,如果成功,返回纹理编号.
//这个代码的处理位图的操作太麻烦了,可以先不管,知道他把位图保存到了一个字节变量pixel中就好
GLuint load_texture(const char* file_name)
{GLint width, height, total_bytes;GLubyte* pixels = 0;GLuint last_texture_ID=0, texture_ID = 0;// 打开文件,如果失败,返回FILE* pFile = fopen(file_name, "rb");if( pFile == 0 ){printf("Wrong!!!!\n");return 0;}// 读取文件中图象的宽度和高度fseek(pFile, 0x0012, SEEK_SET);fread(&width, 4, 1, pFile);fread(&height, 4, 1, pFile);fseek(pFile, BMP_Header_Length, SEEK_SET);// 计算每行像素所占字节数,并根据此数据计算总像素字节数GLint line_bytes = width * 3;while( line_bytes % 4 != 0 )++line_bytes;total_bytes = line_bytes * height;// 根据总像素字节数分配内存pixels = (GLubyte*)malloc(total_bytes);if( pixels == 0 ){fclose(pFile);return 0;}// 读取像素数据if( fread(pixels, total_bytes, 1, pFile) <= 0 ){free(pixels);fclose(pFile);return 0;}// 分配一个新的纹理编号glGenTextures(1, &texture_ID);if( texture_ID == 0 ){free(pixels);fclose(pFile);return 0;}// 绑定新的纹理,载入纹理并设置纹理参数// 在绑定前,先获得原来绑定的纹理编号,以便在最后进行恢复GLint lastTextureID = last_texture_ID;glGetIntegerv(GL_TEXTURE_BINDING_2D, &lastTextureID);glBindTexture(GL_TEXTURE_2D, texture_ID);   //绑定纹理//设置4个常用的纹理参数。。如何把纹理像素映射成像素glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //指定纹理贴图与材质的混合模式//参数: 目标纹理,多重细节层次(不考虑多重纹理为0),RGB数据存储格式,二维纹理像素宽高,纹理边框大小//       纹理像素数据的格式,数据保存形式(像素数据类型,字节),内存中指向纹理图像的指针(纹理图像的内参快地址)glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels); //为纹理对象指定一个纹理glBindTexture(GL_TEXTURE_2D, lastTextureID);  //恢复之前的纹理绑定free(pixels);return texture_ID;
}void display(void)
{// 清除屏幕glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// 设置视角和观察点glMatrixMode(GL_PROJECTION);glLoadIdentity();gluPerspective(75, 1, 1, 21);glMatrixMode(GL_MODELVIEW);glLoadIdentity();gluLookAt(-4, 7,7, 0, 0, 0, 0, 0, 1);glRotatef(angle, 0.0f, 0.0f, 1.0f); //旋转矩形,实现物体的旋转// 绘制底面以及纹理glBindTexture(GL_TEXTURE_2D, texSea);glBegin(GL_QUADS);glTexCoord2f(0.0f, 0.0f);   //纹理坐标配置函数glVertex3f(-8.0f, -8.0f, 0.0f);glTexCoord2f(0.0f, 3.0f);glVertex3f(-8.0f, 8.0f, 0.0f);glTexCoord2f(3.0f, 3.0f);glVertex3f(8.0f, 8.0f, 0.0f);glTexCoord2f(3.0f, 0.0f);glVertex3f(8.0f, -8.0f, 0.0f);glEnd();//比如显示3行2列个位图(共6个),坐标可以这样:(0.0f, 0.0f)、(0.0f, 3.0f)、(2.0f, 3.0f)、(2.0f, 0.0f)。//该函数主要与glVertex3f()配合使用,glTexCoord2f()是配置纹理坐标,glVertex3f()是配置图形坐标。// 绘制立面glBindTexture(GL_TEXTURE_2D, texSky);glBegin(GL_QUADS);glTexCoord2f(0.0f, 0.0f);glVertex3f(-6.0f, -3.0f, 0.0f);glTexCoord2f(0.0f, 1.0f);glVertex3f(-6.0f, -3.0f, 5.0f);glTexCoord2f(2.0f, 1.0f);glVertex3f(6.0f, -3.0f, 5.0f);glTexCoord2f(2.0f, 0.0f);glVertex3f(6.0f, -3.0f, 0.0f);glEnd();//绘制另外一个立面glBegin(GL_QUADS);glTexCoord2f(2.0f, 0.0f);glVertex3f(6.0f, -3.0f, 0.0f);glTexCoord2f(0.0f, 0.0f);glVertex3f(6.0f, 9.0f, 0.0f);glTexCoord2f(0.0f, 1.0f);glVertex3f(6.0f, 9.0f, 5.0f);glTexCoord2f(2.0f, 1.0f);glVertex3f(6.0f, -3.0f, 5.0f);glEnd();glutSwapBuffers();
}//旋转角度
void myIdle(void)
{angle += 0.01f; //1.8fif( angle >= 360.0f )angle = 0.0f;display();
}int main(int argc, char* argv[])
{// GLUT初始化glutInit(&argc, argv);glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);glutInitWindowPosition(100, 100);glutInitWindowSize(WindowWidth, WindowHeight);glutCreateWindow(WindowTitle);glEnable(GL_DEPTH_TEST);glEnable(GL_TEXTURE_2D);    // 启用2D纹理功能texSea = load_texture("C:\\Users\\user\\Desktop\\贴图1_方块\\sea.bmp");texSky = load_texture("C:\\Users\\user\\Desktop\\贴图1_方块\\sky.bmp");  //加载纹理//绘图glutDisplayFunc(&display);glutIdleFunc(&myIdle);glutMainLoop();return 0;
}


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部