1. 程式人生 > >自己動手實現光柵化直線生成演算法

自己動手實現光柵化直線生成演算法

前期準備:搭建可以在螢幕上畫一個畫素的開發環境,我使用OpenGL的glfw庫來畫點。

為了提高畫線演算法的可讀性,我先把自己使用的畫點函式寫出來

//點 繪製
/*
point2D是一個包含x,y座標位置的物件 R,G,B - color pointSize是畫素點的大小
*/
void drawPoint(point2D point,float R,float G,float B,float pointSize);

常用的直線生成演算法有:DDA演算法、中值演算法、bresenham演算法等等

一、為什麼要“光柵化”?

在寫演算法之前,我們先聊一下什麼叫光柵化直線。比如我在螢幕上以x、y同時遞增0.01的速度,希望畫出一條直線

for(float i=0;i<1;i+=0.01)
{
    drawPoint(i,i,1.0, 0.0, 0.0);
}
效果:


但是我們發現這條直線並不“直”,這是因為在計算機的螢幕上,是以類似網格形式的畫素點存在的。當我們一以位置(0,0)、(0.01,0.01)(0.02,0.02)(0.03,0.03)...畫點時,它不一定會恰好落在我們合適的畫素點中,因此直線會產生扭曲。

我們的演算法來判斷哪個畫素點被點亮以接近我們真正的任務,這個過程被稱為光柵化。

例如,如我們用DDA畫線演算法來畫這條線,依然以每次0.01的速度遞增,影象如下:


我們會發現這條“直線”更“直”,如果我們將畫素點調小並將增長速度減小,那麼畫直線的精度會更大,影象也更接近直線。

這就是軟光柵化直線的一個示例。

二、DDA直線生成演算法

DDA演算法,又稱數值微分畫線演算法,它的演算法思想是:

1)每次下一個點距離上一個點X(或Y)方向前進一個距離,另一個方向前進1/k個距離,根據直線的斜率k,確定哪個方向前進1個距離,如果|k|>1,Y前進1個距離,X前進1/k個距離,如果|k|<1,X前進1個距離

2)前進後畫點並重進進入步驟1直到畫線完成

演算法的程式碼演示

void drawLine_DDA(point2D point1,point2D point2,float R,float G,float B)
{
    float dm = 0,dx = 0,dy = 0;
    if(fabs(point2.x-point1.x) >= fabs(point2.y-point1.y))
    {
        dm = fabs(point2.x-point1.x);
    }else
    {
        dm = fabs(point2.y-point1.y);
    }
    dx = (float)(point2.x-point1.x)/(dm*base);
    dy = (float)(point2.y-point1.y)/(dm*base);
    for(float i=0;i<dm*base;i++)
    {
        point2D tempPoint(point1.x,point1.y);
        drawPoint(tempPoint,R,G,B,mrender_pointSize);
        point1.x+=dx;
        point1.y+=dy;
    }
}
三、中點直線生成演算法