按下b,然后同时按下down和right方向键
#include "stdafx.h" #include <iostream> #define GLUT_DISABLE_ATEXIT_HACK #include "glut.h" #include "glaux.h" using namespace std; bool g_bBlend;// 是否混合? bool g_bKeyB = false;// B 键按下了么? bool g_bLight =false;// 光源的开/ 关 bool g_bKeyL =false;// L键按下了么? bool g_bKeyF =false;// F键按下了么? GLfloat g_fXrot =5; // X 旋转 GLfloat g_fYrot =5;// Y 旋转 GLfloat g_fXSpeed =0;// X 旋转速度 GLfloat g_fYSpeed =0;// Y 旋转速度 GLfloat g_fZ =-5.0f;// 深入屏幕的距 // 接着设置用来创建光源的数组。我们将使用两种不同的光。第一种称为环境光。环境光来自于四面 // 八方。所有场景中的对象都处于环境光的照射中。第二种类型的光源叫做漫射光。漫射光由特定的 // 光源产生,并在您的场景中的对象表面上产生反射。处于漫射光直接照射下的任何对象表面都变得 // 很亮,而几乎未被照射到的区域就显得要暗一些。这样在我们所创建的木板箱的棱边上就会产生的很不错的阴影效果。 // 创建光源的过程和颜色的创建完全一致。前三个参数分别是RGB三色分量,最后一个是alpha通道参数。 // 因此,下面的代码我们得到的是半亮(0.5f)的白色环境光。如果没有环境光,未被漫射光照到的地方会变得十分黑暗。 GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f };// 环境光参数 //下一行代码我们生成最亮的漫射光。所有的参数值都取成最大值1.0f 。它将照在我们木板箱的前面,看起来挺好。 GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f };// 漫射光参数 // 最后我们保存光源的位置。前三个参数和glTranslate中的一样。依次分别是XYZ轴上的位移。由于 // 我们想要光线直接照射在木箱的正面,所以XY轴上的位移都是0.0f 。第三个值是Z 轴上的位移。为 // 了保证光线总在木箱的前面,所以我们将光源的位置朝着观察者( 就是您哪。) 挪出屏幕。我们通常 // 将屏幕也就是显示器的屏幕玻璃所处的位置称作Z 轴的0.0f 点。所以Z 轴上的位移最后定为2.0f 。假 // 如您能够看见光源的话,它就浮在您显示器的前方。当然,如果木箱不在显示器的屏幕玻璃后面的 // 话,您也无法看见箱子。 GLfloat LightPosition[]= { 0.0f, 0.0f, 2.0f, 1.0f };// 光源位置 // filter 变量跟踪显示时所采用的纹理类型。 //第一种纹理(texture[0])使用gl_nearest(不光滑) 滤波方式构建。 //第二种纹理 (texture[1])使用gl_linear(线性滤波)方式,离屏幕越近的图像看起来就越光滑。 //第三种纹理 (texture[2])使用mipmapped滤波方式,这将创建一个外观十分优秀的纹理。 //根据我们的使用类型,filter 变量的值分别等于0,1或2。下面我们从第一种纹理开始。 //GLuint texture[3] 为三种不同纹理分配储存空间。它们分别位于在 texture[0], texture[1]和texture[2] 中。 GLuint filter; // 滤波类型 GLuint texture[3]; // 3种纹理的储存空间 //现在载入一个位图,并用它创建三种不同的纹理。这一课使用glaux辅助库来载入位图,因此在编译 //时您应该确认是否包含了glaux库。我知道Delphi 和VC++都包含了glaux库,但别的语言不能保证都 //有。『译者注:glaux是OpenGL辅助库,根据OpenGL的跨平台特性,所有平台上的代码都应通用。 //但辅助库不是正式的OpenGL标准库,没有出现在所有的平台上。但正好在Win32平台上可用。 AUX_RGBImageRec *TextureImage=new AUX_RGBImageRec; //辅助函数 AUX_RGBImageRec *LoadBMP(char* FileName) { FILE *file = 0; if(!FileName) return 0; file = fopen(FileName,"r"); if(file) { fclose(file); cout<<"start open!"; return auxDIBImageLoad(FileName); //如果此处出现Fail to open DIB是字符串的问题 //修改项目配置,字符集中将Unicode改成多级字符即可 } return 0; } void LoadTexture() { //图像的宽和高必须是2的n次方 memset(TextureImage,0,sizeof(void *)*1); //现在载入位图,并将其转换为纹理。 TextureImage = LoadBMP("E:\pic\box200.bmp"); if(0 == TextureImage) { cout<<"error bmp"<<endl; return; } //告诉OpenGL我们要创建三个纹理,它们将存放在texture[0],texture[1]和texture[2]中 glGenTextures(3,&texture[0]); //第六课中我们使用了线性滤波的纹理贴图。这需要机器有相当高的处理能力,但它们看起来很不 //错。这一课中,我们接着要创建的第一种纹理使用 GL_NEAREST 方式。从原理上讲,这种方式没 //有真正进行滤波。它只占用很小的处理能力,看起来也很差。唯一的好处是这样我们的工程在很快 //和很慢的机器上都可以正常运行。 //您会注意到我们在 MIN 和 MAG 时都采用了GL_NEAREST,你可以混合使用 GL_NEAREST和 //GL_LINEAR。纹理看起来效果会好些,但我们更关心速度,所以全采用低质量贴 //图。MIN_FILTER在图像绘制时小于贴图的原始尺寸时采用。MAG_FILTER在图像绘制时大于贴图 //的原始尺寸时采用。 //###创建 Nearest 滤波贴图### glBindTexture(GL_TEXTURE_2D, texture[0]); // 告诉OpenGL将纹理名字texture绑定到纹理目标上。 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); //glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage->sizeX, TextureImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage->data); gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage->sizeX, TextureImage->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage->data); //###创建线性滤波纹理### glBindTexture(GL_TEXTURE_2D, texture[1]); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage->sizeX, TextureImage->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage->data); //glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage->sizeX, TextureImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage->data); //下面是创建纹理的新方法。 Mipmapping! //您可能会注意到当图像在屏幕上变得很小的时候,很多细节将会 //丢失。刚才还很不错的图案变得很难看。当您告诉OpenGL创建一个 mipmapped 的纹理 //后,OpenGL将尝试创建不同尺寸的高质量纹理。当您向屏幕绘制一个 mipmapped 纹理的时 //候,OpenGL将选择它已经创建的外观最佳的纹理( 带有更多细节) 来绘制,而不仅仅是缩放原先的图 //像( 这将导致细节丢失) 。 //我曾经说过有办法可以绕过OpenGL对纹理宽度和高度所加的限制——64、128、256,等等。 //办法就是 gluBuild2DMipmaps 。据我的发现,您可以使用任意的位图来创建纹理。OpenGL将自动将它缩放到正常的大小。 //因为是第三个纹理,我们将它存到texture[2] 。这样本课中的三个纹理全都创建好了。 glBindTexture(GL_TEXTURE_2D,texture[2]); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST); //下面一行生成 mipmapped 纹理。 gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage->sizeX, TextureImage->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage->data); //释放前面用来存放位图数据的内存 if(TextureImage) { if(TextureImage->data) { free(TextureImage->data); } free(TextureImage); } } void DrawScene(void) { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);//清除屏幕及其缓存 glLoadIdentity();//重置当前模型观察矩阵 glTranslatef(0.0f,0.0f,g_fZ); // 移入/ 移出屏幕 glRotatef(g_fXrot,1.0f,0.0f,0.0f);// 绕X轴旋转 glRotatef(g_fYrot,0.0f,1.0f,0.0f);// 绕Y轴旋转 g_fXrot += g_fXSpeed; g_fYrot += g_fYSpeed; // 下一行代码选择我们使用的纹理。如果您在您的场景中使用多个纹理,您应该使用来 // glBindTexture(GL_TEXTURE_2D, texture[ 所使用纹理对应的数字 ]) 选择要绑定的纹理。当您想改变 // 纹理时,应该绑定新的纹理。有一点值得指出的是,您不能在 glBegin() 和 glEnd() 之间绑定纹理, // 必须在 glBegin() 之前或 glEnd() 之后绑定。注意我们在后面是如何使用 glBindTexture 来指定和绑定纹理的。 glBindTexture(GL_TEXTURE_2D, texture[filter]);// 选择纹理 // 为了将纹理正确的映射到四边形上,您必须将纹理的右上角映射到四边形的右上角,纹理的左上角 // 映射到四边形的左上角,纹理的右下角映射到四边形的右下角,纹理的左下角映射到四边形的左下 // 角。如果映射错误的话,图像显示时可能上下颠倒,侧向一边或者什么都不是。 glBegin(GL_QUADS);//////////////////////////// //glNormal3f 是这一课的新东西。Normal就是法线的意思,所谓法线是指经过面( 多边形)上的一点且 //垂直于这个面多边形的直线。使用光源的时候必须指定一条法线。法线告诉 这个多边形的 //朝向,并指明多边形的正面和背面。如果没有指定法线,什么怪事情都可能发生:不该照亮的面被 //照亮了,多边形的背面也被照亮....。对了,法线应该指向多边形的外侧。 // //看着木箱的前面您会注意到法线与Z 轴正向同向。这意味着法线正指向观察者-您自己。这正是我 //们所希望的。对于木箱的背面,也正如我们所要的,法线背对着观察者。如果立方体沿着X 或Y 轴 //转个180度的话,前侧面的法线仍然朝着观察者,背面的法线也还是背对着观察者。换句话说,不 //管是哪个面,只要它朝着观察者这个面的法线就指向观察者。由于光源紧邻观察者,任何时候法线 //对着观察者时,这个面就会被照亮。并且法线越朝着光源,就显得越亮一些。如果您把观察点放到 //立方体内部,你就会法线里面一片漆黑。因为法线是向外指的。如果立方体内部没有光源的话,当 //然是一片漆黑。 //前侧面 glNormal3f( 0.0f, 0.0f, 1.0f);// 法线指向观察者 glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); //纹理和四边形的左下 glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); //纹理和四边形的右下 glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); //左下 glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); //右下 //后侧面 glNormal3f( 0.0f, 0.0f,-1.0f);// 法线背向观察者 glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); //右下 glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); //右上 glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // 纹理和四边形的左上 glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // 纹理和四边形的左下 //顶面 glNormal3f( 0.0f, 1.0f, 0.0f); // 法线向上 glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // 纹理和四边形的左上 glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // 纹理和四边形的左下 glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // 纹理和四边形的右下 glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // 纹理和四边形的右上 // 底面 glNormal3f( 0.0f,-1.0f, 0.0f); // 法线朝下 glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // 纹理和四边形的右上 glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // 纹理和四边形的左上 glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // 纹理和四边形的左下 glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // 纹理和四边形的右下 // 右面 glNormal3f( 1.0f, 0.0f, 0.0f);// 法线朝右 glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // 纹理和四边形的右下 glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // 纹理和四边形的右上 glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // 纹理和四边形的左上 glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // 纹理和四边形的左下 // 左面 glNormal3f(-1.0f, 0.0f, 0.0f); // 法线朝左 glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // 纹理和四边形的左下 glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // 纹理和四边形的右下 glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // 纹理和四边形的右上 glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // 纹理和四边形的左上 glEnd();/////////////////////////////// glFlush(); } void ReSizeFunc(int width,int height) { glViewport(0,0,width,height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45,width/height,0.1,100); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void KeyBoardFunc(unsigned char key, int x, int y) { cout<<"curren key"<<(int)key<<" what:"<<key<<endl; if(VK_ESCAPE == key) { exit(0); } if((key == 'l') && !g_bKeyL) { g_bKeyL = true; g_bLight = !g_bLight; if(!g_bLight) { glDisable(GL_LIGHTING);// 禁用光源 cout<<"禁用光源"<<endl; } else { glEnable(GL_LIGHTING);// 启用光源 cout<<"启用光源"<<endl; } } //下面的代码查看是否松开了"L" 键。如果松开,变量lp 将设为false 。这意味着"L" 键没有按下。如果 //不作此检查,光源第一次打开之后,就无法再关掉了。计算机会以为"L" 键一直按着呢。 if(key != 'l') { g_bKeyL = false; } if((key == 'f') && !g_bKeyF) { g_bKeyF = true; filter += 1; if(filter>2) { filter = 0; } cout<<"filter="<<filter<<endl; } if(key != 'f') { g_bKeyF = false; } if(('b' == key)&&!g_bKeyB)// B 健按下且bp为 FALSE 么? { g_bKeyB = true;// 若是, bp 设为 TRUE g_bBlend = !g_bBlend;// 切换混合选项的 TRUE / FALSE if(g_bBlend)// 混合打开了么? { glEnable(GL_BLEND);// 打开混合 glDisable(GL_DEPTH_TEST);// 关闭深度测试 } else { glDisable(GL_BLEND);// 关闭混合 glEnable(GL_DEPTH_TEST);// 关闭混合 } } if('b'!=key)// B 键松开了么? { g_bKeyB = false;// 若是, bp 设为 FALSE } DrawScene(); } void SpecialKeys(int key, int x, int y) { cout<<"curren special key"<<(int)key<<" what:"<<key<<endl; //现在检查方向键。按下左右方向键xspeed 相应减少或增加。按下上下方向键yspeed 相应减少或增 //加。记住在以后的教程中如果xspeed 、yspeed 的值增加的话,立方体就转的更快。如果一直按着某 //个方向键,立方体会在那个方向上转的越快。 if(GLUT_KEY_UP == key) { g_fXSpeed -= 0.01; } if(GLUT_KEY_DOWN == key) { g_fXSpeed += 0.01; } if(GLUT_KEY_LEFT == key) { g_fYSpeed -= 0.01; } if(GLUT_KEY_RIGHT == key) { g_fYSpeed += 0.01; } //接着四行检查PageDown键是否按下,若是的话,增加z 变量的值。这样DrawGLScene 函数中包含 //的glTranslatef(0.0f,0.0f,z) 调用将使木箱向着观察者移近一点。 if(GLUT_KEY_PAGE_DOWN == key) { g_fZ+=0.02; } DrawScene(); } int Init() { LoadTexture(); glEnable(GL_TEXTURE_2D);// 启用纹理映射 glShadeModel(GL_SMOOTH);// 启用阴影平滑 glClearColor(0,0,0,0); // 黑色背景 glClearDepth(1); // 设置深度缓存 glEnable(GL_DEPTH_TEST);// 启用深度测试 glDepthFunc(GL_LEQUAL); // 所作深度测试的类型 glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);// 真正精细的透视修正 glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // 设置环境光 glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // 设置漫射光 glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); // 设置光源位置 //我们启用一号光源。我们还没有启用GL_LIGHTING,所以您看不见任何光线。记住:只对 //光源进行设置、定位、甚至启用,光源都不会工作。除非我们启用GL_LIGHTING。 glEnable(GL_LIGHT1); //第一行以全亮度绘制此物体,并对其进行50% 的alpha混合( 半透 // 明) 。当混合选项打开时,此物体将会产生50% 的透明效果。第二行设置所采用的混合类型。 // Rui Martins 的补充: alpha 通道的值为 0.0 意味着物体材质是完全透明的。1.0 则意味着完全不透明。 glColor4f(1,1,1,0.5);// 全亮度, 50% Alpha 混合 glBlendFunc(GL_SRC_ALPHA,GL_ONE);// 基于源象素alpha通道值的半透明混合函数 return 0; } int main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowPosition(100, 100); glutInitWindowSize(500, 500); glutCreateWindow("第八个OpenGL程序"); glutReshapeFunc(ReSizeFunc); glutDisplayFunc(DrawScene); glutKeyboardFunc(KeyBoardFunc); glutSpecialFunc(SpecialKeys); Init(); glutMainLoop(); return 0; }
- 该日志由 guoming0000 于7月前发表在OpenGL分类下,最后更新于 2013年07月02日.
- 转载请注明: NeHe_OpenGL_混合 | 52 Coding +复制链接
- 关键字: OpenGL