[关闭]
@markheng 2016-03-12T04:42:01.000000Z 字数 3105 阅读 1551

第六章 实现图元及属性的算法

计算机图形学


6.1 画线算法

6.1.1 直线方程

直线的笛卡尔斜率截距式方程为

给定两个端点,可以计算斜率和截距


显示直线的算法是以(6.1),(6.2),(6.3)式为基础的.
给出轴或轴上的一个偏移量或者,可以计算相应的另一个坐标轴上的偏移量

6.1.2 DDA算法

数字微分分析仪(digital differential analyzer,DDA)方法
依照式(6.4),(6.5)进行递推计算。

算法过程如下:
1. 输入线段两个端点的位置
2. 端点位置间水平和垂直的插值赋给参数
3. 绝对值大的参数确定参数的值。该值是在即将划出的的这条线段的上的像素数目
4. 按照这个数值,沿线段路径计算每一步的下一个像素位置

  1. #include<stdlib.h>
  2. #include<math.h>
  3. inline int round (const float a) {return int (a + 0.5); }
  4. void lineDDA (int x0, int y0, int xEnd, int yEnd ){
  5. int dx = xEnd - x0, dy = yEnd - y0 , steps, k;
  6. float xIncrement, yIncrement, x = x0, y = y0;
  7. if(fabs (dx) > fabs (dy))
  8. steps = fabs (dx);
  9. else
  10. steps = fabs (dy);
  11. xIncrement = float (dx) / float (steps);
  12. yIncerment = float (dy) / float (steps);
  13. setPixel (round (x), round (y));
  14. for (k = 0; k < steps; k++){
  15. x += xIncrement;
  16. y += yIncrement;
  17. setPixel (round(x), round(y));
  18. }
  19. }

DDA方法计算比直接使用方程(6.1)计算的速度快。它利用光栅特性消除了直线方程中的乘法,二在x或y方向使用合适的增量,从而沿线路径逐步得到个像素的位置。但在浮点增量的连续叠加中,取整误差的积累使得对于较长线段所计算的像素位置偏离实际线段。而且算法中所采用的浮点数计算和取整操作都较费时。我们可以将增量m和1/m分离成整数和小数部分,从而使所有的计算都化简为整数操作来改善DDA算法的性能。

6.1.3 Bresenham画线算法

Bresenham 算法仅使用增量整数计算。

Bresenham 算法思想描述。
从给定的 处开始,逐步处理每个后继列(x位置),并在其扫描线y值最接近线段的像素上绘出一点。假如已经决定要显示的像素在,那么下一步需要确定在列上绘制哪个像素,是在位置,还是在位置

在取样位置x_k + 1, 我们使用来标识两个像素与数学上线路径的垂直便宜,在像素列位置处的直线上的y坐标可计算为:


那么

下一步确定哪一个像素更接近路径,测试这两个像素偏移的差:

重新安排上式,得到画线算法第k步的决策参数,从而可以仅使用整数进行计算。
分别是两端点的垂直和水平偏移量,令,决定参数定义为

在k+1步,决策参数可以从式(6.14)计算得出:

上式减去式(6.14)得到

但是 ,因而得到

其中取值0或1,取决于参数的符号

决策参数的递归计算从线段左端点开始的每个整数x位置进行。起始像素位置的第一个参数通过方程(6.14) 及计算得出

时的Bresenham画线算法:
1. 输入线段的两个端点,并将做端点存储在
2. 将装入帧缓存,画出第一个点
3. 计算常量,并得到决策参数的第一个值:


4. 从 开始,在沿线段庐江的每个处,进行下列检测:
如果,下一个要绘制的点是,并且

否则,下个要绘制的点是,并且

5. 重复步骤4,共

上述算法第四步一共执行

下面程序给出了斜率为0 < m < 1.0 的 Bresenham 画线算法的实现。首先将线段的端点像素位置输入程序,然后从左到右端点绘制像素。

  1. #include<stdlib.h>
  2. #include<math.h>
  3. /*Bresenham line_drawing procedure for |m| < 1.0 */
  4. void lineBres(int x0, int y0, int xEnd, int yEnd){
  5. int dx = fabs (xEnd - x0), dy = fabs (yEnd - y0);
  6. int p = 2 * dy - dx;
  7. int twoDy = 2 * dy , twoDyMinusDx = 2 * (dy - dx);
  8. int x, y;
  9. if ( x0 > xEnd) {
  10. x = xEnd;
  11. y = yEnd;
  12. xEnd = x0;
  13. }
  14. else {
  15. x = x0;
  16. y = y0;
  17. }
  18. setPixel (x, y);
  19. while(x < xEnd){
  20. x++;
  21. if (p < 0)
  22. p += twoDy;
  23. else{
  24. y++;
  25. p += twoDyMinusDx;
  26. }
  27. setPixel (x, y);
  28. }
  29. }

6.1.4 显示折线

通过n-1次调用画线函数实现折线的显示。

6.2 平行画线法

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注