Presentation is loading. Please wait.

Presentation is loading. Please wait.

第三章 输出图元 讲 授:董兰芳 研究方向:科学计算可视化 图形、图像处理 模式识别 中国科学技术大学 视觉计算与可视化实验室

Similar presentations


Presentation on theme: "第三章 输出图元 讲 授:董兰芳 研究方向:科学计算可视化 图形、图像处理 模式识别 中国科学技术大学 视觉计算与可视化实验室"— Presentation transcript:

1 第三章 输出图元 讲 授:董兰芳 研究方向:科学计算可视化 图形、图像处理 模式识别 中国科学技术大学 视觉计算与可视化实验室
讲 授:董兰芳 研究方向:科学计算可视化 图形、图像处理 模式识别 Telephone: Homepage: 中国科学技术大学 视觉计算与可视化实验室

2 第三章 输出图元 图元的生成:从图元的参数表示形式(由图形软件包 的使用者指定)到点阵表示形式(光栅显示系统刷新时所 需的表示形式)的转换。

3 第三章 输出图元 3.1 画线算法 3.2 帧缓冲器的装载 3.3 圆、椭圆和圆弧的生成 3.4 其它曲线 3.5 并行画线算法
3.1 画线算法 3.2 帧缓冲器的装载 3.3 圆、椭圆和圆弧的生成 3.4 其它曲线 3.5 并行画线算法 3.6 像素编址和对象的几何要素 3.7 保留显示物体的几何特性 3.8 填充区图元 3.9 多边形填充区

4 3.1 画线算法 3.1.1 DDA画线算法 3.1.2 Bresenham画线算法 3.1.3 并行画线算法 3.1.4 画线算法的讨论

5 3.1.1 DDA画线算法 直线段生成 求与直线段充分接近的 像素集 像素间网格均匀 坐标是整型 假设 直线段的宽度为1 线段的生成

6 3.1.1 DDA画线算法 数字微分(DDA)画线算法 (Digital Differential Analyzer)

7 3.1.1 DDA画线算法 数字微分(DDA)画线算法 (digital differential analyzer) 直接求交算法:
划分区间[0, 1],dt=1/n 计算坐标 取整 复杂度:乘法+加法+取整

8 3.1.1 DDA画线算法 DDA增量算法 xi+1=x1+∆x*ti+1=xi+∆x*dt=xi+xinc
yi+1=y1+∆y*ti+1=yi+∆y*dt=yi+yinc 复杂度:加法+取整

9 3.1.1 DDA画线算法 DDA算法优点 DDA算法缺点: xi+1=xi+xinc yi+1=yi+yinc
利用光栅特性消除了直线方程中的乘法,比直接使用直线方程的计算速度快! DDA算法缺点: 取整误差的积累使得对于较长线段所计算的像素位置偏离实际线段。 需要进行浮点数运算。 运行效率低。 不便于用硬件实现 。

10 3.1 画线算法 3.1.1 DDA画线算法 3.1.2 Bresenham画线算法 3.1.3 并行画线算法 3.1.4 画线算法的讨论

11 3.1.2 Bresenham画线算法 目标:消除DDA算法中的浮点运算 线段的端点坐标:(x1,y1)和(x2,y2)
线段方程:y=mx+b

12 3.1.2 Bresenham画线算法 Bresenham画线算法思想 (xk,yk)是直线段上的点 H:(xk+1,yk+1)
L:(xk+1,yk) A: (xk+1,y)=(xk+1,m(xk+1)+b) dlower>dupper,取H点 dlower<dupper,取L点 dlower=dupper,选择H或L均可 令p= dlower-dupper, p> 0取上像素 (xk+1, yk+1) , p< 0 采用下像素(xk+1, yk)。

13 3.1.2 Bresenham画线算法 y=m(xk+1)+b dlower=y-yk=m(xk+1)+b-yk
dupper=yk+1-y=yk+1-m(xk+1)-b dlower-dupper=2m(xk+1)-2yk+2b-1 m= 2Δy /Δx pk=Δx(dlower-dupper)=2Δy .xk-2Δx .yk+c pk+1= 2Δy .xk+1- 2Δx .yk+1+c pk+1-pk=2Δy(xk+1-xk)-2Δx(yk+1-yk) pk+1=pk +2Δy(xk+1-xk)-2Δx(yk+1-yk) xk+1-xk=1 pk+1=pk +2Δy-2Δx(yk+1-yk) pk+1> 0取上像素,pk+1< 0 取下像素。 yk+1-yk=0或1,取绝于参数pk的符号。

14 3.1.2 Bresenham画线算法 在x=x1 +1处,dlower=m, dupper=1-m, p1= 2Δy – Δx
只包括整数的加法、减法和左移(乘2)操作,效率高。 适合用硬件实现。 思考:Bresenham画线算法如何应用到其它卦限?

15 3.1.2 Bresenham画线算法 2月21日作业1 实现一个折线函数,用Bresenham画线算法来显示连接n个输入点的一组线段。当n=1时绘制单个点。

16 3.1 画线算法 3.1.1 DDA画线算法 3.1.2 Bresenham画线算法 3.1.3 并行画线算法 3.1.4 画线算法的讨论

17 3.1.3 并行画线算法 让每一个处理器处理一组像素 适用于系统中的处理器非常多 的场合。 给定一条线段,可以得到它的
包围盒,包围盒中共有∆x*∆y 个像素。让每个处理器处理一 个像素,设像素的坐标为(x,y), 则像素到线段的垂直距离: d=A*x+B*y+C 其中,A=-∆y/linelength B=∆x/linelength C=(x1∆x-y1∆x)/linelength 线段的包围盒

18 3.1.3 并行画线算法 像素到线段的垂直距离: d=A*x+B*y+C 其中,A=-∆y/linelength
线段的包围盒 像素到线段的垂直距离: d=A*x+B*y+C 其中,A=-∆y/linelength B=∆x/linelength C=(x1∆x-y1∆x)/linelength Linelength=(∆x2+∆y2)1/2 d小于某个设定值,该像素就被 设置成指定的线段颜色。可以看出, 这种并行画线算法特别适合于画具有 一定宽度的线段。

19 3.1 画线算法 3.1.1 DDA画线算法 3.1.2 Bresenham画线算法 3.1.3 并行画线算法 3.1.4 画线算法的讨论

20 3.1.4 画线算法的讨论 线段端点的次序要求 :线段P1P2与线段P2P1在图元生成后应该生成相同的像素集合,这样才能保证同一线段的像素表示与线段的端点次序无关。 存在问题:前述算法中,线段P1P2与线段P2P1上的点可能不一致。 解决方法:对于|k|≤1的线段,总是以左端点为 起点,从左向右生成;对于|k|>1的线段,总是以下 端点为起点,从下向上生成。

21 3.1.4 画线算法的讨论 线段的亮度 现象:A比B亮。 原因:A上的像素点密集。 解决方法:图形保真技术。

22 3.1 画线算法 3.1.1 DDA画线算法 3.1.2 Bresenham画线算法 3.1.3 并行画线算法 3.1.4 画线算法的讨论

23 第三章 输出图元 3.1 画线算法 3.2 帧缓冲器的装载 3.3 圆、椭圆和圆弧的生成 3.4 其它曲线 3.5 并行画线算法
3.1 画线算法 3.2 帧缓冲器的装载 3.3 圆、椭圆和圆弧的生成 3.4 其它曲线 3.5 并行画线算法 3.6 像素编址和对象的几何要素 3.7 保留显示物体的几何特性 3.8 填充区图元 3.9 多边形填充区

24 3.2 帧缓冲器的装载 addr(x,y)=addr(0,0)+y*xmax+x addr(x+1,y)=addr(x,y)+1
addr(x+1,y+1)=addr(x,y)+xmax+1

25 第三章 输出图元 3.1 画线算法 3.2 帧缓冲器的装载 3.3 圆、椭圆的生成 3.4 其它曲线 3.5 并行画线算法
3.1 画线算法 3.2 帧缓冲器的装载 3.3 圆、椭圆的生成 3.4 其它曲线 3.5 并行画线算法 3.6 像素编址和对象的几何要素 3.7 保留显示物体的几何特性 3.8 填充区图元 3.9 多边形填充区

26 3.3 圆、椭圆的生成 3.3.1 圆的生成 3.3.2 椭圆的生成

27 3.3.1 圆的生成 处理对象:圆心在原点的圆弧 圆的八对称性 两种直接离散方法: 离散点: x2+y2=R (x,sqrt(R2-x2))
离散角度:x=Rcosθ y=Rsinθ 缺点:计算量大。

28 3.3.1 圆的生成 圆弧的正负划分性 F(x,y)=x2+y2-R2 圆弧外的点:F(X,Y)>0 圆弧内的点:F(X,Y)<0

29 3.3.1 圆的生成 中点画圆算法的优点: 效率高。 只用到整数的加法、 减法和左移。 (乘2)运算。 适合用硬件实现。 中点画圆算法示意图

30 3.3.1 圆的生成

31 3.3.1 圆的生成

32 3.3.1 圆的生成 2月21日作业2 教材P

33 3.3 圆、椭圆的生成 3.3.1 圆的生成 3.3.2 椭圆的生成

34 3.3.2 椭圆的生成 椭圆 通过椭圆上任 一点到两个焦点 的距离之和等于 常数。
椭圆方程f(x,y)=ry2x2+rx2y2-rx2ry2=0。 椭圆的对称性。

35 第三章 输出图元 3.1 画线算法 3.2 帧缓冲器的装载 3.3 圆、椭圆的生成 3.4 其它曲线 3.5 并行画线算法
3.1 画线算法 3.2 帧缓冲器的装载 3.3 圆、椭圆的生成 3.4 其它曲线 3.5 并行画线算法 3.6 像素编址和对象的几何要素 3.7 保留显示物体的几何特性 3.8 填充区图元 3.9 多边形填充区

36 3.4 其他曲线 3.4.1 画锥曲线 Ax2+By2+Cxy+Dx+Ey+F=0 3.4.2 多项式曲线
画锥曲线 多项式曲线 Ax2+By2+Cxy+Dx+Ey+F=0 y=a0+a1x+a2x2+……an-1xn-1+anxn

37 第三章 输出图元 3.1 画线算法 3.2 帧缓冲器的装载 3.3 圆、椭圆和圆弧的生成 3.4 其它曲线 3.5 并行画线算法
3.1 画线算法 3.2 帧缓冲器的装载 3.3 圆、椭圆和圆弧的生成 3.4 其它曲线 3.5 并行画线算法 3.6 像素编址和对象的几何要素 3.7 保留显示物体的几何特性 3.8 填充区图元 3.9 多边形填充区

38 3.5 并行曲线画法 圆:等份圆弧或x坐标 椭圆或其它曲线:扫描线分段方法

39 第三章 输出图元 3.1 画线算法 3.2 帧缓冲器的装载 3.3 圆、椭圆和圆弧的生成 3.4 其它曲线 3.5 并行曲线算法
3.6 像素编址和对象的几何要素 3.7 保留显示物体的几何特性 3.8 多边形的填充 3.9 区域填充图元

40 3.6 像素编址和对象的几何要素 当对象经扫描转换进帧缓存后,输入描述变换为 对应有限屏幕区域的像素坐标,且显示的光栅图像
可能并不严格符合相关的尺寸。 解决方法: 简单地按照物体边界与像素区域的覆盖量来 调整物体的显示尺寸。 将世界坐标系映射到像素间的屏幕位置,使物 体的边界与像素边界对齐,而不是与像素中心对 齐。 屏幕上( x,y)占据对角位置(x,y)和(x+1,y+1)处 的单位正方形。

41 第三章 输出图元 3.1 画线算法 3.2 帧缓冲器的装载 3.3 圆、椭圆和圆弧的生成 3.4 其它曲线 3.5 并行画线算法
3.1 画线算法 3.2 帧缓冲器的装载 3.3 圆、椭圆和圆弧的生成 3.4 其它曲线 3.5 并行画线算法 3.6 像素编址和对象的几何要素 3.7 保留显示物体的几何特性 3.8 填充区图元 3.9 多边形填充区

42 3.7 保留显示的物体的几何特性 将物体的几何描述转换为象素 表示时,将把数学上的点转换为有 限的屏幕区域.假如要保留由物体 的输入坐标指定的原始几何度量, 那么在将物体的定义转换到屏幕 显示时,就需要考虑象素的有限尺 寸。

43 第三章 输出图元 3.1 画线算法 3.2 帧缓冲器的装载 3.3 圆、椭圆和圆弧的生成 3.4 其它曲线 3.5 并行画线算法
3.1 画线算法 3.2 帧缓冲器的装载 3.3 圆、椭圆和圆弧的生成 3.4 其它曲线 3.5 并行画线算法 3.6 像素编址和对象的几何要素 3.7 保留显示物体的几何特性 3.8 填充区图元 3.9 多边形填充区

44 3.8 填充区图元 填充区 表面细分

45 第三章 输出图元 3.1 画线算法 3.2 帧缓冲器的装载 3.3 圆、椭圆和圆弧的生成 3.4 其它曲线 3.5 并行画线算法
3.1 画线算法 3.2 帧缓冲器的装载 3.3 圆、椭圆和圆弧的生成 3.4 其它曲线 3.5 并行画线算法 3.6 像素编址和对象的几何要素 3.7 保留显示物体的几何特性 3.8 填充区图元 3.9 多边形填充区 3.10 OpenGL学习

46 3.9 多边形填充区 多 边 形:由三个或更多称为顶点的坐标位置描述的 平面图形。 分 类:凸多边形或凹多边形。
分 类:凸多边形或凹多边形。 退化多边形:共线或重叠坐标位置的顶点集。

47 3.9 多边形填充区 多边形的表示方法 顶点表示 点阵表示

48 3.9 多边形填充区 逐个判断绘图窗口内的像素: 如何判断点与多边形的内外关系? 逐点判断法程序简单, 速度太慢,效率低!

49 3.9 多边形填充区 #define MAX 100 Typedef struct { int PolygonNum; // 多边形顶点个数
Point vertexces[MAX] //多边形顶点数组 } Polygon // 多边形结构 void FillPolygonPbyP(Polygon *P,int polygonColor) { int x,y; 计算 ymin,ymax,xmin,xmax; for(y = ymin;y <= ymax;y++) for(x = xmin;x <= xmax;x++) if(IsInside(P,x,y)) PutPixel(x,y,polygonColor); else PutPixel(x,y,backgroundColor); }/*end of FillPolygonPbyP() */

50 3.9 多边形填充区 射线法 由点Pc(xc,yc)出发向任意方向作射线,计算此射线与 多边形所有交点个数,如果交点个数为奇数,则点在多边
形内部,如果交点个数为偶数,则点在多边形外部.

51 3.9 多边形填充区 多边形网格由若干个相邻的多边形(polygon)组成, 每个多边形由若干条首尾相连的边(edge)组成,每条边
连接两个顶点(vertice),一个顶点至少连接两条边, 一条边至少属于一个多边形并且至多连接两个相邻的多边 形。

52 3.9 多边形填充区

53 3.9 多边形填充区 多边形网格表示的方法: 显式表示 指向顶点表的指针 指向边表的指针 方程表示

54 3.9 多边形填充区 显式表示: P1={(x1,y1,z1), (x2,y2,z2), (x4,y4,z4)}
显式表示的缺点: 浪费空间 没有给出共享顶点与共享边的信息 重复描画 P1={(x1,y1,z1), (x2,y2,z2), (x4,y4,z4)} P2={(x4,y4,z4), (x2,y2,z2), (x3,y3,z3)}

55 3.9 多边形填充区 指向顶点表的指针 每个顶点只在顶点表V={(x1,y1,z1), (x2,y2,z2),…,
(xn,yn,zn)}中存储一次,每个多边形都用指向顶点表 的指针(或索引)列表来表示。 优点:节省空间,便于修改顶点坐标。 缺点:找出共享某一条边的多边形仍然很困难,在画 多边形网格时,共享边仍然会被画两次。

56 3.9 多边形填充区 V={V1,V2,V3,V4}={(x1,y1,z1),…, (x4,y4,z4)}
P1={V1,V2,V4} P2={V4,V2,V3}

57 3.9 多边形填充区 指向边表的指针 用指向边表的指针来表示多边形网格时,每个顶点仍然 只在顶点表V中存储一次,但每个多边形不再用指向顶点表
的指针来表示,而是用指向边表的指针来表示。 边表中每条边只存储一次,每条边都包括构成该边的两 个顶点(用在顶点表中的索引来表示)。 V={V1,V2,V3,V4}={(x1,y1,z1),…, (x4,y4,z4)} E={E1,E2,E3,E4,E5}={(V1,V2),(V2,V3),(V3,V4), (V4,V2),(V4,V1)} P1={E1,E4,E5} P2={E2,E3,E4}

58 3.9 多边形填充区 对多边形网格的典型操作: 确定共享某一顶点的所有边。 确定共享某一顶点或某一条边的所有多边形。
确定构成某一条边的两个顶点。 确定构成某一多边形的所有边。 进行合法性检查(如孤立顶点、边或多边形)等等。

59 3.9 多边形填充区 例1 #Vertex //点数据 #skinhead //特征名称
//点的坐标 …… #facet //面数据 #skinhead //特征名称 //点的索引值

60 3.9 多边形填充区 例2 e …… 网格 624

61 3.9 多边形填充区 V1 V2 V3 V4 V5 E1 E2 E3 E4 E5 E6 S1 S2 多边形表示例子 顶点表
V1:x1,y1,z1 V2:x1,y1,z1 V3:x1,y1,z1 V4:x1,y1,z1 V5:x1,y1,z1 在边表中扩充了 指向面片表的指针 E1:V1,V2,S1 E2:V2,V3,S1 E3:V3,V1,S1,S2 E4:V3,V4,S2 E5:V4,V5,S2 E6:V5,V1,S2 边表 E1:V1,V2 E2:V3,V4 E3:V1,V3 E4:V3,V4 E5:V5,V4 E6:V1,V5 面片表 S1:E1,E2,E3 S2:E3,E4,E5,E6

62 3.9 多边形填充区 凹多边形识别:凹多边形至少有一个内角大于180。 识别凹多边形:通过计算连续两边向量的叉积来识别凹多边形。
向量叉积:E1╳E2=(E1yE2z-E1zE2y, E1zE2x-E1xE2z, E1xE2y-E1yE2x) V1 V2 V3 V4 V5 V6 E1 E2 E3 E4 E5 E6 (E1 ╳ E2)z>0 (E2 ╳ E3)z>0 (E3 ╳ E4)z<0 (E4 ╳ E5)z>0 (E5 ╳ E6)z>0 (E6 ╳ E1)z>0

63 3.9 多边形填充区 分割凹多边形:向量方法 E1= (1,0,0) E2= (1,1,0) E3= (1,-1,0)
1 2 E1= (1,0,0) E2= (1,1,0) E3= (1,-1,0) E4= (0,2,0) E5= (-3,0,0) E6= (0,-2,0) E1 ╳ E2=(0,0,1) E2 ╳ E3=(0,0,-2)z<0 E3 ╳ E4=(0,0,2) E4 ╳ E5=(0,0,6) E5 ╳ E6=(0,0,6) E6 ╳ E1=(0,0,2) 延长E2分割多边形。

64 3.9 多边形填充区 方程表示 Ax+By+Cz+D=0 (A/D)x+(B/D)y+(C/D)z=-1
将平面上不共线的三个点的坐标(x1,y1,z1)、(x2,y2,z2)和(x3,y3,z3)代入上式。 (A/D)x1+(B/D)y1+(C/D)z1=-1 (A/D)x2+(B/D)y2+(C/D)z2=-1 (A/D)x3+(B/D)y3+(C/D)z3=-1

65 3.9 多边形填充区 假设平面的法向量为N,P为平面上任意一点, 则N.P=-D。 点在平面上 Ax+By+Cz+D=0 点在平面后方
点在平面前方 Ax+By+Cz+D>0

66 第三章 输出图元 3.1 画线算法 3.2 帧缓冲器的装载 3.3 圆、椭圆和圆弧的生成 3.4 其它曲线 3.5 并行画线算法
3.1 画线算法 3.2 帧缓冲器的装载 3.3 圆、椭圆和圆弧的生成 3.4 其它曲线 3.5 并行画线算法 3.6 像素编址和对象的几何要素 3.7 保留显示物体的几何特性 3.8 填充区图元 3.9 多边形填充区 3.10 OpenGL学习

67 3.10 OpenGL学习 多边形 像素阵列 字符图元 显示列表 显示窗口重定形

68 3.10 OpenGL学习 glVertex() glRect*() glRecti(200,100,50,250)
int vertext1[]={200,100} int vertex2[]={50,250} glRectv(vertex1,vertex2) glBegin(GL_POLYGON) glVertex2iv(p1); glVertex2iv(p2); glVertex2iv(p3); glVertex2iv(p4); glVertex2iv(p5); ……. glEnd();

69 3.10 OpenGL学习 顶点数组 typedef Glint vertex3[3]; vertex3
pt[8]={ {0,0,0},{0,1,0},{1,0,0},{1,1,0},{0,0,1},{0,1,1}, {1,0,1}, {1,1,1}}; void quad(Glint n1,Glint n2,Glint n3,Glint n4) { glBegin(GL_QUADS); glVertex3iv(pt[n1]); glVertex3iv(pt[n2]); glVertex3iv(pt[n3]); glVertex3iv(pt[n4]); glEnd }

70 3.10 OpenGL学习 复杂的场景描述需要使用几百或几千个坐标描述.另外还必须为各个对象建立各种属性和观察参数。
对象和场景的描述要使用大量的函数调用,这对对系统资源提出了要求并减慢了图形程序的执行。 为了简化这些问题,OpenGL提供了一种机制来减少函数调用。 glEnableClient(GL_VERTEX_ARRAY); glVertexPointer(3,GL_INT,0,pt); GLubyte vertIndex[]=(6,2,3,7,….); glDrawElements(GL_QUADS,24,GL_UNSIGNED_BYTE, vertIndex); glDisableClientState(GL_VERTEX_ARRAY);

71 3.10 OpenGL学习 多边形 像素阵列 字符图元 显示列表 显示窗口重定形

72 3.10 OpenGL学习 缓存都是离散的内存块,由其空间分辨率n*m和每个像 素的位数(深度)k确定。
把缓冲区k个平面中的任一个称为位平面 (bitplane), 空间中特定位置处的k个元素构成一个像素(pixel), 因此一个像素既可以是一个字节,也可以是一个整数, 甚至是一个浮点数,具体与所用的缓存以及信息的存 放格式有关。

