本次课程所要讲的是绘制简单的几何图形,在实际绘制之前,让我们先熟悉一些概念。

一、点、直线和多边形
我们知道数学(具体的说,是几何学)中有点、直线和多边形的概念,但这些概念在计算机中会有所不同。
数学上的点,只有位置,没有大小。但在计算机中,无论计算精度如何提高,始终不能表示一个无穷小的点。另一方面,无论图形输出设备(例如,显示器)如何精确,始终不能输出一个无穷小的点。一般情况下,OpenGL中的点将被画成单个的像素(像素的概念,请自己搜索之~),虽然它可能足够小,但并不会是无穷小。同一像素上,OpenGL可以绘制许多坐标只有稍微不同的点,但该像素的具体颜色将取决于OpenGL的实现。当然,过度的注意细节就是钻牛角尖,我们大可不必花费过多的精力去研究“多个点如何画到同一像素上”。
同样的,数学上的直线没有宽度,但OpenGL的直线则是有宽度的。同时,OpenGL的直线必须是有限长度,而不是像数学概念那样是无限的。可以认为,OpenGL的“直线”概念与数学上的“线段”接近,它可以由两个端点来确定。
多边形是由多条线段首尾相连而形成的闭合区域。OpenGL规定,一个多边形必须是一个“凸多边形”(其定义为:多边形内任意两点所确定的线段都在多边形内,由此也可以推导出,凸多边形不能是空心的)。多边形可以由其边的端点(这里可称为顶点)来确定。(注意:如果使用的多边形不是凸多边形,则最后输出的效果是未定义的——OpenGL为了效率,放宽了检查,这可能导致显示错误。要避免这个错误,尽量使用三角形,因为三角形都是凸多边形)

可以想象,通过点、直线和多边形,就可以组合成各种几何图形。甚至于,你可以把一段弧看成是很多短的直线段相连,这些直线段足够短,以至于其长度小于一个像素的宽度。这样一来弧和圆也可以表示出来了。通过位于不同平面的相连的小多边形,我们还可以组成一个“曲面”。

二、在OpenGL中指定顶点
由以上的讨论可以知道,“点”是一切的基础。
如何指定一个点呢?OpenGL提供了一系列函数。它们都以glVertex开头,后面跟一个数字和1~2个字母。例如:
glVertex2d
glVertex2f
glVertex3f
glVertex3fv
等等。
数字表示参数的个数,2表示有两个参数,3表示三个,4表示四个(我知道有点罗嗦~)。
字母表示参数的类型,s表示16位整数(OpenGL中将这个类型定义为GLshort),
                   i表示32位整数(OpenGL中将这个类型定义为GLint和GLsizei),
                   f表示32位浮点数(OpenGL中将这个类型定义为GLfloat和GLclampf),
                   d表示64位浮点数(OpenGL中将这个类型定义为GLdouble和GLclampd)。
                   v表示传递的几个参数将使用指针的方式,见下面的例子。
这些函数除了参数的类型和个数不同以外,功能是相同的。例如,以下五个代码段的功能是等效的:
(一)glVertex2i(1, 3);
(二)glVertex2f(1.0f, 3.0f);
(三)glVertex3f(1.0f, 3.0f, 0.0f);
(四)glVertex4f(1.0f, 3.0f, 0.0f, 1.0f);
(五)GLfloat VertexArr3[] = {1.0f, 3.0f, 0.0f};
      glVertex3fv(VertexArr3);
以后我们将用glVertex*来表示这一系列函数。
注意:OpenGL的很多函数都是采用这样的形式,一个相同的前缀再加上参数说明标记,这一点会随着学习的深入而有更多的体会。

三、开始绘制
假设现在我已经指定了若干顶点,那么OpenGL是如何知道我想拿这些顶点来干什么呢?是一个一个的画出来,还是连成线?或者构成一个多边形?或者做其它什么事情?
为了解决这一问题,OpenGL要求:指定顶点的命令必须包含在glBegin函数之后,glEnd函数之前(否则指定的顶点将被忽略)。并由glBegin来指明如何使用这些点。
例如我写:

glBegin(GL_POINTS);
glVertex2f(0.0f, 0.0f);
glVertex2f(0.5f, 0.0f);
glEnd();

则这两个点将分别被画出来。如果将GL_POINTS替换成GL_LINES,则两个点将被认为是直线的两个端点,OpenGL将会画出一条直线。
我们还可以指定更多的顶点,然后画出更复杂的图形。
另一方面,glBegin支持的方式除了点GL_POINTS和线GL_LINES,还有平面带GL_LINE_STRIP,GL_LINE_LOOP,三角形GL_TRIANGLES,GL_TRIANGLE_STRIP,平面扇GL_TRIANGLE_FAN等,每种方式的大致效果见下图:

glBegin引用范例:

void myDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glBegin( /* 在这里填上你所希望的模式 */ );
/* 在这里使用glVertex*系列函数 */
/* 指定你所希望的顶点位置 */
glEnd();
glFlush();
}

两个例子
例一、画一个圆
/*
正四边形,正五边形,正六边形,……,直到正n边形,当n越大时,这个图形就越接近圆,当n大到一定程度后,人眼将无法把它跟真正的圆相区别,这时我们已经成功的画出了一个“圆”
(注:画圆的方法很多,这里使用的是比较简单,但效率较低的一种)
试修改下面的const int n的值,观察当n=3,4,5,8,10,15,20,30,50等不同数值时输出的变化情况将GL_POLYGON改为GL_LINE_LOOP、GL_POINTS等其它方式,观察输出的变化情况

#include <math.h>
const int n = ;
const GLfloat R = 0.5f;
const GLfloat Pi = 3.1415926536f;
void myDisplay(void)
{
int i;
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_POLYGON);
for(i=; i<n; ++i)
glVertex2f(R*cos(*Pi/n*i), R*sin(*Pi/n*i));
glEnd();
glFlush();
}

例二、画一个五角星
/*
设五角星的五个顶点分布位置关系如下:
      A
E        B

D    C
首先,根据余弦定理列方程,计算五角星的中心到顶点的距离a(假设五角星对应正五边形的边长为.0)
a = 1 / (2-2*cos(72*Pi/180));
然后,根据正弦和余弦的定义,计算B的x坐标bx和y坐标by,以及C的y坐标
(假设五角星的中心在坐标原点)
bx = a * cos(18 * Pi/180);
by = a * sin(18 * Pi/180);
cy = -a * cos(18 * Pi/180);
五个点的坐标就可以通过以上四个量和一些常数简单的表示出来

#include <math.h>
const GLfloat Pi = 3.1415926536f;
void myDisplay(void)
{
GLfloat a = / (-*cos(*Pi/));
GLfloat bx = a * cos( * Pi/);
GLfloat by = a * sin( * Pi/);
GLfloat cy = -a * cos( * Pi/);
GLfloat
PointA[] = { , a },
PointB[] = { bx, by },
PointC[] = { 0.5, cy },
PointD[] = { -0.5, cy },
PointE[] = { -bx, by }; glClear(GL_COLOR_BUFFER_BIT);
// 按照A->C->E->B->D->A的顺序,可以一笔将五角星画出
glBegin(GL_LINE_LOOP);
glVertex2fv(PointA);
glVertex2fv(PointC);
glVertex2fv(PointE);
glVertex2fv(PointB);
glVertex2fv(PointD);
glEnd();
glFlush();
}

关于glBegin的用法

OpenGL中的物体是用面边界模型来描述的。我们将物体表面分割成许多个平面,记录面的形状、颜色、纹理,OpenGL根据这些参数再把这些个面绘制出来,我们就能在场景中看到立体的实体了。

物体模型最基本的参数是它的形状,形状可以用表面来记录。而记录面的边缘就能描述面的形状。描述边缘的方法是记录边上所有线段的端点。所以用面边界模型描述物体形状的核心就是记录物体表面所有的顶点。这些顶点按所在边的顺序排列起来就能描述一个平面,许多的平面就能表示一个物体的表面,显然平面越多形状越逼真。

OpenGL中描述一个顶点的方法是指定其坐标和属性,命令是:

glVertex*(Coordination);

该命令以参数指定的坐标和当前颜色、纹理坐标、法向等属性定义一个顶点。

OpenGL中描述一个面的方法是glBegin/glEnd命令组:

glBegin(形状);
glVertex(顶点1);
glVertex(顶点2);
……
glEnd();

OpenGL支持点(GL_POINTS)、线段(GL_LINES)、三角形(GL_TRIANGLES)、四边形(GL_QUADS)、多边形(GL_POLYGON)。可以在一个begin/end对中定义多个同一类型的平面,如在glBegin(GL_TRIANGLES);与glEnd();之间输入11个顶点,则会形成3个三角形,最后两个顶点则被舍弃。

OpenGL还支持平面带(STRIP)和平面扇(FAN)。
扇:在glBegin(GL_TRIANGLE_FAN);/glEnd();间输入若干顶点,则第一个顶点做为共同的顶点,第二、三个做为底边定义一个三角形,此后的每个顶点与前一个顶点做为底边定义一个三角形,所以11个顶点就会定义9个共顶点的三角形,这些三角形将形成一个扇形。
带:输入顶点编号为123456789……;定义的三角形为132 243 354 465 567……,相邻三角形共用一条边,形成一条带状;依此类推,定义的四边形为1243 3465 5687……。
 

实际使用中,可用3ds max/softimage/maya之类的工具以直观的方式建立物体模型保存成文件,然后再用专门的解码工具将模型转换成一系列的顶点。解码工具有三类:插件、工具软件、程序库。目前已经有许多的代码库可以解析多种格式的三维场景,如果还没有合适的还也可以自己编写。

例三、画出正弦函数的图形
/*
由于OpenGL默认坐标值只能从-1到1,(可以修改,但方法留到以后讲)所以我们设置一个因子factor,把所有的坐标值等比例缩小,这样就可以画出更多个正弦周期试修改factor的值,观察变化情况

#include <math.h>
const GLfloat factor = 0.1f;
void myDisplay(void)
{
GLfloat x;
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_LINES);
glVertex2f(-1.0f, 0.0f);
glVertex2f(1.0f, 0.0f); // 以上两个点可以画x轴
glVertex2f(0.0f, -1.0f);
glVertex2f(0.0f, 1.0f); // 以上两个点可以画y轴
glEnd();
glBegin(GL_LINE_STRIP);
for(x=-1.0f/factor; x<1.0f/factor; x+=0.01f)
{
glVertex2f(x*factor, sin(x)*factor);
}
glEnd();
glFlush();
}

小结
本课讲述了点、直线和多边形的概念,以及如何使用OpenGL来描述点,并使用点来描述几何图形。
大家可以发挥自己的想象,画出各种几何图形,当然,也可以用GL_LINE_STRIP把很多位置相近的点连接起来,构成函数图象。如果有兴趣,也可以去找一些图象比较美观的函数,自己动手,用OpenGL把它画出来。

OpenGL学习-------绘制简单的几何图形的更多相关文章

  1. OpenGL学习 (一) - 简单窗口绘制

    一.OpenGL 简介 OpenGL 本质: OpenGL(Open Graphics Library),通常可以认为是API,其包含了一系列可以操作图形.图像的函数.但深究下来,它是由Khronos ...

  2. OpenGL学习——绘制矩形

    接下来稍微扩展一步,绘制矩形,即两个拼在一起的三角形. 引入一个概念, EBO Element Buffer Object  元素缓冲对象, EBO用于存放描述“顶点绘制顺序”的对象. 外注:创建VS ...

  3. OpenGL学习——绘制第一个三角形

    终于把三角形绘制出来了,首先一些关键概念.操作. Vertex Data                       顶点数据 VBO Vertex Buffer Objects  顶点缓冲对象 VA ...

  4. OpenGL学习进程(4)第二课:绘制图形

    本节是OpenGL学习的第二个课时,下面介绍如何用点和线来绘制图形:     (1)用点的坐标来绘制矩形: #include <GL/glut.h> void display(void) ...

  5. OpenGL学习进程(11)第八课:颜色绘制的详解

        本节是OpenGL学习的第八个课时,下面将详细介绍OpenGL的颜色模式,颜色混合以及抗锯齿.     (1)颜色模式: OpenGL支持两种颜色模式:一种是RGBA,一种是颜色索引模式. R ...

  6. OpenGL学习进程(8)第六课:点、边和图形(三)绘制图形

    本节是OpenGL学习的第六个课时,下面介绍OpenGL图形的相关知识:     (1)多边形的概念: 多边形是由多条线段首尾相连而形成的闭合区域.OpenGL规定,一个多边形必须是一个“凸多边形”. ...

  7. 学习笔记:HTML5 Canvas绘制简单图形

    HTML5 Canvas绘制简单图形 1.添加Canvas标签,添加id供js操作. <canvas id="mycanvas" height="700" ...

  8. OpenGL学习进程(10)第七课:四边形绘制与动画基础

        本节是OpenGL学习的第七个课时,下面以四边形为例介绍绘制OpenGL动画的相关知识:     (1)绘制几种不同的四边形: 1)四边形(GL_QUADS) OpenGL的GL_QUADS图 ...

  9. OpenGL入门程序二:绘制简单的圆

    学习 绘制一个圆: ; const float Pi = 3.1415926536f; const float R = 0.5f; //绘制一个圆 void DrawCircle() { //绘制一个 ...

随机推荐

  1. 创建简单动画(一) --- 常规hud

    先说下当前我为处理动画的思路: (新手上路, 老司机轻喷,如果有更好的实现方法请大神指教 感恩戴德) #1. 分析动画构成 #2. 如果是位移动画则考虑使用BasicAnimation或者Keyfra ...

  2. HDU 5813 Elegant Construction

    构造.从a[i]最小的开始放置,例如放置了a[p],那么还未放置的,还需要建边的那个点 需求量-1,然后把边连起来. #pragma comment(linker, "/STACK:1024 ...

  3. 第一次使用unity3d

    今天暂且做个记录,因为第一使用了unity3d,进行了很长时间的安装和调试,进行了简单的使用,能简单的在页面上面建立了一个方块和一个球. 简单了解了unity中的一些基本概念.总结一下,一个物体可以有 ...

  4. 让你瞬间萌比的35个python小技巧

    今天在看python算法的时候,看到一篇关于python的小技巧.瞬间萌比了,原来python也可以这样玩,太神奇了.萌比的是原来这么简单的东西自己都不知道,虽然会写.废话不多说了,开始上菜. 1.拆 ...

  5. JS原型和原型链

        1 var decimalDigits = 2, 2 tax = 5; 3 4 function add(x, y) { 5 return x + y; 6 } 7 8 function su ...

  6. vs2010使用C

    html, body { font-size: 15px; } body { font-family: Helvetica, "Hiragino Sans GB", 微软雅黑, & ...

  7. 剑指offer 旋转数组

    class Solution { public: int minNumberInRotateArray(vector<int> rotateArray) { //常规的遍历方法时间是O(N ...

  8. Android学习笔记之Spinner

    pinner就相当于Html中的下拉列表框,在下面的例子里我们共同学习一下spinner的使用. 属性: 属性名称 描述 android:prompt 该提示在下拉列表对话框显示时显示.(译者注:对话 ...

  9. 使用SQL Server 2000索引视图提高性能

    什么是索引视图? 许多年来,Microsoft? SQL Server? 一直都提供创建虚拟表(称为视图)的功能.在过去,这些视图主要有两种用途: 提供安全机制,将用户限制在一个或多个基表中的数据的某 ...

  10. NSTimer定时器

    NSTimer的避免内存泄露与控制器的正确引用和释放: