编程中一个好的天空贴图会给玩家带来舒适的感觉,还有那对周围物体的反射光映射到球、等物体上或许是一个特别愉悦的事件,然而这在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 texturesfor (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;}
实验结果截图: