HTML5 / Canvasはダブルバッファリングをサポートしていますか?


83

私がやりたいのは、グラフィックをバッファに描画し、それをそのままキャンバスにコピーして、アニメーションを実行し、ちらつきを回避できるようにすることです。しかし、私はこのオプションを見つけることができませんでした。誰かが私がこれについてどうやって行くことができるか知っていますか?


12
私の経験では、アニメーションがスムーズになるように、キャンバスの描画がブラウザによって統合されています。説明するときにちらつくコードを共有できますか?
まぶたがない2010年

2
を使用するとIEがちらつく場合があることに気づきましたexplorercanvasが、これはもちろんHTML5ではcanvasなく、VMLによってエミュレートされた要素にすぎません。しかし、他のブラウザがそれを行うのを見たことがありません。
クライオ2010年


2
ちらつきのない本当にばかげた初心者コード。 jsfiddle.net/linuxlizard/ksohjr4f/3 すべての権利により、ちらつくはずです。ブラウザは印象的です。
David Poole

非同期描画機能がある場合にのみ、ダブルバッファリングが必要です。ブラウザに屈しない限り、つまり描画を同期させない限り、問題はありません。そこにpromiseやsetTimeoutなどを追加するとすぐにブラウザに戻り、ブラウザは現在の状態を描画してから、効果的にちらつきを引き起こします。
albertjan

回答:


38

次の役立つリンクは、ダブルバッファリングを使用する例と利点を示すことに加えて、html5キャンバス要素を使用するための他のいくつかのパフォーマンスのヒントを示しています。これには、ブラウザ全体のテスト結果をBrowserscopeデータベースに集約するjsPerfテストへのリンクが含まれています。これにより、パフォーマンスのヒントが確実に検証されます。

http://www.html5rocks.com/en/tutorials/canvas/performance/

便宜上、記事で説明されている効果的なダブルバッファリングの最小限の例を含めました。

// canvas element in DOM
var canvas1 = document.getElementById('canvas1');
var context1 = canvas1.getContext('2d');

// buffer canvas
var canvas2 = document.createElement('canvas');
canvas2.width = 150;
canvas2.height = 150;
var context2 = canvas2.getContext('2d');

// create something on the canvas
context2.beginPath();
context2.moveTo(10,10);
context2.lineTo(10,30);
context2.stroke();

//render the buffered canvas onto the original canvas element
context1.drawImage(canvas2, 0, 0);

83

非常に簡単な方法は、同じ画面位置に2つのcanvas要素を配置し、表示する必要のあるバッファーの可視性を設定することです。隠されたものを描き、終わったら裏返します。

いくつかのコード:

CSS:

canvas { border: 2px solid #000; position:absolute; top:0;left:0; 
visibility: hidden; }

JSでの反転:

Buffers[1-DrawingBuffer].style.visibility='hidden';
Buffers[DrawingBuffer].style.visibility='visible';

DrawingBuffer=1-DrawingBuffer;

このコードでは、配列 'Buffers []'は両方のcanvas-objectsを保持します。したがって、描画を開始する場合でも、コンテキストを取得する必要があります。

var context = Buffers[DrawingBuffer].getContext('2d');

オフトピック:私は個人的にを使用して<noscript>、Javascriptでキャンバス要素を作成するのが好きです。とにかく、通常はJavascriptでキャンバスのサポートを確認する必要があるのに、なぜHTMLにキャンバスのフォールバックメッセージを入れたいのでしょうか。
Shea 2012

19

私がテストしたブラウザはすべて、フレームを描画するコードが完了するまでキャンバスを再描画しないことで、このバッファリングを処理します。WHATWGメーリングリストも参照してください:http//www.mail-archive.com/whatwg@lists.whatwg.org/msg19969.html


10
ちらつきや画面の破れに気づきました。それをどのように説明するかわからない。Linuxで最新のChromeを使用する。
グロム2012

14

いつでも実行できvar canvas2 = document.createElement("canvas"); 、DOMに追加することはできません 。

皆さんがとても夢中にdisplay:none; なっているように見えるので、私にはすっきりしているように見え、ぎこちなく見えないキャンバスを持っているよりも正確にダブルバッファリングのアイデアを模倣しています。


8

2年以上後:

「手動で」ダブルバッファリングを実装する必要はありません。Geary氏は、彼の著書「HTML5Canvas」でこれについて書いています。

ちらつきを効果的に減らすためにrequestAnimationFrame()


