OpenGL_8 光照和键盘

来源:互联网 发布:淘宝店铺域名怎么设置 编辑:程序博客网 时间:2024/06/05 10:16

开始前需要定义全局变量,其中与光照相关的全局变量为

GLfloat LightAmbient[] = { 0.5f,0.5f,0.5f,1.0f };//环境光参数
GLfloat LightDiffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };// 漫射光参数
GLfloat LightPosition[] = { 0.0f, 0.0f, 2.0f, 1.0f };// 光源位置

与纹理映射滤波有关的全局变量为

GLuint filter;         // 滤波类型
GLuint texture[3];        // 3种纹理的储存空间

接下来在LoadGLTextures()函数中载入位图并生成纹理

注意点:OpenGL载入的位图一般要求宽度和高度大小为2的整数次方,如64,128,256等,但是在图像缩小到很小时,将创建一个mipmapping纹理,这时需要用一种绕过大小限制的绑定方法:gluBlind2DMipmaps();同样要注意及时释放内存。

int LoadGLTextures()//载入位图并转换成纹理{int Status = FALSE;AUX_RGBImageRec* TextureImage[1];//创建纹理的存储空间memset(TextureImage, 0, sizeof(void*) * 1);//将指针设为NULLif (TextureImage[0] = LoadBMP("texture.bmp"))//成功载入位图{Status = TRUE;glGenTextures(3, &texture[0]);//创建3个纹理// 创建 Nearest 滤波贴图glBindTexture(GL_TEXTURE_2D, texture[0]);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[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->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);glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);// 创建 MipMapped 纹理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);gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);}if (TextureImage[0])//纹理还存在{if (TextureImage[0]->data)//纹理图形还存在{free(TextureImage[0]->data);}free(TextureImage[0]);}return Status;}

同时,在OpenGL初始化函数中要设置光源,这里定义了光源GL_LIGHT1的环境光、漫反射光,光源位置,并启用光源

int InitGL(GLvoid){if (!LoadGLTextures())//布恩那个调用纹理载入{return FALSE;}glEnable(GL_TEXTURE_2D);//启用纹理映射glShadeModel(GL_SMOOTH);//设置深度缓存glClearColor(0.0f, 0.0f, 0.0f, 0.0f);glClearDepth(1.0f);glEnable(GL_DEPTH_TEST);//启用深度测试glDepthFunc(GL_LEQUAL);//所作深度测试的类型glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);//设置环境光glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);//设置漫反射glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);//设置光源位置glEnable(GL_LIGHT1);//启用一号光源glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);//反锯齿return TRUE;}
在DrawGLScene()函数中,使用光源时需要使用glNormal3f()指定法线,法线需要指向立方体外侧,而不能指向内部

int DrawGLScene(GLvoid){glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);   // 清除屏幕和深度缓存glLoadIdentity();       // 重置当前的模型观察矩阵glTranslatef(0.0f, 0.0f, z);      // 移入/移出屏幕 z 个单位glRotatef(xrot, 1.0f, 0.0f, 0.0f);      // 绕X轴旋转glRotatef(yrot, 0.0f, 1.0f, 0.0f);      // 绕Y轴旋转glBindTexture(GL_TEXTURE_2D, texture[filter]);    // 选择由filter决定的纹理glBegin(GL_QUADS);       // 开始绘制四边形// 前侧面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();        // 四边形绘制结束xrot += xspeed;        // xrot 增加 xspeed 单位yrot += yspeed;        // yrot 增加 yspeed 单位return TRUE;}

在WinMain()函数中定义按键的作用

在NEHE教程中,按键逻辑感觉不符合主流,下面的代码稍加了改动,PageUp定义为立方体移向观察者,PageDown定义为远离观察者,Up定义为yspeed+,Down定义为yspeed-,Left定义为xspeed-,Right定义为xspeed+.

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){MSG msg;BOOL done = FALSE;if (MessageBox(NULL, L"你想在全屏模式下运行吗", L"设置全屏模式", MB_YESNO | MB_ICONQUESTION) == IDNO){fullscreen = FALSE;}if (!CreateGLWindow(L"OpenGL程序框架", 640, 480, 16, fullscreen)){return 0;}while (!done){if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))//有消息在等待吗{if (msg.message == WM_QUIT){done = TRUE;}else{TranslateMessage(&msg);//翻译消息DispatchMessage(&msg);//发送消息}}else{if (active){if (keys[VK_ESCAPE])//ESC按下{done = TRUE;}else{DrawGLScene();SwapBuffers(hDC);}if (keys['L'] && !lp)//L键按下并且未松开{lp = TRUE;light = !light;if (!light)//如果没有光源{glDisable(GL_LIGHTING);//禁用光源}else{glEnable(GL_LIGHTING);//启用光源}}if (!keys['L'])//L键松开了{lp = FALSE;}if (keys['F'] && !fp)//F键按下并且未松开{fp = TURE;filter += 1;if (filter > 2){filter = 0;}}if (!keys['F']){fp = FALSE;}if (keys[VK_PRIOR])//PageDown按下了{z -= 0.02f;//若按下,木箱远离观察者}if (keys[VK_UP])//PageUp按下{z += 0.02f;//若按下,木箱靠近观察者}if (keys[VK_UP])//Up方向键按下{yspeed += 0.01f;}if (keys[VK_DOWN])//Down方向键按下{yspeed -= 0.01f;}if (keys[VK_RIGHT])//Right方向键按下{xspeed += 0.01f;}if (keys[VK_LEFT])//Left方向键按下{xspeed -= 0.01f;}if (keys[VK_F1])//F1按下{keys[VK_F1] = FALSE;KillGLWindow();fullscreen = !fullscreen;if (!CreateGLWindow(L"OpenGL程序框架", 640, 480, 16, fullscreen))//重建OpenGL窗口{return 0;}}}}}KillGLWindow();return(msg.wParam);}