2016年11月28日月曜日

three.jsで3Dモデルをボーンアニメーションさせるには

ボーンアニメーションとは

ボーンアニメーションとは、
3Dツールで骨のように連なる軸を基準として
それに合わせてメッシュをアニメーションさせる技法のことを言います。

three.jsでは主にBlenderという3Dソフトからアニメーションつきのthree.js用の3Dモデルを書き出すことで用意することができます。
Unityのようなゲームエンジンと違い、three.jsではBlenderファイルを放り込んだらパースしてくれるような便利な機能はありません。
ここがもっとやりやすければthree.jsももっと流行りそうなものなのですが・・・

three.jsでボーンアニメーションさせるのに必要なもの

Blender
Blenderとはオープンソースの3Dソフトのことで、以下のサイトから無料でダウンロードできます。
Blenderの公式サイトへ
Blender three.jsエクスポーター
エクスポーターとは3Dソフトから three.jsで使用できる3Dモデルを書き出すためのプラグインのことです。
three.jsをダウンロードした際に解凍したファイルの以下のディレクトリにあります。
three.js-master\utils\exporters\blender\addons\io_three

three.jsから3Dモデルを書き出す順序

  • 1.Blenderにエクスポーターをインストール
  • 2.Blenderでアニメーションモデルを用意
  • 3.Blenderからthree.js用のモデルを書き出す
  • 4.three.jsのjsonLoaderで書き出したモデルを読み込み、アニメーションを再生する

1.Blenderにエクスポーターをインストール

エクスポーターをBlenderにインストール

上に書いたようにthree.jsをダウンロードしたときに入っている以下のエクスポーターを、
three.js-master\utils\exporters\blender\addons\io_three
(io_threeのフォルダリごと)以下のディレクトリに配置(2.78はBlenderのバージョンですので、インストールしているバージョンによってかわります)
C:\Program Files\Blender Foundation\Blender\2.78\scripts\addons

Blenderを起動し、エクスポーターを有効化する

Blenderを起動し、左下のボタンでエディターのウィンドウタイプをUser Preferencesに変更する。

次に以下の画像上部メニューから「Add-ons」を選び、左の検索窓に「three」を入力しEnter、「Import-Export: three.js format」横のチェックボックスを入れる。
この設定を保存する場合は、下の「Save User Settings」をクリックする。こうすることでBlenderを再度立ち上げてもthree.jsのエクスポーターが有効化された状態になります。
これでthree.jsエクスポーターのインストールがされました。

2.Blenderでアニメーションモデルを用意

次にBlenderでアニメーションモデルを用意します。今回は割合します。
注意として、以下を気をつけてモデリングしてください。
書き出しエラーになったり、思ったとおりのアニメーションにならなかったり、やたら大きなサイズで書き出されてしまったり、やたら動作が重くなってしまう原因になります。

  • 一つのArmatureに一つのメッシュ
  • 原点は必ずx:0 y:0 z:0の位置にする
  • 3DモデルのサイズはBlenderの升目以内に入るサイズにする
  • ポリゴン数は5万以内程度
  • IKは書き出し時に無視される
  • 必ず頂点を取りこぼすことなくウェイトペイントすること

3.Blenderからthree.js用のモデルを書き出す

いよいよBlenderから3Dモデルを書き出します。
注意点としては・・・

ClearTransformする

PoseModeでボーン全てを選択後、以下の画像のようにPose→ClearTransform→Allを実行します
この工程は地味ですが、これをやらないとアニメーションがハチャメチャになることがあります。

書き出し時にObjectModeにしてメッシュを選択すること

これをやらないとエラーがでることがあります。

注意事項を読んだら早速書き出しましょう

書き出す

File→Export→Three(.json)をクリックして書き出しましょう。

書き出し設定は以下のとおりです。
※three.jsのエクスポーターはr73バージョン以降とそれ以前では違いがあります。

r73以前

r73以降

4.three.jsのjsonLoaderで書き出したモデルを読み込み、アニメーションを再生する

r73以前とr73以降ではアニメーションの実行の仕方が大幅に違い、ここが大いにはまるポイントだったりします。

r73以前

animationsというオブジェクトにアニメーションデータを格納し、play関数でアニメーションの再生をしています。
毎フレーム処理の中でTHREE.AnimationHandler.update関数を実行する必要があります。

  
var mesh;
var animations = {};

var jsonLoader = new THREE.JSONLoader();
var url = 'models/hellknight/hellknight.json';
jsonLoader.load(url, function( geometry, materials ){
  
  var material = new THREE.MeshFaceMaterial( materials );
        mesh = new THREE.SkinnedMesh( geometry, material );
        animations[ 'animName0' ] = new THREE.Animation( mesh, geometry.animations[0] );
        animations[ 'animName1' ] = new THREE.Animation( mesh, geometry.animations[1] );
  animations[ 'animName0' ].play();
});


//毎フレーム処理
function animate() {
    
    if( mesh ){
        THREE.AnimationHandler.update( .03 );
    }

}
setInterval( animate, 1000 / 30 );
  
r73以降

r73以降ではTHREE.Animationクラスが廃止され、THREE.AnimationMixerに変更されました。setEffectiveWeightはアニメーションを2つ同時に再生した場合に2つのアニメーションをどのぐらいのブレンド具合で混ぜるかを設定します。
こちらも毎フレーム処理でanimationMixer.update関数を実行する必要があります。

  
var clock = new THREE.Clock();

var mesh;
var animationMixer;

var jsonLoader = new THREE.JSONLoader();
var url = 'models/hellknight/hellknight.json';
jsonLoader.load(url, function( geometry, materials ){
  
  var material = new THREE.MeshFaceMaterial( materials );
        mesh = new THREE.SkinnedMesh( geometry, material );

        animationMixer = new THREE.AnimationMixer( mesh );
        for ( var i = 0; i < geometry.animations.length; ++ i ) {
            animationMixer.clipAction( geometry.animations[ i ] );
        }
        animationMixer.clipAction( 'animName0' ).setEffectiveWeight( 1 ).play();
});


//毎フレーム処理
function animate() {
    
    var delta = clock.getDelta();
    if( animationMixer ){
     animationMixer.update( delta );
    }

}
setInterval( animate, 1000 / 30 );
  

編集後記

three.jsでのアニメーション再生の流れをざっと説明しました。如何でしたでしょうか。おそらく多くの人がつまづくのはBlenderとthree.jsの連携だと思います。
今までhtmlやjavaScriptだけ書いていればよかったのが、急に3Dソフトを使う必要があり、しかもそれが癖のあるBlenderとなれば少し躊躇してしまうかもしれません。
しかし、three.jsはwebGLのコードを直接書くのに比べかなり簡略化されており、それに比べればかなり楽にはなっているとは思います(シェーダーも触る必要がありませんし・・・)
3Dコンテンツを作る以上、3Dソフトとの連携はUnityなどの環境でも必ず必要になっているので、やっといて損はないかと
さくっと説明するつもりがかなり長くなってしまった・・・

0 件のコメント:

コメントを投稿