可能有圖片或者下載的鏈接不對,請到原始地址查看.http://dgame.yeah.net
========================================================
普通的Breshenham算法畫線很快,但並不是很精細.通常的整數畫線因爲只能在整數座標上繪圖,所以產生難看的鋸
齒.我在Michael Abrash的一本書力看到一個很好的反走樣直線畫法,並決定用非整數座標改進它.
一個wu直線不僅僅是看上去比一個普通直線好,它也產生更好的動畫.一個普通的直線從一個位置簡單的跳到下一個 位置.然而,一條wu直線非常悠閒的漂到下一個位置. |
它是如何工作的?
讓我們想一下一個反走樣直線究竟意味這什麼.一條恰當的直線看上去應該是什麼樣的?直線有多粗?尾端應該是怎
麼樣的?直線是一個一維物體,無限長.它沒有什麼粗細.線段的尾端看上去什麼都不象,它就是尾端而已.這樣一個直
線不能被畫到一個基於像素的顯示設備上.
在計算機圖形中,通常假定線段爲一個像素粗.這意味這它可以被畫下來.這也意味着他足夠細使得不必考慮它的末
端應該是什麼樣子,因爲它比一個像素還小,不可以畫.
在我們設計一個新的wu直線的時候我們必須制定類似的假定.因爲這個新的算法可以處理非整數座標的端點,對於一
個小於一像素長的線能做什麼呢?
假定
.假定像素在它們座標的中心
.直線是一個像素粗
.直線的末端的形狀不重要
它可以更好,如果:
.兩個平行線段,端點相連接,不能分辨出其中一個,一個長線段
.直線的亮度/透明的可以被定義
最終的算法是怎樣的?
最終的算法相當容易實現,但是在實際應用中顯得太慢.但也不是真正的必要,因爲它的效果和另一個更快速的方法
幾乎相同.不管怎樣,我將闡明一些基本的東西.
想像一下,你可以可以放大我們在上面畫線的屏幕的像素.理想的畫線算法將計算每條線覆蓋的精確的區域,從而增 加那些像素的亮度. 這樣一個算法很容易寫,在一個更高的分辨率重畫屏幕的相關部分,然後把線畫到上面,計算出覆蓋的像素或者 calculating it presicely. |
然而這需要一些精確度.我們來看下一種方法.
一個更明智的算法
這個算法跨騎着直線繪製一對像素.一個主循環將沿着直線的長度畫一對像素,端點的像素對將被分別計算. 像素對: 再想像一次,屏幕的一個特寫.畫一條几乎水平的線. 這個幾乎水平的線穿過垂直的像素列.每次跨過像素,x座標是整數,但是y座標是非整數. 看的更近些,一個單個的跨越點: |
繪製端點
最後的事情就是畫端點.這不好處理,我仍然沒有完全正確的處理它們.這裏是我現在用的一種方法.他不很理想,但
是非常近似.你將注意到在直線從幾乎垂直變得幾乎水平的時候它有小心的失靈,反過程也是.你將在直線緩慢的移
動過45度的時候注意到這點.
真正近距離的看一下端點:
可以看到直線的一個端點,用紅色的點來表示.藍色的點表示像素的中心點.你可以看到,頂點不在像素的中心點上.
計算直線端點的兩個像素的正確亮度:
.把直線延長(向後或向前)到最近的整數x座標(p).向計算直線上普通的像素對的亮度一樣計算這個像素對.然後,因
爲直線只是覆蓋這個像素的很小一部分(i),直線將降低它的亮度.所以亮度應該乘上i.因此,當整條直線向右移動,i
將變小,使得這個像素對平滑的變暗.
特殊的情況
一個長度小於一像素的直線將是怎樣的呢?因爲它的長度太小以至不能精確表現,所以你可以隨便按它應該的模樣畫
.這是我自己的實現方法,我把線拉伸到一個像素常,然後降低它們的亮度.所以一個非常短的直線看上去很暗,當它
變長,它就會變亮,當他是一個像素常,它在所在點上將被正常的畫出.
最後,一些僞代碼
wu直線的定點數計算需要的一些函數: function trunc(x) return integer part of x end of function function frac(x) return fractional part of x end of function function invfrac(x) return 1 - (fractional part of x) end of function |
wu直線程序: procedure WuLine(fixpt x1, fixpt y1, fixpt x2, fixpt y2) variable declerations: fixpt variables: grad, xd, yd, length,xm,ym xgap, ygap, xend, yend, xf, yf brigheness1, brigheness2 integer variables: x, y, ix1, ix2, iy1, iy2 byte variables: c1,c2 code starts here: Width and Height of the line xd = (x2-x1) yd = (y2-y1) if abs(xd) > abs(yd) then check line gradient horizontal(ish) lines if x1 > x2 then if line is back to front swap x1 and x2 then swap it round swap y1 and y2 xd = (x2-x1) and recalc xd & yd yd = (y2-y1) end if grad = yd/xd gradient of the line End Point 1 ----------- xend = trunc(x1+.5) find nearest integer X-coordinate yend = y1 + grad*(xend-x1) and corresponding Y value xgap = invfrac(x1+.5) distance i ix1 = int(xend) calc screen coordinates iy1 = int(yend) brightness1 = invfrac(yend) * xgap calc the intensity of the other brightness2 = frac(yend) * xgap end point pixel pair. c1 = byte(brightness1 * MaxPixelValue) calc pixel values c2 = byte(brightness2 * MaxPixelValue) DrawPixel(ix1,iy1), c1 draw the pair of pixels DrawPixel(ix1,iy1+1), c2 yf = yend+grad calc first Y-intersection for main loop End Point 2 ----------- xend = trunc(x2+.5) find nearest integer X-coordinate yend = y2 + grad*(xend-x2) and corresponding Y value xgap = invfrac(x2-.5) distance i ix2 = int(xend) calc screen coordinates iy2 = int(yend) brightness1 = invfrac(yend) * xgap calc the intensity of the first brightness2 = frac(yend) * xgap end point pixel pair. c1 = byte(brightness1 * MaxPixelValue) calc pixel values c2 = byte(brightness2 * MaxPixelValue) DrawPixel(ix2,iy2), c1 draw the pair of pixels DrawPixel(ix2,iy2+1), c2 MAIN LOOP --------- Loop x from (ix1+1) to (ix2-1) main loop brightness1 = invfrac(yf) calc pixel brightnesses brightness2 = frac(yf) c1 = byte(brightness1 * MaxPixelValue) calc pixel values c2 = byte(brightness2 * MaxPixelValue) DrawPixel(x,int(yf)), c1 draw the pair of pixels DrawPixel(x,int(yf)+1), c2 yf = yf + grad update the y-coordinate end of x loop end of loop else vertical(ish) lines handle the vertical(ish) lines in the same way as the horizontal(ish) ones but swap the roles of X and Y end if end of procedure |
這裏是上面所說的算法的更多的具體描述.爲了方便和速度,我在這裏使用了定點數.在這種情況下,它顯然很方便.
首先,我定義了一些函數.
最後
它被證明是真的可以工作的,而且看上去很奇妙,這裏有一個DEMO.
這個程序在兩種分辨率下畫了一個Newton's Cradle,來演示wu直線可以畫很小的東西,並且仍然看上去ok.你可以看到它們移動的多平滑.