自己動手實現光柵化直線生成演算法
阿新 • • 發佈:2018-12-31
前期準備:搭建可以在螢幕上畫一個畫素的開發環境,我使用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; } }