C++博客 :: 首页 :: 联系 ::  :: 管理
  163 Posts :: 4 Stories :: 350 Comments :: 0 Trackbacks

常用链接

留言簿(48)

我参与的团队

搜索

  •  

积分与排名

  • 积分 - 393364
  • 排名 - 58

最新评论

阅读排行榜

评论排行榜

 这一课我会教您如何使用三种不同的纹理滤波方式。教您如何使用键盘来移动场景中的对象,还会教您在OpenGL场 景中应用简单的光照。这一课包含了很多内容,如果您对前面的课程有疑问的话,先回头复习一下。进入后面的代码之前,很好的理解基础知识十分重要。我们还是 在第一课的代码上加以修改。跟以前不一样的是,只要有任何大的改动,我都会写出整段代码。程序开始,我们先加上几个新的变量。

  #include <windows.h>                    // Windows的头文件
  #include <stdio.h>                     // 标准输入/输出库的头文件 (新增)
  #include <gl\\gl.h>                     // OpenGL32库的头文件
  #include <gl\\glu.h>                    // GLu32库的头文件
  #include <gl\\glaux.h>                   // GLaux库的头文件

  HGLRC hRC=NULL;                      // 永久着色描述表
  HDC hDC=NULL;                       // 私有GDI设备描述表
  HWND hWnd=NULL;                      // 保存我们的窗口句柄
  HINSTANCE hInstance;                    // 保存程序的实例

  bool keys[256];                      // 用于键盘例程的数组
  bool active=TRUE;                     // 窗口的活动标志,缺省为TRUE
  bool fullscreen=TRUE;                   // 全屏标志缺省设定成全屏模式

   下面几行是新的。我们增加三个布尔变量。light变量跟踪光照是否打开。变量lpfp用来存储‘L’和‘F’键是否按下的状态。后面我会解释这些变量的重要性。现在,先放在一边吧。

  BOOL light;                   ?    ?// 光源的开/关
  BOOL lp;                          // L键按下了么?
  BOOL fp;                          // F键按下了么?

   现在设置5个变量来控制绕x轴和y轴旋转角度的步长,以及绕x轴和y轴的旋转速度。另外还创建了一个z变量来控制进入屏幕深处的距离。

  GLfloat xrot;                       // X 旋转
  GLfloat yrot;                       // Y 旋转
  GLfloat xspeed;                      // X 旋转速度
  GLfloat yspeed;                      // Y 旋转速度

  GLfloat z=-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。假如您能够看见光源的话,它就浮在您显示器的前方。当然,如果 木箱不在显示器的屏幕玻璃后面的话,您也无法看见箱子。最后一个参数取为1.0f。这将告诉OpenGL这里指定的坐标就是光源的位置,以后的教程中我会多加解释。

  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种纹理的储存空间
  LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);   // WndProc定义

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

  AUX_RGBImageRec *LoadBMP(char *Filename)          // 载入位图
  {
       FILE *File=NULL;
                  // 文件句柄
      if (!Filename)                   // 确认文件名已初始化
      {
           return NULL;
                // 没有返回 NULL
      }
       File=fopen(Filename,"r");
             // 检查文件是否存在
      if (File)                     // 存在么?
      {
           fclose(File); 
              // 关闭文件句柄
          return auxDIBImageLoad(Filename);     // 载入位图并返回一个指针
      }
      return NULL;                    // 载入失败返回 NULL
  }

   这段代码调用前面的代码载入位图,并将其转换成3个纹理。Status变量跟踪纹理是否已载入并被创建了。

  int LoadGLTextures()                    // 载入位图并转换成纹理
  {
       int Status=FALSE;
                  // Status 指示器
      AUX_RGBImageRec *TextureImage[1];         // 创建纹理的存储空间
      memset(TextureImage,0,sizeof(void *)*1);      // 将指针设为 NULL

现在载入位图并转换成纹理。TextureImage[0]=LoadBMP("Data/Crate.bmp")调用我们的LoadBMP()函数。 Data目录下的“Crate.bmp”将被载入。如果一切正常,图像数据将存放在TextureImage[0]。Status变量被设为TRUE,我 们将开始创建纹理。

      // 载入位图,检查有错,或位图不存在的话退出。
      if (TextureImage[0]=LoadBMP("Data/Crate.bmp"))
       {
           Status=TRUE;
                // Status 设为 TRUE

   现在我们已经将图像数据载入TextureImage[0]。我们将用它来创建3个纹理。下面的行告诉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]);
           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);

   下个纹理与第六课的相同,线性滤波。唯一的不同是这次放在了texture[1]中。因为这是第二个纹理。如果放在texture[0]中的话,他将覆盖前面创建的GL_NEAREST纹理。

          // 创建线性滤波纹理
          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);

