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

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

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

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. 转:CSV Data Set Config 中文乱码问题

    从csv读取中文一直乱码. CSV Data Set Config的File encoding为GB2312,对应参数化文件编码也为GB2312,但读取出变量值一直为乱码,后发现是Allow quot ...

  2. 为什么要重写equals和hashCode

    1.重写equals方法时需要重写hashCode方法,主要是针对Map.Set等集合类型的使用: a: Map.Set等集合类型存放的对象必须是唯一的: b: 集合类判断两个对象是否相等,是先判断e ...

  3. 缓存2 动态缓存 memcached

    01准备下载好memcached.exe文件-->放置c:\memcached目录中02准备下载好php_memcache.dll文件-->放置php\ext扩展目录中03配置 php.i ...

  4. jquery为多个元素添加事件

    html <c:forEach items="${modellist}" var="model" varStatus="status" ...

  5. javascript克隆一个对象

    /* * 克隆一个对象 */ com.ty.repairtech.JsonOperation.clone = function(obj) { // Handle the 3 simple types, ...

  6. win10快捷键大全

    win10快捷键大全大家可以来了解一下,今天小编带来了win10常用快捷键,很多朋友喜欢使用快捷键来操作电脑,那么Windows10系统有哪些新的快捷键呢• 贴靠窗口:Win +左/右> Win ...

  7. docker installation on ubuntu

    Ubuntu Docker is supported on these Ubuntu operating systems: Ubuntu Xenial 16.04 (LTS) Ubuntu Trust ...

  8. UVALive - 3942 Remember the Word

    input 字符串s  1<=len(s)<=300000 n 1<=n<=4000 word1 word2 ... wordn 1<=len(wordi)<=10 ...

  9. linux视频学习6(mysql的安装/)

    1.mysql的优点: 免费,跨平台,轻,支持多并发. 2.mysql的安装步骤: 把安装文件准备好,拷贝到home目录下.mount /mnt/cdrom cp mysql* /home 把安装文件 ...

  10. Android:TextView最小行数设置

    我们有时候为了保证TextView必须有一个最小的高度,那么就需要设置这个行数. 因为如果你不设置的话,在measure这个TextView的时候,此时就无法准确的得到一个最小高度.因为设备不同,所以 ...