2

ランダム ノイズを含むキャンバスを生成しようとしましたが、60 fps でランダム ピクセルのキャンバス全体を生成する余裕がなかったため、最終的にメモリ内の一時キャンバスを使用して小さな 64x64 タイルを生成し、コンテキスト フィルを使用しました。パターンを繰り返し、javascript エンジンを使用する代わりに、ブラウザーがそれらのバイトを画面にプッシュできるようにします。

それははるかに高速で、フルスクリーンでも iOS デバイスで 60 fps を確保できましたが、数分後には fps が低下し、非常に遅くなることに気付きました。

このフィドルでは、60Hz に制限する必要がある requestAnimationFrame を使用していません。代わりにカスタム ループを使用しています。Macbook では、500Hz 前後で開始し、問題を強調するために急速に減速します。

http://jsfiddle.net/Victornpb/m42NT/2/

function loop(){
    drawNoise();
}


function drawNoise(){
    var context = canvas.getContext("2d");
    var pattern = context.createPattern(generatePattern(), "repeat");
    context.rect(0,0, canvas.width, canvas.height);
    context.fillStyle = pattern;
    context.fill()
}

//create a on memory canvas to generate a tile with 64x64 pixels of noise and return it
function generatePattern(){

    var canvas = document.createElement("canvas");
    canvas.width = 64;
    canvas.height = 64;
    var context = canvas.getContext("2d");

    var image = context.getImageData(0, 0, canvas.width, canvas.height);
    var imageData = image.data; // here we detach the pixels array from DOM

    var p;
    var pixels = canvas.width*canvas.height;
    while(pixels--){
        p = pixels*4;
        imageData[p+0] = Math.random() >= 0.5 ? 255 : 0; // Red
        imageData[p+1] = Math.random() >= 0.5 ? 255 : 0; // Green
        imageData[p+2] = Math.random() >= 0.5 ? 255 : 0; // Blue
        imageData[p+3] = 255; // Alpha
    }

    image.data = imageData;
    context.putImageData(image, 0, 0);

    return canvas;
}
4

2 に答える 2

7

新しいパス (beginPath) を作成せずに、メインの描画関数で context.rect を使用しています。したがって、すべてのrectサブパスが追加され、各フレームで再描画が必要になります==>>すぐに遅すぎます。

==>> rect を使用する前に beginPath() を使用するか、fillRect を使用してください。

function drawNoise() {
    var context = canvas.getContext("2d");
    var pattern = context.createPattern(generatePattern(), "repeat");
    context.fillStyle = pattern;
    context.fillRect(0, 0, canvas.width, canvas.height);
}

キャンバスを作成せずに、generatePattern の呼び出しごとに画像データを作成することで、多くの時間を獲得できることに注意してください。代わりに、同じ imageData を何度も再利用します。さらに、アルファを設定できるのは 1 回だけです。

//create a on memory canvas to generate a tile with 64x64 pixels of noise and return it
var generatePattern = (function () {
    var canvas = document.createElement("canvas");
    canvas.width = 64;
    canvas.height = 64;
    var context = canvas.getContext("2d");
    var image = context.getImageData(0, 0, canvas.width, canvas.height);
    var imageData = image.data; // here we detach the pixels array from DOM
    // set the alpha only once.
    var p = 0,
        pixels = canvas.width * canvas.height;
    while (pixels--) {
        imageData[p + 3] = 255; // Alpha
        p += 4;
    }
    var _generatePattern = function () {
        var p = 0;
        var pixels = canvas.width * canvas.height;
        var data = imageData;
        var rnd = Math.random;
        while (pixels--) {
            data[p++ ] = rnd() >= 0.5 ? 255 : 0; // Red
            data[p++ ] = rnd() >= 0.5 ? 255 : 0; // Green
            data[p++ ] = rnd() >= 0.5 ? 255 : 0; // Blue
            p++;
        }
        context.putImageData(image, 0, 0);
        return canvas;
    }
    return _generatePattern;
})();

更新されたフィドルはこちらです:

http://jsfiddle.net/gamealchemist/m42NT/15/

編集: random() への1回の呼び出しを使用して1つのランダムビットを取得するのはやり過ぎです: math.random() を使用してビットフィールドを取得し、空のときにこのビットフィールドを再入力します。ここでは、Math.random() から 21 ビットを取りました。このようにして、同じ結果を得るために、この関数への呼び出しを 21 分の 1 (!!) 使用します。

http://jsfiddle.net/gamealchemist/m42NT/18/

//create a on memory canvas to generate a tile with 64x64 pixels of noise and return it
var generatePattern = (function () {
    var canvas = document.createElement("canvas");
    canvas.width = 64;
    canvas.height = 64;
    var context = canvas.getContext("2d");
    var image = context.getImageData(0, 0, canvas.width, canvas.height);
    var imageData = image.data; // here we detach the pixels array from DOM
    // set the alpha only once.
    var p = 0,
        pixels = canvas.width * canvas.height;
    while (pixels--) {
        imageData[p + 3] = 255; // Alpha
        p += 4;
    }
    var _generatePattern = function () {
        var p = 0;
        var pixels = canvas.width * canvas.height;
        var data = imageData;
        var rnd = Math.random;
        var bitsLeft = 0;
        var multiplier = (1<<22)-1;
        var mask = 0;
        while (pixels--) {
            if (!bitsLeft) {
                bitsLeft=21;
                mask= 0 | (Math.random()*multiplier);
            }
            data[p++ ] = (mask & 1) && 255 ; // Red
            data[p++ ] = (mask & 2 )  && 255 ; // Green
            data[p++ ] = (mask & 4) && 255; // Blue
            p++;
            mask>>=3;
            bitsLeft-=3;
        }
        context.putImageData(image, 0, 0);
        return canvas;
    }
    return _generatePattern;
})();
于 2014-06-27T08:53:54.643 に答える
-2

window.requestAnimationFrame(yourLoopF​​unction); を試してください。ループ関数を呼び出すとき。

function loop(){
    drawNoise();
    window.requestAnimationFrame(loop);
}
loop();
于 2016-05-25T12:16:14.977 に答える