73 3.10 OpenGL学习 应用程序通过OpenGL函数把信息传送到帧缓存, 或者从帧缓存中获取信息。
当应用程序读写像素时,数据不仅要在内存与 图形卡里的帧缓存之间传输,而且还要重新调整 这些数据的格式,使之与帧缓存匹配。

74 3.10 OpenGL学习 颜色缓存内容要被输出到显示设备上。 在双缓存中,颜色缓存由两个缓存组成,分别用于读与写,称为前缓存与后缓存。
颜色缓存k确定可以表示的颜色的多少,通常在RGB模式中为24位,在RGBA模式中为32位。 深度缓冲区的k值确定深度的分辨率,通常是32位,这样与浮点数或整数的精度匹配。

75 3.10 OpenGL学习 数字图像:有限数字数值像素的表示。 合成图像:把几何对象和照相机组合在一起,通过某种 投影过程所得到的结果。
在程序中的图像是像素数组,其大小与类型各异,具 体与图像的类型有关。 对于RGB图像,每一个颜色分量由一个字节表示,则可以定义为:GLubyte myimage[512][512][3]; 如果处理的是单色图像或者灰度图像,那么可以 定义为GLubyte myimage[512][512];

76 3.10 OpenGL学习 创建图像的一种方法就是利用程序代码。 创建512×512由8×8黑白相间方格构成的图像,代码如下:
GLubyte check[512][512][3]; int i,j,k; for(i=0;i<512;i++) for(j=0;j<512;j++) { for(k=0;k<3;k++) check[i][j][k]=0; if((8*(i+j)/64)%64) check[i][j][0]=255; } 从数据获取。 应用光学成像设备摄取。

77 3.10 OpenGL学习 从数码设备采集的图像是以某种“标准”的格式存储的,最常用格式有BMP、GIF、TIFF、PS、EPS以及JPEG。 以某种顺序存储数据,并进行必要的无损压缩或者有损 压缩编码都是为了满足某类应用软件的需要而提出的。

78 3.10 OpenGL学习 BMP图像格式:Windows采用的图形文件格式 位图文件头
(bitmap-fileheader) BITMAPFILEHEADER bmfh   位图信息头 (bitmap-information header) BITMAPINFOHEADER bmih  彩色表 (color table) RGBQUAD aColors[]  图象数据阵列字节  BYTE aBitmapBits[] 

79 3.10 OpenGL学习 位图文件头包含有关于文件类型、文件大小、存放 位置等信息,在Windows 3.0以上版本的位图文件中用
 位图文件头包含有关于文件类型、文件大小、存放 位置等信息,在Windows 3.0以上版本的位图文件中用 BITMAPFILEHEADER结构来定义: typedef struct tagBITMAPFILEHEADER {  /*bmfh*/  UINTbfType; DWORDbfSize;  UINTbfReserved1;  UINTbfReserved2;  DWORD bfOffBits; } BITMAPFILEHEADER; 

80 3.10 OpenGL学习 位图信息头位图信息用BITMAPINFO结构来定义,它由
位图信息头(bitmap-information header)和彩色表(color table)组成,前者用BITMAPINFOHEADER结构定 义,后者用RGBQUAD结构定义。 BITMAPINFO结构具有如下形式:  typedef struct tagBITMAPINFO {  /* bmi */  BITMAPINFOHEADER bmiHeader; RGBQUAD bmiColors[1]; } BITMAPINFO; 

81 3.10 OpenGL学习 BITMAPINFOHEADER结构包含有位图文件的大小、压缩类型和
颜色格式,其结构定义为:  typedef struct tagBITMAPINFOHEADER { /* bmih */  DWORD biSize;  LONG biWidth;  LONG biHeight;  WORD biPlanes;  WORD biBitCount;  DWORD biCompression;  DWORD biSizeImage;  LONG biXPelsPerMeter;  LONG biYPelsPerMeter;  DWORD biClrUsed;  DWORD biClrImportant; } BITMAPINFOHEADER; 

82 3.10 OpenGL学习 图像格式与OpenGL 为了从某种格式中解析出像素数组,需要知道格式的 定义。
数组。

83 3.10 OpenGL学习 在现代的计算机图形系统中,用户程序既可 以向缓存中写入数据,也可以从中读取数据。
对缓存的读写通常是一个矩形的像素块(位块, bit blocks)。

84 3.10 OpenGL学习 在填充多边形时每次光栅化一条扫描线。 当显示光栅字符时写一小块位。 当进行清除操作时,改变缓存中所有像素的值。
需要在硬件和软件方面提供对位块进行尽可能 有效操作的功能称为位块传送操作,也称为光 栅化操作。

