OpenGL超級寶典筆記——曲線和曲面(一)

內部支持的表面

GLU庫中提供了一些二次曲面的支持。這些二次方程能夠渲染球體,圓柱體,圓盤。這些函數有很大的靈活性,咱們能夠指定圓柱體的一端的半徑,而後讓另外一端的半徑爲0,這樣的話就能構建一個圓錐。咱們還能夠繪製一個有洞的圓盤。以下圖: 函數

image

這些二次方程對象能夠構建出更復雜的模型,例如咱們能夠用球體,圓柱體,圓錐,圓盤來構建一個3D座標系的模型。在glTools中有提供了這個函數: oop

void gltdDrawUnitAxes(); spa

image

設置二次方程狀態

在繪製二次方程對象以前,咱們能夠爲其制定法線向量,紋理座標等。若是咱們每次在繪製這些二次方程對象時,把這些可選項都經過參數的方式傳遞,那工做量就變得很大。因此OpenGL用二次方程狀態對象的方式來實現,這樣咱們能夠經過一些函數來設置這個二次方程狀態對象,之後每次繪製二次方程對象的時候只要傳遞這個二次方程狀態,OpenGL就知道是以什麼樣的方式繪製二次方程對象了。(利用面向對象的方式來達到複用的目的)。 .net

步驟是: 3d

  1. 首先咱們建立一個二次方程狀態對象.
  2. 調用函數設置二次方程狀態
  3. 以二次方程狀態對象做爲參數,傳到繪製二次方程的函數
  4. 使用完以後銷燬。
GLUquadricObj *pObj; //建立二次方程狀態對象 pObj = gluNewQuadric(); //設置二次方程狀態 gluQuadricDrawStyle(pObj, GLU_LINE);
... //銷燬 gluDeleteQuadric(pObj);

GLU庫的gluNewQuadric()方法不單單爲GLUQuadricObj對象申請了內存空間,並且還初始化了一些默認值。GLU庫有四個函數能夠修改這個二次方程對象的狀態: 指針

void gluQuadricDrawStyle(GLUquadricObj *obj, GLenum drawStyle); code

第一個參數是二次方程對象狀態的指針,第二個參數的枚舉值以下表: orm

常量 描述
GLU_FILL 二次方程對象畫成實體
GLU_LINE 二次方程對象畫成線框
GLU_POINT 二次方程對象畫成一組頂點的集合
GLU_SILHOUETTE 相似於線框,但相鄰的多邊形的邊不被繪製。

void gluQuadricNormals(GLUquadricObj *pbj, GLenum normals); 對象

上面的這個函數指定二次方程對象如何生成法線。第二個參數能夠是:GLU_NONE不生成法線,GLU_FLAT扁平法線,GLU_SMOOTH平滑法線。 內存

若是指定的是平滑法線,那麼每一個頂點都指定了一條法線,垂直於被模擬的表面,這樣能夠產生一個平滑的表面。扁平法線是全部的法線都是面法線,垂直於三角形(多邊形)面。

goid gluQuadricOrientation(GLUQuadricObj *obj, GLenum orientation);

上面的這個函數能夠指定法線的朝向,指向外面仍是隻想裏面。orientation能夠是GLU_OUTSIDE或者是GLU_INSIDE這兩個值。OpenGL默認是以GL_CCW逆時針爲正方向的。

最後,咱們還能夠爲二次方程表面指定紋理座標,經過下面的函數調用來實現:

void gluQuadsricTexture(GLUquadricObj *obj, GLenum textureCoords);

textureCoords這個參數能夠是GL_TRUE或者GL_FALSE.當爲球體和圓柱體生成紋理座標時,紋理是對稱地環繞在球體和圓柱體的表面的。若是應用到圓盤上,那麼紋理的中心就是圓盤的中心,而後以線性插值的方式擴展到圓盤的邊界。

繪製二次方程圖形

void gluSphere(GLUQuadricObj *obj, GLdouble radius, GLint slices, GLint stacks);

上面的函數式繪製球體的函數。第一個參數是指向二次方程狀態的指針,第二個參數是球體的半徑。第三個參數能夠理解爲地球的經線的條數。最後一個參數能夠理解爲緯線的條數。

image

...
   gltDrawUnitAxes();
    GLUquadricObj *quadricObj = gluNewQuadric();
    gluQuadricDrawStyle(quadricObj, GLU_LINE);
    gluSphere(quadricObj, 0.8, 26, 13);
...

image

咱們能夠經過指定底部的半和頂部的半徑(方向是沿z軸正方向向外),還有高度(即圓柱體的長度)來繪製一個圓柱體。繪製圓柱體的函數以下:

void gluCylinder(GLUquadricObj *obj, GLdouble baseRadius, GLdouble topRadius, GLdouble height, GLint slices, GLint stacks);

gltDrawUnitAxes();
    GLUquadricObj *quadricObj = gluNewQuadric();
    gluQuadricDrawStyle(quadricObj, GLU_LINE);
    gluCylinder(quadricObj, 0.7, 0.7, 2, 26, 13);


