CreateJS 1.0.0のStageGLでStageを置き替える

EaselJS 1.0.0に、新たなWebGLへの対応として`StageGL`クラスが導入されました(「[CreateJS: StageGL ー EaselJSのWebGL対応が新たに](http://www.fumiononaka.com/Business/html5/FN1704008.html)」参照)。CreateJS Blogの記事「[Getting Started with StageGL](http://blog.createjs.com/getting-started-with-stagegl/)」には、これまでの`Stage`を`StageGL`に置き替えるときの要点がかいつまんで紹介されています。そこで、jsdo.itのいくつかの簡単な作例で、`Stage`を`StageGL`に変えて動かしてみます(「[EaselJS: StageGL()コンストラクタ](http://fumiononaka.com/Business/html5/FN1705010.html)」参照)。

#ステージの色はグレーがデフォルト
はじめは、[ふたつのShapeインスタンスをドラッグ&ドロップする](http://jsdo.it/FumioNonaka/tVHo)作例です(図001)。つぎのように、コンストラクタ`Stage()`を[`StageGL()`](http://fumiononaka.com/Business/html5/FN1705010.html)に書き替えます。

```js
var stage;
var canvasElement = document.getElementById("myCanvas");
// stage = new createjs.Stage(canvasElement);
stage = new createjs.StageGL(canvasElement);
```

####図001■EaselJS 0.8.2: EaselJSでマウスクリックとドラッグ&ドロップを扱う
![170523_stagegl_001.png](https://qiita-image-store.s3.amazonaws.com/0/128949/760c0e3c-b013-86ca-3847-8c52df89203b.png)
[\>\> jsdo.itへ](http://jsdo.it/FumioNonaka/tVHo)

すると、`Shape`インスタンスが消えて、ステージがグレーに変わります。`StageGL`の背景色はグレーがデフォルトなのです(「[My background is grey](http://blog.createjs.com/getting-started-with-stagegl/#answer-3)」参照)。色は[`Stage.setClearColor()`メソッド](http://www.createjs.com/docs/easeljs-stagegl/classes/StageGL.html#method_setClearColor)によって決めます。引数にカラー名は使えないものの、[RGBAカラー値が渡せます](https://github.com/CreateJS/EaselJS/blob/master/src/easeljs/display/StageGL.js#L1380)。

```js
stage.setClearColor('#FFFFFF');
// stage.setClearColor(0xFFFFFFFF);  // RGBAカラー値も可
```

`StageGL()`コンストラクタの第2引数に渡すオブジェクトで、`transparent`プロパティを`true`に定めれば、背景は透過できます。ただし、負荷が高いので、できれば避けたほうがよいでしょう。CodePen「[Background Transparency](https://codepen.io/dgillen/pen/EmPREK)」にデモが掲げられています。

```js
var stage = new createjs.StageGL(canvasElement, {transparent: true});
```

#Shapeオブジェクトはキャッシュする
WebGLはラスターグラフィックス([ビットマップ画像](https://ja.wikipedia.org/wiki/%E3%83%93%E3%83%83%E3%83%88%E3%83%9E%E3%83%83%E3%83%97%E7%94%BB%E5%83%8F))と[ポリゴンメッシュ](https://ja.wikipedia.org/wiki/%E3%83%9D%E3%83%AA%E3%82%B4%E3%83%B3%E3%83%A1%E3%83%83%E3%82%B7%E3%83%A5)を描くようにつくられています。ところが、ShapeとTextのインスタンスは[ベクター形式](https://ja.wikipedia.org/wiki/%E3%83%99%E3%82%AF%E3%82%BF%E5%BD%A2%E5%BC%8F)のデータです。そのため、ステージから消えてしまうのです。これらのオブジェクトは、キャッシュすれば[ラスタライズ](https://ja.wikipedia.org/wiki/%E3%83%93%E3%83%83%E3%83%88%E3%83%9E%E3%83%83%E3%83%97%E7%94%BB%E5%83%8F#.E3.83.A9.E3.82.B9.E3.82.BF.E3.83.BC.E8.A1.A8.E7.8F.BE)されるので表示できるようになります。

```js
function createCircle(nX, nY, nRadius) {
	var myShape = new createjs.Shape();
	var nThickness = 1;
	var half = nRadius + nThickness;

	myShape.cache(-half, -half, half * 2, half * 2);

}
```

キャッシュしたイメージはテクスチャの中に描かれて、再利用されます。表示オブジェクトのキャッシュについては[`DisplayObject.cache()`メソッド](http://www.createjs.com/docs/easeljs-stagegl/classes/DisplayObject.html#method_cache)をご参照ください。

前掲の作例の`Stage`を`StageGL`に替えて動くようにしたのが「[EaselJS NEXT: Using StageGL with shapes](http://jsdo.it/FumioNonaka/cYhp)」です。`DisplayObject.cache()`メソッドには、引数でキャッシュする領域を渡します(前掲コード参照)。このとき、`Shape`インスタンスに描く線の太さも含めることに気をつけましょう。

#フィルタはそのまま使える
ふたつ目の作例は、[読み込んだビットマップ画像にフィルタを加えます](http://jsdo.it/FumioNonaka/feJF)。読み込み待ちには[`ImageLoader`クラス](http://www.fumiononaka.com/Business/html5/FN1412005.html)を使いました。画像は[`BlurFilter`](http://www.createjs.com/docs/easeljs/classes/BlurFilter.html)でぼかし、ドラッグする軌跡に[`AlphaMaskFilter`](http://www.createjs.com/docs/easeljs/classes/AlphaMaskFilter.html)を加えることでくっきりした画像が描き出されます(図002)。

####図002■ドラッグする軌跡でアルファマスクを描く
![170523_stagegl_002.png](https://qiita-image-store.s3.amazonaws.com/0/128949/d4bb7753-b0c6-3fc6-b05b-57226bcc0baa.png)
[\>\> jsdo.itへ](http://jsdo.it/FumioNonaka/feJF)

この作例のコンストラクタ`Stage()`を`StageGL()`に書き替えたのが「[EaselJS NEXT: Using StageGL with filters](http://jsdo.it/FumioNonaka/y8uG)」です。ふたつのフィルタは何の手も加えずに動きました。ビットマップ画像の扱いや読み込み待ちもコードはそのままです。

ただ、カーソル代わりに動かしていた`Shape`インスタンスは、前の作例と同じくキャッシュしなければなりませんでした。

```js
function createCursor() {
	cursor = new createjs.Shape();

	cursor.cache(-radius, -radius, radius * 2, radius * 2);

}
```

#処理を速める
`Shape`オブジェクトは、キャッシュすることで`StageGL`に描くことができます。けれど、`Stage`を使った場合と比べて、処理が速くなるとはかぎりません。

たとえば、「[EaselJS 1.0.0 + ES6: Bursting particles animation with StageGL](http://jsdo.it/FumioNonaka/2uWj)」の作例です。1ピクセルの`Shape`インスタンス3,000個を`StageGL`上でマウスポインタに合わせて弾けるようにアニメーションさせています。`Stage`オブジェクトを使ったもとの「[EaselJS 0.8.0: Bursting particles animation with the linked list](http://jsdo.it/FumioNonaka/qi7O)」と比べると、明らかに遅くなっています。

WebGLの速さを活かすには、オブジェクトそのものをビットマップにするのがよいでしょう。「[EaselJS 1.0.0 + ES6: Bursting particles animation with StageGL](http://jsdo.it/FumioNonaka/eIzz6)」は、パーティクルのPGN画像を`Bitmap`インスタンスに読み込みました。この作例では粒子数を10倍の30,000個にし、表示領域も拡げています。それでも動きの滑らかさは、もとの例と変わりません。

WebGLの処理を最適化するには、読み込むビットマップ画像は一辺が2の累乗の正方形にしておきます(「[I don’t like the image quality](http://blog.createjs.com/getting-started-with-stagegl/#answer-4)」参照)。これはWebGLの制約で、WebGL 2.0では取り除かれるようです。

実際に用いるイメージは、一辺が2の累乗とか、正方形でなくて構いません。使う領域は、[`Bitmap.sourceRect`プロパティ](http://www.createjs.com/docs/easeljs-stagegl/classes/Bitmap.html#property_sourceRect)に`Rectangle`オブジェクトで定めて切り抜きます。スプライトシートを使うのは有効でしょう。

```js
var imageWidth = 180;
var imageHeight = 180;

function draw(eventObject) {
	var image = eventObject.result;

	// var imageWidth = imageSize.x = image.width;
	// var imageHeight = imageSize.y = image.height;
	imageSize.x = image.width = imageWidth;
	imageSize.y = image.height = imageHeight;

}
function createBitmap(image, nX, nY) {
	var myBitmap = new createjs.Bitmap(image);

	myBitmap.sourceRect = new createjs.Rectangle(0, 0, 180, 180);

}
```

ビットマップイメージの拡大や回転をするとき、`StageGL()`コンストラクタの第2引数で、`antialias`プロパティに`true`を与えれば滑らかに表示されます(読み込む画像は一辺が2の累乗の正方形にしなければなりません)。ただし、負荷は高まるでしょう。前出「Getting Started with StageGL」の[比較画像](http://blog.createjs.com/wp-content/uploads/2017/05/SamplingExample.png)をお確かめください。

#Canvasの領域を変えたとき
Canvasの幅や高さを変えたとき、WebGLに新たなサイズを伝えなければ正しく描画されません。そのためには、[`StageGL.updateViewport()`メソッド](http://www.createjs.com/docs/easeljs-stagegl/classes/StageGL.html#method_updateViewport)を呼び出します。CodePen「[Resizing](https://codepen.io/dgillen/pen/vxooXa)」のデモで結果が確かめられます。