OpenGL织梦之旅【第三章】第1节.纹理贴图

来源:互联网 发布:广电网络移机怎么办 编辑:程序博客网 时间:2024/06/05 06:22

       在了解纹理贴图之前,我们先要对BMP位图文件要有一定的了解。在Windows中,BMP格式是一个很常见的图像文件储存格式。位图文件由4个部分构成:位图文件头,位图信息头,彩色表以及定义位图的字节列阵。24位的真彩色图像不使用彩色表,所以可以暂时不用管它。

   我们写个函数

int LoadBitmap(constchar *file)


      图像bmp文件的地址是file,返回值int我们等一下再说为什么。

      在windows.h中,定义了两个结构体BITMAPFILEHEADERBITMAPINFOHEADER分别表示位图文件头和位图信息头。然后在定义一个byte数组image用于读入位图的数据信息。Widthheight用于接受图像的长宽(单位:像素)。注意:每个像素因为由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 IDID返回。

      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

 

原创粉丝点击