1
ダブルバッファリングを使用することで見られたパフォーマンスの向上をどのように説明しますか?html5rocks.com/en/tutorials/canvas/performance
Rick Suggs

@ricksuggsええと、html5rocksで言及されている「ダブルバッファリング」または「オフスクリーンレンダリング」は、私が思っていたものとは少し異なります。私はDBを(vram内の)画面ページの交換と見なしました。これは事実上、メモリチャンクをコピーするのではなく、ポインタ操作にすぎませんでした。OPは、ちらつきを回避するためにDBを使用するように要求しました。これは、requestAnimationFrame()によって実際に対処されます。オフスクリーンレンダリングに関するこの記事は興味深いかもしれません。そこで、スプライトバッファを使用してバッファリングされた画像データをコピーして画面に貼り付けることに関するOPの質問に答えます
ohager 2014年

6

Joshは、ちらつきを避けるために、ブラウザが「描画プロセスがいつ終了するか」をどのように知っているかについて(しばらく前に)尋ねました。私は彼の投稿に直接コメントしたでしょうが、私の担当者は十分に高くありません。また、これは私の意見です。私はそれを裏付ける事実を持っていませんが、私はそれについてかなり自信を持っており、将来これを読んでいる他の人に役立つかもしれません。

描画が完了したとき、ブラウザは「認識」していないと思います。ただし、ほとんどのJavaScriptと同様に、コードがブラウザーへの制御を放棄せずに実行される限り、ブラウザーは基本的にロックされ、UIを更新/更新/応答できません。ブラウザの制御を放棄せずにキャンバスをクリアしてフレーム全体を描画すると、完了するまで実際にはキャンバスが描画されないと思います。

レンダリングが複数のsetTimeout / setInterval / requestAnimationFrame呼び出しにまたがる状況を設定した場合、1回の呼び出しでキャンバスをクリアし、次の数回の呼​​び出しでキャンバスに要素を描画し、(たとえば)5回の呼び出しごとにサイクルを繰り返します。呼び出しのたびにキャンバスが更新されるため、ちらつきが表示されることは間違いありません。

とはいえ、それを信頼できるかどうかはわかりません。私たちはすでに、実行前にjavascriptがネイティブマシンコードにコンパイルされる段階にあります(少なくとも、私が理解していることから、ChromeのV8エンジンはそれを実行します)。ブラウザがUIとは別のスレッドでJavaScriptを実行し、UI要素へのアクセスを同期して、UIにアクセスしていないJavaScriptの実行中にUIを更新/応答できるようになるまで、それほど長くはかからなかったとしても、驚くことではありません。それが発生した場合(そして、他のコードを実行しているときにイベントハンドラーが開始されるなど、克服しなければならない多くのハードルがあることを理解しています)、使用していないキャンバスアニメーションでちらつきが発生する可能性がありますある種のダブルバッファリング。

個人的には、2つのキャンバス要素を重ねて配置し、各フレームに表示/描画するというアイデアが大好きです。かなり邪魔にならず、おそらく数行のコードで既存のアプリケーションに簡単に追加できます。


丁度。ここJSFiddleを参照してくださいstackoverflow.com/questions/11777483/...例えば。
エリック

6

不信者のために、ここにいくつかのちらつきコードがあります。前の円を消去することを明示的にクリアしていることに注意してください。

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");

function draw_ball(ball) {
    ctx.clearRect(0, 0, 400, 400);
    ctx.fillStyle = "#FF0000";
    ctx.beginPath();
    ctx.arc(ball.x, ball.y, 30, 0, Math.PI * 2, true);
    ctx.closePath();
    ctx.fill();
}

var deltat = 1;
var ball = {};
ball.y = 0;
ball.x = 200;
ball.vy = 0;
ball.vx = 10;
ball.ay = 9.8;
ball.ax = 0.1;

function compute_position() {
    if (ball.y > 370 && ball.vy > 0) {
        ball.vy = -ball.vy * 84 / 86;
    }
    if (ball.x < 30) {
        ball.vx = -ball.vx;
        ball.ax = -ball.ax;
    } else if (ball.x > 370) {
        ball.vx = -ball.vx;
        ball.ax = -ball.ax;
    }
    ball.ax = ball.ax / 2;
    ball.vx = ball.vx * 185 / 186;
    ball.y = ball.y + ball.vy * deltat + ball.ay * deltat * deltat / 2
    ball.x = ball.x + ball.vx * deltat + ball.ax * deltat * deltat / 2
    ball.vy = ball.vy + ball.ay * deltat
    ball.vx = ball.vx + ball.ax * deltat
    draw_ball(ball);
}

