像素直線


像素英文為 pixel,拆開來看是 pix 與 el,也就是 picture 與 element,意謂著圖像基本元素,呈現圖像可用的基本元素不多時,圖像明顯就會看出許多小方塊,現在電子產品多擁有高解析度,可呈現的圖像元素極高,這種小方塊,大概就是在 LED 點矩陣螢幕、小尺寸液晶螢幕(像是計算機),或者是故意將點陣圖降低解析度並拉大才看得到了。

然而,螢幕或點陣圖本身還是基於像素在繪圖或儲存圖像資訊,那麼在電腦中畫直線這件事是怎麼一回事呢?只是透過一些演算,然後許多的像素加上高解析度,讓你看起來像直線罷了。

圖像軟體、繪圖 API 基本都代勞了這件事,那為什麼這邊要討論像素直線呢?我是因為先前玩過 Minecraft 模組開發,才會需要瞭解一下像素方面的運算,因為 Minecraft 的世界,就是一個又一個的方塊組成,瞭解如何處理像素,或許也可以用來製作一些復古風繪圖軟體吧!…XD

這邊先從直線開始認識一下繪圖上的像素處理,給你兩個點的座標,應該會很直覺地基於斜率來繪製吧!很可惜地,這行不通:

這邊使用 square 繪製方塊來呈現像素風格,指定的方塊寬度會將畫布平分當作每個像素,雖然自行計算斜率來算也是可以,不過更方便的是,利用 p5.Vectorlerp 來進行兩個向量間的內插,簡單來說,v2 - v1 的長度當成是 1 的話,若 n 為 0 到 1 間的值,lerp 可以得到長度為 n 的向量。

像素直線

像素座標基本上應該都是整數,然而這邊的 pxLine 可以接受浮點數,透過 round 取整數執行以上的範例,畫出來的線並沒有接在一起,方塊會散落,這是自然結果,將畫布畫分為格子,然後在每個座標處依上面的公式手算一下,就知道為什麼了:

像素直線

這跟你在指定 square 的座標時是採 roundfloorceil 無關,只要是取整數,一定就會有這類的結果,你也許會想,這是因為範例中計算斜率是以 x 為主,改為以 y 為主就不會了,如果只是 (0, 0) 到 (5.5, 8.5) 的話,是沒錯啦!

然而,如果是 (0, 0) 到 (8.5, 5.5) 就還是會有問題的,簡單來說,單以 x 為主或 y 為主,只要斜率不是 1,差距小的一邊都會畫出不連續的像素,那麼就看哪個差距大好了:

在注重效率的場合,可以採用〈Bresenham's line algorithm〉,基本原理相同,然而可預先計算斜率,後續單純地基於累計及誤差值判斷來尋找整數座標。

如果有一組點代表路徑,想畫出折線的話,可以模仿 p5.js 的 beginShapevertexendShape,來寫組 beginPxPolylinepxVertexendPxPolyline

能不能用以上方式來畫圓呢?基本上是可以:

只不過畫出來的圓稍微有些不對稱,如果要畫圓,其實有另一種計算方式,這之後的文件再來談。