直线渲染算法

概述

目前直线渲染算法主要分为五种:

  • 朴素算法
  • DDA(Digital Differential Analyzer)算法
  • Bresenham算法
  • Xiaolin Wu算法
  • Gupta-Sproull算法
    Xiaolin Wu算法和Gupta-Sproull算法主要解决直线渲染抗锯齿的问题,意义不大,暂时搁置。下面详细介绍主流算法:DDA和Bresenham算法。

朴素算法

直接根据微分方程计算,源代码如下:

//plot (x1,y1) to (x2,y2)
//x1,y1,x2,y2 是整型

double dx=x2-x1;     //由于要做乘除法,所以使用double型
double dy=y2-y1;
double k=dy/dx;
for(int x=x1;x<=x2;x++)   //逐像素
{
   y=k*x+x1;                
   drawPixel(x,round(y))
}

如下图所示:网格上每个点代表像素点,蓝色的点代表被渲染的点。当k绝对值小于1时(左图),较为正常,但当k的绝对值大于1时(右图),会造成像素点过于稀疏(左侧)。此时,交换x,y即可(右侧)。

DDA算法

DDA算法实际上就是综合考虑了斜率绝对值小于1以及大于等于1的情况,源代码如下:

//plot (x1,y1) to (x2,y2)
//x1,y1,x2,y2 是整型
double dx=x2-x1;     //由于要做乘除法,所以使用double型
double dy=y2-y1;
double step;
if(abs(dx)>abs(dy)) step=abs(dx);
else                step=abs(dy);
dx=dx/step;
dy=dy/step;
int i=0;
while(i<step)
{
   drawPixel(round(x),round(y));
   x+=dx;
   y+=dy;
   i++;
}

Bresenham算法

Bresenham算法主要解决DDA算法中使用浮点数运算的问题。由于浮点数运算速度比整数运算要慢,所以为提高效率,Bresenham算法只使用整数运算。Bresenham算法将直线分为八个计算域,如下图左。首先需要说的的是:对于任意一条直线,可以把平面分为两个部分,对于两个相邻的像素点,如果它们的中间点,在直线下方,则渲染上面的像素;如果中间点在直线上方,则渲染下面的像素。如下图右,可以看到中间点 (xk,yk+12) 在直线下方,则应该渲染像素点 (xk,yk+1)

如上图(右)所示,当已知一条直线,以及两个相邻的像素点,那么可以求解两个像素点的中点,接下来判断中间点在直线上面还是下面,来决定渲染哪一个像素点。由于不能使用浮点数,在计算过程中,在不影响结果的情况下,可以将浮点数转化为整数进行运算。
已知直线:起点(x0,y0),终点(xn,yn),渲染该直线。可以得到直线方程 :f(x,y)=(yny0)(xx0)(xnx0)(yy0)=0,化为一般形式f(x,y)=Ax+By+C=0.
其中A=yny0=dy,B=(xnx0)=dx,C=y0xnynx0.
在第1个计算域中,直线斜率小于1,所以如果第k个被渲染的像素点为(xk,yk),那么下一个像素点为(xk+1,yk)或者(xk+1,yk+1)。接下来通过中心点(xk,yk+12) 来判断渲染哪一个像素点。若f(xk+1,yk+12)>0,则渲染(xk+1,yk+1),否则渲染(xk+1,yk)。那么接下来的问题是如何判断f(xk+1,yk+12)的符号。
Dk=2f(xk+1,yk+12),注意到f(x0,y0)=0,即D0=2f(x0+1,y0+12)=2A+B
δD=Dk+1Dk=2A(xk+1xk)+2B(yk+1yk)=2A+2B(yk+1yk),则可得: D0=2A+BδD=Dk+1Dk={2A,Dk<0yk+1=yk2A+2B,Dk>=0yk+1=yk+1 则第一个象限代码为:
//plot from (x0,y0) to (xn,yn)
int a=yn-y0;
int b=-(xn-x0);
int d=2*a+b;
int x=x0,y=y0;
while(x<xn)
{
  if(d>=0)
  {
     drawPixel(++x,++y);
     d+=2a+2b;
     y++;
  }else
  {
    drawPixel(++x,y);
    d+=2a;
  }
}

Reference

  1. Line drawing algorithm Wiki
  2. WhatWhenHow
posted @   木子七维  阅读(148)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示