opengl 光照,材质,BMP纹理贴图的代码模板

时间:2021-10-30 04:47:26

纹理贴图模板

BMP纹理贴图,在这里我们考虑BMP格式的纹理贴图。

首先把纹理图片,用画图另存为转成BMP格式(24bit-bmp)


(1)第一步: 复制以下纹理加载函数

//两个纹理对象的编号
GLuint tex1;
GLuint tex2;
int power_of_two(int n)
{
if (n <= 0)
return 0;
return (n & (n - 1)) == 0;
}

/* 函数load_texture
* 读取一个BMP文件作为纹理
* 如果失败,返回0,如果成功,返回纹理编号
*/
GLuint load_texture(const char* file_name)
{
GLint width, height, total_bytes;
GLubyte* pixels = 0;

GLint last_texture_ID;//上一次绑定的纹理编号
GLuint texture_ID = 0;//纹理编号

// 打开参数中传入的纹理文件,如果失败,返回
FILE* pFile = fopen(file_name, "rb");
if (pFile == 0)
return 0;

// 读取文件中图象的宽度和高度
fseek(pFile, 0x0012, SEEK_SET);
fread(&width, 4, 1, pFile);//int32 8位4个字节
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;
}

// 在旧版本的OpenGL中
// 如果图象的宽度和高度不是的整数次方,则需要进行缩放
// 这里并没有检查OpenGL版本,出于对版本兼容性的考虑,按旧版本处理
// 另外,无论是旧版本还是新版本,
// 当图象的宽度和高度超过当前OpenGL实现所支持的最大值时,也要进行缩放
{
GLint max;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);//获取支持的最大纹理

//如果长宽有一个不是整数次方,或有一个大于支持的最大纹理,就重新设置长宽重新算一遍
if (!power_of_two(width) || !power_of_two(height) || width > max || height > max)
{
//设定一些用于中间计算的新的值,这些值会在稍后被替代

const GLint new_width = 256;
const GLint new_height = 256; // 规定缩放后新的大小为边长的正方形
GLint new_line_bytes, new_total_bytes;
GLubyte* new_pixels = 0;

// 计算每行需要的字节数和总字节数
new_line_bytes = new_width * 3;
while (new_line_bytes % 4 != 0)
++new_line_bytes;
new_total_bytes = new_line_bytes * new_height;

// 重新分配内存
new_pixels = (GLubyte*)malloc(new_total_bytes);
if (new_pixels == 0)
{
free(pixels);
fclose(pFile);
return 0;
}

// 进行像素缩放
gluScaleImage(GL_RGB, width, height, GL_UNSIGNED_BYTE, pixels,
new_width, new_height, GL_UNSIGNED_BYTE, new_pixels);

// 释放原来的像素数据,把pixels指向新的像素数据,并重新设置width和height
free(pixels);

pixels = new_pixels;
width = new_width;
height = new_height;
}
}

// 分配一个新的纹理编号,并不是分配编号1,而是分配1个新的编号到textureID....
glGenTextures(1, &texture_ID);

if (texture_ID == 0)
{
free(pixels);
fclose(pFile);
return 0;
}

// 绑定新的纹理,载入纹理并设置纹理参数
// 在绑定前,先获得原来绑定的纹理编号,以便在最后进行恢复
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture_ID); //第一个参数,表示你要得到什么状态的值,第二个参数即输出这个值

glBindTexture(GL_TEXTURE_2D, texture_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_REPEAT);
//x坐标越界怎么办,GL_CLAMP表示超过的1.0的都按1.0那点的坐标绘制,GL_REPEAT表示不足重复补充直至达到那个值
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
//y坐标越界怎么办,重复
GLfloat fColor[4] = { 1.0f,0.0f,0.0f,0.0f };
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, fColor);

//载入pixels数组中的图像为当前的纹理状态
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels);

//glBindTexture(GL_TEXTURE_2D, last_texture_ID);

// 之前为pixels分配的内存可在使用glTexImage2D以后释放
// 因为此时像素数据已经被OpenGL另行保存了一份(可能被保存到专门的图形硬件中)
free(pixels);
//该ID可以唯一标识一纹理
return texture_ID;
}


第二步:在main函数里复制下面的代码加载纹理

glEnable(GL_TEXTURE_2D);
tex1 = load_texture("wood2.bmp");
tex2 = load_texture("ground2.bmp");
//加载两个纹理的编号,编号可以唯一标识一个对象


第三步:在绘制时绑定稳定使用纹理
glVertex3f(x,y,z);
glTexCoord2f(i, j);
//i,j是一个小于1的数,如i=0.1,j=0.1就代表横向纹理图片1/10处映射到这个点,纵向纹理图片1/10处映射到这个点


添加光照模板

(1)第一步:复制光照函数,设置光照参数

void light(void)
{
GLfloat position[]={0.0f,30.0f,30.0f,1.0f};
GLfloat ambient[]={0.0f,0.0f,0.0f,1.0f};
GLfloat diffuse[]={0.0f, 0.8f, 0.8f, 1.0f};
GLfloat specular[]={0.0f, 0.6f, 0.6f, 1.0f};

glLightfv(GL_POSITION,GL_POSITION,position);
glLightfv(GL_LIGHT0,GL_AMBIENT,ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, specular);

glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
}


(2)第二步:在main函数里加载光照

light();


添加材质模板

(1)第一步:在绘制函数里声明材质

GLfloat wall_mat_ambient[] = { 0.105882, 0.058824, 0.113725, 1.000000};
GLfloat wall_mat_diffuse[] = { 0.427451, 0.470588, 0.541176, 1.000000};
GLfloat wall_mat_specular[] ={ 0.933333, 0.733333, 0.521569, 1.000000};
GLfloat wall_mat_emission[] = {0.0f, 0.0f, 0.0f, 1.0f};
GLfloat wall_mat_shininess = 9.846150;
glMaterialfv(GL_FRONT, GL_AMBIENT, wall_mat_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, wall_mat_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, wall_mat_specular);
//glMaterialfv(GL_FRONT, GL_EMISSION, wall_mat_emission);
glMaterialf (GL_FRONT, GL_SHININESS, wall_mat_shininess);


glEnable(GL_TEXTURE_2D);//必须在draw里加这句否则纹理贴不上去

(2)第二步:声明完直接画图形,画出来就是这个材质