上一课中,我们学习了如何绘制几何图形,但大家如果多写几个程序,就会发现其实还是有些郁闷之处。例如:点太小,难以看清楚;直线也太细,不舒服;或者想画虚线,但不知道方法只能用许多短直线,甚至用点组合而成。

这些问题将在本课中被解决。

下面就点、直线、多边形分别讨论。

1、关于点

点的大小默认为1个像素,但也可以改变之。改变的命令为glPointSize,其函数原型如下:

void glPointSize(GLfloat size);

size必须大于0.0f,默认值为1.0f,单位为“像素”。

注意:对于具体的OpenGL实现,点的大小都有个限度的,如果设置的size超过最大值,则设置可能会有问题。

例子:

void myDisplay(void)

{

     glClear(GL_COLOR_BUFFER_BIT);

     glPointSize(5.0f);

     glBegin(GL_POINTS);

         glVertex2f(0.0f, 0.0f);

         glVertex2f(0.5f, 0.5f);

     glEnd();

     glFlush();

}

2、关于直线

(1)直线可以指定宽度:

void glLineWidth(GLfloat width);其用法跟glPointSize类似。

(2)画虚线。

首先,使用glEnable(GL_LINE_STIPPLE);来启动虚线模式(使用glDisable(GL_LINE_STIPPLE)可以关闭之)。

然后,使用glLineStipple来设置虚线的样式。

void glLineStipple(GLint factor, GLushort pattern);

pattern是由1和0组成的长度为16的序列,从最低位开始看,如果为1,则直线上接下来应该画的factor个点将被画为实的;如果为0,则直线上接下来应该画的factor个点将被画为虚的。

以下是一些例子:

void myDisplay(void)

{

     glClear(GL_COLOR_BUFFER_BIT);

     glEnable(GL_LINE_STIPPLE);

     glLineStipple(, 0x0F0F);

     glLineWidth(10.0f);

     glBegin(GL_LINES);

         glVertex2f(0.0f, 0.0f);

         glVertex2f(0.5f, 0.5f);

     glEnd();

     glFlush();

}

3、关于多边形

多边形的内容较多,我们将讲述以下四个方面。

(1)多边形的两面以及绘制方式。

虽然我们目前还没有真正的使用三维坐标来画图,但是建立一些三维的概念还是必要的。

从三维的角度来看,一个多边形具有两个面。每一个面都可以设置不同的绘制方式:填充、只绘制边缘轮廓线、只绘制顶点,其中“填充”是默认的方式。可以为两个面分别设置不同的方式。

glPolygonMode(GL_FRONT, GL_FILL);            // 设置正面为填充方式

glPolygonMode(GL_BACK, GL_LINE);             // 设置反面为边缘绘制方式

glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); // 设置两面均为顶点绘制方式

(2)反转

一般约定为“顶点以逆时针顺序出现在屏幕上的面”为“正面”,另一个面即成为“反面”。生活中常见的物体表面,通常都可以用这样的“正面”和“反面”,“合理的”被表现出来(请找一个比较透明的矿泉水瓶子,在正对你的一面沿逆时针画一个圆,并标明画的方向,然后将背面转为正面,画一个类似的圆,体会一下“正面”和“反面”。你会发现正对你的方向,瓶的外侧是正面,而背对你的方向,瓶的内侧才是正面。正对你的内侧和背对你的外侧则是反面。这样一来,同样属于“瓶的外侧”这个表面,但某些地方算是正面,某些地方却算是反面了)。

但也有一些表面比较特殊。例如“麦比乌斯带”(请自己Google一下),可以全部使用“正面”或全部使用“背面”来表示。

可以通过glFrontFace函数来交换“正面”和“反面”的概念。

glFrontFace(GL_CCW);   // 设置CCW方向为“正面”,CCW即CounterClockWise,逆时针

glFrontFace(GL_CW);    // 设置CW方向为“正面”,CW即ClockWise,顺时针

