|
最大最小法 僅適用於曲面函式可以用顯函式y = f(x, z)來表示時,如果曲面函式非顯函式形式,則無法使用最大最小法來處理深度問題。
Z Buffer有些類似畫家演算法,都是以近景遮蓋遠景的方法來處理深度問題,所不同的是Z
Buffer使用的是裁剪(culling)的方法,並以像素為處理的對象,Z
Buffer將繪圖畫布內所有的座標當作一個深度緩衝區陣列zbuf[]的索引,每一個zbuf[]的元素記錄一個像素繪製時的Z深度資訊,可以使用它來
處理隱函式的圖形繪製。
假設畫布大小為600X400(X,
Y),則zbuf[]的大小必須設定為600*400=240000(X*Y),一開始時所有zbuf[]元素的值設定為一個極小值,也就是所有的像素都
表示空間中一個極深的位置,開始繪製之後,必須在zbuf[]中記錄每一個像素的z值。
zbuf[]是個一維陣列,所以我們必須計算座標的索引值,如果以列為主的話,則(x, y)對應的zbuf[]元素值為:zbuf[x + y * 畫布高度];當然您也可以使用二維陣列zbuf[][]來直接對應。
如果後來要繪製的點之z值大於zbuf[]中記錄的值,表示此點在之前所繪點的前面,於是繪製此點來覆蓋之前所繪的點,並更新zbuf[]
中的z值為目前點的z值;如果後來要繪製的點之z值小於zbuf[]中記錄的值,表示此點在之前所繪點的後面,於是不用繪製此點,當然也不用更新zbuf
[]中的z值。
Z Buffer的深度處理方式無論從哪一個點開始繪製,都不會影響處理的結果;Z buffer的缺點就是使用大量的記憶體作為緩衝區,而由於它是以像素為處理的單位,所以需耗用相當大量的運算資源。
下面這個程式並不是一個很好的示範,因為我們並不是每個像素都考慮到,但可以讓您瞭解Z Buffer的演算法,如果要考慮所有的像素,這個程式要畫的好,最好加上陰影的效果,繪製的圖形之參數式如下,其中 a 表示圓的粗細:
x = (1+a*cosθ) * sinφ
y = a * sinθ
z = (1+a*cosθ)*cosφ
0 < a < 1, 0 <= θ <= 2π, 0 <= φ <= 2π
package onlyfun.caterpillar; import java.awt.Color; import java.awt.Graphics; import javax.swing.JApplet; public class ZBufferMethodDemo extends JApplet { private int orgX; private int orgY; private double[] zbuf; public void init() { super.init(); setBackground(Color.black); orgX = (int)getSize().width /2; orgY = (int) (getSize().height / 2); zbuf = new double[getSize().width * getSize().height]; } public void paint(Graphics g) { g.setColor(Color.yellow); // 從斜角繪製 // 繞 x 軸轉 30 度 double angleX = Math.toRadians(30); double a = 0.3; double k = 200.0; for(int l = 0; l < zbuf.length; l++) zbuf[l] = -10000.0; // 由於是單色,調整一下 j 與 i 可以看的明顯一些 for(double j = 0; j < 360; j+=0.2) { for(double i = 0; i < 360; i+=0.1) { double x = (1 + a*Math.cos(Math.toRadians(i))) * Math.sin(Math.toRadians(j)); double y = a * Math.sin(Math.toRadians(i)); double z = (1 + a*Math.cos(Math.toRadians(i))) * Math.cos(Math.toRadians(j));
// 立體旋轉,從斜角繪製,調整繪圖中心至視窗中心 double pointX = orgX + k * x; double pointY = orgY - k * (y*Math.cos(angleX) - z*Math.sin(angleX)); // Z buffer處理 int index = (int) (pointX + pointY * getSize().width); if(z > zbuf[index]) { g.drawLine((int)pointX, (int)pointY, (int)pointX, (int)pointY); zbuf[index] = z; } } } } }
 |