OpenGL天空贴图以及反射纹理映射即镜面反射

编程中一个好的天空贴图会给玩家带来舒适的感觉,还有那对周围物体的反射光映射到球、等物体上或许是一个特别愉悦的事件,然而这在opengl里实现又不太难,
请看下面的代码:

#include <GL\glew.h>
#include <GL\GLAUX.H>
#define GLUT_DISABLE_ATEXIT_HACK
#include <gl\glut.h> 
#include <stdio.h>
#include <stdlib.h>

// 摄像机参数
static float cameraTheta = 0, cameraPhi = 0;
static int mouseX = 0, mouseY = 0, mouseDownX = 0, mouseDownY = 0;

//天空渲染模式
static int cubeMapAvailable = 0;

//纹理
static UINT textureObjectCubeMap;
static UINT textureObjects2d[6];


//接收反射光物体参数

static int rotateObject = 1;
static int objectAngle = 0;

//渲染函数
static void drawSkybox(void);
static void drawSkyboxCubeEnvironment(void);


//初始化函数
static BOOL initSkybox(void);
static void shutdownSkybox(void);

//加载bmp图片
//swap_bytes用于翻转倒* BMP文件

BOOL loadImage(GLenum target, const char *fileName);
#define SWAP_BYTES(b1,b2) (b1)=(b1)^(b2);(b2)=(b1)^(b2);(b1)=(b1)^(b2);


static void onTimer(int value);
static void onDisplay(void);
static void onMouseMoveButtonDown(int x, int y);
static void onMouseDown(int b, int s, int x, int y);
static void onSpecialKey(int key, int x, int y);
static void onKey(unsigned char key, int x, int y);



//用立方体环境映射绘制天空盒 Skybox的立方体绘制两三角扇形
//以立方体的相对角为中心
void drawSkyboxCubeEnvironment(void)
{
	drawSkybox();//绘制天空盒
	//设置对象矩阵
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();
	glTranslatef(0, 0, -8);
	glRotatef(cameraPhi, 1, 0, 0);
	glRotatef(cameraTheta, 0, 1, 0);

	//旋转
	glRotatef((float)objectAngle, 1, 0, 0);
	glRotatef((float)2 * objectAngle, 0, 1, 0);

	//旋转纹理矩阵匹配摄像机矩阵
	//mode 指定哪一个矩阵堆栈是下一个矩阵操作的目标,
	//可选值: GL_MODELVIEW、GL_PROJECTION、GL_TEXTURE.
	glMatrixMode(GL_TEXTURE);
	glPushMatrix();
	glLoadIdentity();
	glRotatef(-cameraTheta, 0, 1, 0);
	glRotatef(-cameraPhi, 1, 0, 0);
	//绘制映射物体
	if (cubeMapAvailable)
	{
		glDisable(GL_TEXTURE_2D);
		glEnable(GL_DEPTH_TEST);//开启深度测试
		glEnable(GL_TEXTURE_CUBE_MAP_ARB);//开启映射
		glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, textureObjectCubeMap);//绑定映射纹理
		//绘制反光物体
		//建立映射坐标生成
		glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB);
		glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB);
		glTexGenf(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB);
		glEnable(GL_TEXTURE_GEN_S);
		glEnable(GL_TEXTURE_GEN_T);
		glEnable(GL_TEXTURE_GEN_R);
		glutSolidSphere(3, 16, 16);
		//禁用反射映射
		glDisable(GL_TEXTURE_GEN_S);
		glDisable(GL_TEXTURE_GEN_T);
		glDisable(GL_TEXTURE_GEN_R);
		glDisable(GL_DEPTH_TEST);//关闭深度测试
	}
	glPopMatrix();
	//恢复模型矩阵
	glMatrixMode(GL_MODELVIEW);
	glPopMatrix();//恢复矩阵
	
}


//采用六面和六2D纹理绘制天空盒
void drawSkybox(void)
{
	//禁用映射
	glDisable(GL_TEXTURE_CUBE_MAP_ARB);
	glEnable(GL_TEXTURE_2D);
	float skyHei = 20;                      //天空的高度
	float skyLen = 40;                   //天空的长度
	float skyWid = 40;                   //天空的宽度
	//后面
	glBindTexture(GL_TEXTURE_2D, textureObjects2d[0]);
	glBegin(GL_TRIANGLE_FAN);
	glTexCoord2f(1, 0);
	glVertex3f(skyLen, skyHei, skyWid);
	glTexCoord2f(1, 1);
	glVertex3f(skyLen, -skyHei, skyWid);
	glTexCoord2f(0, 1);
	glVertex3f(-skyLen, -skyHei, skyWid);
	glTexCoord2f(0, 0);
	glVertex3f(-skyLen, skyHei, skyWid);
	glEnd();

	//前面
	glBindTexture(GL_TEXTURE_2D, textureObjects2d[1]);
	glBegin(GL_TRIANGLE_FAN);
	glTexCoord2f(1, 0);
	glVertex3f(-skyLen, skyHei, -skyWid);
	glTexCoord2f(1, 1);
	glVertex3f(-skyLen, -skyHei, -skyWid);
	glTexCoord2f(0, 1);
	glVertex3f(skyLen, -skyHei, -skyWid);
	glTexCoord2f(0, 0);
	glVertex3f(skyLen, skyHei, -skyWid);
	glEnd();

	
	//右面
	glBindTexture(GL_TEXTURE_2D, textureObjects2d[2]);
	glBegin(GL_TRIANGLE_FAN);
	glTexCoord2f(1, 0);
	glVertex3f(skyLen, skyHei, -skyWid);
	glTexCoord2f(1, 1);
	glVertex3f(skyLen, -skyHei, -skyWid);
	glTexCoord2f(0, 1);
	glVertex3f(skyLen, -skyHei, skyWid);
	glTexCoord2f(0, 0);
	glVertex3f(skyLen, skyHei, skyWid);
	glEnd();

	
	//左面
	glBindTexture(GL_TEXTURE_2D, textureObjects2d[3]);
	glBegin(GL_TRIANGLE_FAN);
	glTexCoord2f(1, 0);
	glVertex3f(-skyLen, skyHei, skyWid);
	glTexCoord2f(1, 1);
	glVertex3f(-skyLen, -skyHei, skyWid);
	glTexCoord2f(0, 1);
	glVertex3f(-skyLen, -skyHei, -skyWid);
	glTexCoord2f(0, 0);
	glVertex3f(-skyLen, skyHei, -skyWid);
	glEnd();

    //顶面
	glBindTexture(GL_TEXTURE_2D, textureObjects2d[4]);
	glBegin(GL_TRIANGLE_FAN);
	glTexCoord2f(0, 1);
	glVertex3f(-skyLen, skyHei, skyWid);
	glTexCoord2f(0, 0);
	glVertex3f(-skyLen, skyHei, -skyWid);
	glTexCoord2f(1, 0);
	glVertex3f(skyLen, skyHei, -skyWid);
	glTexCoord2f(1, 1);
	glVertex3f(skyLen, skyHei, skyWid);
	glEnd();

	//底面
	glBindTexture(GL_TEXTURE_2D, textureObjects2d[5]);
	glBegin(GL_TRIANGLE_FAN);
	glTexCoord2f(0, 1);
	glVertex3f(-skyLen, -skyHei, -skyWid);
	glTexCoord2f(0, 0);
	glVertex3f(-skyLen, -skyHei, skyWid);
	glTexCoord2f(1, 0);
	glVertex3f(skyLen, -skyHei, skyWid);
	glTexCoord2f(1, 1);
	glVertex3f(skyLen, -skyHei, -skyWid);
	glEnd();
	glDisable(GL_TEXTURE_2D);//关闭纹理
}




void onDisplay(void)
{
	float w = (float)glutGet(GLUT_WINDOW_WIDTH), h = (float)glutGet(GLUT_WINDOW_HEIGHT);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(100.0, w / h, 1, 100);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glRotatef(cameraPhi, 1, 0, 0);
	glRotatef(cameraTheta, 0, 1, 0);
	glClear(GL_DEPTH_BUFFER_BIT);
	drawSkyboxCubeEnvironment();
	glutSwapBuffers();
	glutPostRedisplay();
}

//定时器
void onTimer(int value)
{
	if (rotateObject)
	{
		objectAngle = (objectAngle + 1) % 360;
	}
	glutTimerFunc(10, onTimer, 0);
}


//鼠标事件
void onMouseMoveButtonDown(int x, int y)
{
	cameraTheta += (float)(x - mouseDownX);
	cameraPhi += (float)(y - mouseDownY);

	cameraPhi = max(-90, min(cameraPhi, 90));

	mouseDownX = x;
	mouseDownY = y;
}


void onMouseDown(int b, int s, int x, int y)
{
	if (s == GLUT_DOWN)
	{
		mouseDownX = x;
		mouseDownY = y;
		glutMotionFunc(onMouseMoveButtonDown);
	}
	else
	{
		glutMotionFunc(0);
	}
}