下面是一个示例程序,请用它替换第一课中的myDisplay函数,并将glFrontFace(GL_CCW)修改为glFrontFace(GL_CW),并观察结果的变化。

void myDisplay(void)

{

     glClear(GL_COLOR_BUFFER_BIT);

     glPolygonMode(GL_FRONT, GL_FILL); // 设置正面为填充模式

     glPolygonMode(GL_BACK, GL_LINE);   // 设置反面为线形模式

     glFrontFace(GL_CCW);               // 设置逆时针方向为正面

     glBegin(GL_POLYGON);               // 按逆时针绘制一个正方形,在左下方

         glVertex2f(-0.5f, -0.5f);

         glVertex2f(0.0f, -0.5f);

         glVertex2f(0.0f, 0.0f);

         glVertex2f(-0.5f, 0.0f);

     glEnd();

     glBegin(GL_POLYGON);               // 按顺时针绘制一个正方形,在右上方

         glVertex2f(0.0f, 0.0f);

         glVertex2f(0.0f, 0.5f);

         glVertex2f(0.5f, 0.5f);

         glVertex2f(0.5f, 0.0f);

     glEnd();

     glFlush();

}

(3)剔除多边形表面

在三维空间中,一个多边形虽然有两个面,但我们无法看见背面的那些多边形,而一些多边形虽然是正面的,但被其他多边形所遮挡。如果将无法看见的多边形和可见的多边形同等对待,无疑会降低我们处理图形的效率。在这种时候,可以将不必要的面剔除。

首先,使用glEnable(GL_CULL_FACE);来启动剔除功能(使用glDisable(GL_CULL_FACE)可以关闭之)

然后,使用glCullFace来进行剔除。

glCullFace的参数可以是GL_FRONT,GL_BACK或者GL_FRONT_AND_BACK,分别表示剔除正面、剔除反面、剔除正反两面的多边形。

注意:剔除功能只影响多边形,而对点和直线无影响。例如,使用glCullFace(GL_FRONT_AND_BACK)后,所有的多边形都将被剔除,所以看见的就只有点和直线。

(4)镂空多边形

直线可以被画成虚线,而多边形则可以进行镂空。

首先,使用glEnable(GL_POLYGON_STIPPLE);来启动镂空模式(使用glDisable(GL_POLYGON_STIPPLE)可以关闭之)。

然后,使用glPolygonStipple来设置镂空的样式。

void glPolygonStipple(const GLubyte *mask);

其中的参数mask指向一个长度为128字节的空间,它表示了一个32*32的矩形应该如何镂空。其中:第一个字节表示了最左下方的从左到右(也可以是从右到左,这个可以修改)8个像素是否镂空(1表示不镂空,显示该像素;0表示镂空,显示其后面的颜色),最后一个字节表示了最右上方的8个像素是否镂空。

但是,如果我们直接定义这个mask数组,像这样:

static GLubyte Mask[] =

{

     0x00, 0x00, 0x00, 0x00,    //   这是最下面的一行

     0x00, 0x00, 0x00, 0x00,

     0x03, 0x80, 0x01, 0xC0,    //   麻

     0x06, 0xC0, 0x03, 0x60,    //   烦

     0x04, 0x60, 0x06, 0x20,    //   的

     0x04, 0x30, 0x0C, 0x20,    //   初

     0x04, 0x18, 0x18, 0x20,    //   始

     0x04, 0x0C, 0x30, 0x20,    //   化

     0x04, 0x06, 0x60, 0x20,    //   ,

     0x44, 0x03, 0xC0, 0x22,    //   不

     0x44, 0x01, 0x80, 0x22,    //   建

     0x44, 0x01, 0x80, 0x22,    //   议

     0x44, 0x01, 0x80, 0x22,    //   使

     0x44, 0x01, 0x80, 0x22,    //   用

     0x44, 0x01, 0x80, 0x22,

     0x44, 0x01, 0x80, 0x22,

     0x66, 0x01, 0x80, 0x66,

     0x33, 0x01, 0x80, 0xCC,

     0x19, 0x81, 0x81, 0x98,

     0x0C, 0xC1, 0x83, 0x30,

     0x07, 0xE1, 0x87, 0xE0,

     0x03, 0x3F, 0xFC, 0xC0,

     0x03, 0x31, 0x8C, 0xC0,

     0x03, 0x3F, 0xFC, 0xC0,

     0x06, 0x64, 0x26, 0x60,

     0x0C, 0xCC, 0x33, 0x30,

     0x18, 0xCC, 0x33, 0x18,

     0x10, 0xC4, 0x23, 0x08,

     0x10, 0x63, 0xC6, 0x08,

     0x10, 0x30, 0x0C, 0x08,

     0x10, 0x18, 0x18, 0x08,

     0x10, 0x00, 0x00, 0x08    // 这是最上面的一行

};