85 3.10 OpenGL学习 要把源缓存中的一块n×m像素复制到目标缓存中, 那么进行这种操作的位块传送函数应当具有形式。
write_block(source,n,m,x,y,destination,u,v); 本函数调用改变了整个目标块。 针对位块传送操作优化的硬件具有与几何操作的 流水线硬件完全不同的框架。

86 3.10 OpenGL学习 写入操作的模型和读写内存不同,位块传送操作有 多种写入方式,在写入源像素前可读出目标缓存中 的像素。
像素逻辑运算 源像素: s 目标像素: d 写入的目标像素: d’ d’ = f(s, d) 其中s = 0 或1, d = 0 or 1

87 3.10 OpenGL学习 源像素与目标像素逐位结合在一起,有16种 可选的函数(表格中的每列为一种)。

88 3.10 OpenGL学习 定义矩形的形状或图案,可以使用位图和像素图。 像素图:一个彩色像素阵列
像素阵列的参数包括指向颜色矩阵的指针、矩阵的大小及其将要影响的屏幕区域。 实现像素阵列的另一种方法是为矩阵中的每一个元素赋值为0或1。此时,阵列简化成位图,有时也称为掩膜,它指出 一个像素是否被赋予预定颜色。

89 3.10 OpenGL学习 OpenGL维持了一个当前光栅位置,它是状态的一部分, 可看作在屏幕坐标系中定义的内部光标,指示光栅化像
素写入的位置。 当前光栅位置由glRasterPos*()设置。 例 glRasterPos3f(x,y,z); 三个浮点数定义了一个光栅位置,在变换为屏幕坐标 前要经过模型-视图变换和投影变换。

90 3.10 OpenGL学习 绘制位图 glBitmap(width, height, x0, y0, xi, yi, bitmap)
width和height的单位是位,表示bitmap 的行数和 列数。 x0, y0是相对于当前光栅位置的偏移值,给出了位 图左下角的起始绘制位置。 xi, yi表示位图绘制后当前光栅的移动值。

91 3.10 OpenGL学习 例子:棋盘 GLubyte wb[2] = {0x00, 0xff}; GLubyte check[512];
int i, j; for(i=0; i<64; i++) for (j=0; j<64, j++) check[i*8+j] = wb[(i/8+j)%2]; glBitmap( 64, 64, 0.0, 0.0, 0.0, 0.0, check);

92 3.10 OpenGL学习 光栅颜色来自于用glColor*()设置的绘图颜色。
最后一次调用glRasterPos*()时的当前绘图颜色作为 光栅颜色。 glColor3d(1.0,0.0,0.0); glRasterPos3d(x,y,z); glColor3d(0.0,0.0,1.0); glBitmap(…); glBegin(GL_LINES); glVertex3d(…); glEnd(); 几何体以蓝色绘制,位图采用红色显示。

93 3.10 OpenGL学习 处理器内存->帧缓存
glDrawPixels(width,height,format,type,myimage); 从当前光栅位置开始写入像素格式与类型。 格式format描述图像在处理器内存中的存储格式。 图像格式:RGB, RGBA, 颜色索引 类型type是在应用程序中所采用的数据类型:int, float 例如: GLubytemyimage[512][512][3]; glDrawPixels(512,512,GL_RGB, GL_UNSIGNED_BYTE, myimage);

94 3.10 OpenGL学习 帧缓存->处理器内存 glReadPixels(x,y,width,height,format,type,
myimage) x,y:帧缓存中的开始像素位置 width,height:大小 format:图像格式 type:像素类型 myimage:指向处理器内存的指针 GLubyte myimage[512][512][3]; glReadPixels(0,0, 512, 512, GL_RGB, GL_UNSIGNED_BYTE, myimage);

95 3.10 OpenGL学习 帧缓存->帧缓存 将一块像素数据从OpenGL缓存的一个位置复制到另一个位置。
glCopyPixels(xmin,ymin,width,height,pixelValue) xmin,ymin:块的左下角屏幕坐标位置 width,height:要复制的列数和行数 pixelValue:要复制的数据种类,可以取GL_COLOR、GL_DEPTH和GL_STENCIL。 glCopyPixels (0,0, 100, 100, GL_COLOR);

96 3.10 OpenGL学习 多边形 像素阵列 字符图元 显示列表 显示窗口重定形

97 3.10 OpenGL学习 glutBitmapCharacter(font,character) 显示字符串
glRasterPosition2i(x,y) for(k=0;k<36;k++) glutBitmapCharacter(GLUT_BITMAP_9_BY_15, text[k]); 显示轮廓字符 glutStrokeCharacter(font,character)

