WebGL学習記録(5) 複数のモデル、再帰処理でアニメーション


参考[webglorg](http://wgld.org/);
原則として上記ページを見ながら学習した記録です。
![Screen Shot 2015-10-29 at 16.04.35.png](https://qiita-image-store.s3.amazonaws.com/0/54225/efa7a0ae-17e7-db39-59df-eeecf5bad9fe.png "Screen Shot 2015-10-29 at 16.04.35.png")

## 複数モデルのレンダリング
### 頂点バッファの再利用
VBOを再利用し、座標変換行列を操作して複数モデルの描写を表現する。

## 座標変換行列の再利用
座標変換行列も再利用します。
実際、複数モデルを違う位置にレンダリングするとき、操作するのはモデル変換行列のみ。

手順としては

* ビュー・プロジェクションのりょう左表変換行列を用意
* あらかじめ二つは掛け合わせておく(pv)
* 一つのモデル座標変換行列を用意(m1)
* m1にpvを掛け合わせて uniform に登録
* 一つ目のモデルを描写
* 二つ目のモデル座標変換行列を用意(m2)
* m2 に pv を掛け合わせて uniform 登録
* 二つ目のモデルを描写
* コンテキストのリフレッシュをして再描写

## つまりどうなるか

一部抜粋。

```javascript
// 各種行列の生成と初期化
var mMatrix = m.identity(m.create());
var vMatrix = m.identity(m.create());
var pMatrix = m.identity(m.create());
var tmpMatrix = m.identity(m.create());
var mvpMatrix = m.identity(m.create());

// ビュー×プロジェクション座標変換行列
m.lookAt([0.0, 0.0, 3.0], [0, 0, 0], [0, 1, 0], vMatrix);
m.perspective(90, c.width / c.height, 0.1, 100, pMatrix);
m.multiply(pMatrix, vMatrix, tmpMatrix);

// 一つ目のモデルを移動するためのモデル座標変換行列
m.translate(mMatrix, [1.5, 0.0, 0.0], mMatrix);

// モデル×ビュー×プロジェクション(一つ目のモデル)
m.multiply(tmpMatrix, mMatrix, mvpMatrix);

// uniformLocationへ座標変換行列を登録し描画する(一つ目のモデル)
gl.uniformMatrix4fv(uniLocation, false, mvpMatrix);
gl.drawArrays(gl.TRIANGLES, 0, 3);

// 二つ目のモデルを移動するためのモデル座標変換行列
m.identity(mMatrix);
m.translate(mMatrix, [-1.5, 0.0, 0.0], mMatrix);

// モデル×ビュー×プロジェクション(二つ目のモデル)
m.multiply(tmpMatrix, mMatrix, mvpMatrix);

// uniformLocationへ座標変換行列を登録し描画する(二つ目のモデル)
gl.uniformMatrix4fv(uniLocation, false, mvpMatrix);
gl.drawArrays(gl.TRIANGLES, 0, 3);

// コンテキストの再描画
gl.flush();
```

## 再帰処理と移動・回転・拡大縮小
今回は合計3つのポリゴンを描写する。
VBOや一部の座標変換行列を使い回すことによって、少ないリソースで大量のモデルを描写することが可能。

## 恒常ループ処理を実装する
変化の過程を常に更新し続ける、つまりアニメーションを実装する。
基本は setTimeout メソッドを使うことにする。
setTimeout メソッドは、第一引数に呼び出すことになる関数(処理)を、第二引数に関数を呼び出す経過時間をミリ秒で指定。

## arguments クラスと callee プロパティ
arguments クラスの callee プロパティを参照することで、関数自身への山椒を得ることが可能。

## 再帰関数の中に詰め込む処理を選別

 * 画面のクリア
 * モデル座標変換行列の生成
 * uniform への座標変換行列の登録
 * 描写命令
 * 画面の更新
 * setTimeout + arguments.callee

つまりこうなる。

```javasctipt
// minMatrix.js を用いた行列関連処理
// matIVオブジェクトを生成
var m = new matIV();

// 各種行列の生成と初期化
var mMatrix = m.identity(m.create());
var vMatrix = m.identity(m.create());
var pMatrix = m.identity(m.create());
var tmpMatrix = m.identity(m.create());
var mvpMatrix = m.identity(m.create());

// ビュー×プロジェクション座標変換行列
m.lookAt([0.0, 0.0, 5.0], [0, 0, 0], [0, 1, 0], vMatrix);
m.perspective(45, c.width / c.height, 0.1, 100, pMatrix);
m.multiply(pMatrix, vMatrix, tmpMatrix);

// カウンタの宣言
var count = 0;

// 恒常ループ
(function(){
    // canvasを初期化
    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    gl.clearDepth(1.0);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    
    // カウンタをインクリメントする
    count++;
    
    // カウンタを元にラジアンを算出
    var rad = (count % 360) * Math.PI / 180;
    
    // モデル1は円の軌道を描き移動する
    var x = Math.cos(rad);
    var y = Math.sin(rad);
    m.identity(mMatrix);
    m.translate(mMatrix, [x, y + 1.0, 0.0], mMatrix);
    
    // モデル1の座標変換行列を完成させレンダリングする
    m.multiply(tmpMatrix, mMatrix, mvpMatrix);
    gl.uniformMatrix4fv(uniLocation, false, mvpMatrix);
    gl.drawArrays(gl.TRIANGLES, 0, 3);
    
    // モデル2はY軸を中心に回転する
    m.identity(mMatrix);
    m.translate(mMatrix, [1.0, -1.0, 0.0], mMatrix);
    m.rotate(mMatrix, rad, [0, 1, 0], mMatrix);
    
    // モデル2の座標変換行列を完成させレンダリングする
    m.multiply(tmpMatrix, mMatrix, mvpMatrix);
    gl.uniformMatrix4fv(uniLocation, false, mvpMatrix);
    gl.drawArrays(gl.TRIANGLES, 0, 3);
    
    // モデル3は拡大縮小する
    var s = Math.sin(rad) + 1.0;
    m.identity(mMatrix);
    m.translate(mMatrix, [-1.0, -1.0, 0.0], mMatrix);
    m.scale(mMatrix, [s, s, 0.0], mMatrix)
    
    // モデル3の座標変換行列を完成させレンダリングする
    m.multiply(tmpMatrix, mMatrix, mvpMatrix);
    gl.uniformMatrix4fv(uniLocation, false, mvpMatrix);
    gl.drawArrays(gl.TRIANGLES, 0, 3);
    
    // コンテキストの再描画
    gl.flush();
    
    // ループのために再帰呼び出し
    setTimeout(arguments.callee, 1000 / 30);
})();
```
![Screen Shot 2015-10-29 at 19.41.04.png](https://qiita-image-store.s3.amazonaws.com/0/54225/2e49936a-6ff8-7b6b-1d3c-ecbac6a3a342.png "Screen Shot 2015-10-29 at 19.41.04.png")