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管线 ...
随机推荐
- 共享内存+互斥量实现linux进程间通信 分类: Linux C/C++ 2015-03-26 17:14 67人阅读 评论(0) 收藏
一.共享内存简介 共享内存是进程间通信中高效方便的方式之一.共享内存允许两个或更多进程访问同一块内存,就如同 malloc() 函数向不同进程返回了指向同一个物理内存区域的指针,两个进程可以对一块共享 ...
- kuangbin_ShortPath A (POJ 2387)
最短路模板题 但是其实很费时间 因为要看明白dij floyd 以及 dij优化 spfa优化 交了三次 大概是理解了 不过涉及到priority_queue的重载运算符问题 以后要在C++里面好好看 ...
- Fragment用app包还是v4包解析
转自:http://blog.csdn.net/zc0908/article/details/50721553 1)问题简述 相信很多的朋友在调用Fragment都会遇到下面的情况: 这个时候问题来了 ...
- excel动态去重和动态排序
其实去重和排序的方法很多,没有哪一种更好,实时去重总会省一些时间,刚好也练习了下数组公式 动态去重: =IF(ROW()<=COUNTA(员工基础数据!H:H),INDEX(员工基础数据!H:H ...
- microsoft Ebook
http://social.technet.microsoft.com/wiki/contents/articles/11608.e-book-gallery-for-microsoft-techno ...
- C#中调用C++的dll的参数为指针类型的导出函数(包括二级指针的情况)
严格来说这篇文章算不上C++范围的,不过还是挂了点边,还是在自己的blog中记录一下吧. C++中使用指针是家常便饭了,也非常的好用,这也是我之所以喜欢C++的原因之一.但是在C#中就强调托管的概念了 ...
- C#学习之LinqtoSql类的简单例子
LinqtoSql类把访问.操作数据库的细节封装了起来,把连接操作数据库变得相当简单.下面是简单的例子. 第一步:添加LinqtoSql类 1.创建一个控制台应用程序项目,下载一个NrothWind ...
- Oracle数据库——基本操作
一.涉及内容 1.掌握Oracle 10g 相关服务的启动.停止. 2.熟练掌握数据库配置助手(DBA).企业管理器(OEM).SQL*Plus等工具的使用. 3.掌握使用STARTUP和SHUTDO ...
- wikioi1012 最大公约数和最小公倍数问题(2001年NOIP全国联赛普及组)
题目描述 Description 输入二个正整数x0,y0(2<=x0<100000,2<=y0<=1000000),求出满足下列条件的P,Q的个数 条件: 1.P,Q是正整 ...
- selenium+python自动化之元素定位
自动化按步骤拆分的话,可以分为四步操作:定位元素,操作元素,获取返回结果,断言(返回结果与期望结果是否一致),最后自动出测试报告.本篇接下来讲基本的八种元素定位方法.说的通俗一点,就是教大家找对象. ...