タグ別アーカイブ: Morph animation

Blenderとthree.jsを使って行うモーフィングアニメーション

今回は、Blenderでモデリング、アニメーションをつけて、JSON形式で書き出して、three.jsでJSONデータを読み込んで、モーフィングアニメーションを再現する流れを、ざっくりと説明出来ればと思います。

20150108_img11
ソースコードは、以下よりダウンロード頂けます。

モデリングとアニメーションの作成にBlenderを使っています。Blenderはオープンソース(無償)の3DCG制作ツール
で、現時点での最新バージョンは2.72bになります。3DCG制作ツールはMaya3dsMaxLightwave3D等、高機能なプロ用ソフトが多くありますが、どれもそれなりの価格になります。Webコンテンツでの利用においては、レンダリングはあくまでブラウザ上なので、使う機能と言えば、せいぜいモデリングとアニメーション程度になり、高価で高機能な3DCG制作ツールは、オーバースペックだと思います。Blenderは無償ですが、高機能な3DCG制作ツールに、勝るとも劣らない機能を有している、素晴らしいツールだと思っています。

20150108_img


Blenderでモデリング

まずはBlenerでアニメーションを行うキャラクターのモデリングを行います。Blenderで作業するのに、まず覚えなくてはならないのはショートカットです。今回使ったショートカットをリストアップしました。マウスホイールやテンキーも多用するショートカットになっているので、テンキーとホイール付きのマウスがないと、Blenderの作業は厳しいかもしれません。

  • マウス操作
    • マウス左ボタン : 移動の確定
    • マウス右ボタン : 選択/選択解除
    • マウス右ボタン+ Shift : 追加で選択/選択解除
    • マウス右ボタン(プレス) + ドラッグ : 選択した物を移動
    • マウスホイール(プレス) + ドラッグ : 視点移動
    • マウスホイール(回す) : 拡大/縮小
    • マウスホイール(回す) + Shift : 移動(上/下)
    • マウスホイール(回す) CTRL : 移動(左右)
  • 表示・モード切り換え系ショートカット
    • Tab : Objectモード/Editモードを切り替え
    • アーマチュアを選択 + CTRL + Tab : ポーズモード
    • オブジェクトを選択 + CTRL + Tab : ウエイトペイント
    • Z : ワイヤーフレーム/ポリゴン表示を切り替え
    • N : プロパティパネル
    • T : ツールシェルフ
    • 5 : 透視投影/平行投影
    • 7 : 視点切り替え(上)
    • 1 : 視点切り替え(前)
    • 3 : 視点切り替え(横)
    • 0 : 視点切り替え(カメラ)
  • 選択系ショートカット
    • A : オブジェクトを全選択/全選択解除
    • B : 矩形範囲選択
  • 移動・変形系ショートカット
    • G : 移動
    • R : 回転
    • S : 拡大/縮小
    • E : 押し出し
    • F : 面を張る
    • CTRL + T : 四角形を三角形に分割
    • CTRL + R : ループカット
  • アニメーション系ショートカット
    • Option + R : ボーンの回転をクリア
    • Option + G : ボーンの移動をクリア
    • ボーンを選択した状態でI、LocRotを選択
      : ボーンの移動(Location)と回転(Rotation)のキーフレームを打つ
  • その他ショートカット
    • X : 削除
    • Shift + A : 新たなオブジェクトを追加
    • CTRL + J : 複数のオブジェクトを一つに結合
    • Shift + C : 3Dカーソルを中心に
    • M : オブジェクトごとにレイヤーを分ける

Blenderの基本操作は、以下のサイトのチュートリアルが、非常に分かりやすいです。

このチュートリアルを実践していくうちに、Blenderにも慣れてくると思います。今回はAway3Dの時から、three.jsやBlenderでもよく見かける猿のあたまを利用して、簡単なモデリングを行いました。

20150108_img2


Blenderでアーマチュアを作成し、設定

