畫家演算法,又稱深度排序法。
我們先看看它的演算法:
(1)將螢幕設成背景色,
(2)把要畫的物體(多邊形)按其離開視點的從遠到近排序(#add 確定可以排序麼?不會有交叉的面?這個距離又是指哪個點到哪個點? 從後文得知,畫家演算法不適用於交叉的情況,只能針對包圍體,此距離也是個最小距離)。由此構成深度優先順序表。然後從遠到近畫物體(多邊形),近的就因為優先順序高而覆蓋遠的多邊形。由此可消隱。
z緩衝區演算法(Z-buffer演算法)
先開一個框架緩衝區記錄每個像素的亮度值,再開一個Z緩衝區存放每個像素的深度值。那麼對於每個像素而言,它有兩個參數值,需要定義兩個數組。所以,對於每一個像素,由於有了深度這個數組,它在記憶體中就是立體的了,所以,在記憶體中整個映像都是立體的。
然後,漸進式掃描,就可以測出每一行的深度值了。以此達到消隱的作用。
由此,我們可以看到畫家演算法和Z-buffer演算法1的不同之處。
應該說,它們之間最本質的區別在於:畫家演算法是按照物體(多邊形)的深度進行排序,比較容易實現;而Z-buffer演算法是按照映像每一個像素進行排序,比總體排序靈活簡單。
立方體畫家消隱演算法與Z-Buffer消隱演算法在別的方面有所類似,在<電腦圖形學實踐教程VC++ 孔令德>中,兩個演算法用到的立方體都是正交投影,而不是透視投影,即立方體遠離視點時顯示的立方體仍然是原大小,不變化.只是二種演算法核心思想不同:
一.立方體Z-Buffer消隱是對於某一個像素點,不必對在靠近或遠離視點的面進行排序,只需在遍曆各面後找出該像素的深度最大的點(Z最大,即離視點最近)(先找深度大的點setPixel(),如果以後還有深度更大的,則通過設定新的顏色setPixel()來覆蓋以前的點,其中要注意以yi為掃描線時,掃描線可能不與螢幕平行,可能是傾斜著的,就像把opengl的X軸繞Y軸旋轉一個角度,如向量(1,-1,0),此次每次隨x增大,z也會相應變化-A/C,其中(A,B,C)為該面的法向量),可以說它是對逐個像素進行深度判斷進行的.主要代碼如下:
for(T1=HeadE;T1!=NULL;T1=T1->next)//填充掃描線和多邊形相交的區間
{
if(In==false)
{
xb=T1->x;
CurDeep=-(xb*A+CurrentB->ScanLine*B+D)/C;//z=-(Ax+By+D)/C
In=true;//每訪問一個結點,把In值取反一次
}
else//如果In值為真,則填充從當前結點的x值開始到下一結點的x值結束的區間
{
xe=T1->x;
for(double x=xb;x<=xe;x++)
{
if(CurDeep>=ZB[ROUND(x)+200][CurrentB->ScanLine+200])//如果新的採樣點的深度大於原採樣點的深度,因為繪製每個面都會調用該函數,故以後的面中如果有更深度更大的點,則會覆蓋以前的點的顏色.注意,此處要遍曆[xb,xe]上的每個整數點,繪製連續的像素點,以連成一條線 .
{
ZB[ROUND(x)+200][CurrentB->ScanLine+200]=CurDeep;//xy座標與數組下標保持一致,加200
mdc->SetPixel(ROUND(x),CurrentB->ScanLine,RGB[Face]);
}
CurDeep+=DeepStep;
}
In=false;
}
}
二.立方體畫家消隱演算法是對每個面求Z最小的值MinDeep,然後對這6個面按MinDeep值從小到大進行排序(即離視點近的面後畫,來覆蓋離視點遠的面),然後再按從遠到近畫六個面即可.不過這種演算法還是有局限的,它只是針對包圍體(如立方體)來說的,如果對於那種不閉合的體(如2個相交且無限延伸的平面(就像opengl座標繫上的平面XOY和平面YOZ)),則會出現問題. 主要代碼如下:
for(T1=HeadE;T1!=NULL;T1=T1->next)
{
xb=T1->x; CurDeep=-(xb*A+CurrentB->ScanLine*B+D)/C;//z=-(Ax+By-D)/C
if(CurDeep<=F[Face].MinDeep)// 找一個面上深度最小(即Z最小,最遠離視點)的點,此處不像Z-Buffer那樣每次找2個點xb,xe,且需要遍曆其中的每個x點,它只需找到最小值,而這個最小值必定線上段的2個端點上(要麼是xb,要麼是xe),故可以一個端點一個端點地訪問找出Z的最小值即可,而且它暫時不繪製像素點,而是在最後把6個面按先遠後近的順序進行排序後再繪製這6個面.
{
F[Face].MinDeep=CurDeep;//同上一行記錄
}
CurDeep+=DeepStep;
}