NeHe OpenGL教程 第十八课:二次几何体
前言
声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改。对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢。
NeHe OpenGL第十八课:二次几何体
二次几何体:
利用二次几何体,你可以很容易的创建球,圆盘,圆柱和圆锥。
二次曲面是一种画复合对象的方法,这种方法通常并不需要很多的三角形。我们将要使用第七课的代码。我们将要增加7个变量以及修改纹理以增加一些变化 :
bool sp; // 空格键是否按下
int part1; // 圆盘的起始角度
int part2; // 圆盘的结束角度
int p1=0; // 增量1
int p2=1; // 增量1
GLUquadricObj *quadratic; // 二次几何体
GLuint object=0; // 二次几何体标示符
好了我们现在开始搞InitGL()函数。我们打算增加3行代码用来初始化我们的二次曲面。这3行代码将在你使1号光源有效后增加,但是要在返回之前。第一行代码将初始化二次曲面并且创建一个指向改二次曲面的指针
,如果改二次曲面不能被创建的话,那么该指针就是NULL。第二行代码将在二次曲面的表面创建平滑的法向量,这样当灯光照上去的时候将会好看些。另外一些可能的取值是:GLU_NONE和GLU_FLAT。最后我们使在二
次曲面表面的纹理映射有效。
quadratic=gluNewQuadric(); // 创建二次几何体
gluQuadricNormals(quadratic, GLU_SMOOTH); // 使用平滑法线
gluQuadricTexture(quadratic, GL_TRUE); // 使用纹理
现在我决定在本课里保留立方体,这样你可以看到纹理是如何映射到二次曲面对象上的。而且我打算将绘制立方体的代码定义为一个单独的函数,这样我们在定义函数Draw()的时候它将会变的不那么凌乱。每个人都应
该记住这些代码:
GLvoid glDrawCube() // 绘制立方体
{
glBegin(GL_QUADS);
// 前面
glNormal3f( 0.0f, 0.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
// 后面
glNormal3f( 0.0f, 0.0f,-1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
// 上面
glNormal3f( 0.0f, 1.0f, 0.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
// 下面
glNormal3f( 0.0f,-1.0f, 0.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
// 右面
glNormal3f( 1.0f, 0.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
// 左面
glNormal3f(-1.0f, 0.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glEnd();
}
接下来就是场景绘制函数了,在这里我只写一个简单的例子。并且当我绘制一个部分的盘子的时候,我将使用一个静态变量(一个局部的变量,该变量可以保留他的值不论你任何时候调用他)来表达一个非常酷的效果。
为了清晰起见我将要重写DrawGLScene函数。
你们将会注意到当我讨论这些正在使用的参数时我忽略了当前函数的第一个参数(quadratic)。这个参数将被除立方体外的所有对象使用。所以当我讨论这些参数的时候我忽略了它。
int DrawGLScene(GLvoid)
{
//...
// 这部分是新增加的
switch(object) // 绘制哪一种二次几何体
{
case 0: // 绘制立方体
glDrawCube();
break;
我们创建的第2个对象是一个圆柱体。参数1(1.0F)是圆柱体的底面半径,参数2(1.0F)是圆柱体的饿顶面半径,参数3(3.0F)是圆柱体的高度。参数4(32)是纬线(环绕Z轴有多少细分),参数5(32)是经线
(沿着Z轴有多少细分)。细分越多该对象就越细致。我们可以用增加细分的方法来增加对象的多边形数。因此你可以牺牲速度换回质量(以时间换质量),大多数的时候我们都可以很容易的找到一个合适的“度”。
case 1: // 绘制圆柱体
glTranslatef(0.0f,0.0f,-1.5f);
gluCylinder(quadratic,1.0f,1.0f,3.0f,32,32);
break;
对象3将会创建一个CD样子的盘子。参数1(0.5F)是盘子的内圆半径,该参数可以为0,则表示在盘子中间没孔,内圆半径越大孔越大。参数2(1.5F)表示外圆半径,这个参数必须比内圆半径大。参数3(32)是组成
该盘子的切片的数量,这个数量可以想象成披萨饼中的切片的数量。切片越多,外圆边缘就越平滑。最后一个参数(32)是组成盘子的环的数量。环很像唱片上的轨迹,一环套一环。这些环从内圆半径细分到外圆半径。
再说一次,细分越多,速度越慢。
case 2: // 绘制圆盘
gluDisk(quadratic,0.5f,1.5f,32,32);
break;
我们的第4个对象我知道你们为描述它耗尽精力。就是球。绘制球将会变的非常简单。参数1是球的半径。如果你无法理解半径/直径等等的话,可以理解成物体中心到物体外部的距离,在这里我们使用1.3F作为半径。接
下来两个参数就是细分了,和圆柱体一样,参数2是纬线,参数3是经线。细分越多球看起来就越平滑,通常球需要多一些的细分以使他们看起来平滑。
case 3: // 绘制球
gluSphere(quadratic,1.3f,32,32);
break;
我们创建的第4个对象使用与我们曾经创建的圆柱体一样的命令来创建,如果你还记得的话,我们可以通过控制参数2和参数3来控制顶面半径和地面半径。因此我们可以使顶面半径为0来绘制一个圆锥体,顶面半径为0将
会在顶面上创建一个点。因此在下面的代码中,我们使顶面半径等于0,这将会创建一个点,同时也就创建了我们的圆锥。
case 4: // 绘制圆锥
glTranslatef(0.0f,0.0f,-1.5f);
gluCylinder(quadratic,1.0f,0.0f,3.0f,32,32);
break;
我们的第6个对象将被gluPartialDisk函数创建。我们打算创建的这个对象使用了一些命令,这些命令在我们创建对象之前,你将会清楚的看到。但是命令gluPartialDisk拥有两个新的参数。第5个参数是我们想要
绘制的部分盘子的开始角度,参数6是旋转角,也就是转过的角度。我们将要增加旋转角,这将引起盘子沿顺时针方向缓慢的被绘制在屏幕上。一旦旋转角达到360度我们将开始增加开始角度,这样盘子看起来就想是被逐
渐的抹去一样。我们将重复这些过程。
case 5: // 绘制部分圆盘
part1+=p1;
part2+=p2;
if(part1>359)
{
p1=0;
part1=0;
p2=1;
part2=0;
}
if(part2>359)
{
p1=1;
p2=0;
}
gluPartialDisk(quadratic,0.5f,1.5f,32,32,part1,part2-part1);
break;
};
//...
}
In the KillGLWindow()
section of code, we need to delete the quadratic to free up system
resources. We do this with the command gluDeleteQuadratic.
GLvoid KillGLWindow(GLvoid)
{
gluDeleteQuadric(quadratic); // 删除二次几何体
在最后,我给出键盘输入代码。仅仅增加一些对剩余键的检查。
if (keys[' '] && !sp) // 空格是否按下
{
sp=TRUE; // 是,则绘制下一种二次几何体
object++;
if(object>5)
object=0;
}
if (!keys[' ']) // 空格是否释放
{
sp=FALSE; // 记录这个状态
}
原文及其个版本源代码下载:
NeHe OpenGL教程 第十八课:二次几何体的更多相关文章
- NeHe OpenGL教程 第二十八课:贝塞尔曲面
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第二十六课:反射
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第十九课:粒子系统
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第十五课:纹理图形字
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第二十九课:Blt函数
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第二十五课:变形
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第二十四课:扩展
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第十六课:雾
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第十四课:图形字体
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
随机推荐
- spark新能优化之多次使用RDD的持久化或checkPoint
如果程序中,对某一个RDD,基于它进行了多次transformation或者action操作.那么就非常有必要对其进行持久化操作,以避免对一个RDD反复进行计算. 此外,如果要保证在RDD的持久化数据 ...
- kuangbin_ShortPath N (POJ 1847)
模板题辣很简单的 只有两种val 0 和1 #include <iostream> #include <string> #include <cstdio> #inc ...
- python3安装Fabric模块
streamparse 项目的issuehttps://github.com/Parsely/streamparse/issues/172 fabric的一个支持Python3.4的forkhttps ...
- audition输出参数设置
- struts2获得request和session对象
在struts1中,获得到系统的request或者session对象非常方便,都是按照形参传递的,但是在struts2中,request和session都被隐藏了 struts2提供两种方式访问ses ...
- CSS和JS实现单行、多行文本溢出显示省略号(该js方法有问题不对)
如果实现单行文本的溢出显示省略号同学们应该都知道用text-overflow:ellipsis属性来,当然还需要加宽度width属来兼容部分浏览. 实现方法: overflow: hidden; te ...
- 大白话系列之C#委托与事件讲解(二)
什么是事件?EVENT?点击事件?加载事件?一连串的模糊的概念冲击着我们弱小的脑袋 那我们首先来看一下比较正统的感念吧: 事件是类在发生其关注的事情时用来提供通知的一种方式. 事件的发生一般都牵扯2个 ...
- PostgreSQL Hardware Performance Tuning
Bruce Momjian POSTGRESQL is an object-relational database developed on the Internet by a group of de ...
- linq字符串搜索条件,排序条件-linq动态查询语句 Dynamic LINQ
在做搜索和排序的时候,往往是前台传过来的字符串做条件,参数的数量还不定,这就需要用拼sql语句一样拼linq语句.而linq语句又是强类型的,不能用字符串拼出来. 现在好了,有个开源的linq扩展方法 ...
- 01-Java基础知识:数据类型与变量、标识符、运算符、表达式
Java基础知识:数据类型与变量.标识符.运算符.表达式 一.数据类型 Java定义了基本数据类型.引用数据类型.自定义类型. 八种基本数据类型:byte (1). short (2). int ( ...