內部支持的表面
GLU庫中提供了一些二次曲面的支持。這些二次方程可以渲染球體,圓柱體,圓盤。這些函數有很大的靈活性,我們可以指定圓柱體的一端的半徑,然後讓另一端的半徑為0,這樣的話就能構建一個圓錐。我們還可以繪制一個有洞的圓盤。如下圖:
這些二次方程對象可以構建出更復雜的模型,例如我們可以用球體,圓柱體,圓錐,圓盤來構建一個3D坐標系的模型。在glTools中有提供了這個函數:
void gltdDrawUnitAxes();
在繪制二次方程對象之前,我們可以為其制定法線向量,紋理坐標等。如果我們每次在繪制這些二次方程對象時,把這些可選項都通過參數的方式傳遞,那工作量就變得很大。所以OpenGL用二次方程狀態對象的方式來實現,這樣我們可以通過一些函數來設置這個二次方程狀態對象,以後每次繪制二次方程對象的時候只要傳遞這個二次方程狀態,OpenGL就知道是以什麼樣的方式繪制二次方程對象了。(利用面向對象的方式來達到復用的目的)。
步驟是:
GLUquadricObj *pObj; //創建二次方程狀態對象 pObj = gluNewQuadric(); //設置二次方程狀態 gluQuadricDrawStyle(pObj, GLU_LINE); ... //銷毀 gluDeleteQuadric(pObj);
GLU庫的gluNewQuadric()方法不僅僅為GLUQuadricObj對象申請了內存空間,而且還初始化了一些默認值。GLU庫有四個函數可以修改這個二次方程對象的狀態:
void gluQuadricDrawStyle(GLUquadricObj *obj, GLenum drawStyle);
第一個參數是二次方程對象狀態的指針,第二個參數的枚舉值如下表:
常量 描述 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);
上面的函數式繪制球體的函數。第一個參數是指向二次方程狀態的指針,第二個參數是球體的半徑。第三個參數可以理解為地球的經線的條數。最後一個參數可以理解為緯線的條數。
... gltDrawUnitAxes(); GLUquadricObj *quadricObj = gluNewQuadric(); gluQuadricDrawStyle(quadricObj, GLU_LINE); gluSphere(quadricObj, 0.8, 26, 13); ...
我們可以通過指定底部的半和頂部的半徑(方向是沿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);
把頂部半徑設置為0.
gluCylinder(quadricObj, 0.7, 0.0, 2, 26, 13);
繪制圓盤的函數
void gluDisk(GLUquadricObj *obj, GLdouble innerRadius, GLdouble outerRadius, GLint slices, GLint loops);
指定內半徑為0才是實心的圓盤。
gluDisk(quadricObj, 0.0, 0.7, 26, 13);
gluDisk(quadricObj, 0.2, 0.7, 26, 13); 中間有洞的圓盤。
下面是一個雪人的例子。這個雪人由3個雪球堆成,由兩個小眼睛和一個鼻子。還帶了一頂帽子。步驟如下:
代碼示例如下:
#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; }
OpenGL超級寶典 第4版 中文版PDF+英文版+源代碼 見 http://www.linuxidc.com/Linux/2013-10/91413.htm
OpenGL編程指南(原書第7版)中文掃描版PDF 下載 http://www.linuxidc.com/Linux/2012-08/67925.htm
OpenGL 渲染篇 http://www.linuxidc.com/Linux/2011-10/45756.htm
Ubuntu 13.04 安裝 OpenGL http://www.linuxidc.com/Linux/2013-05/84815.htm
OpenGL三維球體數據生成與繪制【附源碼】 http://www.linuxidc.com/Linux/2013-04/83235.htm
Ubuntu下OpenGL編程基礎解析 http://www.linuxidc.com/Linux/2013-03/81675.htm
如何在Ubuntu使用eclipse for c++配置OpenGL http://www.linuxidc.com/Linux/2012-11/74191.htm
更多《OpenGL超級寶典學習筆記》相關知識 見 http://www.linuxidc.com/search.aspx?where=nkey&keyword=34581