OpenGL入门学习 课程 (三) 绘制几何图形的一些细节问题
http://oulehui.blog.163.com/blog/static/79614698201191832753312/
先回顾一下我们都学习了些什么:
第一课,编写第一个OpenGL程序
第二课,绘制几何图形
第三课,绘制几何图形的一些细节问题 ——→ 本次课程的内容
在第二课中,我们学习了如何绘制几何图形,但大家如果多写几个程序,就会发现其实还是有些郁闷之处。例如:点太小,难以看清楚;直线也太细,不舒服;或者想画虚线,但不知道方法只能用许多短直线,甚至用点组合而成。
这些问题将在本课中被解决。
下面就点、直线、多边形分别讨论。
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个点将被画为虚的。
以下是一些例子:
声明:该图片来自www.opengl.org,该图片是《OpenGL编程指南》一书的附图,由于该书的旧版(第一版,1994年)已经流传于网络,我希望没有触及到版权问题。
示例代码:
void myDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_LINE_STIPPLE);
glLineStipple(2, 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[128] =
{
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[128];
FILE *fp;
fp = fopen("mask.bmp", "rb");
if( !fp )
exit(0);
// 移动文件指针到这个位置,使得再读sizeof(Mask)个字节就会遇到文件结束
// 注意-(int)sizeof(Mask)虽然不是什么好的写法,但这里它确实是正确有效的
// 如果直接写-sizeof(Mask)的话,因为sizeof取得的是一个无符号数,取负号会有问题
if( fseek(fp, -(int)sizeof(Mask), SEEK_END) )
exit(0);
// 读取sizeof(Mask)个字节到Mask
if( !fread(Mask, sizeof(Mask), 1, fp) )
exit(0);
fclose(fp);
好的,现在请自己编辑一个图片作为mask,并用上述方法取得Mask数组,运行后观察效果。
说明:绘制虚线时可以设置factor因子,但多边形的镂空无法设置factor因子。请用鼠标改变窗口的大小,观察镂空效果的变化情况。
#include <stdio.h>
#include <stdlib.h>
void myDisplay(void)
{
static GLubyte Mask[128];
FILE *fp;
fp = fopen("mask.bmp", "rb");
if( !fp )
exit(0);
if( fseek(fp, -(int)sizeof(Mask), SEEK_END) )
exit(0);
if( !fread(Mask, sizeof(Mask), 1, fp) )
exit(0);
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入门学习 课程 (三) 绘制几何图形的一些细节问题的更多相关文章
- OpenGL入门学习(三)
http://developer.178.com/201103/94954704639.html 在第二课中,我们学习了如何绘制几何图形,但大家如果多写几个程序,就会发现其实还是有些郁闷之处.例如:点 ...
- SCARA——OpenGL入门学习三
OpenGL入门学习[三] 在第二课中,我们学习了如何绘制几何图形,但大家如果多写几个程序,就会发现其实还是有些郁闷之处.例如:点太小,难以看清楚:直线也太细,不舒服:或者想画虚线,但不知道方法只能用 ...
- opengl基础学习专题 (三) 多边形绘制的几种样式
题外话 聪明人之所以不会成功,是由于他们缺乏坚韧的毅力. ——艾萨克·牛顿(1643年1月4日—1727年3月31日)英国 也许可以理解为 想更深一步的时候,坚持,努力和聪明缺一不可. 挺直腰杆在此向 ...
- opengl入门学习
OpenGL入门学习 说起编程作图,大概还有很多人想起TC的#include <graphics.h>吧? 但是各位是否想过,那些画面绚丽的PC游戏是如何编写出来的?就靠TC那可怜的640 ...
- OpenGL入门学习(转)
OpenGL入门学习 http://www.cppblog.com/doing5552/archive/2009/01/08/71532.html 说起编程作图,大概还有很多人想起TC的#includ ...
- OpenGL入门学习(转载)
说起编程作图,大概还有很多人想起TC的#include <graphics.h>吧? 但是各位是否想过,那些画面绚丽的PC游戏是如何编写出来的?就靠TC那可怜的640*480分辨率.16色 ...
- SCARA——OpenGL入门学习五六(三维变换、动画)
OpenGL入门学习(五) 此课为三维变换的内容,比较枯燥.主要是因为很多函数在单独使用时都不好描述其效果, 在前面绘制几何图形的时候,大家是否觉得我们绘图的范围太狭隘了呢?坐标只能从-1到1,还只能 ...
- SCARA——OpenGL入门学习四(颜色)
OpenGL入门学习[四] 本次学习的是颜色的选择.终于要走出黑白的世界了~~ OpenGL支持两种颜色模式:一种是RGBA,一种是颜色索引模式. 无论哪种颜色模式,计算机都必须为每一个像素保存一些数 ...
- 【转载】salesforce 零基础开发入门学习(三)sObject简单介绍以及简单DML操作(SOQL)
salesforce 零基础开发入门学习(三)sObject简单介绍以及简单DML操作(SOQL) salesforce中对于数据库操作和JAVA等语言对于数据库操作是有一定区别的.salesfo ...
随机推荐
- Echarts 解决饼图文字过长重叠的问题
之前在网上查找了很多关于解决饼图文字描述过长导致重叠的问题,找了很多一直没有一个合适的解决方案,最后自己只能花时间研究echarts文档,功夫不负有心人,终于解决了文字重叠展示不全等问题. 废话不多说 ...
- 小白日记1:kali环境Wpscan渗透Wordpress
一.什么是Wpscan?什么是Wordpres? 1.Wpscan WPScan是一款针对wordpress的安全扫描软件:可以扫描出wordpress的版本,主题,插件,后台用户以及爆破后台用户密码 ...
- 模块hashlib和logging
Python的hashlib提供了常见的摘要算法MD5. 我们以常见的摘要算法MD5为例,计算出一个字符串的MD5值: import hashlib md5=hashlib.md5() md5.upd ...
- Android通过用代码画虚线椭圆边框背景来学习一下shape的用法
在Android程序开发中,我们经常会去用到Shape这个东西去定义各种各样的形状,shape可以绘制矩形环形以及椭圆,所以只需要用椭圆即可,在使用的时候将控件比如imageview或textview ...
- Pascal小游戏 随机函数
一个被人写滥了的小程序,新手学习,Pascal By Chaobs 初学者可以用它来学习随机函数的运用,当然你完全可以自己写一个随机函数. var player1,player2:longint; ...
- Lua2
1. 迭代器与Closure 在Lua中,迭代器通常为函数,每调用一次函数,即返回集合中的“下一个”元素.每个迭代器都需要在每次成功调用之间保持一些状态,这样才能知道它所在的位置和下一次遍历时的位置. ...
- (原)Unreal渲染模块 管线 - 程序和场景查询
@author: 白袍小道 查看随意,转载随缘 第一部分: 这里主要关心加速算法,和该阶段相关的UE模块的结构和组件的处理. What-HOW-Why-HOW-What(嘿嘿,老规矩) 1.渲 ...
- Virtual box 虚拟机 不可使用的一种解决方法
在win7下开着一个ubuntu虚拟机,写了好几小时代码,然后饿了,去吃点东西 回来发现,电脑由于win7 自动更新已经重启 ubuntu下的代码我已经走开时保存过了,所以不怎么担心 但是打开virt ...
- 团队冲刺Alpha(九)
目录 组员情况 组员1(组长):胡绪佩 组员2:胡青元 组员3:庄卉 组员4:家灿 组员5:凯琳 组员6:翟丹丹 组员7:何家伟 组员8:政演 组员9:黄鸿杰 组员10:刘一好 组员11:何宇恒 展示 ...
- (转)详解JavaScript模块化开发
https://segmentfault.com/a/1190000000733959 什么是模块化开发? 前端开发中,起初只要在script标签中嵌入几十上百行代码就能实现一些基本的交互效果,后来j ...