GLU库中提供了一些二次曲面的支持。这些二次方程能够渲染球体,圆柱体,圆盘。这些函数有很大的灵活性,咱们能够指定圆柱体的一端的半径,而后让另外一端的半径为0,这样的话就能构建一个圆锥。咱们还能够绘制一个有洞的圆盘。以下图: 函数
这些二次方程对象能够构建出更复杂的模型,例如咱们能够用球体,圆柱体,圆锥,圆盘来构建一个3D坐标系的模型。在glTools中有提供了这个函数: oop
void gltdDrawUnitAxes(); spa
在绘制二次方程对象以前,咱们能够为其制定法线向量,纹理坐标等。若是咱们每次在绘制这些二次方程对象时,把这些可选项都经过参数的方式传递,那工做量就变得很大。因此OpenGL用二次方程状态对象的方式来实现,这样咱们能够经过一些函数来设置这个二次方程状态对象,之后每次绘制二次方程对象的时候只要传递这个二次方程状态,OpenGL就知道是以什么样的方式绘制二次方程对象了。(利用面向对象的方式来达到复用的目的)。 .net
步骤是: 3d
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);
上面的函数式绘制球体的函数。第一个参数是指向二次方程状态的指针,第二个参数是球体的半径。第三个参数能够理解为地球的经线的条数。最后一个参数能够理解为纬线的条数。
... 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; }