OpenGL 二次曲面

原 文:Lesson 18: Quadrics
译 者:sakura

  二次曲面是一种画复合对象的方法,这种方法通常并不需要很多的三角形。我们将要使用第七课的代码。我们将要增加7个变量以及修改纹理以增加一些变化 :

  #include <windows.h>               // Header File For Windows
  #include <stdio.h>                // Header File For Standard Input/Output
  #include <gl/gl.h>                // Header File For The OpenGL32 Library
  #include <gl/glu.h>                // Header File For The GLu32 Library
  #include <gl/glaux.h>               // Header File For The GLaux Library

  HDC    hDC=NULL;               // Private GDI Device Context
  HGLRC   hRC=NULL;               // Permanent Rendering Context
  HWND    hWnd=NULL;               // Holds Our Window Handle
  HINSTANCE hInstance;               // Holds The Instance Of The Application

  bool  keys[256];                // Array Used For The Keyboard Routine
  bool  active=TRUE;               // Window Active Flag Set To TRUE By Default
  bool  fullscreen=TRUE;         // Fullscreen Flag Set To Fullscreen Mode By Default
  bool  light;                  // Lighting ON/OFF
  bool  lp;                    // L Pressed?
  bool  fp;                    // F Pressed?
  bool  sp;                    // Spacebar Pressed? ( NEW )

  int   part1;                  // Start Of Disc ( NEW )
  int   part2;                  // End Of Disc ( NEW )
  int   p1=0;                   // Increase 1 ( NEW )
  int   p2=1;                   // Increase 2 ( NEW )

  GLfloat xrot;                   // X Rotation
  GLfloat yrot;                   // Y Rotation
  GLfloat xspeed;                  // X Rotation Speed
  GLfloat yspeed;                  // Y Rotation Speed

  GLfloat z=-5.0f;                 // Depth Into The Screen

  GLUquadricObj *quadratic;             // Storage For Our Quadratic Objects ( NEW )

  GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f };  // Ambient Light Values
  GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f };  // Diffuse Light Values
  GLfloat LightPosition[]= { 0.0f, 0.0f, 2.0f, 1.0f };  // Light Position

  GLuint filter;                     // Which Filter To Use
  GLuint texture[3];                   // Storage for 3 textures
  GLuint object=0;                    // Which Object To Draw ( NEW )

  LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc

  好了我们现在开始搞InitGL()函数。我们打算增加3行代码用来初始化我们的二次曲面。这3行代码将在你使1号光源有效后增加,但是要在返回之前。第一行代码将初始化二次曲面并且创建一个指向改二次曲面的指针,如果改二次曲面不能被创建的话,那么该指针就是NULL。第二行代码将在二次曲面的表面创建平滑的法向量,这样当灯光照上去的时候将会好看些。另外一些可能的取值是:GLU_NONE和GLU_FLAT。最后我们使在二次曲面表面的纹理映射有效。

  quadratic=gluNewQuadric();          // Create A Pointer To The Quadric Object ( NEW )
  gluQuadricNormals(quadratic, GLU_SMOOTH);   // Create Smooth Normals ( NEW )
  gluQuadricTexture(quadratic, GL_TRUE);    // Create Texture Coords ( NEW )

  现在我决定在本课里保留立方体,这样你可以看到纹理是如何映射到二次曲面对象上的。而且我打算将绘制立方体的代码定义为一个单独的函数,这样我们在定义函数Draw()的时候它将会变的不那么凌乱。每个人都应该记住这些代码:

  GLvoid glDrawCube()                          // Draw A Cube
  {
    glBegin(GL_QUADS);                         // Start Drawing Quads
      // Front Face
      glNormal3f( 0.0f, 0.0f, 1.0f);                // Normal Facing Forward
      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
      glNormal3f( 0.0f, 0.0f,-1.0f);                // Normal Facing Away
      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
      glNormal3f( 0.0f, 1.0f, 0.0f);                // Normal Facing Up
      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
      glNormal3f( 0.0f,-1.0f, 0.0f);                // Normal Facing Down
      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
      glNormal3f( 1.0f, 0.0f, 0.0f);                // Normal Facing Right
      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
      glNormal3f(-1.0f, 0.0f, 0.0f);                // Normal Facing Left
      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();                             // Done Drawing Quads
  }

  接下来就是场景绘制函数了,在这里我只写一个简单的例子。并且当我绘制一个部分的盘子的时候,我将使用一个静态变量(一个局部的变量,该变量可以保留他的值不论你任何时候调用他)来表达一个非常酷的效果。为了清晰起见我将要重写DrawGLScene函数。
  你们将会注意到当我讨论这些正在使用的参数时我忽略了当前函数的第一个参数(quadratic)。这个参数将被除立方体外的所有对象使用。所以当我讨论这些参数的时候我忽略了它。

  int DrawGLScene(GLvoid)                  // Here's Where We Do All The Drawing
  {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  // Clear The Screen And The Depth Buffer
    glLoadIdentity();                   // Reset The View
    glTranslatef(0.0f,0.0f,z);               // Translate Into The Screen

    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

    glBindTexture(GL_TEXTURE_2D, texture[filter]);     // Select A Filtered Texture

    // This Section Of Code Is New ( NEW )
    switch(object)                     // Check object To Find Out What To Draw
    {
    case 0:                        // Drawing Object 1
      glDrawCube();                   // Draw Our Cube
      break;

  我们创建的第2个对象是一个圆柱体。参数1(1.0F)是圆柱体的底面半径,参数2(1.0F)是圆柱体的饿顶面半径,参数3(3.0F)是圆柱体的高度。参数4(32)是纬线(环绕Z轴有多少细分),参数5(32)是经线(沿着Z轴有多少细分)。细分越多该对象就越细致。我们可以用增加细分的方法来增加对象的多边形数。因此你可以牺牲速度换回质量(以时间换质量),大多数的时候我们都可以很容易的找到一个合适的“度”。

    case 1:                        // Drawing Object 2
      glTranslatef(0.0f,0.0f,-1.5f);           // Center The Cylinder
      gluCylinder(quadratic,1.0f,1.0f,3.0f,32,32);    // Draw Our Cylinder
      break;                       // Done

  对象3将会创建一个CD样子的盘子。参数1(0.5F)是盘子的内圆半径,该参数可以为0,则表示在盘子中间没孔,内圆半径越大孔越大。参数2(1.5F)表示外圆半径,这个参数必须比内圆半径大。参数3(32)是组成该盘子的切片的数量,这个数量可以想象成披萨饼中的切片的数量。切片越多,外圆边缘就越平滑。最后一个参数(32)是组成盘子的环的数量。环很像唱片上的轨迹,一环套一环。这些环从内圆半径细分到外圆半径。再说一次,细分越多,速度越慢。

    case 2:                        // Drawing Object 3
      gluDisk(quadratic,0.5f,1.5f,32,32);        // Draw A Disc (CD Shape)
      break;                       // Done

  我们的第4个对象我知道你们为描述它耗尽精力。就是球。绘制球将会变的非常简单。参数1是球的半径。如果你无法理解半径/直径等等的话,可以理解成物体中心到物体外部的距离,在这里我们使用1.3F作为半径。接下来两个参数就是细分了,和圆柱体一样,参数2是纬线,参数3是经线。细分越多球看起来就越平滑,通常球需要多一些的细分以使他们看起来平滑。

    case 3:                        // Drawing Object 4
      gluSphere(quadratic,1.3f,32,32);          // Draw A Sphere
      break;                       // Done

  我们创建的第4个对象使用与我们曾经创建的圆柱体一样的命令来创建,如果你还记得的话,我们可以通过控制参数2和参数3来控制顶面半径和地面半径。因此我们可以使顶面半径为0来绘制一个圆锥体,顶面半径为0将会在顶面上创建一个点。因此在下面的代码中,我们使顶面半径等于0,这将会创建一个点,同时也就创建了我们的圆锥。

    case 4:                        // Drawing Object 5
      glTranslatef(0.0f,0.0f,-1.5f);           // Center The Cone
      gluCylinder(quadratic,1.0f,0.0f,3.0f,32,32);    // A Cone With A Bottom Radius Of .5 And A Height Of 2
      break;                       // Done

  我们的第6个对象将被gluPartialDisk函数创建。我们打算创建的这个对象使用了一些命令,这些命令在我们创建对象之前,你将会清楚的看到。但是命令gluPartialDisk拥有两个新的参数。第5个参数是我们想要绘制的部分盘子的开始角度,参数6是旋转角,也就是转过的角度。我们将要增加旋转角,这将引起盘子沿顺时针方向缓慢的被绘制在屏幕上。一旦旋转角达到360度我们将开始增加开始角度,这样盘子看起来就想是被逐渐的抹去一样。我们将重复这些过程。

    case 5:                        // Drawing Object 6
      part1+=p1;                     // Increase Start Angle
      part2+=p2;                     // Increase Sweep Angle

      if(part1>359)                   // 360 Degrees
      {
        p1=0;                     // Stop Increasing Start Angle
        part1=0;                    // Set Start Angle To Zero
        p2=1;                     // Start Increasing Sweep Angle
        part2=0;                    // Start Sweep Angle At Zero
      }
      if(part2>359)                   // 360 Degrees
      {
        p1=1;                     // Start Increasing Start Angle
        p2=0;                     // Stop Increasing Sweep Angle
      }
      gluPartialDisk(quadratic,0.5f,1.5f,32,32,part1,part2-part1); // A Disk Like The One Before
      break;                       // Done
    };

    xrot+=xspeed;                     // Increase Rotation On X Axis
    yrot+=yspeed;                     // Increase Rotation On Y Axis
    return TRUE;                      // Keep Going
  }

  在最后,我给出键盘输入代码。仅仅增加一些对剩余键的检查。

  if (keys[' '] && !sp)                   // Is Spacebar Being Pressed?
  {
    sp=TRUE;                       // If So, Set sp To TRUE
    object++;                       // Cycle Through The Objects
    if(object>5)                     // Is object Greater Than 5?
      object=0;                     // If So, Set To Zero
  }
  if (!keys[' '])                      // Has The Spacebar Been Released?
  {
    sp=FALSE;                       // If So, Set sp To FALSE
  }

  这就是全部了。现在你可以在OpenGL中绘制二次曲面了。最后放上我的网站和Email(译者:还是访问我的网站或给我写信吧)。

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/lovetangtang/archive/2006/01/16/580606.aspx

你可能感兴趣的:(OpenGL 二次曲面)