image

把頂部半徑設置爲0.

gluCylinder(quadricObj, 0.7, 0.0, 2, 26, 13);

image

繪製圓盤的函數

void gluDisk(GLUquadricObj *obj, GLdouble innerRadius, GLdouble outerRadius, GLint slices, GLint loops);

指定內半徑爲0纔是實心的圓盤。

gluDisk(quadricObj, 0.0, 0.7, 26, 13);

image

gluDisk(quadricObj, 0.2, 0.7, 26, 13); 中間有洞的圓盤。

image

用二次方程進行建模

下面是一個雪人的例子。這個雪人由3個雪球堆成,由兩個小眼睛和一個鼻子。還帶了一頂帽子。步驟以下:

  1. 先從底部向上使用gluSphere函數繪製三個雪球(使用平移glTranslate)
  2. 用gluSphere再繪製兩個眼睛,用gluCylinder繪製一個圓錐形的鼻子
  3. 使用gluCylinder繪製圓柱體的帽子,再使用gluDisk畫帽子的邊。

代碼示例以下:

#include "gltools.h" #include "math3d.h" #include "glframe.h" #include <stdio.h>

GLFrame objFrame; void SetupRC()
{
  glClearColor(0.3f, 0.3f, 0.5f, 1.0f); //開啓深度檢測,消除隱藏面 glEnable(GL_DEPTH_TEST);
  glEnable(GL_CULL_FACE);
  glCullFace(GL_BACK);
  glFrontFace(GL_CCW); //開啓光照 GLfloat whiteLight[] = {0.05f, 0.05f, 0.05f, 1.0f};
  GLfloat sourceLight[] = {0.25f, 0.25f, 0.25f, 1.0f};
  GLfloat lightPos[] = {-5.0f, 15.0f, 5.0f, 1.0f};

  glEnable(GL_LIGHTING);
  glLightModelfv(GL_LIGHT_MODEL_AMBIENT, whiteLight);
  glLightfv(GL_LIGHT0, GL_AMBIENT_AND_DIFFUSE, sourceLight);
  glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
  glEnable(GL_LIGHT0); //開啓顏色追蹤 glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
  glEnable(GL_COLOR_MATERIAL);

} 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, 40.0);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
} void RenderScene()
{
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //設置二次方程的狀態 GLUquadricObj *quadricObj = gluNewQuadric();
  gluQuadricNormals(quadricObj, GLU_SMOOTH);

  glPushMatrix();
    glTranslatef(0.0f, -.6f, -8.0f);
    objFrame.ApplyCameraTransform();
    glPushMatrix(); //畫三個雪球 glColor3f(1.0f, 1.0f, 1.0f);
      gluSphere(quadricObj, .65f, 26, 13);

      glTranslatef(0.0f, 0.85f, 0.0f);
      gluSphere(quadricObj, 0.42f, 26, 13);

      glTranslatef(0.0f, 0.63f, 0.0f);
      gluSphere(quadricObj, 0.36f, 26, 13); //畫兩個眼睛 glTranslatef(-0.2f, 0.1f, 0.31f);
      glColor3f(0.0f, 0.0f, 0.0f);
      gluSphere(quadricObj, 0.05f, 26, 13);

      glTranslatef(0.4f, 0.0f, 0.0f);
      gluSphere(quadricObj, 0.05f, 26,13); //畫一個鼻子 glTranslatef(-0.2f, -0.08f, 0.03f);
      glColor3f(1.0f, 0.3f, 0.3f);
      gluCylinder(quadricObj, 0.04f, 0.0f, 0.6f, 26, 13);
    glPopMatrix(); //畫帽子 glPushMatrix();
      glColor3f(0.0f, 0.0f, 0.0f);
      glTranslatef(0.0f, 2.2f, 0.0f);
      glRotatef(90.0, 1.0f, 0.0f, 0.0f);
      gluCylinder(quadricObj, 0.2f, 0.2f, 0.4f, 26, 13);

      glDisable(GL_CULL_FACE);
      gluDisk(quadricObj, 0.17f, 0.2f, 26, 13);

      glTranslatef(0.0f, 0.0f, 0.40f);
      gluDisk(quadricObj, 0.0f, 0.4f, 26, 13);
      glEnable(GL_CULL_FACE);
    glPopMatrix();

  glPopMatrix();
  glutSwapBuffers();
} //經過按鍵來移動和旋轉 void SpecialKey(int value, int x, int y)
{ if (value == GLUT_KEY_RIGHT)
  {
    objFrame.RotateLocalY(0.5f);
  } if (value == GLUT_KEY_LEFT)
  {
    objFrame.RotateLocalY(-0.5f);
  } if (value == GLUT_KEY_UP)
  {
    objFrame.MoveUp(0.5f);
  } if (value == GLUT_KEY_DOWN)
  {
    objFrame.MoveUp(-0.5f);
  }

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

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

  glutSpecialFunc(SpecialKey);
  glutMainLoop(); return 0;
}

image

相關文章
相關標籤/搜索