这样一堆数据非常缺乏直观性,我们需要很费劲的去分析,才会发现它表示的竟然是一只苍蝇。

如果将这样的数据保存成图片,并用专门的工具进行编辑,显然会方便很多。下面介绍如何做到这一点。

首先,用Windows自带的画笔程序新建一副图片,取名为mask.bmp,注意保存时,应该选择“单色位图”。在“图象”->“属性”对话框中,设置图片的高度和宽度均为32。

用放大镜观察图片,并编辑之。黑色对应二进制零(镂空),白色对应二进制一(不镂空),编辑完毕后保存。

然后,就可以使用以下代码来获得这个Mask数组了。

static GLubyte Mask[];

FILE *fp;

fp = fopen("mask.bmp", "rb");

if( !fp )

     exit();

// 移动文件指针到这个位置,使得再读sizeof(Mask)个字节就会遇到文件结束

// 注意-(int)sizeof(Mask)虽然不是什么好的写法,但这里它确实是正确有效的

// 如果直接写-sizeof(Mask)的话,因为sizeof取得的是一个无符号数,取负号会有问题

if( fseek(fp, -(int)sizeof(Mask), SEEK_END) )

     exit();

// 读取sizeof(Mask)个字节到Mask

if( !fread(Mask, sizeof(Mask), , fp) )

     exit();

fclose(fp);

好的,现在请自己编辑一个图片作为mask,并用上述方法取得Mask数组,运行后观察效果。

说明:绘制虚线时可以设置factor因子,但多边形的镂空无法设置factor因子。请用鼠标改变窗口的大小,观察镂空效果的变化情况。

#include <stdio.h>

#include <stdlib.h>

void myDisplay(void)

{

     static GLubyte Mask[];

     FILE *fp;

     fp = fopen("mask.bmp", "rb");

     if( !fp )

         exit();

     if( fseek(fp, -(int)sizeof(Mask), SEEK_END) )

         exit();

     if( !fread(Mask, sizeof(Mask), , fp) )

         exit();

     fclose(fp);

     glClear(GL_COLOR_BUFFER_BIT);

     glEnable(GL_POLYGON_STIPPLE);

     glPolygonStipple(Mask);

     glRectf(-0.5f, -0.5f, 0.0f, 0.0f);   // 在左下方绘制一个有镂空效果的正方形

     glDisable(GL_POLYGON_STIPPLE);

     glRectf(0.0f, 0.0f, 0.5f, 0.5f);     // 在右上方绘制一个无镂空效果的正方形

     glFlush();

}

小结

本课学习了绘制几何图形的一些细节。

点可以设置大小。直线可以设置宽度;可以将直线画成虚线。

多边形的两个面的绘制方法可以分别设置;在三维空间中,不可见的多边形可以被剔除;可以将填充多边形绘制成镂空的样式。

了解这些细节会使我们在一些图象绘制中更加得心应手。

另外,把一些数据写到程序之外的文件中,并用专门的工具编辑之,有时可以显得更方便。