アニメーションを行うには、まず動きの元となる骨格(ボーン)が必要となります。アーマチュアとは、そのボーンの集合体の事を言います。アーマチュアの設定は、以下の流れになります。

  1. モデルデータにアーマチュアを追加して関連づけます。
  2. モデルデータに合わせて、アーマチュア内にボーンを作成していきます。
  3. 後々分かりやすいように、ボーンに名前を付け、ボーン同士の親子関係や、動きの連動を設定します。
  4. ウエイトペイントモードで頂点のグループを作って、それぞれの頂点が、どのボーンに追従するかを設定します。

ボーン : 太い方の丸がRoot、細い方の丸がTipで、太い方から細い方に、親 -> 子へとボーンが繋がっていきます。

20150108_img3

ウェイトペイントモード : 頂点毎に、青 -> 赤と、選択しているボーンとの連動具合に応じてペイントを行います。

20150108_img5

このような流れで、モデリングデータにアーマチュアを追加する事が出来ました。

20150108_img4


Blenderでアニメーションの設定

作成したアーマチュアを元に、アニメーションを設定します。アニメーションをつける方法は、タイムラインにキーフレームを打つFlashと同じイメージです。以下の流れになります。

  1. ポーズモードでボーンを移動、回転させて、ポーズをとらせます。
  2. ドープシートを使って、とらせたポーズを元にキーフレームを打つことで、キーフレーム間の差異が補完されて、自動的にアニメーションがつきます。
  3. 作成したアニメーションをアクションパターンとして登録します。
  4. NLAエディターでアクションパターンを組み合わせ、調整します。

20150108_img6


Blenderでモデルとアニメーションを書き出す

作成したモデルデータとアニメーションを、three.jsで扱いやすいthree.js用のJSON形式で書き出すのですが、デフォルトではBlenderは、three.js用のJSON形式の書き出しが出来ません。three.js公式のBlenerのアドオンを追加する必要があります。

20150108_img7

ちなみに、以前試したBlender2.7では、アドオン(2.65)が正常に動きませんでしたが、Blender2.72bではアドオン(2.65)が、問題なく動くようです。

three.js用のJSON形式での書き出し設定

cp -r three.js-master/utils/exporters/blender/2.65/scripts/addons/ /Applications/Blender/blender.app/Contents/Resources/2.72/scripts/addons/
  • Step3 : Blenderを起動し、File -> User Preferences -> AddonsタブとImport-Exportを選択して、Import-Export:three.js formatにチェックし、Save User Settingsを押下します。

20150108_img8

  • Step4 : File -> Export にThree.js(.json)が表示されれば設定完了です。

20150108_img9

モデルデータとアニメーションを、three.js用のJSON形式で書き出す

いよいよモデルデータとアニメーションを書き出します。File -> Export -> Three.js(.json)で、書き出し設定パネルが表示されます。

20150108_img10

アニメーション部分で特に重要なのが、Morph animationSkeletal animationのチェック項目です。

  • Morph animation
    • キーフレームごとの頂点位置を補完し、その補完された全頂点データを保存して、頂点情報を切り替えながらアニメーションさせます。
    • 計算負荷は低くなりますが、複雑なモデルやアニメーション自体が長くなると、その分のデータ量が増えます。
  • Skeletal animation
    • ボーンの動きだけを保存し、そのボーンの状態に応じて、頂点位置を計算します。
    • 読み込むデータ量が少なくなりますが、計算負荷が高くなります。

今回はMorph animationを選択します。これでBlenderの作業は完了です。


three.jsでの基本設定

今回は、three.jsの基本的な部分を、特に説明しませんが、いつも通りにシーン、カメラ、光源、レンダラー等を設定しています。

