Kevin Reid のpreserveDrawingBuffer
提案は正しいものですが、(通常) より良いオプションがあります。tl;dr は最後のコードです。
レンダリングされた Web ページの最終的なピクセルをまとめるにはコストがかかる可能性があり、それを WebGL コンテンツのレンダリングと調整するとさらにコストがかかります。通常の流れは次のとおりです。
- JavaScript が描画コマンドを WebGL コンテキストに発行します
- JavaScript が返され、コントロールがメインのブラウザ イベント ループに戻ります
- WebGL コンテキストは、現在画面にレンダリングされている Web ページに統合するために、描画バッファー (またはその内容) をコンポジターに渡します。
- 画面に表示された WebGL コンテンツを含むページ
これは、ほとんどの OpenGL アプリケーションとは異なることに注意してください。それらでは、レンダリングされたコンテンツは通常、ページ上の他の多くのものと合成されるのではなく、直接表示されます。その一部は、実際には WebGL コンテンツの上にあり、ブレンドされている場合があります。
WebGL 仕様は、手順 3 の後で描画バッファーを本質的に空として扱うように変更されました。devtools で実行しているコードは、手順 4 の後に来るため、空のバッファーが得られます。この仕様の変更により、ステップ 3 の後のブランキングが基本的にハードウェアで実際に発生するプラットフォーム (多くのモバイル GPU など) でパフォーマンスが大幅に向上しました。これを回避して、ステップ 3 の後に WebGL コンテンツのコピーを時々作成する場合、ブラウザーはステップ 3 の前に常に描画バッファーのコピーを作成する必要があります。これにより、一部のプラットフォームでフレームレートが急激に低下します。
trueに設定することで、まさにそれを実行して、ブラウザに強制的にコピーを作成させ、画像コンテンツへのアクセスを維持させることができpreserveDrawingBuffer
ます。仕様から:
このデフォルトの動作は、WebGLContextAttributes オブジェクトの preserveDrawingBuffer 属性を設定することで変更できます。このフラグが true の場合、描画バッファの内容は、作成者が消去または上書きするまで保持されます。このフラグが false の場合、レンダリング関数が返された後に、このコンテキストをソース イメージとして使用して操作を実行しようとすると、未定義の動作が発生する可能性があります。これには、readPixels または toDataURL 呼び出し、またはこのコンテキストを別のコンテキストの texImage2D または drawImage 呼び出しのソース イメージとして使用することが含まれます。
あなたが提供した例では、コードはコンテキスト作成行を変更しているだけです:
gl = canvas.getContext("experimental-webgl", {preserveDrawingBuffer: true});
何をどのようにレンダリングしているかによっては、一部のブラウザーでより遅いパスが強制され、パフォーマンスが低下することに注意してください。コピーを実際に作成する必要がないほとんどのデスクトップ ブラウザーでは問題ないはずです。これらは、WebGL 対応ブラウザーの大部分を占めていますが、今のところだけです。
ただし、別のオプションがあります (仕様の次の段落で少し紛らわしく述べられているように)。
基本的に、ステップ 2 の前に自分でコピーを作成します。つまり、すべての描画呼び出しが終了した後、コードからブラウザーに制御を戻す前です。これは、WebGL 描画バッファーがまだ無傷でアクセス可能な場合であり、ピクセルへのアクセスに問題はないはずです。同じものを使用するtoDataUrl
かreadPixels
、他の方法で使用する呼び出しを使用します。重要なのはタイミングだけです。
ここでは、両方の長所を活用できます。preserveDrawingBuffer
描画バッファーのコピーを取得しますが、 trueに設定した場合のように、コピーが不要なフレーム (ほとんどの場合) であっても、すべてのフレームで料金を支払う必要はありません。
提供した例では、コードを の一番下に追加するだけdrawScene
で、キャンバスのコピーがすぐ下に表示されます。
function drawScene() {
...
var webglImage = (function convertCanvasToImage(canvas) {
var image = new Image();
image.src = canvas.toDataURL('image/png');
return image;
})(document.querySelectorAll('canvas')[0]);
window.document.body.appendChild(webglImage);
}