OpenGL学习-------点、直线、多边形的更多相关文章

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

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

  2. OpenGL学习--------颜色的选择

    OpenGL支持两种颜色模式:一种是RGBA,一种是颜色索引模式.无论哪种颜色模式,计算机都必须为每一个像素保存一些数据.不同的是,RGBA模式中,数据直接就代表了颜色:而颜色索引模式中,数据代表的是 ...

  3. OpenGL学习-------绘制简单的几何图形

    本次课程所要讲的是绘制简单的几何图形,在实际绘制之前,让我们先熟悉一些概念. 一.点.直线和多边形我们知道数学(具体的说,是几何学)中有点.直线和多边形的概念,但这些概念在计算机中会有所不同.数学上的 ...

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

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

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

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

  6. OpenGL学习进程(7)第五课:点、边和图形(二)边

    本节是OpenGL学习的第五个课时,下面介绍OpenGL边的相关知识: (1)边的概念: 数学上的直线没有宽度,但OpenGL的直线则是有宽度的.同时,OpenGL的直线必须是有限长度,而不是像数学概 ...

  7. openGl学习之基本图元

    从本篇開始,会给出一些代码实例,所以要配置好编译环境. 环境配置: vs2012下配置链接http://www.cnblogs.com/dreampursuer/archive/2014/05/27/ ...

  8. OpenGL学习进程(13)第十课:基本图形的底层实现及算法原理

        本节介绍OpenGL中绘制直线.圆.椭圆,多边形的算法原理.     (1)绘制任意方向(任意斜率)的直线: 1)中点画线法: 中点画线法的算法原理不做介绍,但这里用到最基本的画0<=k ...

  9. OpenGL学习笔记3——缓冲区对象

    在GL中特别提出了缓冲区对象这一概念,是针对提高绘图效率的一个手段.由于GL的架构是基于客户——服务器模型建立的,因此默认所有的绘图数据均是存储在本地客户端,通过GL内核渲染处理以后再将数据发往GPU ...

  10. OpenGL学习之路(一)

    1 引子 虽然是计算机科班出身,但从小对几何方面的东西就不太感冒,空间想象能力也较差,所以从本科到研究生,基本没接触过<计算机图形学>.为什么说基本没学过呢?因为好奇(尤其是惊叹于三维游戏 ...

随机推荐

  1. C语言_IP地址解析

    #include<stdio.h> #include<stdlib.h> void main() { unsigned long input_IP; unsigned int ...

  2. 您可能无法使用服务器管理器,如果两个线程同时访问 IIS 管理 IIS 的修补程序

    http://support.microsoft.com/kb/946517 如果多线程操作 win2003 iis 失败, 打上这个补丁就好了

  3. 通过C++修改系统时间代码

    #include <windows.h>#include <stdio.h>#include <iostream>using namespace std;int m ...

  4. POJ2524:Ubiquitous Religions (并查集模板)

    Description There are so many different religions in the world today that it is difficult to keep tr ...

  5. could not perform addBatch

    在执行存数据到数据库的操作时,由于增加的ID值小于或等于对应的索引值时会报这个错误

  6. IBM Mq Spring JMS 的xml配置

    <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.spr ...

  7. 关于table参数的一些问题

    1.关于单元格合并 写在td标签上,如: <td rowspan="3"></td> 跨行合并:rowspan 跨列合并:colspan 2.关于多行输入框 ...

  8. ckediter

    ckediter ##<link rel='stylesheet' href='/css/index.css' /> <script type="text/javascri ...

  9. androidstudio 问题

    Error:(1, 1) A problem occurred evaluating project ':app'. > Failed to apply plugin [id 'com.andr ...

  10. [DP]一道理想收入问题【转】

    题意:以一元为本金,能获得的最大收入,第i天股票价格为v[i],1<=i<=m 思路: (1)DP思路明显,直接进行动态规划,令f[i]代表第i天所获得的最大收入.那么有公式: f[i] ...