• NeHe OpenGL教程 第二十三课:球面映射


    转自【翻译】NeHe OpenGL 教程

    前言

    声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改。对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢。

    NeHe OpenGL第二十三课:球面映射

    球面映射:

    这一个将教会你如何把环境纹理包裹在你的3D模型上,让它看起来象反射了周围的场景一样。
     
    球体环境映射是一个创建快速金属反射效果的方法,但它并不像真实世界里那么精确!我们从18课的代码开始来创建这个教程,教你如何创建这种效果。
    在我们开始之间,看一下红宝书中的介绍。它定义球体环境映射为一幅位于无限远的图像,把它映射到球面上。

    在Photoshop中创建一幅球体环境映射图。

    首先,你需要一幅球体环境映射图,用来把它映射到球体上。在Photoshop中打开一幅图并选择所有的像素,创建它的一个复制。
    接着,我们把图像变为2的幂次方大小,一般为128x128或256x256。
    最后使用扭曲(distort)滤镜,并应用球体效果。然后把它保存为*.bmp文件。

    我们并没有添加任何全局变量,只是把纹理组的大小变为6,以保存6幅纹理。

    GLuint texture[6];        // 保存6幅纹理

    下面我们要做的就是载入这些纹理 
      
    int LoadGLTextures()        
    {
     int Status=FALSE;       

     AUX_RGBImageRec *TextureImage[2];      // 创建纹理的保存空间

     memset(TextureImage,0,sizeof(void *)*2);                // 清空为0

     // 载入*.bmp图像
     if ((TextureImage[0]=LoadBMP("Data/BG.bmp")) &&    // 背景图
      (TextureImage[1]=LoadBMP("Data/Reflect.bmp")))   // 反射图(球形纹理图)
     {
      Status=TRUE;       

      glGenTextures(6, &texture[0]);     // 创建6个纹理

      for (int loop=0; loop<=1; loop++)
      {
       // 创建临近点过滤纹理图
       glBindTexture(GL_TEXTURE_2D, texture[loop]);   // 创建纹理0和1
       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[loop]->sizeX, TextureImage[loop]->sizeY,
        0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop]->data);

       // 创建线形过滤纹理图
       glBindTexture(GL_TEXTURE_2D, texture[loop+2]);  // 创建纹理2,3
       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[loop]->sizeX, TextureImage[loop]->sizeY,
        0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop]->data);

       // 创建线形Mipmap纹理图
       glBindTexture(GL_TEXTURE_2D, texture[loop+4]);  // 创建纹理4,5
       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[loop]->sizeX, TextureImage[loop]->sizeY,
        GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop]->data);
      }
      for (loop=0; loop<=1; loop++)
      {
             if (TextureImage[loop])      // 如果图像存在则清除
          {
               if (TextureImage[loop]->data)   
            {
                 free(TextureImage[loop]->data); 
         }
         free(TextureImage[loop]);  
       }
      }
     }

     return Status;    
    }

    我们对立方体的绘制代码做了一些小的改动,把法线的范围从[-1,1]缩放到[-0.5,0.5]。如果法向量太大的话,会产生一些块状效果,影响视觉效果。 
      
    GLvoid glDrawCube()
    {
      glBegin(GL_QUADS);
      // 前面
      glNormal3f( 0.0f, 0.0f, 0.5f);
      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,-0.5f);
      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, 0.5f, 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,-0.5f, 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( 0.5f, 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(-0.5f, 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();
    }

    在初始化OpenGL中,我们添加一些新的函数来使用球体纹理映射。
    下面的代码让OpenGL自动为我们计算使用球体映射时,顶点的纹理坐标。 

     glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);   // 设置s方向的纹理自动生成
     glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);   // 设置t方向的纹理自动生成
      
    我们几乎完成了所有的工作!接下来要做的就是就是绘制渲染,我删除了一些二次几何体,因为它们的视觉效果并不好。当然我们需要OpenGL为这些几何体自动生成坐标,接着选择球体映射纹理并绘制几何体。最后把

    OpenGL状态设置正常模式。 
      
    int DrawGLScene(GLvoid)
    {
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);   
     glLoadIdentity();       // 重置视口

     glTranslatef(0.0f,0.0f,z);

     glEnable(GL_TEXTURE_GEN_S);      // 自动生成s方向纹理坐标
     glEnable(GL_TEXTURE_GEN_T);      // 自动生成t方向纹理坐标

     glBindTexture(GL_TEXTURE_2D, texture[filter+(filter+1)]);  // 绑定纹理
     glPushMatrix();
     glRotatef(xrot,1.0f,0.0f,0.0f);
     glRotatef(yrot,0.0f,1.0f,0.0f);
     switch(object)
     {
     case 0:
      glDrawCube();
      break;
     case 1:
      glTranslatef(0.0f,0.0f,-1.5f);     // 创建圆柱
      gluCylinder(quadratic,1.0f,1.0f,3.0f,32,32);   
      break;
     case 2:
      gluSphere(quadratic,1.3f,32,32);     // 创建球
      break;
     case 3:
      glTranslatef(0.0f,0.0f,-1.5f);     // 创建圆锥
      gluCylinder(quadratic,1.0f,0.0f,3.0f,32,32);   
      break;
     };

     glPopMatrix();
     glDisable(GL_TEXTURE_GEN_S);      // 禁止自动生成纹理坐标
     glDisable(GL_TEXTURE_GEN_T);     

     xrot+=xspeed;
     yrot+=yspeed;
     return TRUE;        // 成功返回
    }

    最后我们使用空格来切换各个不同的几何体 
      
        if (keys[' '] && !sp)
        {
         sp=TRUE;
         object++;
         if(object>3)
          object=0;
        }
    原文及其个版本源代码下载:

    http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=23

     
     
  • 相关阅读:
    F. Journey
    D. Divide
    C. Counting Pair
    A. A Big Dinner
    E
    D -Sale
    第十三课 历史记录画笔工具
    第十二课 文字工具
    第十一课 模糊工具、海绵工具、仿制图章工具
    第十课 切片工具 修复画笔工具 修补工具 颜色替换工具
  • 原文地址:https://www.cnblogs.com/arxive/p/6239496.html
Copyright © 2020-2023  润新知