11---
22title : オフスクリーンキャンバス
33author : 池田 泰延
4- published_date : 2019-02-12
5- modified_date : 2019-02-12
4+ published_date : 2019-02-14
5+ modified_date : 2019-02-14
66---
77
8- オフスクリーンキャンバスはWeb Workers(ウェブワーカーズ)を使用してWorkerスレッドで描画処理を行える機能です。負荷の高い描画処理をWorkerスレッドに移動することで、メインスレッドの負担が軽くなり、余裕ができます。これによりメインスレッドでスムーズなユーザー操作を実現できるようになり、ユーザー体験の向上が期待できます。
8+ オフスクリーンキャンバスはWeb Workers(ウェブワーカーズ)を使用してWorkerスレッドで描画処理を行える機能です。負荷の高い描画処理をWorkerスレッドに移動することで、メインスレッドの負担が軽くなり、余裕ができます。これによりメインスレッドでスムーズなユーザー操作を実現できるようになり、ユーザー体験の向上が期待できます。具体的には、 ` canvas ` の描画処理が大きかった場合にオフスクリーンキャンバスを使うと、ボタンクリック時の反応やCSSアニメーションが滑らかになるでしょう。
99
1010Three.jsでもオフスクリーンキャンバスを利用できます。複雑なことをしなければ難しくなく、通常のThree.jsのコードに少しの実装を追加するだけで実現できます。
1111
12- オフスクリーンキャンバスの機能については記事「[ オフスクリーンキャンバスを使ったJSのマルチスレッド描画 – スムーズなユーザー操作実現の切り札 \- ICS MEDIA ] ( https://ics.media/entry/19043 ) 」で詳しく解説しています。Three.jsで利用する前に一読をオススメします 。
12+ オフスクリーンキャンバスの機能については記事「[ オフスクリーンキャンバスを使ったJSのマルチスレッド描画 – スムーズなユーザー操作実現の切り札] ( https://ics.media/entry/19043 ) 」で詳しく解説しています。この解説を読み進める前に一読ください 。
1313
1414
15- ## 使い方
15+ ## Three.jsでの使い方
1616
17- ワーカーを利用するにあたって、メインスレッド側とワーカー側と処理を分離する必要があります。これはファイル単位で分けなければなりません。まずはメインスレッド側のコードを紹介します。HTMLに` canvas ` 要素を配置し、JavaScriptではワーカー側に` canvas ` 要素のオフスクリーン用オブジェクトを転送します。
17+ ワーカーを利用するにあたって、メインスレッド側とワーカー側と処理を分離する必要があります。これはファイル単位で分けなければなりません。まずはメインスレッド側のコードを紹介します。HTMLに` canvas ` 要素を配置し、JavaScriptでは` canvas ` 要素のオフスクリーン用オブジェクトを取得します。ワーカーインスタンスで投げてしまいます。
18+
19+ ![ ] ( ../imgs/osc_simple.png )
20+
21+ - [ サンプルを再生する] ( https://ics-creative.github.io/tutorial-three/samples/osc_simple.html )
22+ - サンプルのソースコードを確認する
23+ - [ メインスレッド側] ( ../samples/osc_simple.html )
24+ - [ ワーカー側] ( ../samples/osc_simple_worker.js )
25+
26+
27+
28+ ### メインスレッド側
1829
1930``` html
2031<canvas id =" myCanvas" ></canvas >
@@ -31,7 +42,11 @@ const worker = new Worker('osc_simple_worker.js');
3142worker .postMessage ({ canvas: offscreenCanvas }, [offscreenCanvas]);
3243```
3344
34- 続いて、ワーカー側の処理を解説します。ワーカー側では、Three.jsを` importScripts() ` メソッドを使って読み込みます。` importScripts() ` メソッドはワーカーでのみ利用できる機能です。
45+ ### ワーカー側
46+
47+ ワーカー側では、Three.jsを` importScripts() ` メソッドを使って読み込みます。` importScripts() ` メソッドはワーカーでのみ利用できる機能です。外部のJSファイルを読み込むことができます。
48+
49+ ※ES Modules形式はワーカーで利用できないため注意ください。
3550
3651``` js
3752importScripts (
@@ -49,20 +64,31 @@ onmessage = event => {
4964 // ・・・いろいろ処理
5065` ` `
5166
52- バッドノウハウですが、 ひとつだけ工夫しなければ、Three.jsをワーカー側で利用できません。Three.jsは内部でCanvas要素のstyleにアクセスします 。しかし、OffscreenCanvasはDOM要素ではないため、` style` 属性を持ちません。Three.jsで使用する場合はランタイムエラーを避けるため、OffscreenCanvasオブジェクトに明示的に` style` プロパティを付加します。
67+ ひとつだけ工夫しなければ、Three.jsをワーカー側で利用できません。Three.jsは内部で ` canvas ` 要素の ` style ` 属性にアクセスします 。しかし、OffscreenCanvasはDOM要素ではないため、` style` 属性を持ちません。Three.jsで使用する場合はランタイムエラーを避けるため、OffscreenCanvasオブジェクトに明示的に` style` プロパティを付加します。
5368
5469` ` ` js
5570 // Three.jsのライブラリの内部で style.width にアクセスされてしまう
5671 // 対策しないと、エラーが発生するためダミーの値を指定
5772 canvas .style = { width: 0 , height: 0 };
5873` ` `
5974
60- あとは普通にコードをかけばThree.jsが動きます。コードを全部みて呆気なさを感じてください。
75+ あとは普通にコードをかけばThree.jsが動きます。次のコードを見て、呆気なさを感じてください。
76+
77+
78+ ## オフスクリーンキャンバスでの画像の使い方
6179
80+ オフスクリーンキャンバスで画像を使うには` ImageBitmap ` オブジェクトを利用します。
6281
63- ## 画像の使い方
82+ 
6483
65- オフスクリーンキャンバスで画像を使うには` ImageBitmap ` を利用します。通常の` THREE .ImageLoader ()` だとDOM APIの` Image` オブジェクト、つまり` img` タグが使われます。ワーカー側ではDOM APIが利用できないため、` img` タグで画像を読み込むことはできないのです。オフスクリーンキャンバスと同時期に用意された、` ImageBitmap ` オブジェクトを使います。Three.jsでは` THREE .ImageBitmapLoader ()` でファイルを読み込み、` ImageBitmap ` インスタンスを` THREE .CanvasTexture ` でテクスチャーへと変換します。あとは、適当なマテリアルにテクスチャーとして設定するだけです。
84+ - [サンプルを再生する](https://ics-creative.github.io/tutorial-three/samples/osc_imagebitmap.html)
85+ - サンプルのソースコードを確認する
86+ - [メインスレッド側](../samples/osc_imagebitmap.html)
87+ - [ワーカー側](../samples/osc_imagebitmap_worker.js)
88+
89+
90+
91+ 通常の` THREE .ImageLoader ()` メソッドだとDOM APIの` Image` オブジェクト、つまり` img` タグが使われます。ワーカー側ではDOM APIが利用できないため、` img` タグで画像を読み込むことはできないのです。オフスクリーンキャンバスと同時期に用意された` ImageBitmap ` オブジェクトでは、DOM APIの` Image` オブジェクトを使わずに画像データを扱えます。Three.jsでは` THREE .ImageBitmapLoader ()` でファイルを読み込み、` ImageBitmap ` インスタンスを` THREE .CanvasTexture ` でテクスチャーへと変換します。あとは、適当なマテリアルにテクスチャーとして設定するだけです。
6692
6793` ` ` js
6894// テクスチャーを読み込み
@@ -76,11 +102,24 @@ const texture = await new Promise(resolve => {
76102const material = new THREE.MeshStandardMaterial ({ map: texture });
77103` ` `
78104
79- ## リサイズの方法
105+ 上記のコードではawait/asyncの構文を使っています。オフスクリーンキャンバスが動作するような新しいブラウザーのバージョンであれば、ECMAScript 2018ぐらいは動作するでしょう。
106+
107+ ## オフスクリーンキャンバスでのリサイズの方法
80108
81109通常のThree.jsのりサイズ処理は、記事「[リサイズ処理](renderer_resize.md)」を先に読んで学習しておいてください。その上で解説します。
82110
83- オフスクリーンキャンバスからだと、メインスレッド側のりサイズを検知できません。メインスレッド側のりサイズは、メインスレッド側で検知しなけばなりません。たとえば、次のようなコードで、ワーカー側にリサイズイベントを通知します。ワーカー側では` worker .postMessage ()` メソッドにより通達を受けますが、初期化なのかリサイズイベントなのか判断する手がかりが必要なため、任意の` type` プロパティーを付与しています。
111+ 
112+
113+ - [サンプルを再生する](https://ics-creative.github.io/tutorial-three/samples/osc_resize.html)
114+ - サンプルのソースコードを確認する
115+ - [メインスレッド側](../samples/osc_resize.html)
116+ - [ワーカー側](../samples/osc_resize_worker.js)
117+
118+
119+
120+ オフスクリーンキャンバスからだと、メインスレッド側のリサイズイベントを検知できません。メインスレッド側のリサイズイベントは、メインスレッド側で検知しなけばなりません。
121+
122+ たとえば、次のようなコードでワーカー側にリサイズイベントを通知します。ワーカー側では` worker .postMessage ()` メソッドにより通達を受けますが、初期化なのかリサイズイベントなのか判断する手がかりが必要となります。引数には区別ができるように任意の` type` プロパティーを付与しています。
84123
85124` ` ` js
86125// 普通のキャンバスを取得
@@ -90,7 +129,7 @@ const offscreenCanvas = canvasElement.transferControlToOffscreen();
90129const worker = new Worker (' osc_resize_worker.js' );
91130worker .postMessage (
92131 {
93- type: ' init' ,
132+ type: ' init' , // 処理区別のために追加
94133 canvas: offscreenCanvas,
95134 width: innerWidth,
96135 height: innerHeight,
@@ -101,7 +140,7 @@ worker.postMessage(
101140
102141window .addEventListener (' resize' , event => {
103142 worker .postMessage ({
104- type: ' resize' ,
143+ type: ' resize' , // 処理区別のために追加
105144 width: innerWidth,
106145 height: innerHeight,
107146 devicePixelRatio: devicePixelRatio
0 commit comments