View on GitHub

lectures

Three.js(lec02)

three_js/Home


演習

base20.html のコピー

前項と同じように雛形となるファイルをコピーして演習を進める。
雛形はThreeJS-master/lec02/base20.htmlである。このファイルをThreeJS-master/lec02/work21.htmlのようにコピーする。

以降、主にアニメーションに関する演習を行う。ここでは位置や姿勢の値を直接計算する非常に単純なアニメーションを扱う。
なお、ThreeJS-master/lec02/base20.htmlThreeJS-master/lec01/base10.htmlとほとんど同じであるが、以下の部分で物体のローカル座標軸を表示するようにしている。

/* 球体の生成 */
const sphere =
...
sphere.add(new THREE.AxesHelper(2)); /* 物体のローカル座標軸を表示する */
scene.add(sphere);
...
/* 立方体の生成 */
const cubeGeometry =
...
cube.add(new THREE.AxesHelper(5)); /* 物体のローカル座標軸を表示する */
scene.add(cube);

また、AUTO_SCROLL_DEBUGtrueにしている。 これによりtaDebugText.valueに文字列を追加すると、追加した文字列が表示されるように自動的に<textarea id="debugText">がスクロールする。

/* デバッグ用の出力 */
const AUTO_SCROLL_DEBUG = true; // taDebugText を常に最新の行までスクロールさせるかどうか。

work21 物体の等速運動( position )

物体をアニメーションさせる場合、画面の描画更新処理内に位置や姿勢の変化をプログラムする必要がある。work21.htmlの下記の場所である。

/* アニメーションのための描画更新処理 */
function renderFrame() {
  const deltaTime = clock.getDelta(); /* 前フレームからの経過時間。物体の移動に使う。 */
  /* ↓↓↓work21~work24 の追記場所↓↓↓ */

  /* ↑↑↑work21~work24 の追記場所↑↑↑ */
...
}

ここで、前フレームからの経過時間const deltaTimeを使い、例えばconst cubeを x 軸に沿って秒速 2m(注)で移動させるには次のように記述する。

/* アニメーションのための描画更新処理 */
function renderFrame() {
  const deltaTime = clock.getDelta(); /* 前フレームからの経過時間。物体の移動に使う。 */
  /* ↓↓↓work21~work24 の追記場所↓↓↓ */
  cube.position.x += (2 * deltaTime);
  /* ↑↑↑work21~work24 の追記場所↑↑↑ */
...
}

work21.png

work22 物体の等速運動( rotation )

位置の変化はpositionの値を変更していくことでプログラムできた。 姿勢については専用のメソッドrotateX, rotateY, rotateZ、を使う。 これらのメソッドは Three.js で生成するほとんどの物体が利用でき、引数に与えた角度だけ物体を回転させられる。

引数の単位は「ラジアン」である(π radian = 180 度)が、便利な単位の変換関数THREE.Math.degToRad(度)(「度」->「ラジアン」への変換)とTHREE.Math.radToDeg(ラジアン)(「ラジアン」->「度」への変換)があるので、それらを使用すれば何の問題もない。

/* ↓↓↓work21~work24 の追記場所↓↓↓ */
cube.position.x += 2 * deltaTime;
cube.rotateY(THREE.Math.degToRad(60) * deltaTime); // 秒速60度で Y 軸中心に回転させる。
/* ↑↑↑work21~work24 の追記場所↑↑↑ */

work22.png

回転に関する補足

Three.js に関する WEB 資料や参考書では、姿勢の変更もpositionと似たようなコードでrotation.y += ***のように書いてあるものが多い。
CG の表示だけならそれでもほとんど問題はないが、本演習の付録で紹介する物理エンジンと組み合わせた際に不具合が生じるため、メソッドを使って姿勢を変化させている。

work23 物体の等速運動(物体の親子関係生成によるワールド座標系での回転)

work22では物体のrotateYメソッドを使用することで物体を回転させた。 このとき、物体のローカル座標軸を中心に回転していることに注目してほしい。
例えば、太陽系の CG を表現するようなシーンで地球が太陽の周囲を公転するシーンを想定する。このとき、太陽をワールド座標の中心に据えて地球は太陽を中心に回転させたい、と考えるのが自然である。
しかし、work22の方法では地球を自転させることはできても公転させる場合にpositionに対して面倒な計算が必要となる。

