一、建立纹理的代码
GLuint CTexture::BuildTexFromTGA(const char* filename)
{
GLubyte headerTGA[12]={0,0,2,0,0,0,0,0,0,0,0,0};//TGA类型(未压缩)头信息
GLubyte headerRead[12];//TGA类型(未压缩)头信息
GLubyte headerNext[6];//图像基础信息的头信息
GLubyte temp; //调整色彩数据用
GLuint bytesPerPixal;//每像素所用字节数节
GLuint imageSize;//图像数据的大小
FILE* file = fopen(filename,"rb");
if(file == NULL)
return NULL;
if(fread(headerRead,1,sizeof(headerRead),file)!=sizeof(headerRead) ||
headerRead[2]!=headerTGA[2] ||
fread(headerNext,1,sizeof(headerNext),file)!=sizeof(headerNext)
)
{
fclose(file);
return NULL;
}
Width = headerNext[0] + headerNext[1]*256;
Height = headerNext[2] + headerNext[3]*256;
Bitpp = headerNext[4];
if(Width <=0 || Height<=0 ||
(Bitpp!=24 && Bitpp!=32))
{
fclose(file);
return NULL;
}
GLuint type = GL_RGBA;
if(Bitpp==24)
type = GL_RGB;
bytesPerPixal = Bitpp/8;
ImageSize = Width*Height*bytesPerPixal;
ImageData = new GLubyte[ImageSize];
if(ImageData == NULL)
{
fclose(file);
return NULL;
}
if(fread(ImageData,1,ImageSize,file)!=ImageSize)
{
fclose(file);
return NULL;
}
for(GLuint i = 0; i<ImageSize; i+=bytesPerPixal)
{
temp = ImageData[i];
ImageData[i] = ImageData[i+2];
ImageData[i+2] = temp;
}
fclose(file);
//生成纹理贴图
//1.向GL申请纹理贴图索引号
glGenTextures(1,&TexID);
//2.告知GL操作与索引号相对应的纹理贴图资源
glBindTexture(GL_TEXTURE_2D,TexID);
//3.反走样模式
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
//4.加入资源所需的图像数据
glTexImage2D(GL_TEXTURE_2D,0,type,Width,Height,0,type,GL_UNSIGNED_BYTE,ImageData);
//GL另有空间存储纹理数据,因此可以删除读取用的图像数据
delete ImageData;
ImageData = NULL;
return TexID;
}
前面的学Nehe,略有改动(原代码是过程式的,我重构为类的方式,将这段放在一个CTexture的类中),最后释放图像数据空间是自己添上的。因为实践中发现建立完纹理后,OpenGL完全不再需要一段额外图像数据,对于一个3D游戏而言各种资源都是宝贵的。
二、哪种写法更好?
我在为物品建立纹理时有两种写法,一个是所有物品的纹理由一个专门的纹理生成器生成,二是物品类中自带纹理生成方法。
第一种写法是:
CView::Init()
{
Sky.TextureID = TextureBuilder.BuildText(Sky.TexFileName);
}
第二种写法是:
CSky::Init()
{
CTextureBuilder* TextureBuilder = new CTextureBuilder();
this->TextureID = TextureBuilder->BuildText(this->TexFileName);
delete TextureBuilder;
}
以我现在的认识,第二种写法是标准的类编码方式,但因此每个物品类都要额外分配额外的作用相同的代码空间,即使像我上面的代码一个即时分配,即时释放,在一个拥有无数物品的3D游戏中,从游戏的运行效率考虑这样的冗余是否必要呢?我现在经验是,还是倾向于采用第一种方式编码。不知对否?
三、纹理的重复
1、平铺
//设置s方向与t方向纹理重复,为重复设置。
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);不过好像这是默认的重复方式
建立纹理时,无论是否有上面的代码,在显示时,只要将glCoord2f(x,y)中的x值像如下方式设置就可以实现横向重复:
float n =3;
glBegin(GL_QUADS);// Start Drawing A Quad
glTexCoord2f(0.0f,0.0f); glVertex3f(-0.0f,-Height,-0.0f);// Bottom Left
glTexCoord2f(n, 0.0f); glVertex3f( Width,-Height,-0.0f);// Bottom Right
glTexCoord2f(n, 1.0f); glVertex3f( Width, 0.0f,-0.0f);// Top Right
glTexCoord2f(0.0f,1.0f); glVertex3f(-0.0f, 0.0f,-0.0f);// Top Left
glEnd(); // Done Drawing Quad
n为几,就可以重复几次。纵向重复以此类推。
2、镜像平铺。
根据《OpneGL编程技术详解》只要将GL_REPEAT 改成 GL_MIRRORED_REPEAT即可实现镜像平铺,但编译时说这是一个未申明的标识符,实在让人郁闷。不知是哪个头文件没包括,还是我的版本旧。