Animating objects with WebGL

by 2 contributors:

 

前の例で作成したコードはすでに、WebGL のシーンを 15 ミリ秒ごとに再描画するよう設定されています。今までは単純に、毎回同じものをそのまま再描画していました。これから、正方形が実際に動くようにコードを変えていきます。

今回の例では 2D の正方形を 3 次元空間で、実際に回転や移動させます。これにより、作成したのは 2D のオブジェクトですが、それは 3D 空間に存在していることが証明されます。

正方形を回転させる

正方形を回転させてみましょう。始めに、正方形の回転をたどる変数が必要です:

var squareRotation = 0.0;

そして、描画する際に正方形に回転を適用するよう、drawScene() 関数を更新する必要があります。正方形の初期描画位置に移した後、回転を以下のように適用します:

mvPushMatrix();
mvRotate(squareRotation, [1, 0, 1]);

これを現在のモデルビュー行列に保存し、そして行列を現在の squareRotation の値を基に、X 軸および Z 軸で回転させます。

描画後は、元の行列に戻す必要があります:

  mvPopMatrix();

後に描画する別のオブジェクトを回転させてしまうことを防ぐために、元の行列の保存と復元を行います。

実際に動かすために、時間がたつにつれて squareRotation の値を変えていくコードを追加する必要があります。これは最後にアニメーションを行った時刻を追跡する新たな変数 (lastSquareUpdateTime と呼びましょう) を作成することで実現できるので、drawScene() 関数の末尾に以下のコードを追加します。:

  var currentTime = (new Date).getTime();
  if (lastSquareUpdateTime) {
  	var delta = currentTime - lastSquareUpdateTime;
  	
  	squareRotation += (30 * delta) / 1000.0;
  }
  
  lastSquareUpdateTime = currentTime;

このコードは正方形をどれだけ回転させるかを決めるために、最後に squareRotation の値を更新してから経過した時間を使用しています。

正方形を動かす

同様に、描画前に位置情報を変えていくことで正方形を移動させることができます。以下の例で、いくつかの基本的なアニメーションを行ってみます (明らかに、実際はここまで極端に動かそうとは思わないでしょう) 。

新しい変数で、移動する際の各軸のオフセットをたどりましょう:

var squareXOffset = 0.0;
var squareYOffset = 0.0;
var squareZOffset = 0.0;

また、各軸の値をどれだけ変化させるかを以下の変数で示します:

var xIncValue = 0.2;
var yIncValue = -0.4;
var zIncValue = 0.3;

そして前の回転させる例のコードを、以下のコードを追加することで更新します:

    squareXOffset += xIncValue * ((30 * delta) / 1000.0);
    squareYOffset += yIncValue * ((30 * delta) / 1000.0);
    squareZOffset += zIncValue * ((30 * delta) / 1000.0);
    
    if (Math.abs(squareYOffset) > 2.5) {
      xIncValue = -xIncValue;
      yIncValue = -yIncValue;
      zIncValue = -zIncValue;
    }

これにより、正方形が回転するとともにズームイン・ズームアウトしながら、環境内を近づいたり遠ざかったりするようランダムに動き回ります。これはスクリーンセーバーのようです。

WebGL 対応のブラウザを実行している場合は、こちらをクリックして 実際の動きを見てみましょう。

より複雑な操作

この例は、行列をスタックから取り出す・スタックへ格納する 2 つのルーチンや、与えられた角度の値に基づいて行列を回転させるルーチンといった複雑な操作を行っています。参考として、以下にそれを掲載します:

var mvMatrixStack = [];

function mvPushMatrix(m) {
  if (m) {
    mvMatrixStack.push(m.dup());
    mvMatrix = m.dup();
  } else {
    mvMatrixStack.push(mvMatrix.dup());
  }
}

function mvPopMatrix() {
  if (!mvMatrixStack.length) {
    throw("Can't pop from an empty matrix stack.");
  }
  
  mvMatrix = mvMatrixStack.pop();
  return mvMatrix;
}

function mvRotate(angle, v) {
  var inRadians = angle * Math.PI / 180.0;
  
  var m = Matrix.Rotation(inRadians, $V([v[0], v[1], v[2]])).ensure4x4();
  multMatrix(m);
}

これらのルーチンは、以前 Vlad Vukićević 氏が記述されたサンプルより取り入れています。

ドキュメントのタグと貢献者

Contributors to this page: ethertank, yyss
最終更新者: ethertank,