OpenGL编程学习实战教程(8)

在了解纹理贴图之前,我们先要对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,当我们的图像映射到多边形表面并转换为屏幕坐标的时候,应该如何让像素一一对应。如图,一个正方形的图像纹理,映射到一个如右图的长方形表面时,应该如何映射。

OpenGL编程学习实战教程

比如说这两种贴图方式

OpenGL编程学习实战教程

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个RGBA

width,                     

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方便啊。。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/1dd33752d840e115225e85aedc5cc649.html