OpenGL 超级宝典笔记 —— 纹理高级(二)

立方体贴图

还有两种纹理生成模式未介绍,GL_REFLECTION_MAP 和 GL_NORMAL_MAP, 这两种模式需要用到新的纹理目标:立方体贴图。一个立方体贴图被当做一个纹理来看待,它由六个正方形的 2D 图像(必须是正方形)来组成立方体的六个面。下图展示了 cubemap 示例的立方体的六个面:

这六个面分别是 - X,+X,-Y,+Y,-Z,+Z. 然后我们使用 GL_REFLECTION_MAP 的模式来生成纹理,能够制造一个真实的表面的倒影。

加载立方体贴图

立方体贴图有六个新的值作为参数传给 glTexImage2D:

GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,

GL_TEXTURE_CUBE_MAP_POSITIVE_Y,GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,

GL_TEXTURE_CUBE_MAP_POSITIVE_Z,GL_TEXTURE_CUBE_MAP_NEGATIVE_Z.

例如我们要加载正 X 方向的贴图,如下所示:

glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA, iWidth, iHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, pImage);

在 cubemap 示例中,我们把立方体的六个图像的路径保存到一个数组中,然后循环加载这六个面的纹理贴图:

//
纹理文件目录
static const char * szCubeFile[] = { " ..\\pos_x.tga " , " ..\\neg_x.tga " , " ..\\pos_y.tga " , " ..\\neg_y.tga " , " ..\\pos_z.tga " , " ..\\neg_z.tga " }; 
//
立方体纹理
static
GLenum cube[] =
{GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z}; 
.....
.....

GLint iWidth, iHeight, iComponents; GLenum eFormat; 
//
设置纹理环境
glTexEnvi(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_ENV, GL_REPLACE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); 
for ( int i = 0 ; i < 6 ; ++ i)
{
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 

  void* pImage = gltLoadTGA(szCubeFile[i], & iWidth, & iHeight, & iComponents, & eFormat);

if(pImage)
{
	glTexImage2D(cube[i],  0 , iComponents, iWidth, iHeight,   0 , eFormat, GL_UNSIGNED_BYTE, pImage);
	free(pImage);
}
}

然后我们需要启用立方体贴图:glEnable (GL_TEXTURE_CUBE_MAP); 如果 GL_TEXTURE_CUBE_MAP 和 GL_TEXTURE_2D 同时开启的话,GL_TEXTURE_CUBE_MAP 优先起作用。PS:glTexParameter 同时对这立方体的六张图像起作用,这六张图像在一个立方体纹理中。

立方体贴图的纹理坐标与一般的 3D 纹理坐标不同,S,T 和 R 纹理坐标代表着一个从立方体贴图中心出发的有符号向量,这个向量会与立方体的六个面中的一个相交,然后对相交的纹理单元进行采样。

使用立方体贴图

立方体贴图常用于创建一个对周围景象进行反射的物体。下面的代码创建一个天空盒,一个有效的天空盒包含了六个面,从盒子的中心出发朝六个方向看去可以看到六张图像。天空盒是有六个正方形构成的,每个面使用 glTexCoord3f 来手工设置纹理坐标。

  glPushMatrix();
    //手动指定纹理坐标
    glBegin(GL_QUADS);
      //-x
      glTexCoord3f(-1.0f, 1.0f, -1.0f);
      glVertex3f(-fExtent, fExtent, -fExtent);
      glTexCoord3f(-1.0f, 1.0f, 1.0f);
      glVertex3f(-fExtent, fExtent, fExtent);
      glTexCoord3f(-1.0f, -1.0f, 1.0f);
      glVertex3f(-fExtent, -fExtent, fExtent);
      glTexCoord3f(-1.0f, -1.0f, -1.0f);
      glVertex3f(-fExtent, -fExtent, -fExtent);

      //+x
      glTexCoord3f(1.0f, -1.0f, -1.0f);
      glVertex3f(fExtent, -fExtent, -fExtent);
      glTexCoord3f(1.0f, -1.0f, 1.0f);
      glVertex3f(fExtent, -fExtent, fExtent);
      glTexCoord3f(1.0f, 1.0f, 1.0f);
      glVertex3f(fExtent, fExtent, fExtent);
      glTexCoord3f(1.0f, 1.0f, -1.0f);
      glVertex3f(fExtent, fExtent, -fExtent);

      //+y
      glTexCoord3f(-1.0f, 1.0f, -1.0f);
      glVertex3f(-fExtent, fExtent, -fExtent);
      glTexCoord3f(-1.0f, 1.0f, 1.0f);
      glVertex3f(-fExtent, fExtent, fExtent);
      glTexCoord3f(1.0f, 1.0f, 1.0f);
      glVertex3f(fExtent, fExtent, fExtent);
      glTexCoord3f(1.0f, 1.0f, -1.0f);
      glVertex3f(fExtent, fExtent, -fExtent);

      //-y
      glTexCoord3f(1.0f, -1.0f, -1.0f);
      glVertex3f(fExtent, -fExtent, -fExtent);
      glTexCoord3f(1.0f, -1.0f, 1.0f);
      glVertex3f(fExtent, -fExtent, fExtent);
      glTexCoord3f(-1.0f, -1.0f, 1.0f);
      glVertex3f(-fExtent, -fExtent, fExtent);
      glTexCoord3f(-1.0f, -1.0f, -1.0f);
      glVertex3f(-fExtent, -fExtent, -fExtent);


      //-z
      glTexCoord3f(-1.0f, -1.0f, -1.0f);
      glVertex3f(-fExtent, -fExtent, -fExtent);
      glTexCoord3f(1.0f, -1.0f, -1.0f);
      glVertex3f(fExtent, -fExtent, -fExtent);
      glTexCoord3f(1.0f, 1.0f, -1.0f);
      glVertex3f(fExtent, fExtent, -fExtent);
      glTexCoord3f(-1.0f, 1.0f, -1.0f);
      glVertex3f(-fExtent, fExtent, -fExtent);

      //+z
      glTexCoord3f(-1.0f, 1.0f, 1.0f);
      glVertex3f(-fExtent, fExtent, fExtent);
      glTexCoord3f(1.0f, 1.0f, 1.0f);
      glVertex3f(fExtent, fExtent, fExtent);
      glTexCoord3f(1.0f, -1.0f, 1.0f);
      glVertex3f(fExtent, -fExtent, fExtent);
      glTexCoord3f(-1.0f, -1.0f, 1.0f);
      glVertex3f(-fExtent, -fExtent, fExtent);
    glEnd();
  glPopMatrix();

 为了手工设置纹理坐标,在画天空盒之前我们需要关闭纹理坐标自动生成的功能。

glDisable(GL_TEXTURE_GEN_S);

glDisable(GL_TEXTURE_GEN_T);

glDisable(GL_TEXTURE_GEN_R);

DrawSkyBox();

然后画一个反射周围环境的球体,开启纹理坐标自动生成:

glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);

glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);

glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);

glEnable(GL_TEXTURE_GEN_S);

glEnable(GL_TEXTURE_GEN_T);

glEnable(GL_TEXTURE_GEN_R);

为了制造更加真实的反射效果,我们需要考虑照相机的方向。我们可以从照相机类中获得照相机的旋转矩阵,并进行反转,然后在应用立方体纹理贴图之前,先把它乘以纹理矩阵。没有旋转纹理坐标,立方体贴图将无法正确地反射周围的环境(反射的是固定的图像不随着照相机的旋转而变化)。因为 gltDrawSphere 函数并不影响模型视图矩阵,所以我们可以使矩阵模式为 GL_TEXTURE(纹理模式)直到我们画完球体后再恢复到原始状态。代码如下:

//绘制球体
  glPushMatrix();
    //切换到纹理矩阵
    glMatrixMode(GL_TEXTURE);
    glPushMatrix();
      M3DMatrix44f m,invert;
      //获取照相机的位置,并进行反转,形成正确的反射纹理
      camra.GetCameraOrientation(m);
      m3dInvertMatrix44(invert,m);
      glMultMatrixf(invert);

      gltDrawSphere(0.75f, 41, 41);
    glPopMatrix();
  glMatrixMode(GL_MODELVIEW);
  glPopMatrix();

  glPopMatrix();
  glutSwapBuffers();

效果如下(移动照相机,并旋转可以看到不同的反射面)(code):

 

多重纹理

现代的 OpenGL 硬件实现都支持把多个纹理应用到几何图形上。我们可以通过 GL_MAX_TEXTURE_UNITS 检查有多少个纹理单元是可用的:

GLint iUnits;

glGetIntergv(GL_MAX_TETURE_UNITS, &iUnits);

可用的纹理为从基础的纹理单元 (GL_TEXTURE0) 到最大的纹理单元 (GL_TEXTUREn)(这里的 n 代表纹理单元的下标)。每个纹理单元有自己的纹理环境状态(即每个纹理单元都可通过 glTexEnv 设置自己的纹理环境),纹理坐标生成状态 (glTexGen), 纹理矩阵状态,纹理的启用状态和纹理过滤器等。

纹理结合的过程大致如下:

首先从图形中得到了片段的颜色值作为输入,然后和被应用到图元上的第一个纹理上对应的颜色值进行结合作为输出。把之前的输出作为输入,再与第二个纹理的颜色进行结合,如此循环到最后一个被启用的纹理单元为止。

默认情况下,第一个纹理单元是激活的纹理单元。除了 glTexCoord 之外的所有纹理命令,都只影响当前激活的纹理单元。我们可以通过调用 glActiveTexture 参数为 GL_TEXTUREn 来激活相应的纹理单元(纹理的下标是从 0 开始)。例如:我们激活第二个纹理,并启用 2D 纹理:

glActiveTexture(GL_TEXTURE1);

glEnable(GL_TEXTURE_2D);

相反地禁用则如下:

glDisable(GL_TEXTURE_2D);

glActiveTexutre(GL_TEXTURE0);

所有的纹理函数调用 glTexParameter, glTexEnv,glTexGen,glTexImage 和 glBindTexture 都只对当前激活的纹理单元有效。当图形被渲染时,被启用的纹理单元将被应用。

多重纹理坐标

当我们使用 glTexCoord 指定纹理坐标的时候,这个纹理坐标是针对 GL_TEXTURE0 设置的。如果我们想为其他的纹理单元设置纹理坐标可以通过 glMultiTexCoord 来设置:

glMultiTexCoord1f(GLenum texUnit, GLfloat s);

glMultiTexCoord2f(Glenum texUnit, GLfloat s, GLfloat t);

glMultiTexCoord3f(GLenum texUnit, GLfloat s, GLfloat t, GLfloat r);

其中 texUnit 为 GL_TEXTUREn. 也有相应的不同类型的版本。当然我们也可以用自动生成纹理坐标的方式。

多重纹理的例子

在之前的 CUBEMAP 例子的基础上做一些更改,我们把 cubemap 的纹理作为第二个纹理即 GL_TEXTURE1。第一个纹理是有污点的纹理。然后,让立方体贴图纹理和这个污点纹理相乘,就能得到如下的效果:

完整代码示例如下:

#include "gltools.h"#include "math3d.h"#include "glframe.h"#define COLORMAP 0#define CUBEMAP 1#define TEXTURENUM 2//纹理对象GLuint textureObj[TEXTURENUM] = {0,0};//纹理路径数组static const char *szCubeFile[] = {"..\\pos_x.tga", "..\\neg_x.tga","..\\pos_y.tga", "..\\neg_y.tga","..\\pos_z.tga", "..\\neg_z.tga"};//立方体贴图static GLenum cube[] = {GL_TEXTURE_CUBE_MAP_POSITIVE_X,
GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z};static GLfloat fExtent = 10.0f;static GLFrame camra;void DrawSkyBox()
{
  glPushMatrix();
  glBegin(GL_QUADS);  //-x
  glMultiTexCoord3f(GL_TEXTURE1, -1.0f, 1.0f, -1.0f);
  glVertex3f(-fExtent, fExtent, -fExtent);
  glMultiTexCoord3f(GL_TEXTURE1, -1.0f, 1.0f, 1.0f);
  glVertex3f(-fExtent, fExtent, fExtent);
  glMultiTexCoord3f(GL_TEXTURE1, -1.0f, -1.0f, 1.0f);
  glVertex3f(-fExtent, -fExtent, fExtent);
  glMultiTexCoord3f(GL_TEXTURE1, -1.0f, -1.0f, -1.0f);
  glVertex3f(-fExtent, -fExtent, -fExtent);  //+x
  glMultiTexCoord3f(GL_TEXTURE1, 1.0f, -1.0f, -1.0f);
  glVertex3f(fExtent, -fExtent, -fExtent);
  glMultiTexCoord3f(GL_TEXTURE1, 1.0f, -1.0f, 1.0f);
  glVertex3f(fExtent, -fExtent, fExtent);
  glMultiTexCoord3f(GL_TEXTURE1, 1.0f, 1.0f, 1.0f);
  glVertex3f(fExtent, fExtent, fExtent);
  glMultiTexCoord3f(GL_TEXTURE1, 1.0f, 1.0f, -1.0f);
  glVertex3f(fExtent, fExtent, -fExtent);  //+y
  glMultiTexCoord3f(GL_TEXTURE1, -1.0f, 1.0f, -1.0f);
  glVertex3f(-fExtent, fExtent, -fExtent);
  glMultiTexCoord3f(GL_TEXTURE1, -1.0f, 1.0f, 1.0f);
  glVertex3f(-fExtent, fExtent, fExtent);
  glMultiTexCoord3f(GL_TEXTURE1, 1.0f, 1.0f, 1.0f);
  glVertex3f(fExtent, fExtent, fExtent);
  glMultiTexCoord3f(GL_TEXTURE1, 1.0f, 1.0f, -1.0f);
  glVertex3f(fExtent, fExtent, -fExtent);  //-y
  glMultiTexCoord3f(GL_TEXTURE1, 1.0f, -1.0f, -1.0f);
  glVertex3f(fExtent, -fExtent, -fExtent);
  glMultiTexCoord3f(GL_TEXTURE1, 1.0f, -1.0f, 1.0f);
  glVertex3f(fExtent, -fExtent, fExtent);
  glMultiTexCoord3f(GL_TEXTURE1, -1.0f, -1.0f, 1.0f);
  glVertex3f(-fExtent, -fExtent, fExtent);
  glMultiTexCoord3f(GL_TEXTURE1, -1.0f, -1.0f, -1.0f);
  glVertex3f(-fExtent, -fExtent, -fExtent);  //-z
  glMultiTexCoord3f(GL_TEXTURE1, -1.0f, -1.0f, -1.0f);
  glVertex3f(-fExtent, -fExtent, -fExtent);
  glMultiTexCoord3f(GL_TEXTURE1, 1.0f, -1.0f, -1.0f);
  glVertex3f(fExtent, -fExtent, -fExtent);
  glMultiTexCoord3f(GL_TEXTURE1, 1.0f, 1.0f, -1.0f);
  glVertex3f(fExtent, fExtent, -fExtent);
  glMultiTexCoord3f(GL_TEXTURE1, -1.0f, 1.0f, -1.0f);
  glVertex3f(-fExtent, fExtent, -fExtent);  //+z
  glMultiTexCoord3f(GL_TEXTURE1, -1.0f, 1.0f, 1.0f);
  glVertex3f(-fExtent, fExtent, fExtent);
  glMultiTexCoord3f(GL_TEXTURE1, 1.0f, 1.0f, 1.0f);
  glVertex3f(fExtent, fExtent, fExtent);
  glMultiTexCoord3f(GL_TEXTURE1, 1.0f, -1.0f, 1.0f);
  glVertex3f(fExtent, -fExtent, fExtent);
  glMultiTexCoord3f(GL_TEXTURE1, -1.0f, -1.0f, 1.0f);
  glVertex3f(-fExtent, -fExtent, fExtent);
  glEnd();
  glPopMatrix();
}void SetupRC()
{
  glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

  glEnable(GL_DEPTH_TEST);
  glCullFace(GL_BACK);
  glFrontFace(GL_CCW);
  glEnable(GL_CULL_FACE);

  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  GLint iWidth, iHeight, iComponents;
  GLenum eFormat;

  glGenTextures(TEXTURENUM, textureObj);  //设置立方体纹理对象状态
  glBindTexture(GL_TEXTURE_CUBE_MAP, textureObj[CUBEMAP]);
  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);  for (int i = 0; i < 6; ++i)
  {
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_GENERATE_MIPMAP, GL_TRUE);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);void *pImage = gltLoadTGA(szCubeFile[i], &iWidth, &iHeight, &iComponents, &eFormat);if (pImage)
    {
      glTexImage2D(cube[i], 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pImage);
      free(pImage);
    }
  }  //设置污点纹理对象状态
  glBindTexture(GL_TEXTURE_2D, textureObj[COLORMAP]);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);  void *pImage = gltLoadTGA("..\\tarnish.tga", &iWidth, &iHeight, &iComponents, &eFormat);  if (pImage)
  {
    glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pImage);
    free(pImage);
  }  //激活纹理单元0,并启用2D纹理,设置它的纹理和纹理环境,
  glActiveTexture(GL_TEXTURE0);
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, textureObj[COLORMAP]);
  glTexEnvi(GL_TEXTURE_2D, GL_TEXTURE_ENV, GL_DECAL);  //激活纹理单元1,启用CUBEMAP,并设置它的纹理和纹理环境,纹理生成模式
  glActiveTexture(GL_TEXTURE1);
  glEnable(GL_TEXTURE_CUBE_MAP);
  glBindTexture(GL_TEXTURE_CUBE_MAP, textureObj[CUBEMAP]);
  glTexEnvi(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_ENV, GL_MODULATE);  //设置自动生成纹理坐标的方式为投影
  glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
  glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
  glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);

  camra.MoveForward(-5.0f);

}void RenderScene()
{
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glPushMatrix();
  camra.ApplyCameraTransform();  //先关闭纹理单元0的2D纹理
  glActiveTexture(GL_TEXTURE0);
  glDisable(GL_TEXTURE_2D);  //选择纹理单元1并启用立方体贴图
  glActiveTexture(GL_TEXTURE1);
  glEnable(GL_TEXTURE_CUBE_MAP);  //天空的纹理坐标手工设置
  glDisable(GL_TEXTURE_GEN_S);
  glDisable(GL_TEXTURE_GEN_T);
  glDisable(GL_TEXTURE_GEN_R);
  glTexEnvi(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_ENV, GL_DECAL);

  DrawSkyBox();  //开启纹理坐标自动生成
  glEnable(GL_TEXTURE_GEN_S);
  glEnable(GL_TEXTURE_GEN_T);
  glEnable(GL_TEXTURE_GEN_R);
  glTexEnvi(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_ENV, GL_MODULATE);  //绘制球体,激活纹理0和纹理1进行结合
  glActiveTexture(GL_TEXTURE0);
  glEnable(GL_TEXTURE_2D);
  glPushMatrix();  //注意每个纹理单元都有自己的纹理矩阵,这里我们操作纹理1,立方体贴图
  glActiveTexture(GL_TEXTURE1);
  glMatrixMode(GL_TEXTURE);
  glPushMatrix();
  M3DMatrix44f m,invert;  //获取照相机的位置,并进行反转,形成反射的纹理
  camra.GetCameraOrientation(m);
  m3dInvertMatrix44(invert,m);
  glMultMatrixf(invert);

  gltDrawSphere(0.75f, 41, 41);
  glPopMatrix();
  glMatrixMode(GL_MODELVIEW);
  glPopMatrix();

  glPopMatrix();
  glutSwapBuffers();

}void ShutdownRC()
{
  glDeleteTextures(TEXTURENUM, textureObj);
}void ChangeSize(GLsizei w, GLsizei h)
{  if (h == 0)
    h = 1;

  glViewport(0, 0, w, h);

  GLfloat aspect = (GLfloat)w/(GLfloat)h;

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  gluPerspective(35.0, aspect, 1.0, 100.0);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

  glutPostRedisplay();
}void SpecialKey(int value, int x, int y)
{  if (value == GLUT_KEY_LEFT)
  {
    camra.RotateLocalY(-0.1f);
  }  if (value == GLUT_KEY_RIGHT)
  {
    camra.RotateLocalY(0.1f);
  }  if (value == GLUT_KEY_UP)
  {
    camra.MoveForward(0.1f);
  }  if (value == GLUT_KEY_DOWN)
  {
    camra.MoveForward(-0.1f);
  }

  glutPostRedisplay();
}int main(int args, char *argv[])
{
  glutInit(&args, argv);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
  glutInitWindowSize(800, 600);
  glutCreateWindow("mutiltex");

  glutDisplayFunc(RenderScene);
  glutReshapeFunc(ChangeSize);
  SetupRC();

  glutSpecialFunc(SpecialKey);
  glutMainLoop();
  ShutdownRC();  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值