/* ↓↓↓work23~work24 の追記場所↓↓↓ */
sphere.position.set(0, 0, 0); /* 球体をワールドの中心に据える */
cube.position.set(5, 0, 0); /* 立方体の場所を変更 */
scene.remove(cube); /* 立方体をシーンから削除し... */
sphere.add(cube); /* 球体とまとめて動かせるようにする */
/* ↑↑↑work23~work24 の追記場所↑↑↑ */
/* アニメーションのための描画更新処理 */
function renderFrame() {
  const deltaTime = clock.getDelta(); /* 前フレームからの経過時間。物体の移動に使う。 */
  /* ↓↓↓work21~work24 の追記場所↓↓↓ */
  sphere.rotateY(deltaTime * THREE.Math.degToRad(30)); /* 球体を回転させれば、立方体もまとめて動く */
  /* ↑↑↑work21~work24 の追記場所↑↑↑ */
...
}

work23_01.png

もともとの目的であった「ワールド座標系での回転」を直接的に実現しているわけではない。ここでは座標 0,0,0 に配置したsphere(球体)と座標 5,0,0 に配置したcube(立方体)を一つの物体としてまとめている。ただし、回転や移動の中心はsphere(球体)にしたい。このように複数物体をまとめる際に、基準となる物体を「親」、親に従属して移動する物体を「子」と呼ぶことが多い。
Three.js では親子関係の構築をaddメソッドで行う。以下のコードで、もともとsceneの直接の子であったcubesphereの子としている。

scene.remove(cube); /* 立方体をシーンから削除し... */
sphere.add(cube); /* 球体とまとめて動かせるようにする */

公転と自転を同時に行う

function renderFrame() {
  const deltaTime = clock.getDelta(); /* 前フレームからの経過時間。物体の移動に使う。 */
  /* ↓↓↓work21~work24 の追記場所↓↓↓ */
  sphere.rotateY(deltaTime * THREE.Math.degToRad(30)); /* 球体を回転させれば、立方体もまとめて動く */
  cube.rotateY(deltaTime * -THREE.Math.degToRad(90)); /* 自転 */
  /* ↑↑↑work21~work24 の追記場所↑↑↑ */

work23_02.png

work24 スポットライトをアニメーションさせる

これまでの課題で物体の位置や回転を変化させる方法を習得した。これを利用しTHREE.SpotLightの照射方向を変えるアニメーションをプログラミングする。
前項の光源の部分で見たように光源の照射方向はシーンに追加したtargetの位置でコントロールできる。したがって、targetの位置を時間の経過とともに変えてやればよい。

/* ↓↓↓work24 の修正場所↓↓↓ */
const spotLight = /* ...省略... */  /* 色は白、強さは 1.0 のスポットライトを生成する */
spotLight.penumbra = 0.6; /* 半影をどの程度生じさせるか。 */
spotLight.castShadow = true; /* 他の物体に影を落とす */
spotLight. /* 省略 */ ; /* 光源の位置を座標(0, 10, 0)とする */
spotLight. /* 省略 */ ; /* 照射方向は座標(0, 0, 0)とする */
scene.add(spotLight); /* ライト本体と */
scene.add(spotLight.target); /* 照射ターゲットもシーンに追加する必要がある */
/* ↑↑↑work24 の修正場所↑↑↑ */

work24.png

function renderFrame() {
  const deltaTime = clock.getDelta(); /* 前フレームからの経過時間。物体の移動に使う。 */
  /* ↓↓↓work21~work24 の追記場所↓↓↓ */
  spotLight.target.position.x += 1 * deltaTime;
  /* ↑↑↑work21~work24 の追記場所↑↑↑ */

work24_02.png

スポットライトを回転させる

work23 と同じ要領でspotLight.targetを何等かの物体の子供としてやり、親物体を回転させればよい。

/* ↓↓↓work23~work24 の追記場所↓↓↓ */
spotLight.target.position.set(10, 0, 0);
scene.remove(spotLight.target); /* spotLight.target をシーンから削除し... */
cube.add(spotLight.target); /* 立方体とまとめて動かせるようにする */
/* ↑↑↑work23~work24 の追記場所↑↑↑ */
/* アニメーションのための描画更新処理 */
function renderFrame() {
  const deltaTime = clock.getDelta(); /* 前フレームからの経過時間。物体の移動に使う。 */
  /* ↓↓↓work21~work24 の追記場所↓↓↓ */
  /* cube を秒速30度で Y 軸中心に回転させる。省略 */
  /* ↑↑↑work21~work24 の追記場所↑↑↑ */
...

work24_03.png


three_js/Home