setInterval(compute_position, 40);
<!DOCTYPE html>
<html>
<head><title>Basketball</title></head>
<body>
<canvas id="myCanvas" width="400" height="400" style="border:1px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
</body></html>


4
少なくとも、ボールが各フレームの半径を超えて移動していないときは、ちらつきはないようです。Chrome / Windows。
ジュール

10
私はrequestAnimFrameへの呼び出しを追加しました-を参照してここに-あなたの例にでjsfiddle.net/GzSWJ/28 -これ以上ちらつきません
ルー

5

Webブラウザにちらつきはありません!彼らはすでにレンダリングにdblバッファリングを使用しています。Jsエンジンは、表示する前にすべてのレンダリングを行います。また、コンテキストは、キャンバスコンテンツ自体ではなく、スタック変換行列データなどのみを保存および復元します。したがって、dblバッファリングは必要ありません。


8
あなたの主張を裏付ける証拠をいくつか提供できますか?
Rick Suggs 2013年

@ricksuggs DBを使用しないと、アニメーションのジャーキネスが悪くなることがわかりました。まだDBを試していません
FutuToad 2014

3

自分で作成するのではなく、既存のライブラリを使用してクリーンでちらつきのないJavaScriptアニメーションを作成することで、おそらく最高のマイレージを得ることができます。

これが人気のあるものです:http//processingjs.org


94
丁度!275KBのライブラリ全体を少しも手がかりなしに使用できるのに、なぜわざわざ10行の独自のコードを書くのでしょうか。はい、私は皮肉でした。
トム

10
ええ、大変ですか?
davidtbernal 2011年

3

2つのキャンバスが必要です:(css z-indexとposition:absoluteに注意してください)

<canvas id="layer1" width="760" height="600" style=" position:absolute; top:0;left:0; 
visibility: visible;  z-index: 0; solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
<canvas id="layer2" width="760" height="600" style="position:absolute; top:0;left:0; 
visibility: visible;  z-index: 1; solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>

最初のキャンバスが表示され、2番目のキャンバスが非表示になっていることがわかります。その後、非表示に描画するというアイデアを非表示にして、非表示のキャンバスを表示します。それが隠されているとき '明確な隠されたキャンバス

<script type="text/javascript">
var buff=new Array(2);
buff[0]=document.getElementById("layer1");
buff[1]=document.getElementById("layer2");

ctx[0]=buff[0].getContext("2d");
ctx[1]=buff[1].getContext("2d");
var current=0;
// draw the canvas (ctx[ current ]);
buff[1- current ].style.visibility='hidden';
buff[ current ].style.visibility='visible';
ctx[1-current].clearRect(0,0,760,600);
current =1-current;

誰かが手動でダブルバッファリング技術を適用する必要がある場合に備えて、素晴らしい実装です。次の行を追加するだけです。varctx= new Array(2); 上記のコードの空の行に移動します。
dimmat

2

Opera 9.10は非常に遅く、描画プロセスを示しています。ブラウザがダブルバッファリングを使用しないようにしたい場合は、Opera9.10を試してみてください。

一部の人々は、ブラウザが描画プロセスがいつ終了するかを何らかの形で決定していると示唆しましたが、それがどのように機能するかを説明できますか?Firefox、Chrome、IE9では、描画が遅い場合でも明らかなちらつきに気づかなかったので、それが彼らのやっているように見えますが、それがどのように達成されるかは私には謎です。さらに描画命令が実行される直前に、ブラウザが表示を更新していることをどのようにして知ることができますか?キャンバス描画命令を実行せずに5ms以上の間隔が経過した場合、バッファを安全に交換できると想定しているので、ちょうどいいタイミングだと思いますか?


2

ほとんどの場合、これを行う必要はありません。ブラウザがこれを実装します。しかし、常に役立つとは限りません!

図面が非常に複雑な場合でも、これを実装する必要があります。ほとんどの画面更新レートは約60Hzで、16msごとに画面が更新されることを意味します。ブラウザの更新レートはこの数値に近い可能性があります。シェイプを完成させるのに100msが必要な場合は、未完成のシェイプが表示されます。したがって、この状況でダブルバッファリングを実装できます。

テストを行いました。Clear a rect, wait for some time, then fill with some color.時間を10msに設定すると、ちらつきは見られません。しかし、20msに設定すると、ちらつきが発生します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.