Welcome 微信登录
编程资源 图片资源库 蚂蚁家优选 PDF转换器

首页 / 操作系统 / Linux / OpenGL超级宝典学习笔记——曲线和曲面(一)

内部支持的表面 GLU库中提供了一些二次曲面的支持。这些二次方程可以渲染球体,圆柱体,圆盘。这些函数有很大的灵活性,我们可以指定圆柱体的一端的半径,然后让另一端的半径为0,这样的话就能构建一个圆锥。我们还可以绘制一个有洞的圆盘。如下图:

这些二次方程对象可以构建出更复杂的模型,例如我们可以用球体,圆柱体,圆锥,圆盘来构建一个3D坐标系的模型。在glTools中有提供了这个函数:void gltdDrawUnitAxes();

设置二次方程状态

在绘制二次方程对象之前,我们可以为其制定法线向量,纹理坐标等。如果我们每次在绘制这些二次方程对象时,把这些可选项都通过参数的方式传递,那工作量就变得很大。所以OpenGL用二次方程状态对象的方式来实现,这样我们可以通过一些函数来设置这个二次方程状态对象,以后每次绘制二次方程对象的时候只要传递这个二次方程状态,OpenGL就知道是以什么样的方式绘制二次方程对象了。(利用面向对象的方式来达到复用的目的)。步骤是:
  1. 首先我们创建一个二次方程状态对象.
  2. 调用函数设置二次方程状态
  3. 以二次方程状态对象作为参数,传到绘制二次方程的函数
  4. 使用完之后销毁。
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个雪球堆成,由两个小眼睛和一个鼻子。还带了一顶帽子。步骤如下:
  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;}OpenGL超级宝典 第4版 中文版PDF+英文版+源代码 见  http://www.linuxidc.com/Linux/2013-10/91413.htmOpenGL编程指南(原书第7版)中文扫描版PDF 下载 http://www.linuxidc.com/Linux/2012-08/67925.htmOpenGL 渲染篇 http://www.linuxidc.com/Linux/2011-10/45756.htmUbuntu 13.04 安装 OpenGL http://www.linuxidc.com/Linux/2013-05/84815.htmOpenGL三维球体数据生成与绘制【附源码】 http://www.linuxidc.com/Linux/2013-04/83235.htmUbuntu下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本文永久更新链接地址:http://www.linuxidc.com/Linux/2015-02/114024.htm