void onSpecialKey(int key, int x, int y)
{
	switch (key)
	{
	
	case GLUT_KEY_RIGHT:
		cameraTheta = cameraTheta + 5;
		while (cameraTheta > 360) cameraTheta -= 360;
		break;
	case GLUT_KEY_LEFT:
		cameraTheta = cameraTheta - 5;
		while (cameraTheta < 0) cameraTheta += 360;
		break;
	case GLUT_KEY_UP:
		cameraPhi = cameraPhi + 5;
		if (cameraPhi > 90) cameraPhi = 90;
		break;
	case GLUT_KEY_DOWN:
		cameraPhi = cameraPhi - 5;
		if (cameraPhi < -90) cameraPhi = -90;
		break;
	};
}

void onKey(unsigned char key, int x, int y)
{
	switch (key)
	{
	case VK_ESCAPE:exit(0); break;
	case 'r':
	case 'R':
		rotateObject = !rotateObject;
		break;
	};
}


//加载bmp图片
BOOL loadImage(GLenum target, const char *fileName)
{
	int i, topRow, bottomRow;
	AUX_RGBImageRec *image = auxDIBImageLoad(fileName);
	if (image != 0)
	{
		topRow = 0;
		bottomRow = 3 * image->sizeX*(image->sizeY - 1);
		while (topRow < bottomRow)
		{
			for (i = 0; i<3 * image->sizeX; i++)
			{
				SWAP_BYTES(image->data[bottomRow + i], image->data[topRow + i]);
			}
			bottomRow -= 3 * image->sizeX;
			topRow += 3 * image->sizeX;
		}

		glTexImage2D(target, 0, 3, image->sizeX, image->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image->data);
		free(image->data);
		free(image);
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

//初始化
BOOL initSkybox(void)
{
	int i;
	int clampMode;
	BOOL succeeded = GL_TRUE;
	char *imageFiles[] = { "data/image1.bmp", "data/image2.bmp", "data/image3.bmp", 
		"data/image4.bmp", "data/image5.bmp", "data/image6.bmp" };
	glGenTextures(6, textureObjects2d);
	glGenTextures(1, &textureObjectCubeMap);
	//单位化
	glEnable(GL_NORMALIZE);
	//如果我们能用gl_clamp_to_edge
	//判定是否支持特定的OpenGL扩展
	//extension是指定要测试的OpenGL扩展的名称
	if (glutExtensionSupported("GL_EXT_texture_edge_clamp"))
	{
		clampMode = GL_CLAMP_TO_EDGE;//去除接缝间的空隙边框是否处理?(不处理)
	}
	else
	{
		clampMode = GL_CLAMP;
	}

	//生成 2d textures
	for (i = 0; i<6; i++)
	{
		glBindTexture(GL_TEXTURE_2D, textureObjects2d[i]);
		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
		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, clampMode);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, clampMode);//去除接缝间的空隙边框是否处理?(不处理)
		succeeded = succeeded && loadImage(GL_TEXTURE_2D, imageFiles[i]);
	}

	//生成多维数据集映射,如果支持
	if (glutExtensionSupported("GL_ARB_texture_cube_map"))
	{
		cubeMapAvailable = 1;
		glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, textureObjectCubeMap);
		glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

		succeeded = succeeded && loadImage(GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, imageFiles[0]);
		succeeded = succeeded && loadImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, imageFiles[1]);

		succeeded = succeeded && loadImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, imageFiles[2]);
		succeeded = succeeded && loadImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, imageFiles[3]);

		succeeded = succeeded && loadImage(GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, imageFiles[4]);
		succeeded = succeeded && loadImage(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, imageFiles[5]);

	}
	else
	{
		cubeMapAvailable = 0;
	}
	return succeeded;

}

// 删除内存
void shutdownSkybox(void)
{
	glDeleteTextures(6, textureObjects2d);
	glDeleteTextures(1, &textureObjectCubeMap);
}


int main(int argc, char **argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutCreateWindow("天空盒及照在物体上的反射光");
	glutReshapeWindow(1366, 768);
	glutDisplayFunc(onDisplay);
	glutMouseFunc(onMouseDown);
	glutSpecialFunc(onSpecialKey);
	glutKeyboardFunc(onKey);
	glutTimerFunc(10, onTimer, 0);

	if (!initSkybox())
	{
		shutdownSkybox();
		return 0;
	}
	glutMainLoop();
	shutdownSkybox();
	return 0;
}

实验结果截图:


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值