1
计通学院 计算机科学系
计算机图形学
第 4 章 二维填充图元的生成
2
本章目标掌握如何绘制填充图元(矩形、多边形等)
扫面转换算法(扫描线算法) 填充算法
学会使用 OpenGL 的绘制函数
3
主要内容填充图元扫描转换矩形扫描转换多边形扫描转换扇形区域区域填充以图像填充区域字符的表示与输出 OpenGL 相关函数
4
4.1 填充图元填充( Filling )
矩形 (Rectangle) 多边形 (Polygon) 扇形 (Ellipse Arc)
步骤 确定那些像素位于填充图元的内部 用指定颜色绘制这些像素
两类方法 扫描转换( Scan Converting ) : 参数- > 点阵 填充( Filling ) : 点阵- > 点阵
5
4.2 扫描转换矩形含义
用指定颜色填充矩形内部区域定义矩形的参数
左下角坐标 (xmin, ymin) 右上角坐标 (xmax, ymax)
void FillRectangle(Rectangle *rect,int color)
{ int x,y;
for(y = rect->ymin; y <= rect->ymax; y++)
for(x = rect->xmin; x <= rect->xmax; x++)
SetPixel(x, y, color);
}/*end of FillRectangle() */
(xmin, ymin)
(xmax, ymax)
6
4.2 扫描转换矩形问题
矩形是简单的多边形,那么为什么要单独处理矩形?比一般多边形可简化计算应用非常多,如窗口系统
共享边界如何处理?原则:左闭右开,下闭上开
属于谁?
7
4.3 扫描转换多边形 多边形的表示方法
顶点表示顶点序列 P0P1P2…Pn
点阵表示 扫描转换多边形:将顶点表示形式转换成点阵表示形式 三种方法:逐点判断法;扫描线算法;边缘填充法
多边形分类(只考虑:简单多边形,即多边形边不自相交) 凸多边形 (convex) :内角小于 180 度 凹多边形 (concave) :存在内角大于 180 度
8
4.3 扫描转换多边形 如何识别多边形的凸凹性
方法 1 :观察多边形边的延长线是否划分顶点在两侧方法 2 :向量的叉积每条边建立一个向量,测试相邻边的叉积 z 坐标的正负( 1 )如果叉积同号,那么是凸多边形( 2 )如果叉积不同号,那么是凹多边形
(E1×E2 )z > 0(E2×E3 )z > 0(E3×E4 )z < 0
(E4×E5 )z > 0(E5×E6 )z > 0(E6×E1 )z > 0
9
4.3 扫描转换多边形向量叉积( Cross Product of Two Vector )
kji
kji
ba
)()()( xyyxzxxzyzzy
zyx
zyx
babababababa
bbb
aaa
当 a 与 b 为二维向量时, a×b 矢量中 x , y 分量为 0
10
4.3.1 逐点判断法基本原理
判断绘图窗口内的像素是否位于多边形内,若是,则用指定颜色绘制该像素
问题 如何判断点在多边形的内外关系?
射线法累计角度法 *编码法 *
P1
P2
(xmin, ymin)
(xmax, ymax)
11
4.3.1 逐点判断法算法
假设判断点是否在多边形内的函数为 IsInside ()
void FillPolygon(Polygon *P, int polygonColor){ int x,y;
for(y = ymin;y <= ymax;y++) for(x = xmin;x <= xmax;x++)
if(IsInside(P,x,y)) SetPixel(x, y, polygonColor);else SetPixel(x,y,backgroundColor);
}/*end of FillPolygonPbyP() */
#define MAX 100typedef struct { // 多边形顶点个数 int PolygonNum; // 多边形顶点数组 Point vertexces[MAX]} Polygon; // 多边形结构
12
4.3.1 逐点判断法判断点是否在多边形内-射线法 步骤
从待判别点 v 发出射线 求与多边形交点个数 k k 的奇偶性决定了点与多边形的内外关系
偶数:外奇数:内
v1
p2
p1
p3
v2
13
4.3.1 逐点判断法判断点是否在多边形内-射线法 奇异情况
射线在边上:无数个点 判断是否与边同线 交点为顶点:算几个?
异侧: 1 个同侧: 2 个
14
4.3.1 逐点判断法逐点判断扫描转换方法
特点程序简单测试点是否在多边形内的算法速度太慢,效率低
改进逐点判断法孤立考虑各个像素与多边形的内外关系利用内部点的连续性
15
4.3.1 逐点判断法思考题
下图是某油田油井分布图,已知每口油井的位置( x, y坐标值)和产油量,如何求任意多边形(虚线所示)中的总产油量?
油井
利用射线法判断油井是否在多边形内?
16
4.3.2 扫描线算法英文: Scan-Line Algorithm目标
利用相邻像素之间的连贯性,提高算法效率处理对象:简单多边形
非自交多边形 (边与边之间除了顶点外无其它交点)扫描线 (Scanning Line)
平行于坐标轴的直线 一般取平行于 X 轴 区间:扫描线与边的交点间的线段
17
4.3.2 扫描线算法连贯性 (Coherence)
边的连贯性 (Edge Coherence)某条边与当前扫描线相交,也可能与下一条扫描线相交
扫描线的连贯性 (Scan-line Coherence)当前扫描线与各边的交点顺序与 下一条扫描线与各边的交点顺序可能相同或类似
区间的连贯性 (Span Coherence)同一区间上的像素取同一颜色属性
18
4.3.2 扫描线算法基本原理
将整个绘图窗口内扫描多边形的问题分解到一条条扫描线,只要完成每条扫描线的绘制就实现了多边形的扫描转换
一条扫描线与多边形的边有偶数个交点,每 2 个点形成一区间
步骤 ( 对于每一条扫描线 )(1) 计算扫描线与边的交点(2) 交点按 x 坐标从小到大排序(3) 交点两两配对,填充区间
19
4.3.2 扫描线算法计算交点
分类第一类交点:位于同一条边上的后继交点 --(P2, P4)
第二类交点:新出现的边与扫描线的交点 --(P3)
计算:由扫描线 y = e 与多边形的交点递推计算扫描线
y = e + 1 的交点第一类交点: x’ = x + 1/m第二类交点: 线段的下端点即为交点
P3 P4
P0
P2
P1
20
4.3.2 扫描线算法计算交点(续)
交点取整规则:要求:使生成的像素全部位于多边形之内用于线画图元扫描转换的四舍五入原则导致部分像素位于多边形之外,从而不可用
扫描转换 位于多边形内
21
4.3.2 扫描线算法 取整规则
假定非水平变与扫描线 y=e 相交,交点的横坐标为x规则 1
X 为小数,即交点落于扫描线上两个相邻像素之间 (a) 交点位于左边之上,向右取整 (b) 交点位于右边之上,向左取整
22
4.3.2 扫描线算法规则 2
落在右上边界的像素不予填充。
具体实现时,只要对扫描线与多边形的相交区间左闭右开
23
4.3.2 扫描线算法规则 3
扫描线与多边形的顶点相交时,采用上开下闭及右开左闭取交点,保证交点正确配对。
检查两相邻边在扫描线的哪一侧。 只要检查顶点的两条边的另外两个端点的 Y 值,两个 Y值中大于交点 Y 值的个数是 0 , 1 , 2 ,来决定取 0 , 1 ,2 个交点
24
4.3.2 扫描线算法计算交点(续)
水平边不考虑
排序 扫描线连贯性 采用插入排序
交点两两配对与区间绘制 区间连续性 连续绘制区间上的像素
H
F
A B
C D
G
J
A , B 算交点C 不算, D算I 不算, H算G , F 不算
Y
25
4.3.2 扫描线算法算法实现-数据结构
( 1 )边的分类表 ET ( Edge Table )(又称新边表)按照边的下端点 y 坐标,对非水平边进行分类的链表下端点 y 坐标值等于 i 的边属于第 i 类作用:避免盲目求交
26
4.3.2 扫描线算法 ET 定义
每条扫描线,对应一个链表链表中每个结点的结构
typedef struct {int ymax; float x, deltax; Edge *nextEdge; }Edge;
ET 的结点信息:ymax: 边的上端点的 y 坐标值x :边的下端点的 x 坐标deltax :边的斜率的倒数nextEdge: 下一条边的指针
27
4.3.2 扫描线算法结点结构解释
typedef struct {int ymax; float x, deltax; Edge *nextEdge; }Edge;
float x, deltax; 用于递推计算交点 x’ = x +1/mint ymax ;当扫描线 y = e+1 == ymax ,说明下一条扫描线与此边不相交
28
4.3.2 扫描线算法( 2 )活性边表 AEL(Active Edge List)
存放活性边的顺序链表,且按交点 x 的值从小到大排序 活性边:与当前扫描线相交的边 边结构定义:typedef struct {int ymax; float x, deltax; Edge *nextEdge; }Edge;
AEL 的结点信息:ymax: 所交边的最高扫描线号x :当前扫描线与边的交点的 x 坐标deltax :边的斜率的倒数nextEdge: 下一条边的指针
29
4.3.2 扫描线算法实例
(a) Y=6 对应的活性边表
(b) Y=7 对应的活性边表
30
4.3.2 扫描线算法 算法 (Scan-Line Algorithm)
1 、建立 ET;2 、将扫描线纵坐标 y 的初值置为 ET 中非空 元素的最小序号,如图中, y=1;3 、置 AEL 为空;4 、执行下列步骤直至 ET 和 AEL都为空.4.1 、如 ET 中的第 y 类非空,则将其中的所有 边取出并插入 AEL 中;4.2 、如果有新边插入 AEL ,则对 AEL 中各边排序;4.3 、对 AEL 中的边两两配对,( 1 和 2 为一对, 3 和 4 为一对,…),将每对边中 x 坐标按规则取整,获得有效的填充区段,再填充.
4.4 、将当前扫描线纵坐标 y 值递值 1;4.5 、将 AEL 中满足 y = ymax 边删去(因为每条边被看作下闭上开
的);4.6 、对 AEL 中剩下的每一条边的 x递增 deltax ,即 x = x+deltax.
31
4.3.2 扫描线算法4.3.2 扫描线算法例子
y=5 y=6 y=7
y=8
AET:y=1 y=2 y=3
y=4
4 4 -1
5 7 5/4 ^
4 5 -1
5 33/4 5/4 ^
5 19/2 5/4 ^ 4 3 -1
8 2 0 5 43/4 5/4 ^
8 2 0
8 2 0
8 2 0
11 12 0 1̂1 12 0 ^8 7 -5
11 7 5/4 11 12 0 ^11 33/4 5/4 11 12 0
^
32
4.3.2 扫描线算法 思考问题
算法如何体现连贯性? 对凸多边形而言,算法是否可以简化?如何简化? 对三角形而言,算法如何简化?
三角形广泛应用于物体建模
33
思考题思考问题 如何高效计算平面上 n 条线段的交点?
利用扫描线和边的连贯性,时间复杂性 m×n’ ( m 为扫描线条数 , n’ 为与扫描线相交边的平均条数, n’ << n )
一般方法:两两求交点,时间复杂性 n2
34
4.3.3 边缘填充算法 *写像素的逻辑操作
主要包括:拷贝、异或(求余)等 写模型:像素的颜色与源像素及像素当前颜色相关
35
4.3.3 边缘填充算法 *求余运算
假定 A 为一个正整数,则 M 的余定义为 A – M, 记为
求余运算可用异或逻辑运算实现
例
性质
11Xor001Xor1
Xor
AMMAM
00110110
11111111
11001001
Xor
11001001
11111111
00110110
Xor
MM
M
36
4.3.3 边缘填充算法 *求余运算(续)
应用:光标移动、橡皮筋线和加亮菜单等操作 如:交互绘制线段时的橡皮筋线
交互方式:( 1 )点击鼠标左键输入线段的一个端点( 2 )点击右键(或左键)输入另一端点( 3 )鼠标移动过程中绘制瞬时线段
注意:不能采用直接绘制(复制、拷贝)方法
37
4.3.3 边缘填充算法 *
边缘填充算法 光栅图形中,如果某区域已着上值为 M 的颜色值后,做偶数次求余运算,该区域颜色不变;而做奇数次求余运算,则该区域颜色变为值为 的颜色
这一规律应用于多边形扫描转换,称为边缘填充算法。算法基本思想
对于每条扫描线和每条多边形边的交点,将该扫描线上交点右方的所有像素取余
M 为填充色, A 为当前背景色
M
38
4.3.3 边缘填充算法 *
算法 1 (以扫描线为中心的边缘填充算法) 1 、将当前扫描线上的所有像素着上值为 颜色; 2 、求余: for(i=0; i<=m; i++) 在当前扫描线上,从横坐标为 xi的交点向右求余;
M
图中次序: x0, x1, x2, x3 次序可以任意
39
4.3.3 边缘填充算法 *
算法 2 (以边为中心的边缘填充算法)1 、将绘图窗口的背景色置为 ;2 、对多边形的每一条非水平边做:
从该边上的每个像素开始向右求余
M
40
特点 适合用于具有帧缓存的图形系统。处理后,按扫描线顺序读出帧缓存的内容,送入显示设备
优点:算法简单 缺点:对于复杂图形,每一像素可能被访问多次,输入 /输出的量比扫描线算法大得多
4.3.3 边缘填充算法 *
41
扇形区域的描述 圆的半径 R 起始角度: 1
终止角度: 2
原理:同扫描转换多边形 对每条扫描线,首先计算与扇形区域边界的交点,再用指定颜色绘制绘制配对交点间的像素
问题 如何确定扫描线与直线段和圆弧段的交点及相交顺序?
4.4 扫描转换扇形区域
42
方法:分类 按点 P1(x, y) 和 P2(x, y) 点所处象限的不同,需要将扇形区域分成 4×4=16 种情况
假设 P1 点落在第一象限 扫描线和区域边界只有 2 个交点扇形区域的扫描转换分四种情况(1) P2落在第一象限区域: OP1A 和 AP1P2
4.4 扫描转换扇形区域
43
(2)P2落在第二象限,此时又分为两种情况 当 时
三个区域: OAP1 、 AP1BP2 和 P2BC
当 时
三个区域: OAP2 、 AP1BP2 和 P1BC
4.4 扫描转换扇形区域
y y1 2
21 yy
),(),( 222
12
21
2yyRBy
y
xyA
),(),( 122
21
12
1yyRBy
y
xyA
44
(3) P2 落在第三象限
三个区域: P1CA 、 BOP1A 和 P2OB
(4) P2落在第四象限
三个区域: AP1D 、 BOP1 A 、 CP2OB
和 CEP2
4.4 扫描转换扇形区域
),0()0,(),( 121
2 RCRByyRA
),0()0,(
),(),( 222
21
21
2
RDRC
yyRByyRA
45
遗留问题:当 P1 落在其它区域时 ? P1 落在第二、三、四象限时,将扇形区域绕坐标原点顺时针旋转 90 度( 180 , 270 ),使 P1 落在第 1 象限
扫描转换 再逆时针旋转 90 度( 180 , 270 )
4.4 扫描转换扇形区域
P1P2P2
P1
P1落在第四象限
P2P1
P1落在第一象限
P1
P2
P1落在第四象限
旋转 270 度 扫描转换逆旋转 270度
46
区域:点阵表示的图形,像素集合表示方法:内点表示、边界表示内点表示
枚举出区域内部的所有像素 内部的所有像素为同一个颜色 边界像素与内部像素的颜色不同
边界表示 枚举出边界上所有的像素 边界上的所有像素为同一颜色 内部像素与边界像素的颜色不同
4.5 区域填充
47
种子填充法 对区域重新着色的过程 将指定的颜色从种子点开始扩展到整个区域 区域填充算法要求区域是连通的
4.5 区域填充
48
连通性 4 连通区域:区域中任意两点可通过上下左右四个方向互
相 到达 8 连通区域:区域中任意两点可通过上下左右和对角线八 个方向互相到达
4.5 区域填充
49
4.5 区域填充4 连通与 8 连通区域的区别
连通性: 4 连通可看作 8 连通区域,但对边界有要求不同
依据区域内点能否访问到区域外的点,对边界的要求是4 连通区域,边界只要 8 连通即可8 连通区域,边界必须是 4 连通
例:如左图( 1 ) 4 连通区域,边界为 像素( 2 ) 8 连通区域,边界为 和 像素
50
4.5.1 种子填充法种子填充算法(泛滥填充: flood-fill ) ( 1 )内点表示的 4 连通区域
种子 P(x,y) ,原色 oldColor ,新颜色 newColor
方法:先判断 P(x, y) 的颜色,若其值不等于 oldColor ,说明该像素位于区域外,或已设置为 newColor ,算法结束;
否则,置像素颜色为 newColor ,再对其相邻的上下左右四个像素分别作为种子作上述递归处理。
void FloodFill4(int x,int y,int oldColor,int newColor){ if(GetPixel(x,y) == oldColor) { SetPixel(x,y,newColor); FloodFill4(x,y+1,oldColor,newColor); FloodFill4(x,y-1,oldColor,newColor); FloodFill4(x-1,y,oldColor,newColor); FloodFill4(x+1,y,oldColor,newColor); }}/*end of FloodFill4() */
51
4.5.1 种子填充法
①FloodFill4(x, y+1, oldColor, newColor);②FloodFill4(x, y-1, oldColor, newColor);③FloodFill4(x-1, y, oldColor, newColor);④FloodFill4(x+1, y, oldColor, newColor);
52
( 2 )边界表示的 4 连通区域
4.5.1 种子填充法
void BoundaryFill4(int x, int y, int oldColor, int newColor){//oldColor 边界像素颜色 int color;
color = GetPixel(x, y); if((color != oldColor) && (color != newColor)) { SetPixel(x, y, newColor); BoundaryFill4(x,y+1,oldColor,newColor); BoundaryFill4(x,y-1,oldColor,newColor); BoundaryFill4(x-1,y,oldColor,newColor); BoundaryFill4(x+1,y,oldColor,newColor); }}/*end of BoundaryFill4( ) */
53
缺点 有些像素需要重复判断,降低算法效率 栈结构占空间 递归执行,算法简单,但效率不高,区域内每一像素都引起一次递归,进 / 出栈,费时费内存
改进 减少递归次数,提高效率 方法之一使用扫描线填充算法
4.5.1 种子填充法
54
4.5.2 扫描线算法 *
扫描线算法 目标:减少递归层次 适用于内点表示的 4 连通区域 基本过程:
当给定种子点时,首先填充种子点所在的扫描线上的位于给定区域的一个区段,然后确定与这一区段相通的上下两条扫描线上位于给定区域内的区段,并依次保存下来。反复这个过程,直到填充结束
55
4.5.2 扫描线算法 *
算法步骤 1 、初始化 :将种子区段压入堆栈 2 、出栈:如果堆栈为空,则算法结束;
否则取栈顶元素 (x,y)作为种子点 3 、区段填充:从种子点 (x, y) 开始沿纵坐标为 y 的扫描行向左右两个方向逐个像素填色,直到边界为止
4 、定范围:以 [xLeft, xRight] 为 (3)得到的区段 5 、进栈:分别在与当前扫描线相邻的上下扫描线上,确定位于区间 [xLeft, xRight] 内的区段。
如果区段内的像素颜色值为 newColor 或 boundaryColor ,则转到( 2 )
区段压入堆栈,转到( 2 )
56
• 例
4.5.2 扫描线算法 *
像素中的序号标指它所在区段位于堆栈中的位置
57
多边形扫描转换与区域填充方法比较 基本思想不同
前者:顶点表示转换成点阵表示后者:只改变区域内填充颜色,没有改变表示方法
对边界的要求不同前者:扫描线与多边形边界交点个数为偶数后者:区域封闭,防止递归填充跨界
基本的条件不同前者:从边界顶点信息出发后者:区域内种子点
4.5.3 扫描转换与区域填充的比较
58
填充方式 ( 1 )均匀着色( 2 )位图不透明 (3) 位图透明 (4) 像素图填充 在确定区域内的像素后,查询它对应的位图或图像中的单元,再以该单元的值按填充方式的不同显示该像素
方法 (1)均匀着色方法:将图元内部像素置成同一颜色 (2) 位图不透明:若像素对应的位图单元为 1 ,则以前景色显示
该像素;若为 0 ,则以背景色显示该像素; (3) 位图透明:若像素对应的位图单元为 1 ,则以前景色显示该
像素;若为 0 ,则不做任何处理。 (4) 像素图填充:以像素对应的像素图单元的颜色值显示该像素。
4.6 以图像填充区域
59
基本问题 建立区域与图像间的对应关系方法 1 :建立整个绘图空间与图像空间的 1-1映射
4.6 以图像填充区域
图像(纹理) 绘图空间
60
例
适用:动画中漫游图像,如透过车窗看外景
4.6 以图像填充区域
61
方法 2 :建立区域局部坐标空间与图像空间的 1-1映射
4.6 以图像填充区域
适用:图像作为区域表面属性的情况,例如,桌面与其上的木纹
62
字符集 ASCII 码: 128 个字符 GB2312 - 80 :汉字 6763 个, 682 个图形符号
点阵字体 存储(压缩与非压缩) 显示:检索与写缓冲
矢量字体 表示:笔画组成曲线(参数) 扫描转换:参数到点阵 显示: 1 、由编码检索 2 、扫描转换 存储:空间少 ( windows 下的仿宋体库: SIMFANG.TTF 为 3904
K )
4.7 字符的表示与输出
63
4.8 OpenGL相关函数区域函数(填充作用)
矩形函数: glRect[i|s|f|d]{v}() glBegin() 中的参数 GL_POLYGON 、 GL_TRIANGLES 、
GL_TRIANGLE_STRIP 、 GL_TRIANGLE_FAN
三角形的三种绘制参数int p1[]={20,100},p2[]={50,50};int p3[]={110,50},p4[]={140,100};int p5[]={110,150},p6[]={50,150};
glBegin(GL_TRIANGLES); glVertex2iv(p1); glVertex2iv(p2); glVertex2iv(p3); glVertex2iv(p4); glVertex2iv(p5); glVertex2iv(p6);glEnd();
GL_TRIANGLE_STRIP
GL_TRIANGLES
GL_TRIANGLE_FAN
p1
p1
p1
64
菜单函数 int glutCreateMenu(void (*func)(int value));//创建菜单 void glutAddMenuEntry(char *name, int value);//添加菜单项 void glutAddSubMenu(char *name, int menu);//添加子菜单 glutAttachMenu(int button);
例:
4.8 OpenGL相关函数
void MenuInit(){ int sub_menu1 = glutCreateMenu(objectMenu);
glutAddMenuEntry(" 直线 ",11); glutAddMenuEntry(" 多边形 ",12); glutCreateMenu(topMenu); glutAddSubMenu(" 图形 ",sub_menu1); glutAddMenuEntry(" 退出 ",2); glutAttachMenu(GLUT_RIGHT_BUTTON);}
void objectMenu(int id){ if (id==11) GraphicsType = 11; else if (id==12) GraphicsType = 12; else GraphicsType = 0;}void topMenu(int id){ if (id==2) exit(0);}
65
线框图与填充图 函数: glPloygonMode(face , displayMode) face :指定前后面。可选值: GL_FRONT 、 GL_BACK 和
GL_FRONT_AND_BACK displayMode : GL_FILL 和 GL_LINE
4.8 OpenGL相关函数
void display (void){ glClearColor (1.0, 1.0, 1.0, 0.0); glClear (GL_COLOR_BUFFER_BIT); glPolygonMode(GL_FRONT, GL_LINE); glBegin(GL_POLYGON); glColor3f(1.0,0,0); glVertex2f(0.5,0); glVertex2f(-0.5,0.5); glVertex2f(-0.5,-0.5); glVertex2f(0.6,-0.5); glEnd();
glFlush();}
前向面:顶点序列逆时针顺序排列
66
颜色插值模式 函数: glShadeModel(mode) Mode: GL_FLAT 和 GL_SMOOTH 例:
4.8 OpenGL相关函数
void display (void){ glClearColor (1.0, 1.0, 1.0, 0.0); glClear (GL_COLOR_BUFFER_BIT); glShadeModel(GL_FLAT);// 默认为 GL_SMOOTH glBegin(GL_POLYGON); glColor3f(1,0,0); glVertex2f(-0.5,0.5); glColor3f(0,1,0); glVertex2f(-0.5,-0.5); glColor3f(0,0,1); glVertex2f(0.5,-0.5); glColor3f(1,1,1); glVertex2f(0.5,0.5); glEnd();
glFlush();}
GL_FLAT 方式下以第 1 个点颜色填充
67
顶点数组 原因:复杂图形需要很多坐标描述,导致函数调用量大增,影响程序的执行效率
采用顶点数组减少函数调用 方法
调用函数 glEnableClientState(GL_VERTEX_ARRAY), 激活顶点数组特性
调用 glVertexPointer 指定顶点坐标的位置和数据格式 使用与数组相关的函数绘制图形
4.8 OpenGL相关函数
68
例:glClear (GL_COLOR_BUFFER_BIT);
glColor3f (1.0, 0.0, 0.0);
vertex2 pt[]={{20,100},{50,50},{110,50},{140,100},{110,150},{50,150}};
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2,GL_INT,0,pt);
GLubyte vertIndex[]={0,1,2,3,4,5};
glDrawElements(GL_TRIANGLES,24,GL_UNSIGNED_BYTE, vertIndex);
glFlush ( );
4.8 OpenGL相关函数
69
4.8 OpenGL相关函数写像素模式
16 种,默认方式为 GL_COPY 模式改变时,需要调用
glEnable ( GL_COLOR_LOGIC_OP ) 设置模式: glLogicOp ( GL_XOR ) 例:异或模式
00000000 11111111 11111111
000000001111111100000000
000000000000000011111111
00000000 11111111 00000000
000000001111111100000000
000000000000000000000000
Xor
Xor背景
正方形
70
4.8 OpenGL相关函数填充图案函数
启用函数: glEnable ( GL_POLYGON_STIPPLE ) 关闭函数: glDisable ( GL_POLYGON_STIPPLE ) 设置掩模( mask ): glPolygonStipple ( fillPattern ) 注意: filePattern 类型为 GLubyte ,大小为 32×32
GLubyte fillPattern[]= {0x96,0x96,0x96,0x96, 0x84,0x84,0x84,0x84,
0x48,0x48,0x48,0x48, 0x20,0x20,0x20,0x20, 0x10,0x10,0x10,0x10, 0x10,0x10,0x10,0x10, 0x18,0x18,0x18,0x18, 0x64,0x64,0x64,0x64,
。。。。 ( 重复 3 次 ) }
71
4.8 OpenGL相关函数 OpenGL 位图函数
void glRasterPos{234}{SIFD}[V](TYPE x, TYPE y,
TYPE z, TYPE w);
设置当前所画位图或图像的原点 glBitmap(width, height, x0,y0,xOffset,yOffset,bitShape)
设定当前光栅位置 该函数显示二值位图。 bitShape 中的元素值为 0 或 1 ,当为 1时,用设定的颜色绘制对应的像素,否则对应像素不受影响
位图的存储模式:字节 glPixelStorei (
GL_UNPACK_ALIGNMENT, 1 ) ;
72
4.8 OpenGL相关函数程序 void display()
{ // 最好放在初始化函数中 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glColor3f (0.0, 0.0, 0.0); glRasterPos2i (100, 200); glBitmap (8, 12, 0.0, 0.0, 20.0, 20.0, rasters);
glColor3f (1.0, 0.0, 0.0); glRasterPos2i (120, 220); glBitmap (8, 12, 0.0, 0.0, 0.0, 0.0, rasters);
glColor3f (0.0, 0.0, 1.0); glRasterPos2i (150, 200); glBitmap (8, 12, 0.0, 0.0, 0.0, 0.0, rasters);
glFlush ( );}
rasters
73
4.8 OpenGL相关函数绘制字符
OpenGL 基本库:位图方法,需要自己创建字库 GLUT工具包:位图和轮廓字体 位图字符函数: glutBitmapCharacter(font, character)
font: 指定字型,常量(如 GLUT_BITMAP_8_BY_13 ) Character :字符的 ASCII 码值
轮廓字符函数: glutStrokeCharacter(font, character) font: 指定字型,常量(如 GLUT_STROKE_ROMAN ) Character :字符的 ASCII 码值
位图和轮廓字符比较前者速度快,后者放大缩小不变形
74
4.8 OpenGL相关函数程序
void display(){ glColor3f (1.0, 0.0, 0.0); glRasterPos2i (50, 50); glutBitmapCharacter (GLUT_BITMAP_9_BY_15,66); glRasterPos2i (80, 50); glutBitmapCharacter (GLUT_BITMAP_TIMES_ROMAN_10,66);
glColor3f (0.0, 0.0, 1.0); glPushMatrix(); glTranslatef(50,100,0);glScalef(0.2,0.2,1); glutStrokeCharacter(GLUT_STROKE_ROMAN,66); glPopMatrix();
glTranslatef(100,100,0); glScalef(0.6,0.6,1); glutStrokeCharacter(GLUT_STROKE_ROMAN,66); glutSwapBuffers();}
75
小结多边形的扫描转换
点是否在区域内的判断方法(射线法) 扫描线算法(思想、步骤和算法实现)
多边形的区域填充 种子填充(连通性)
扇形区域的扫描转换字符的绘制方法 OpenGL 函数
76
作业1 、多边形扫描转换的扫描线算法利用了扫描线的连贯性和边
的连贯性,在数据结构和算法中各体现在何处?2 、一个多边形的顶点坐标如下图所示。 ( a )写出边的分类表 ( b )说明扫描线 y = 6 , 7 , 8 , 9 和 10 时,哪些边
是活性边。并给出活性边表。
77
作业3 、内点表示的区域和边界表示的区域在填充时有什么不同?
4 、根据三角形的特殊性,如何简化扫描转换三角形的扫描线算法。
78
上机题 1:补充添加填充图元的功能
填充多边形 多边形交互输入、颜色定义和填充