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

一、点、直线和多边形
我们知道数学(具体的说,是几何学)中有点、直线和多边形的概念,但这些概念在计算机中会有所不同。
数学上的点,只有位置,没有大小。但在计算机中,无论计算精度如何提高,始终不能表示一个无穷小的点。另一方面,无论图形输出设备(例如,显示器)如何精确,始终不能输出一个无穷小的点。一般情况下,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. 用Replace Pioneer 提取正则内容

    推荐用软件Replace Pioneer完成,支持正则表达式和文本替换,提取,很灵活容易. 以下举例说明怎样把<a href 和 </a>之间的内容提取出来,其他的全部删除. 1. ...

  2. Chapter 1 First Sight——34

    "Was that the boy I sat next to in Biology?" I asked artlessly. 你是生物课坐在我旁边的男生吗?我天真烂漫的问道. & ...

  3. 如何查找僵尸进程并Kill之,杀不掉的要查看父进程并杀之

    转自:如何查找僵尸进程并Kill之,杀不掉的要查看父进程并杀之 用ps和grep命令寻找僵尸进程#ps -A -ostat,ppid,pid,cmd | grep -e '^[Zz]'命令注解:-A ...

  4. java 正则

    ava - 正则表达式 - Pattern - Matcher 2013-08-21 14:35 3325人阅读 评论(0) 收藏 举报  分类: JavaSE(30)  版权声明:本文为博主原创文章 ...

  5. JavaScript高级程序设计:第九章

    第九章 一.使用能力检测 能力检测的目标不是识别特定的浏览器,而是识别浏览器的能力.能力检测的基本模式如下: if ( object.propertyInQuestion ) { //使用object ...

  6. word转pdf swf 在线预览

    来源:http://www.cnblogs.com/wuhenke/archive/2010/08/01/1789750.html 之前在项目中研究使用了一套word转PDF,然后将PDF转成SWF的 ...

  7. Android Service学习之IntentService 深入分析

          什么是IntentService? (本文转自http://blog.csdn.net/gaojie314/archive/2010/11/28/6040701.aspx) 官方的解释是: ...

  8. python http请求

    from httplib2 import Http def postDada(): http=Http() heads={"pragma":"no-cache" ...

  9. Eclipse的Console乱码

    1.找到服务器bin目录:例:D:\WebLogic_11g\Middleware\user_projects\domains\dsrhd_domain\bin, 在该目录下找到setDomainEn ...

  10. mysql if then

    CREATE PROCEDURE userinfo_modify( IN id INT ,IN loginid INT ,IN levelid INT ,IN namestr VARCHAR(50) ...