下面是创建纹理的新方法:Mip-mapping(纹理细化)。您可能会注意到当图像在屏幕上变得很小的时候,很多细节将会丢失。刚才还很不错的图案变得 很难看。当您告诉OpenGL创建一个mipmapped的纹理后,OpenGL将尝试创建不同尺寸的高质量纹理。当您向屏幕绘制一个mipmapped 纹理的时候,OpenGL将选择它已经创建的外观最佳的纹理(带有更多细节)来绘制,而不仅仅是缩放原先的图像(这将导致细节丢失)。
我曾经说过有办法可以绕过OpenGL对纹理宽度和高度所加的限制 — 64、128、256,等等。办法就是 gluBuild2DMipmaps。据我的发现,您可以使用任意的位图来创建纹理。OpenGL将自动将它缩放到正常的大小。因为是第三个纹理,我们将 它存到texture[2]。这样本课中的三个纹理全都创建好了。

          // 创建 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);
// (新增)

下面一行生成mipmapped纹理。我们使用三种颜色(红,绿,蓝)来生成一个2D纹理。TextureImage[0]->sizeX 是位图宽度,extureImage[0]->sizeY是位图高度,GL_RGB意味着我们依次使用RGB色彩。 GL_UNSIGNED_BYTE意味着纹理数据的单位是字节。TextureImage[0]->data指向我们创建纹理所用的位图。

          gluBuild2DMipmaps(GL_TEXTURE_2D, 3,
               TextureImage[0]->sizeX, TextureImage[0]->sizeY,
               GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
  // ( 新增 )
      }

   现在释放用来存放位图数据的内存。我们先查看位图数据是否存放在TextureImage[0]中,如果有,删掉。然后释放位图结构以确保内存被释放。

      if (TextureImage[0])                // 纹理是否存在
      {
           if (TextureImage[0]->data)
         // 纹理图像是否存在
          {
               free(TextureImage[0]->data);
    // 释放纹理图像占用的内存
          }
           free(TextureImage[0]);
           // 释放图像结构
      }

   最后我们返回status变量。如果一切OK,status变量的值为TRUE。否则为FALSE。

      return Status;                  // 返回 Status 变量
  }

   接着应该载入纹理并初始化OpenGL设置了。InitGL函数的第一行使用上面的代码载入纹理。创建纹理之后,我们调用glEnable(GL_TEXTURE_2D)启用2D纹理映射。阴影模式设为平滑阴影(smooth shading)。背景色设为黑色,我们启用深度测试,然后我们启用优化透视计算。

  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);// 高度优化的透视投影计算

   现在开始设置光源。下面下面一行设置环境光的发光量,光源light1开始发光。这一课的开始处我们我们将环境光的发光量存放在LightAmbient数组中。现在我们就使用此数组(半亮度环境光)。

      glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);  // 设置环境光

   接下来我们设置漫射光的发光量。它存放在LightDiffuse数组中(全亮度白光)。

      glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);  // 设置漫射光

   然后设置光源的位置。位置存放在 LightPosition 数组中(正好位于木箱前面的中心,X-0.0f,Y-0.0f,Z方向移向观察者2个单位[位于屏幕外面])。

      glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); // 光源位置

   最后,我们启用一号光源。我们还没有启用GL_LIGHTING,所以您看不见任何光线。记住:只对光源进行设置、定位、甚至启用,光源都不会工作。除非我们启用GL_LIGHTING。

      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轴移动Z单位。glRotatef(xrot,1.0f,0.0f,0.0f)将立方体绕X轴旋转xrot。glRotatef(yrot,0.0f,1.0f,0.0f)将立方体绕Y轴旋转yrot

      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轴旋转

下一行与我们在第六课中的类似。有所不同的是,这次我们绑定的纹理是texture[filter],而不是上一课中的texture[0]。任何时候, 我们按下F键,filter的值就会增加。如果这个数值大于2,变量filter 将被重置为0。程序初始时,变量filter的值也将设为0。使用变量filter我们就可以选择三种纹理中的任意一种。

      glBindTexture(GL_TEXTURE_2D, texture[filter]);  // 选择由filter决定的纹理
      glBegin(GL_QUADS);                // 开始绘制四边形

glNormal3f是这一课的新东西。Normal就是法线的意思,所谓法线是指经过面(多边形)上的一点且垂直于这个面(多边形)的直线。使用光源的 时候必须指定一条法线。法线告诉OpenGL这个多边形的朝向,并指明多边形的正面和背面。如果没有指定法线,什么怪事情都可能发生:不该照亮的面被照亮 了,多边形的背面也被照亮....。对了,法线应该指向多边形的外侧。
看着木箱的前面您会注意到法线与Z轴正向同向。这意味着法线正指向观察者-您自己。这正是我们所希望的。对于木箱的背面,也正如我们所要的,法线背对着观 察者。如果立方体沿着X或Y轴转个180度的话,前侧面的法线仍然朝着观察者,背面的法线也还是背对着观察者。换句话说,不管是哪个面,只要它朝着观察者 这个面的法线就指向观察者。由于光源紧邻观察者,任何时候法线对着观察者时,这个面就会被照亮。并且法线越朝着光源,就显得越亮一些。如果您把观察点放到 立方体内部,你就会法线里面一片漆黑。因为法线是向外指的。如果立方体内部没有光源的话,当然是一片漆黑。

          // 前侧面
          glNormal3f( 0.0f, 0.0f, 1.0f);      // 法线指向观察者
          glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);// Point 1 (Front)
          glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);// Point 2 (Front)
          glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // Point 3 (Front)
          glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Point 4 (Front)

          // 后侧面
          glNormal3f( 0.0f, 0.0f,-1.0f);      // 法线背向观察者
          glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);// Point 1 (Back)
          glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // Point 2 (Back)
          glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // Point 3 (Back)
          glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);// Point 4 (Back)

          // 顶面
          glNormal3f( 0.0f, 1.0f, 0.0f);     // 法线向上
          glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);// Point 1 (Top)
          glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Point 2 (Top)
          glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // Point 3 (Top)
          glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);// Point 4 (Top)

          // 底面
          glNormal3f( 0.0f,-1.0f, 0.0f);     // 法线朝下
          glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);// Point 1 (Bottom)
          glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);// Point 2 (Bottom)
          glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // Point 3 (Bottom)
          glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // Point 4 (Bottom)

          // 右侧面
          glNormal3f( 1.0f, 0.0f, 0.0f);    // 法线朝右
          glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);// Point 1 (Right)
          glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // Point 2 (Right)
          glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // Point 3 (Right)
          glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // Point 4 (Right)

          // 左侧面
          glNormal3f(-1.0f, 0.0f, 0.0f);    // 法线朝左
          glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);// Point 1 (Left)
          glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // Point 2 (Left)
          glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // Point 3 (Left)
          glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // Point 4 (Left)
      glEnd();     ?            ?// 四边形绘制结束

   下两行代码将xotyrot的旋转值分别增加xspeedyspeed个单位。xspeedyspeed的值越大,立方体转得就越快。

      xrot+=xspeed;                // xrot 增加 xspeed 单位
      yrot+=yspeed;                // yrot 增加 yspeed 单位
      return TRUE;
  }

现在转入WinMain()主函数。我们将在这里增加开关光源、旋转木箱、切换过滤方式以及将木箱移近移远的控制代码。在接近WinMain()函数结束 的地方你会看到SwapBuffers(hDC)这行代码。然后就在这一行后面添加如下的代码。代码将检查L键是否按下过。如果L键已按下,但lp的值不是false的话,意味着L键还没有松开,这时什么都不会发生。

                      SwapBuffers(hDC);  // 交换缓存 (双缓存)
                      if (keys[\’L\’] && !lp)// L 键已按下并且松开了?
                      {

   如果lp的值是false的话,意味着L键还没按下,或者已经松开了,接着lp将被设为TRUE。同时检查这两个条件的原因是为了防止L键被按住后,这段代码被反复执行,并导致窗体不停闪烁。
  lp设为true之后,计算机就知道L键按过了,我们则据此可以切换光源的开/关:布尔变量light控制光源的开关。
                           lp=TRUE;   // lp 设为 TRUE
                           light=!light;// 切换光源的 TRUE/FALSE

   下面几行来检查光源是否应该打开,并根据light变量的值。

                           if (!light) // 如果没有光源
                           {
                                glDisable(GL_LIGHTING);
//禁用光源
                           }
                            else
     // Otherwise
                           {
                                glEnable(GL_LIGHTING);
//启用光源
                           }
                        }

   下面的代码查看是否松开了“L”键。如果松开,变量lp将设为false。这意味着“L”键没有按下。如果不作此检查,光源第一次打开之后,就无法再关掉了。计算机会以为“L”键一直按着呢。

                      if (!keys[\’L\’])   // L键松开了么?
                      {
                            lp=FALSE;
  // 若是,则将lp设为FALSE
                      }

然后对“F”键作相似的检查。如果有按下“F”?⑶摇癋”键没有处于按着的状态或者它就从没有按下过,将变量fp设为true。这意味着这个键正被按着 呢。接着将filter变量加一。如果filter变量大于2(因为这里我们的使用的数组是texture[3],大于2的纹理不存在),我们重置 filter变量为0。

                      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
                      }

   这四行检查是否按下了PageUp键。若是的话,减少z变量的值。这样DrawGLScene函数中包含的glTranslatef(0.0f,0.0f,z)调用将使木箱离观察者更远一点。

                      if (keys[VK_PRIOR]) // PageUp按下了?
                      {
                            z-=0.02f;
 // 若按下,将木箱移向屏幕内部。
                      }

   接着四行检查PageDown键是否按下,若是的话,增加z变量的值。这样DrawGLScene函数中包含的glTranslatef(0.0f,0.0f,z)调用将使木箱向着观察者移近一点。

                      if (keys[VK_NEXT])  // PageDown按下了么?
                      {
                            z+=0.02f;
  //若按下的话,将木箱移向观察者。
                      }

   现在检查方向键。按下左右方向键xspeed相应减少或增加。按下上下方向键yspeed相应减少或增加。记住在以后的教程中如果xspeedyspeed的值增加的话,立方体就转的更快。如果一直按着某个方向键,立方体会在那个方向上转的越快。

                      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;

                          KillGLWindow();    // 销毁当前的窗口
                          fullscreen=!fullscreen;// 切换 全屏/窗口 模式
                           // 重建 OpenGL 窗口(修改)
                          if (!CreateGLWindow("NeHe\’s Textures, Lighting & Keyboard Tutorial",640,480,16,fullscreen))
                           {
                                return 0;
// 如果窗口未能创建,程序退出
                          }
                       }

                   }
               }
            }

      // 关闭
      KillGLWindow();                  // 销毁窗口
      return (msg.wParam);                // 退出程序
  }

posted on 2007-12-11 18:10 sdfasdf 阅读(686) 评论(0)  编辑 收藏 引用 所属分类: OPENGL

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理