OpenGL学习笔记 (7) —— 三种不同的纹理滤波方式,光照和键盘控制

2011-04-17 wcdj

 

三种纹理滤波方式

(1) Nearest 滤波贴图 Nearest Filtered Texture
(2) 线性滤波纹理 Linear Filtered Texture
(3) MipMapped 纹理 MipMapped Texture


两种光

(1) 环境光 The Ambient Light
(2) 漫射光 The Diffuse Light

 

在这一课里,我们将添加光照和键盘控制 ,它让程序看起来更美观。
这一课我会教您如何使用:
(1) 三种不同的纹理滤波方式
(2) 如何使用键盘来移动场景中的对象
(3) 在OpenGL场景中应用简单的光照
这一课包含了很多内容,如果您对前面的课程有疑问的话,先回头复习一下。

我们增加三个布尔变量。 light 变量跟踪光照是否打开。变量lp和fp用来存储'L' 和'F'键是否按下的状态。后面我会解释这些变量的重要性。
现在设置5个变量来控制绕x轴和y轴旋转角度的步长,以及绕x轴和y轴的旋转速度。另外还创建了一个z变量来控制进入屏幕深处的距离。
接着设置用来创建光源的数组。我们将使用两种不同的光。第一种称为环境光 。环境光来自于四面八方。所有场景中的对象都处于环境光的照射中。第二种类型的光源叫做漫射光 。漫射光由特定的光源产生,并在您的场景中的对象表面上产生反射。处于漫射光直接照射下的任何对象表面都变得很亮,而几乎未被照射到的区域就显得要暗一些。这样在我们所创建的木板箱的棱边上就会产生的很不错的阴影效果。
创建光源的过程和颜色的创建完全一致。前三个参数分别是RGB三色分量,最后一个是alpha通道参数。
因此,下面的代码我们得到的是半亮(0.5f)的白色环境光。如果没有环境光,未被漫射光照到的地方会变得十分黑暗。
下一行代码我们生成最亮的漫射光。所有的参数值都取成最大值1.0f。它将照在我们木板箱的前面,看起来挺好。

最后我们保存光源的位置。前三个参数和glTranslate中的一样。依次分别是XYZ轴上的位移。由于我们想要光线直接照射在木箱的正面,所以XY轴上的位移都是0.0f。第三个值是Z轴上的位移。为了保证光线总在木箱的前面,所以我们将光源的位置朝着观察者(就是您哪。)挪出屏幕。我们通常将屏幕也就是显示器的屏幕玻璃所处的位置称作Z轴的0.0f点。所以Z轴上的位移最后定为2.0f。假如您能够看见光源的话,它就浮在您显示器的前方。当然,如果木箱不在显示器的屏幕玻璃后面的话,您也无法看见箱子。『译者注:我很欣赏NeHe的耐心。说真的有时我都打烦了,这么简单的事他这么废话干嘛?但如果什么都清楚,您还会翻着这样的页面看个没完么?』最后一个参数取为1.0f。这将告诉OpenGL这里指定的坐标就是光源的位置,以后的教程中我会多加解释。

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]中。

现在载入一个位图,并用它创建三种不同的纹理。这一课使用glaux辅助库 来载入位图,因此在编译时您应该确认是否包含了glaux库。我知道 Delphi和VC++都包含了glaux库,但别的语言不能保证都有。『译者注:glaux是OpenGL辅助库,根据OpenGL的跨平台特性,所有平台上的代码都应通用。但辅助库不是正式的OpenGL标准库,没有出现在所有的平台上。但正好在Win32平台上可用。呵呵,BCB当然也没问题了。』这里我只对新增的代码做注解。如果您对某行代码有疑问的话,请查看教程六。那一课很详细的解释了载入、创建纹理的内容。
在上一段代码后面及ReSizeGLScene()之前的位置,我们增加了下面的代码。这和第六课中载入位图的代码几乎相同。

新知识点
(1)
下面是创建纹理的新方法。 Mipmapping!『译者注:这个词的中文我翻不出来,不过没关系。看完这一段,您就知道意思最重要。』您可能会注意到当图像在屏幕上变得很小的时候,很多细节将会丢失。刚才还很不错的图案变得很难看。当您告诉OpenGL创建一个 mipmapped的纹理后,OpenGL将尝试创建不同尺寸的高质量纹理。当您向屏幕绘制一个 mipmapped纹理的时候,OpenGL将选择它已经创建的外观最佳的纹理(带有更多细节)来绘制,而不仅仅是缩放原先的图像(这将导致细节丢失)。
我曾经说过有办法可以绕过OpenGL对纹理宽度和高度所加的限制——64、128、256 ,等等。办法就是 gluBuild2DMipmaps 。据我的发现,您可以使用任意的位图来创建纹理。OpenGL将自动将它缩放到正常的大小。
因为是第三个纹理,我们将它存到texture[2]。这样本课中的三个纹理全都创建好了。
(2)
glNormal3f 是这一课的新东西。Normal就是法线的意思,所谓法线 是指经过面(多边形)上的一点且垂直于这个面(多边形)的直线。使用光源的时候必须指定一条法线。法线告诉OpenGL这个多边形的朝向,并指明多边形的正面和背面。如果没有指定法线,什么怪事情都可能发生:不该照亮的面被照亮了,多边形的背面也被照亮....。对了,法线应该指向多边形的外侧。
看着木箱的前面您会注意到法线与Z轴正向同向。这意味着法线正指向观察者-您自己。这正是我们所希望的。对于木箱的背面,也正如我们所要的,法线背对着观察者。如果立方体沿着X或Y轴转个180度的话,前侧面的法线仍然朝着观察者,背面的法线也还是背对着观察者。换句话说,不管是哪个面,只要它朝着观察者这个面的法线就指向观察者。由于光源紧邻观察者,任何时候法线对着观察者时,这个面就会被照亮。并且法线越朝着光源,就显得越亮一些。如果您把观察点放到立方体内部,你就会法线里面一片漆黑。因为法线是向外指的。如果立方体内部没有光源的话,当然是一片漆黑。

 

BOOL light; // 光源的开/关 BOOL lp; // L键按下了么? BOOL fp; // F键按下了么? GLfloat xrot; // X 旋转 GLfloat yrot; // Y 旋转 GLfloat xspeed; // X 旋转速度 GLfloat yspeed; // Y 旋转速度 GLfloat z=-5.0f; // 深入屏幕的距离 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种纹理的储存空间

调试成功的代码:

// OpenGLWin32GUI.cpp : 定义应用程序的入口点。 // #include "stdafx.h" #include "OpenGLWin32GUI.h" ////////////////////////////////////////////////////////////////////////// #include // Windows的头文件 #include // 标准输入/输出库的头文件 // 系统默认已有的头文件 #include // OpenGL32库的头文件 #include // GLu32库的头文件 #include // GLaux库的头文件 // 使用另外下载的glut工具包 //#include // 附加lib文件 #pragma comment( lib, "opengl32.lib") // OpenGL32连接库 #pragma comment( lib, "glu32.lib") // GLu32连接库 #pragma comment( lib, "glaux.lib") // GLaux连接库 //#pragma comment(lib, "glut32.lib") HGLRC hRC=NULL; // 永久着色描述表 HDC hDC=NULL; // 私有GDI设备描述表 HWND hWnd=NULL; // 保存我们的窗口句柄 HINSTANCE hInstance; // 保存程序的实例 bool keys[256]; // 用于键盘例程的数组 bool active=TRUE; // 窗口的活动标志,缺省为TRUE bool fullscreen=TRUE; // 全屏标志缺省设定成全屏模式 GLfloat rtri; // 用于三角形的角度 GLfloat rquad; // 用于四边形的角度 // GLfloat xrot; // X 旋转量 // GLfloat yrot; // Y 旋转量 // GLfloat zrot; // Z 旋转量 //GLuint texture[1]; // 存储一个纹理 BOOL light; // 光源的开/关 BOOL lp; // L键按下了么? BOOL fp; // F键按下了么? GLfloat xrot; // X 旋转 GLfloat yrot; // Y 旋转 GLfloat xspeed; // X 旋转速度 GLfloat yspeed; // Y 旋转速度 GLfloat z=-5.0f; // 深入屏幕的距离 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种纹理的储存空间 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);// WndProc的定义 AUX_RGBImageRec *LoadBMP(char *Filename)// Loads A Bitmap Image { FILE *File=NULL; if (!Filename)// Make Sure A Filename Was Given { return NULL;// If Not Return NULL } File=fopen(Filename,"r");// Check To See If The File Exists if (File)// Does The File Exist? { fclose(File); // Close The Handle return auxDIBImageLoad(Filename);// Load The Bitmap And Return A Pointer } return NULL;// If Load Failed Return NULL } int LoadGLTextures() // Load Bitmaps And Convert To Textures { int Status=FALSE;// Status Indicator AUX_RGBImageRec *TextureImage[1];// Create Storage Space For The Texture memset(TextureImage,0,sizeof(void *)*1);// Set The Pointer To NULL // Load The Bitmap, Check For Errors, If Bitmap's Not Found Quit if (TextureImage[0]=LoadBMP("Data/Crate.bmp")) { Status=TRUE;// Set The Status To TRUE glGenTextures(3, &texture[0]);// Create The Texture // Create Nearest Filtered Texture 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); // Create Linear Filtered Texture 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); // Create MipMapped Texture 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); // // Typical Texture Generation Using Data From The Bitmap // glBindTexture(GL_TEXTURE_2D, texture[0]); // // // Generate The Texture // glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); // // glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);// Linear Filtering // glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);// Linear Filtering } if (TextureImage[0])// If Texture Exists { if (TextureImage[0]->data)// If Texture Image Exists { free(TextureImage[0]->data);// Free The Texture Image Memory } free(TextureImage[0]);// Free The Image Structure } return Status;// Return The Status } GLvoid ReSizeGLScene(GLsizei width, GLsizei height)// 重置并初始化GL窗口大小 { if (height==0)// 防止被零除 { height=1;// 将Height设为1 } glViewport(0, 0, width, height);// 重置当前的视口(Viewport) glMatrixMode(GL_PROJECTION);// 选择投影矩阵 glLoadIdentity();// 重置投影矩阵 // 计算窗口的外观比例 gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f); glMatrixMode(GL_MODELVIEW);// 选择模型观察矩阵 glLoadIdentity();// 重置模型观察矩阵 } int InitGL(GLvoid)// 此处开始对OpenGL进行所有设置 { if (!LoadGLTextures())// 调用纹理载入子例程 { return FALSE;// 如果未能载入,返回FALSE } glEnable(GL_TEXTURE_2D);// 启用纹理映射 glShadeModel(GL_SMOOTH);// 启用阴影平滑 glClearColor(0.0f, 0.0f, 0.0f, 0.5f);// 黑色背景 glClearDepth(1.0f);// 设置深度缓存 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);// 设置光源位置 glEnable(GL_LIGHT1);// 启用一号光源 return TRUE;// 初始化 OK } 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 单位 // glTranslatef(0.0f,0.0f,-5.0f);// Move Into The Screen 5 Units // // glRotatef(xrot,1.0f,0.0f,0.0f);// Rotate On The X Axis // glRotatef(yrot,0.0f,1.0f,0.0f);// Rotate On The Y Axis // glRotatef(zrot,0.0f,0.0f,1.0f);// Rotate On The Z Axis // // glBindTexture(GL_TEXTURE_2D, texture[0]);// Select Our Texture // // glBegin(GL_QUADS); // // Front Face // glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // Bottom Left Of The Texture and Quad // glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // Bottom Right Of The Texture and Quad // glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // Top Right Of The Texture and Quad // glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Top Left Of The Texture and Quad // // Back Face // glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // Bottom Right Of The Texture and Quad // glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // Top Right Of The Texture and Quad // glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // Top Left Of The Texture and Quad // glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // Bottom Left Of The Texture and Quad // // Top Face // glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // Top Left Of The Texture and Quad // glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Bottom Left Of The Texture and Quad // glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // Bottom Right Of The Texture and Quad // glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // Top Right Of The Texture and Quad // // Bottom Face // glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // Top Right Of The Texture and Quad // glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // Top Left Of The Texture and Quad // glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // Bottom Left Of The Texture and Quad // glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // Bottom Right Of The Texture and Quad // // Right face // glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // Bottom Right Of The Texture and Quad // glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // Top Right Of The Texture and Quad // glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // Top Left Of The Texture and Quad // glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // Bottom Left Of The Texture and Quad // // Left Face // glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // Bottom Left Of The Texture and Quad // glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // Bottom Right Of The Texture and Quad // glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Top Right Of The Texture and Quad // glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // Top Left Of The Texture and Quad // glEnd(); // // xrot+=0.3f;// X Axis Rotation // yrot+=0.2f;// Y Axis Rotation // zrot+=0.4f;// Z Axis Rotation ////////////////////////////////////////////////////////////////////////// // [1] 三角形 -> 四棱锥 // glTranslatef(-1.5f, 0.0f, -6.0f);// 左移1.5单位,并移入屏幕6.0 // glRotatef(rtri, 0.0f, 1.0f, 0.0f);// 绕Y轴旋转三角形 // // // glBegin(GL_TRIANGLES);// 绘制三角形 // // /* 前侧面 */ // glColor3f(1.0f, 0.0f, 0.0f); // 红色 // glVertex3f(0.0f, 1.0f, 0.0f); // 上顶点 // glColor3f(0.0f, 1.0f, 0.0f); // 绿色 // glVertex3f(-1.0f,-1.0f, 1.0f); // 左下 // glColor3f(0.0f, 0.0f, 1.0f); // 蓝色 // glVertex3f(1.0f, -1.0f, 1.0f); // 右下 // // /* 右侧面 */ // glColor3f(1.0f, 0.0f, 0.0f); // 红色 // glVertex3f(0.0f, 1.0f, 0.0f); // 三角形的上顶点 // glColor3f(0.0f, 0.0f, 1.0f); // 蓝色 // glVertex3f(1.0f, -1.0f, 1.0f); // 三角形的左下顶点 // glColor3f(0.0f, 1.0f, 0.0f); // 绿色 // glVertex3f(1.0f, -1.0f, -1.0f); // 三角形的右下顶点 // // /* 后侧面 */ // glColor3f(1.0f, 0.0f, 0.0f); // 红色 // glVertex3f(0.0f, 1.0f, 0.0f); // 三角形的上顶点 // glColor3f(0.0f, 1.0f, 0.0f); // 绿色 // glVertex3f(1.0f, -1.0f, -1.0f); // 三角形的左下顶点 // glColor3f(0.0f, 0.0f, 1.0f); // 蓝色 // glVertex3f(-1.0f, -1.0f, -1.0f);// 三角形的右下顶点 // // /* 左侧面 */ // glColor3f(1.0f, 0.0f, 0.0f); // 红色 // glVertex3f(0.0f, 1.0f, 0.0f); // 三角形的上顶点 // glColor3f(0.0f, 0.0f, 1.0f); // 蓝色 // glVertex3f(-1.0f, -1.0f, -1.0f);// 三角形的左下顶点 // glColor3f(0.0f, 1.0f, 0.0f); // 绿色 // glVertex3f(-1.0f, -1.0f, 1.0f); // 三角形的右下顶点 // // glEnd();// 三角形绘制结束 // // ////////////////////////////////////////////////////////////////////////// // // [2] 正方形 -> 立方体 // // glLoadIdentity();// 重置模型观察矩阵 // glTranslatef(1.5f, 0.0f, -7.0f); // 右移1.5单位,并移入屏幕7.0 // //glTranslatef(1.5f, 0.0f, -6.0f); // 右移1.5单位,并移入屏幕6.0 // //glTranslatef(3.0f, 0.0f, 0.0f); // 右移3单位 // glRotatef(rquad, 1.0f, 1.0f, 1.0f); // 在XYZ轴上旋转立方体 // //glRotatef(rquad, 1.0f, 0.0f, 0.0f); // 绕X轴旋转四边形 // // // glBegin(GL_QUADS);// 绘制正方形 // // // glColor3f(0.5f,0.5f,1.0f);// 一次性将当前色设置为蓝色 // // glVertex3f(-1.0f, 1.0f, 0.0f);// 左上 // // glVertex3f( 1.0f, 1.0f, 0.0f);// 右上 // // glVertex3f( 1.0f,-1.0f, 0.0f);// 右下 // // glVertex3f(-1.0f,-1.0f, 0.0f);// 左下 // // /* Top */ // glColor3f(0.0f, 1.0f, 0.0f); // Set The Color To Green // glVertex3f( 1.0f, 1.0f,-1.0f); // Top Right Of The Quad (Top) // glVertex3f(-1.0f, 1.0f,-1.0f); // Top Left Of The Quad (Top) // glVertex3f(-1.0f, 1.0f, 1.0f); // Bottom Left Of The Quad (Top) // glVertex3f( 1.0f, 1.0f, 1.0f); // Bottom Right Of The Quad (Top) // // /* Bottom */ // glColor3f(1.0f, 0.5f, 0.0f); // Set The Color To Orange // glVertex3f( 1.0f,-1.0f, 1.0f); // Top Right Of The Quad (Bottom) // glVertex3f(-1.0f,-1.0f, 1.0f); // Top Left Of The Quad (Bottom) // glVertex3f(-1.0f,-1.0f,-1.0f); // Bottom Left Of The Quad (Bottom) // glVertex3f( 1.0f,-1.0f,-1.0f); // Bottom Right Of The Quad (Bottom) // // /* Front */ // glColor3f(1.0f, 0.0f, 0.0f); // Set The Color To Red // glVertex3f( 1.0f, 1.0f, 1.0f); // Top Right Of The Quad (Front) // glVertex3f(-1.0f, 1.0f, 1.0f); // Top Left Of The Quad (Front) // glVertex3f(-1.0f,-1.0f, 1.0f); // Bottom Left Of The Quad (Front) // glVertex3f( 1.0f,-1.0f, 1.0f); // Bottom Right Of The Quad (Front) // // /* Back */ // glColor3f(1.0f, 1.0f, 0.0f); // Set The Color To Yellow // glVertex3f( 1.0f,-1.0f,-1.0f); // Bottom Left Of The Quad (Back) // glVertex3f(-1.0f,-1.0f,-1.0f); // Bottom Right Of The Quad (Back) // glVertex3f(-1.0f, 1.0f,-1.0f); // Top Right Of The Quad (Back) // glVertex3f( 1.0f, 1.0f,-1.0f); // Top Left Of The Quad (Back) // // /* Left */ // glColor3f(0.0f, 0.0f, 1.0f); // Set The Color To Blue // glVertex3f(-1.0f, 1.0f, 1.0f); // Top Right Of The Quad (Left) // glVertex3f(-1.0f, 1.0f,-1.0f); // Top Left Of The Quad (Left) // glVertex3f(-1.0f,-1.0f,-1.0f); // Bottom Left Of The Quad (Left) // glVertex3f(-1.0f,-1.0f, 1.0f); // Bottom Right Of The Quad (Left) // // /* Right */ // glColor3f(1.0f, 0.0f, 1.0f); // Set The Color To Violet // glVertex3f( 1.0f, 1.0f,-1.0f); // Top Right Of The Quad (Right) // glVertex3f( 1.0f, 1.0f, 1.0f); // Top Left Of The Quad (Right) // glVertex3f( 1.0f,-1.0f, 1.0f); // Bottom Left Of The Quad (Right) // glVertex3f( 1.0f,-1.0f,-1.0f); // Bottom Right Of The Quad (Right) // // glEnd();// 正方形绘制结束 // // rtri+=1.0f; // 增加三角形的旋转变量 // //rtri+=0.2f; // 增加三角形的旋转变量 // rquad-=0.15f; // 减少四边形的旋转变量 /*******************************************************/ return TRUE; } GLvoid KillGLWindow(GLvoid)// 正常销毁窗口 { if (fullscreen)// 处于全屏模式吗 { ChangeDisplaySettings(NULL,0);// 是的话,切换回桌面 ShowCursor(TRUE);// 显示鼠标指针 } if (hRC)// 拥有着色描述表吗 { if (!wglMakeCurrent(NULL,NULL))// 能否释放DC和RC描述表 { MessageBox(NULL,_T("Release Of DC And RC Failed."),_T("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION); } if (!wglDeleteContext(hRC))// 能否删除RC { MessageBox(NULL,_T("Release Rendering Context Failed."),_T("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION); } hRC=NULL;// 将RC设为NULL } if (hDC && !ReleaseDC(hWnd,hDC))// 能否释放DC { MessageBox(NULL,_T("Release Device Context Failed."),_T("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION); hDC=NULL;// 将DC设为NULL } if (hWnd && !DestroyWindow(hWnd))// 能否销毁窗口 { MessageBox(NULL,_T("Could Not Release hWnd."),_T("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION); hWnd=NULL;// 将hWnd设为NULL } if (!UnregisterClass(_T("OpenGL"),hInstance))// 能否注销窗口类 { MessageBox(NULL,_T("Could Not Unregister Class."),_T("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION); hInstance=NULL;// 将hInstance设为NULL } } BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag) //BOOL CreateGLWindow(LPCWSTR title, int width, int height, int bits, bool fullscreenflag) { GLuint PixelFormat; // 保存查找匹配的结果 WNDCLASS wc; // 窗口类结构 DWORD dwExStyle; // 扩展窗口风格 DWORD dwStyle; // 窗口风格 RECT WindowRect; // 取得矩形的左上角和右下角的坐标值 WindowRect.left=(long)0; // 将Left设为 0 WindowRect.right=(long)width; // 将Right设为要求的宽度 WindowRect.top=(long)0; // 将Top设为 0 WindowRect.bottom=(long)height; // 将Bottom设为要求的高度 fullscreen=fullscreenflag; // 设置全局全屏标志 hInstance = GetModuleHandle(NULL); // 取得窗口的实例 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // 移动时重画,并为窗口取得DC wc.lpfnWndProc = (WNDPROC) WndProc; // WndProc处理消息 wc.cbClsExtra = 0; // 无额外窗口数据 wc.cbWndExtra = 0; // 无额外窗口数据 wc.hInstance = hInstance; // 设置实例 wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // 装入缺省图标 wc.hCursor = LoadCursor(NULL, IDC_ARROW); // 装入鼠标指针 wc.hbrBackground = NULL; // GL不需要背景 wc.lpszMenuName = NULL; // 不需要菜单 wc.lpszClassName = _T("OpenGL"); // 设定类名字 if (!RegisterClass(&wc)) // 尝试注册窗口类 { MessageBox(NULL,_T("Failed To Register The Window Class."),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION); return FALSE;// 退出并返回FALSE } if (fullscreen)// 要尝试全屏模式吗 { DEVMODE dmScreenSettings; // 设备模式 memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); // 确保内存分配 dmScreenSettings.dmSize=sizeof(dmScreenSettings); // Devmode 结构的大小 dmScreenSettings.dmPelsWidth = width; // 所选屏幕宽度 dmScreenSettings.dmPelsHeight = height; // 所选屏幕高度 dmScreenSettings.dmBitsPerPel = bits; // 每象素所选的色彩深度 dmScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT; // 尝试设置显示模式并返回结果。注: CDS_FULLSCREEN 移去了状态条。 if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL) { // 若模式失败,提供两个选项:退出或在窗口内运行。 if (MessageBox(NULL,_T("The Requested Fullscreen Mode Is Not Supported By/nYour Video Card. Use Windowed Mode Instead?"),_T("NeHe GL"),/ MB_YESNO|MB_ICONEXCLAMATION)==IDYES) { fullscreen=FALSE;// 选择窗口模式(Fullscreen=FALSE) } else { // Pop Up A Message Box Letting User Know The Program Is Closing. MessageBox(NULL,_T("Program Will Now Close."),_T("ERROR"),MB_OK|MB_ICONSTOP); return FALSE;//退出并返回FALSE } } } if (fullscreen)// 仍处于全屏模式吗 { dwExStyle=WS_EX_APPWINDOW; // 扩展窗体风格 dwStyle=WS_POPUP; // 窗体风格 ShowCursor(FALSE); // 隐藏鼠标指针 } else { dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // 扩展窗体风格 dwStyle=WS_OVERLAPPEDWINDOW; // 窗体风格 } AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);// 调整窗口达到真正要求的大小 if (!(hWnd=CreateWindowEx( dwExStyle, // 扩展窗体风格 _T("OpenGL"), // 类名字 title, // 窗口标题 WS_CLIPSIBLINGS | // 必须的窗体风格属性 WS_CLIPCHILDREN | // 必须的窗体风格属性 dwStyle, // 选择的窗体属性 0,0, // 窗口位置 WindowRect.right-WindowRect.left, // 计算调整好的窗口宽度 WindowRect.bottom-WindowRect.top, // 计算调整好的窗口高度 NULL, // 无父窗口 NULL, // 无菜单 hInstance, // 实例 NULL))) // 不向WM_CREATE传递任何东东 { KillGLWindow();// 重置显示区 MessageBox(NULL,_T("Window Creation Error."),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION); return FALSE;// 返回 FALSE } static PIXELFORMATDESCRIPTOR pfd = //pfd 告诉窗口我们所希望的东东 { sizeof(PIXELFORMATDESCRIPTOR), //上述格式描述符的大小 1, // 版本号 PFD_DRAW_TO_WINDOW | // 格式必须支持窗口 PFD_SUPPORT_OPENGL | // 格式必须支持OpenGL PFD_DOUBLEBUFFER, // 必须支持双缓冲 PFD_TYPE_RGBA, // 申请 RGBA 格式 bits, // 选定色彩深度 0, 0, 0, 0, 0, 0, // 忽略的色彩位 0, // 无Alpha缓存 0, // 忽略Shift Bit 0, // 无聚集缓存 0, 0, 0, 0, // 忽略聚集位 16, // 16位 Z-缓存 (深度缓存) 0, // 无模板缓存 0, // 无辅助缓存 PFD_MAIN_PLANE, // 主绘图层 0, // 保留 0, 0, 0 // 忽略层遮罩 }; if (!(hDC=GetDC(hWnd)))// 取得设备描述表了么 { KillGLWindow();// 重置显示区 MessageBox(NULL,_T("Can't Create A GL Device Context."),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION); return FALSE;// 返回 FALSE } if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd)))// Windows 找到相应的象素格式了吗 { KillGLWindow();// 重置显示区 MessageBox(NULL,_T("Can't Find A Suitable PixelFormat."),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION); return FALSE;// 返回 FALSE } if(!SetPixelFormat(hDC,PixelFormat,&pfd))// 能够设置象素格式么 { KillGLWindow();// 重置显示区 MessageBox(NULL,_T("Can't Set The PixelFormat."),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION); return FALSE;// 返回 FALSE } if (!(hRC=wglCreateContext(hDC)))// 能否取得着色描述表 { KillGLWindow();// 重置显示区 MessageBox(NULL,_T("Can't Create A GL Rendering Context."),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION); return FALSE;// 返回 FALSE } if(!wglMakeCurrent(hDC,hRC))// 尝试激活着色描述表 { KillGLWindow();// 重置显示区 MessageBox(NULL,_T("Can't Activate The GL Rendering Context."),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION); return FALSE;// 返回 FALSE } ShowWindow(hWnd,SW_SHOW); // 显示窗口 SetForegroundWindow(hWnd); // 略略提高优先级 SetFocus(hWnd); // 设置键盘的焦点至此窗口 ReSizeGLScene(width, height); // 设置透视 GL 屏幕 if (!InitGL())// 初始化新建的GL窗口 { KillGLWindow();// 重置显示区 MessageBox(NULL,_T("Initialization Failed."),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION); return FALSE;// 返回 FALSE } return TRUE;// 成功 } LRESULT CALLBACK WndProc( HWND hWnd, // 窗口的句柄 UINT uMsg, // 窗口的消息 WPARAM wParam, // 附加的消息内容 LPARAM lParam) // 附加的消息内容 { switch (uMsg)// 检查Windows消息 { case WM_ACTIVATE:// 监视窗口激活消息 { if (!HIWORD(wParam))// 检查最小化状态 { active=TRUE;// 程序处于激活状态 } else { active=FALSE;// 程序不再激活 } return 0;// 返回消息循环 } case WM_SYSCOMMAND:// 中断系统命令Intercept System Commands { switch (wParam)// 检查系统调用Check System Calls { case SC_SCREENSAVE:// 屏保要运行? case SC_MONITORPOWER:// 显示器要进入节电模式? return 0;// 阻止发生 } break;// 退出 } case WM_CLOSE:// 收到Close消息? { PostQuitMessage(0);// 发出退出消息 return 0; } case WM_KEYDOWN:// 有键按下么? { keys[wParam] = TRUE;// 如果是,设为TRUE return 0;// 返回 } case WM_KEYUP:// 有键放开么? { keys[wParam] = FALSE;// 如果是,设为FALSE return 0;// 返回 } case WM_SIZE: { ReSizeGLScene(LOWORD(lParam),HIWORD(lParam)); return 0; } } // 向DefWindowProc传递所有未处理的消息。 return DefWindowProc(hWnd,uMsg,wParam,lParam); } int WINAPI WinMain( HINSTANCE hInstance, // 实例 HINSTANCE hPrevInstance, // 前一个实例 LPSTR lpCmdLine, // 命令行参数 int nCmdShow) // 窗口显示状态 { MSG msg; // Windowsx消息结构 BOOL done=FALSE; // 用来退出循环的Bool 变量 // 提示用户选择运行模式 if (MessageBox(NULL,_T("Would You Like To Run In Fullscreen Mode?"),_T("Start FullScreen?"),MB_YESNO|MB_ICONQUESTION)==IDNO) { fullscreen=FALSE; // 窗口模式 } // 创建OpenGL窗口 if (!CreateGLWindow(_T("WCDJ's OpenGL Framework"),640,480,16,fullscreen)) { return 0;// 失败退出 } while(!done)// 保持循环直到 done=TRUE { if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))// 有消息在等待吗? { if (msg.message==WM_QUIT)// 收到退出消息? { done=TRUE;// 是,则done=TRUE } else// 不是,处理窗口消息 { TranslateMessage(&msg); // 翻译消息 DispatchMessage(&msg); // 发送消息 } } else// 如果没有消息 { // 绘制场景。监视ESC键和来自DrawGLScene()的退出消息 if (active)// 程序激活的么? { if (keys[VK_ESCAPE])// ESC 按下了么? { done=TRUE;// ESC 发出退出信号 } else// 不是退出的时候,刷新屏幕 { DrawGLScene();// 绘制场景 SwapBuffers(hDC);// 交换缓存 (双缓存) ////////////////////////////////////////////////////////////////////////// // Lesson 7 if (keys['L'] && !lp)// L 键已按下并且松开了? { lp=TRUE; // lp 设为 TRUE light=!light; // 切换光源的 TRUE/FALSE if (!light) // 如果没有光源 { glDisable(GL_LIGHTING);// 禁用光源 } else// 否则 { glEnable(GL_LIGHTING);// 启用光源 } } if (!keys['L'])// L键松开了么? { lp=FALSE;// 若是,则将lp设为FALSE } if (keys['F'] && !fp)// F键按下了么? { fp=TRUE; // fp 设为 TRUE filter+=1; // filter的值加一 if (filter>2) // 大于2了么? { filter=0; // 若是重置为0 } } if (!keys['F'])// F键放开了么? { fp=FALSE;// 若是fp设为FALSE } if (keys[VK_PRIOR])// PageUp按下了? { z-=0.02f;// 若按下,将木箱移向屏幕内部 } if (keys[VK_NEXT])// PageDown按下了么? { z+=0.02f;// 若按下的话,将木箱移向观察者 } if (keys[VK_UP])// Up方向键按下了么? { xspeed-=0.01f;// 若是,减少xspeed } if (keys[VK_DOWN])// Down方向键按下了么? { xspeed+=0.01f;// 若是,增加xspeed } if (keys[VK_RIGHT])// Right方向键按下了么? { yspeed+=0.01f;// 若是,增加yspeed } if (keys[VK_LEFT])// Left方向键按下了么? { yspeed-=0.01f;// 若是, 减少yspeed } ////////////////////////////////////////////////////////////////////////// } } if (keys[VK_F1])// 允许用户按下F1键在全屏模式和窗口模式间切换 { keys[VK_F1]=FALSE;// 若是,使对应的Key数组中的值为 FALSE KillGLWindow();// 销毁当前的窗口 fullscreen=!fullscreen; // 切换 全屏 / 窗口 模式 // 重建 OpenGL 窗口 if (!CreateGLWindow(_T("WCDJ's OpenGL Framework"),640,480,16,fullscreen)) { return 0;// 如果窗口未能创建,程序退出 } } } } // 关闭程序 KillGLWindow();// 销毁窗口 return (msg.wParam);// 退出程序 } ////////////////////////////////////////////////////////////////////////// /* #define MAX_LOADSTRING 100 // 全局变量: HINSTANCE hInst; // 当前实例 TCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本 TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名 // 此代码模块中包含的函数的前向声明: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); // TODO: 在此放置代码。 MSG msg; HACCEL hAccelTable; // 初始化全局字符串 LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_OPENGLWIN32GUI, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // 执行应用程序初始化: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_OPENGLWIN32GUI)); // 主消息循环: while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return (int) msg.wParam; } // // 函数: MyRegisterClass() // // 目的: 注册窗口类。 // // 注释: // // 仅当希望 // 此代码与添加到 Windows 95 中的“RegisterClassEx” // 函数之前的 Win32 系统兼容时,才需要此函数及其用法。调用此函数十分重要, // 这样应用程序就可以获得关联的 // “格式正确的”小图标。 // ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_OPENGLWIN32GUI)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = MAKEINTRESOURCE(IDC_OPENGLWIN32GUI); wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); return RegisterClassEx(&wcex); } // // 函数: InitInstance(HINSTANCE, int) // // 目的: 保存实例句柄并创建主窗口 // // 注释: // // 在此函数中,我们在全局变量中保存实例句柄并 // 创建和显示主程序窗口。 // BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; hInst = hInstance; // 将实例句柄存储在全局变量中 hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } // // 函数: WndProc(HWND, UINT, WPARAM, LPARAM) // // 目的: 处理主窗口的消息。 // // WM_COMMAND - 处理应用程序菜单 // WM_PAINT - 绘制主窗口 // WM_DESTROY - 发送退出消息并返回 // // LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; switch (message) { case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // 分析菜单选择: switch (wmId) { case IDM_ABOUT: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: 在此添加任意绘图代码... EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } // “关于”框的消息处理程序。 INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: return (INT_PTR)TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } break; } return (INT_PTR)FALSE; } */

 

这一课完了之后,您应该学会创建和使用这三种不同的纹理映射过滤方式。并使用键盘和场景中的对象交互。最后,您应该学会在场景中应用简单的光源,使得场景看起来更逼真。


参考
http://www.yakergong.com/nehe/
http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=07

 

你可能感兴趣的:(OpenGL)