98 3.10 OpenGL学习 多边形 像素阵列 字符图元 显示列表 显示窗口重定形

99 3.10 OpenGL学习 将对象描述成一个命名的语句序列并存储起来,称为 显示列表。
使用glNewList/glEndList函数包围一组OpenGL命令 就可形成显示列表。 glNewList(listID,listMode) . glEndList(); 让OpenGL生成一个标志 listID=glGenLists(1); 查询 glIsList(listID); 删除 glDeleteLists(startID,nLists);

100 3.10 OpenGL学习 例: regHex=glGenLists(1); glNewList(regHex,GL_COMPILE);
glBegin(GL_POLYGON); for(k=0;k<6;k++){ theta=TWO_PI*k/6.0; x= *cos(theta); y= *sin(theta); } glEnd(); glEndList(); glCallList(regHex);

101 3.10 OpenGL学习 例:字体的存储 光栅字体的显示速度比矢量字体快很多。 假设要定义8x13字体中的128个字符,可以如下应用数组
GLubyte my_font[128][13]; 可以应用显示列表定义字体 base=glGenLists(128); for(i=0;i<128;i++){ glNewList(base+i, GL_COMPILE); glBitMap(8,13,0.0,2.0,10.0,0.0,my_font[i]); glEndList();} 注意:每个字符从当前光栅位置上移2位开始,当字符绘 制后,向右平移2位,这样字符间有2位的水平和竖直间距。

102 3.10 OpenGL学习 多边形 像素阵列 字符图元 显示列表 显示窗口重定形

103 3.10 OpenGL学习 窗口重定形函数 glutReshapeFunc(winReshapeFcn)

104 3.10 OpenGL学习 #include <GL/glut.h> #include <math.h>
#include <stdlib.h> const double TWO_PI = ; /* Initial display-window size. */ GLsizei winWidth = 400, winHeight = 400; GLuint regHex; class screenPt { public: GLint x, y; };

105 3.10 OpenGL学习 static void init (void) { screenPt hexVertex, circCtr;
GLdouble theta; GLint k; /* Set circle center coordinates. */ circCtr.x = winWidth / 2; circCtr.y = winHeight / 2; glClearColor (1.0, 1.0, 1.0, 0.0);// Display-window color = white. /* Set up a display list for a red regular hexagon. * Vertices for the hexagon are six equally spaced * points around the circumference of a circle. */

106 3.10 OpenGL学习 例子 regHex = glGenLists (1);
// Get an identifier for the display list. glNewList (regHex, GL_COMPILE); glColor3f (1.0, 0.0, 0.0); // Set fill color for hexagon to red. glBegin (GL_POLYGON); for (k = 0; k < 6; k++) { theta = TWO_PI * k / 6.0; hexVertex.x = circCtr.x * cos (theta); hexVertex.y = circCtr.y * sin (theta); glVertex2i (hexVertex.x, hexVertex.y); } glEnd ( ); glEndList ( ); } void regHexagon (void) { glClear (GL_COLOR_BUFFER_BIT); glCallList (regHex); glFlush ( ); }

107 3.10 OpenGL学习 void winReshapeFcn (int newWidth, int newHeight)
{ glMatrixMode (GL_PROJECTION); glLoadIdentity ( ); gluOrtho2D (0.0, (GLdouble) newWidth, 0.0, (GLdouble) newHeight); glClear (GL_COLOR_BUFFER_BIT); } void main (int argc, char** argv) { glutInit (&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutInitWindowPosition (100, 100); glutInitWindowSize (winWidth, winHeight); glutCreateWindow ("Reshape-Function & Display-List Example"); init ( ); glutDisplayFunc (regHexagon); glutReshapeFunc (winReshapeFcn); glutMainLoop ( ); }

108 3.10 OpenGL学习

109 第三章 输出图元 3.1 画线算法 3.2 帧缓冲器的装载 3.3 圆、椭圆和圆弧的生成 3.4 其它曲线 3.5 并行画线算法
3.1 画线算法 3.2 帧缓冲器的装载 3.3 圆、椭圆和圆弧的生成 3.4 其它曲线 3.5 并行画线算法 3.6 像素编址和对象的几何要素 3.7 保留显示物体的几何特性 3.8 填充区图元 3.9 多边形填充区 3.10 OpenGL学习

110 计算机图形学 谢谢 欢迎交流! 更多信息请参见


Download ppt "第三章 输出图元 讲 授:董兰芳 研究方向:科学计算可视化 图形、图像处理 模式识别 中国科学技术大学 视觉计算与可视化实验室"

Similar presentations


Ads by Google