OpenGL织梦之旅【第三章】第1节.纹理贴图
来源:互联网 发布:广电网络移机怎么办 编辑:程序博客网 时间:2024/06/05 06:22
在了解纹理贴图之前,我们先要对BMP位图文件要有一定的了解。在Windows中,BMP格式是一个很常见的图像文件储存格式。位图文件由4个部分构成:位图文件头,位图信息头,彩色表以及定义位图的字节列阵。24位的真彩色图像不使用彩色表,所以可以暂时不用管它。
我们写个函数
int LoadBitmap(constchar *file)
图像bmp文件的地址是file,返回值int我们等一下再说为什么。
在windows.h中,定义了两个结构体BITMAPFILEHEADER和BITMAPINFOHEADER分别表示位图文件头和位图信息头。然后在定义一个byte数组image用于读入位图的数据信息。Width和height用于接受图像的长宽(单位:像素)。注意:每个像素因为由RGB三种不同光组合而成,所以实际上image数组保存数据的长度是width*height*3。
int width,height,i; byte *image; //接受图像数据 FILE *fp; //文件指针 BITMAPFILEHEADER FileHeader; //接受位图文件头 BITMAPINFOHEADER InfoHeader; //接受位图信息头 fp=fopen(file,"rb"); if (fp == NULL) { perror("LoadBitmap"); //打开文件失败 return -1; } fread(&FileHeader, sizeof(BITMAPFILEHEADER), 1, fp); if(FileHeader.bfType != BITMAP_ID) //确保文件是一个位图文件,效验文件类型 { printf("Error: This file is not a bmp file!"); fclose(fp); return -1; } fread(&InfoHeader, sizeof(BITMAPINFOHEADER), 1, fp); width=InfoHeader.biWidth; height=InfoHeader.biHeight; if (InfoHeader.biSizeImage == 0) //确保图像数据的大小 { InfoHeader.biSizeImage = width*height*3; } fseek(fp, FileHeader.bfOffBits, SEEK_SET); //将文件指针移动到实际图像数据处 image=(byte *)malloc(sizeof(byte)*InfoHeader.biSizeImage); //申请空间 if (image == NULL) { free(image); printf("Error: No enough space!"); return -1; } fread(image, 1, InfoHeader.biSizeImage, fp);
这样图像文件的数据就算是被读入了,但是还有一个步骤没有完成。因为BMP文件的像素信息是按照BGR的顺序排列的。于是我们需要写一个交换器,把每一个像素的B值和R值交换一下,以保证OpenGL可以顺利地生成纹理。
for(i=0; i<InfoHeader.biSizeImage; i+=3) { t=image[i]; image[i]=image[i+2]; image[i+2]=t; } fclose(fp);
好的,至此我们已经做好了准备工作。接下来的工作就是要调用OpenGL函数把图像指定为纹理。
首先,我们需要用一个非0的无符号整数作为纹理对象名。为了避免重用对象名,使用void glGenTexture(GLsizei n,GLuint * textureNames)函数来获得未被占用的对象名。这个函数可以通过textureNames数组返回n个未使用的纹理对象名。
unsigned int ID;glGenTextures(1, &ID);
再调用void glBindTexture(Glenum target,Gluint textureName)函数,创建纹理。其中target说明你创建的是几维的纹理,如:GL_TEXTURE_2D..textureName就是刚刚获取到的对象名。
glBindTexture(GL_TEXTURE_2D, ID);
接下来我们需要告诉OpenGL,当我们的图像映射到多边形表面并转换为屏幕坐标的时候,应该如何让像素一一对应。如图,一个正方形的图像纹理,映射到一个如右图的长方形表面时,应该如何映射。
比如说这两种贴图方式
(图丑别喷我。。。)
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_CLAMP);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
glTexParameteri这个函数用于指定放大和缩小过滤方法。更多的参数和用法还是参见红书第9章吧,这里鉴于篇幅就不多介绍了。
最后,在调用gluBuild2Dmipmaps函数生成纹理。
glBuildImage2D(GL_TEXTURE_2D, //申明纹理是2维纹理3, //像素是有多少个颜色组成,如3个RGB,4个RGBAwidth, height, GL_RGB, //有哪几个颜色组成GL_UNSIGNED_BYTE, //数据的数据类型Image //数据的地址);
在return ID将ID返回。
LoadBitmap函数就算是写完了。
这个函数的用法很简单,像这样:
int ID;ID=LoadBitmap(“Photo.bmp”);if (ID == -1) printf("图像读取失败!");OpenGL_Draw_BMP(ID); //这个函数负责接受ID,并绘制图像
接下来的工作就是把OpenGL_Draw_BMP()函数完成,也就是完成绘制部分的工作。
首先我们需要启动纹理贴图功能,调用
glEnable(GL_TEXTURE_2D);
然后是绘制过程,glTexCoord2f指定纹理的坐标,表示把纹理坐标的4个角分配给这个多边形。
glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f);glVertex2f(-1,-1); glTexCoord2f(1.0f, 0.0f);glVertex2f(1,-1); glTexCoord2f(1.0f, 1.0f);glVertex2f(1,1); glTexCoord2f(0.0f, 1.0f);glVertex2f(-1,1);glEnd();
最后,glutSwapBuffers()就完成了!
总结一下,大体的流程是这样的。先调用LoadBitmap读取和分配纹理对象,再调用display函数把图片显示一下。
附本节代码:
#include<GL/glut.h>#include<stdio.h>#include<math.h>#include<time.h>#include<stdlib.h>#include<windows.h>#include<vector>#include<iostream>using std::vector;using std::cout;using std::endl;unsignedint ID;int LoadBitmap(constchar *file){ unsignedint ID; //纹理的id int width,height,i; byte *image,t; //接受图像数据 FILE *fp; //文件指针 BITMAPFILEHEADER FileHeader; //接受位图文件头 BITMAPINFOHEADER InfoHeader; //接受位图信息头 fp=fopen(file,"rb"); if (fp == NULL) { perror("LoadBitmap"); //打开文件失败 return -1; } fread(&FileHeader, sizeof(BITMAPFILEHEADER), 1, fp); if(FileHeader.bfType != 0x4D42) //确保文件是一个位图文件,效验文件类型 { printf("Error: This file is not a bmp file!"); fclose(fp); return -1; } fread(&InfoHeader, sizeof(BITMAPINFOHEADER), 1, fp); width=InfoHeader.biWidth; height=InfoHeader.biHeight; if (InfoHeader.biSizeImage == 0) //确保图像数据的大小 { InfoHeader.biSizeImage = width*height*3; } fseek(fp, FileHeader.bfOffBits, SEEK_SET); //将文件指针移动到实际图像数据处 image=(byte *)malloc(sizeof(byte)*InfoHeader.biSizeImage); //申请空间 if (image == NULL) { free(image); printf("Error: No enough space!"); return -1; } fread(image, 1, InfoHeader.biSizeImage, fp); for(i=0; i<InfoHeader.biSizeImage; i+=3) { t=image[i]; image[i]=image[i+2]; image[i+2]=t; } fclose(fp); glGenTextures(1, &ID); glBindTexture(GL_TEXTURE_2D, ID); 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_CLAMP); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP); gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, GL_RGB, GL_UNSIGNED_BYTE, image); return ID; }void Draw(){ glClearColor(0.0,0.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, ID); glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f);glVertex2f(-1,-1); glTexCoord2f(1.0f, 0.0f);glVertex2f(1,-1); glTexCoord2f(1.0f, 1.0f);glVertex2f(1,1); glTexCoord2f(0.0f, 1.0f);glVertex2f(-1,1); glEnd(); glDisable(GL_TEXTURE_2D); glutSwapBuffers();}void Update(){ glutPostRedisplay();}void Reshape(int w,int h){ w=w>h?h:w; glViewport(0,0,(GLsizei)w,(GLsizei)w);}void init(){ ID=LoadBitmap("Hulaoshi.bmp"); if (ID == -1) exit(0);}int main(int argc, char *argv[]){ glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); glutInitWindowPosition(100, 100); glutInitWindowSize(400, 400); glutCreateWindow("ShowBitmap"); glutReshapeFunc(&Reshape); glutIdleFunc(&Update); glutDisplayFunc(&Draw); init(); glutMainLoop(); return 0;}
说在后面的话。额...最后还是从ubuntu换成了win7,比较MSOffice用起来比LibreOffice方便啊。。
日期:2012/12/7
作者:plusplus7
- OpenGL织梦之旅【第三章】第1节.纹理贴图
- [OpenGL]图形学之旅:纹理贴图三部曲
- OpenGL之纹理贴图(1):Basic
- Qt+OpenGL之纹理贴图
- OpenGL之纹理贴图(2):Texture Objects
- OpenGL学习笔记之纹理贴图
- OpenGL织梦之旅【第三章】第2节.循环显示图片
- OpenGL织梦之旅【第三章】第3节.实现截图功能
- OpenGL织梦之旅【第三章】第4节.glut键盘鼠标响应
- OpenGL纹理贴图 JPEG纹理
- OpenGL纹理贴图 JPEG纹理
- OpenGL系统设计-纹理贴图(1)
- OpenGL ES纹理贴图
- OpenGL ES纹理贴图
- opengl 关于纹理贴图
- OpenGL 纹理贴图
- OpenGL--纹理贴图基础
- Qt OpenGL----纹理贴图
- 程序员面试100题之十五 和 三十, 含有指针成员的类的拷贝(异常安全的赋值运算符重载)
- U-Boot的设备管理
- jQuery Ajax 实例 全解析
- poj 3167 构造比较函数的kmp
- MySQL 主从服务器的配置步骤
- OpenGL织梦之旅【第三章】第1节.纹理贴图
- MyEclipse快捷键大全
- bx lr 和 mov pc,lr
- 利用栈将十十进制转换为其他进制
- JDBC—Java数据库连接
- Monad 最简介绍
- linux中中断和定时机制
- 哈密顿回路,状态dp poj2288
- vim 编辑命令