var width = window.innerWidth;
var height = window.innerHeight;
// シーン
scene = new THREE.Scene();
scene.fog = new THREE.FogExp2(0x000000, 0.00035);
// カメラ
camera = new THREE.PerspectiveCamera(50, width/height, 1, 10000);
camera.position.z = 1000;
camera.position.y = 200;
// 光源
var directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(200, 200, 200);
scene.add(directionalLight);
// 環境光
var ambientLight = new THREE.AmbientLight(0x999999);
scene.add(ambientLight);
// 地面
var ground = new THREE.Mesh(new THREE.PlaneGeometry(10000, 10000, 1, 1), new THREE.MeshLambertMaterial({color: 0x333333}));
ground.position.y = -200;
ground.rotation.x = Math.PI / -2;
scene.add(ground);
// レンダラー
renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height);
//
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.autoRotate = true;
controls.autoRotateSpeed = -1.0;
//
document.body.appendChild(renderer.domElement);

three.jsでJSON形式のモデルデータとアニメーションを読み込む

Blenderで書き出したJSON形式のモデルデータとアニメーションを、THREE.JSONLoaderで読み込みます。読み込み完了後に、マテリアルのmorphTargetsにtrueを代入して、モーフィングアニメーションを有効にしてください。読み込んだGeometryとMaterialsを元に、アニメーション用のメッシュを作成してください。今回はTHREE.MorphAnimMeshを使用しています。

  • THREE.MorphAnimMesh : フレーム(タイムライン)を扱うのに便利なメソッドが用意されています。
  • THREE.SkinnedMesh : ボーンを扱う事ができます。
// モデル
var loader = new THREE.JSONLoader();
loader.load('models/monkey2.json', function (geometry, materials) {
    for (var i = 0, l = materials.length; i < l; i++) {
        materials[i].morphTargets = true;
    }
    mesh = new THREE.MorphAnimMesh(geometry, new THREE.MeshFaceMaterial(materials));
    mesh.position.set(0, -200, 0);
    mesh.scale.set(100, 100, 100);
    scene.add(mesh);
    //
    animate();
});

three.jsで表示するフレームを切り替えながらレンダリング

アニメーションをレンダリングします。mesh.morphTargetInfluences[index]で表示するフレームを切り替えながらレンダリングしていきます。mesh.morphTargetInfluences[index]は、アニメーションのフレーム数と同一数のインデックスの配列となっていて、表示したいフレームのインデックスに1を代入し、それ以外の非表示のフレームに0を代入する事で、表示するフレームを切り替える事ができます。ちなみにTHREE.MorphAnimMeshでは、.updateAnimation(delta)メソッドを実行するだけで、自動的にフレームを切り替えながらレンダリングしてくれます。今回のような単純なループアニメーションの場合は、これで十分かとおもいます。

function animate() {
    requestAnimationFrame(animate);
    // モーフィングアニメーション
    lastKeyFrame = currentKeyFrame;
    currentKeyFrame ++;
    if (TOTAL_FRAMES < currentKeyFrame) {
        currentKeyFrame = 0;
    }
    mesh.morphTargetInfluences[lastKeyFrame] = 0;
    mesh.morphTargetInfluences[currentKeyFrame] = 1;
    //
    renderer.render(scene, camera);
    //
    controls.update();
}

これで完了です。モーフィングアニメーションが再現されたかと思います。


モーフィングアニメーションのパフォーマンステスト

今回のサンプルでは、60フレーム程度のアニメーションで、2M近いデータ容量となりました。モーフィングアニメーションは、フレーム毎の頂点データを保持していますので、データ容量は、モデリングデータのポリゴン数と、アニメーションのフレーム数が増えるに応じて、増えて行きます。そのため、モーフィングアニメーションを行うキャラクタやポーズが増えてくると、Webコンテンツとしては、容量的に現実的ではなくなります。

メリットとしては、読み込んだデータを表示するだけですので、計算負荷はそれほど高くなりません。試しに400体配置して、モーフィングアニメーションを行ってみました。

20150108_img12


まとめ

このような流れで、モーフィングアニメーション実装する事ができます。Blenderは、とにかく触って慣れるしか無いと思いますが、と言ってる僕も複雑な作業は全然出来ません。もうすこし、ちゃんとモデリングしたデータでモーフィングアニメーションを行いたいですね。もっと精進したいと思います。