HTML5 Canvas 提高班(一) —— 光柵圖形學(1)中點畫圓算法


    本系列的隨筆在於給大家提供一些難度較深的canvas應用場景,借用數學或物理模型實現效果或性能媲美桌面應用的案例;並且此系將盡可能使用最簡明的js代碼展示效果。

    推薦使用:chrome、ie9瀏覽器進行閱讀,同時我還在做一個基於canvas的矢量渲染器的類庫,希望大家關注。

    話不多說,我們現在開始第一次隨筆的內容。

光柵圖形學(1)中點畫圓算法

    我們平時在使用canvas繪制圖形時,通常會調用context的各種API,如設置樣式的strokeline、fillcolor等;再如繪制圖形的context.arc,context.fillRect等。

    如果我們現在有一個場景,需要繪制1W個以上的圖形,並且要求其刷新頻率達到12fps以上,也就是說我們必須要在1秒內完成10W次canvasAPI的調用,想想這有多么可怕,大家可以在機子的機器上嘗試一下。。得卡到強制關閉瀏覽器。

    下面我們引入了光柵圖形學中的中點畫圓算法。

   1.獲取context元素的像素數組:

    var cxt= canvas.getContext("2d");
    cxt.clearRect(0, 0, width, height);
    var data = cxt.getImageData(0, 0,width, height);
    imageData = data.data;

    現在imageData變量便引用了當前canvas元素的所有像素數組。

    imageData的數據結構是一維數組,每四個元素表示一個像素的所有屬性,依次表示:r、g、b、alpha 的值,其范圍均是是(0——255)。

    有了這樣的理論邏輯我們可以通過canvas上的任意一點(x,y)計算出imageData中表示次像素的第一個元素的索引值。

    計算方式如下代碼:

function getStartIndex(x, y) {
    return y * width * 4 + x * 4;
}

    有了上面的理論知識,大家應該知道我們下面要做什么了吧?對就是利用中點畫圓算法對每一個像素進行顏色值(rgb)的修改。

    2.光柵學——中點畫圓

    首先我們通過圓的對稱性將其分為8個部分。

    

    現在我們假設,這個圓的中點位於(0,0)的位置。

    設d是點p(x,y)到圓心的距離:則我們得到這樣的圓方程FX(X,Y)  = d 。

    這里我們按照Bresenham算法,推出:

    

   (此部分可能需要有圖形學學習經驗的同學,再以后的隨筆中可能會介紹Bresenham算法)。

    如果dM<0,表示下一點M在圓內,得

    

    如果dM>0,表示下一點M在圓外,得

    

    有了上面的理論知識,我們就可以輕松的寫出繪制圓的算法了:

// 中點畫圓法
function circle(x, y, r, color) {
    var tx = 0, ty = r, d = 1 - r;

    while(tx <= ty){
        // 利用圓的八分對稱性畫點
        putpixel(x + tx, y + ty, color);
        putpixel(x + tx, y - ty, color);
        putpixel(x - tx, y + ty, color);
        putpixel(x - tx, y - ty, color);
        putpixel(x + ty, y + tx, color);
        putpixel(x + ty, y - tx, color);
        putpixel(x - ty, y + tx, color);
        putpixel(x - ty, y - tx, color);
        if(d < 0){
            d += 2 * tx + 3;
        }else{
            d += 2 * (tx - ty) + 5;
            ty--;
        }
        tx++;
    }
}

    putpixel函數用於將每一個像素的顏色值填入對應的數組當中,這里我們的顏色只表示灰度值,因為還沒有對彩色做任何處理。

function putpixel(x, y, color){
    var index = getStartIndex(x, y);
    for(var i = 0; i< 4; i++) {
        if(i == 3) {
            imageData[index + i] = 255;
        }
        else{
            // var co = parseInt(Math.random() * 255)
            imageData[index + i] = color;
        }
    }
}

    至此我們就已經把一個圓的像素填入我們的像素數組當中,最后將像素對象放回原來的canvas當中,就實現了圓的光柵畫法:

cxt.putImageData(data, 0, 0);

    3.案例 

    下面這個案例以1w個圓的邊界碰撞檢測運動為例,說明了我們實現的光柵圖形性能完全可以勝任各種bt場景。(首要推薦chrome18其他瀏覽器可能解析js代碼比較慢)

 


    下次提高班預告:實現光柵算法中的畫線算法。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM