blog
※この記事はGoogleChrome9以上 またはFireFox4以上で見てください。
前回までの内容で、Blenderからオリジナルモデルを出力できるようになりました。
ここから先はスケルトンを用いたアニメーションの解説となります。さあ、ここからが本番です。
1、Blenderで人体モデルを用意します。
Boxの一面ポリゴンを選択して、 左にあるメッシュツールの「個々に押し出し」を繰り返して人体形成
2、骨入れます。
追加>アーマーチェアで、カーソルのあるところに一本骨ができる。
編集モードにしてEキー(左のアーマーチェアツール > 押し出し)を押すと1本目の先端から2本目のアーマーチェアを伸ばせる。
3、エンベロープの設定をします。
モデルを選択した後、シフト押しながらアーマーチェア選択。ctlPでペアレントする。自動エンベロープでウェイト設定
4、リギングします。今回は足だけIKにします。
骨をオブジェクト選択 >ポーズモード > 先端の骨を選択 > ポーズ > インバースキネマティクス>IKをボーンに追加>新規エンプティーオブジェクトでIKを設定。 IKのルートを足の付け根にするためには、IKを設定した先端の骨を選択し、右メニューにあるボーンコンストレイントタブから、チェーンの長さを調整します。
5、動かします。
ポーズモードにしてアーマーチェアやIKを動かしてキーを打つ。これを繰り返してアニメーションを作る。
6、出力します。
出来たら、オブジェクトモードに戻し、モデルを選択。Three.jsでエキスポートします。エキスポート設定はデフォルトのままでOKですが、MorphAnimationにチェックが入っていることを確認してください。
では、実装します。青色表記のところはオリジナルのパスに変更してね。
<html> <body> <script src="build/three.min.js"></script> <script src="js/controls/TrackballControls.js"></script> <script> var clock = new THREE.Clock(); var morphs = []; init(); animate(); function init() { //Camera camera = new THREE.PerspectiveCamera( 70, 640/480, 1, 2000 ); camera.position.set( 0, 50, 500 ); trackball = new THREE.TrackballControls( camera ); //Scene scene = new THREE.Scene(); // Json var loader = new THREE.JSONLoader(); loader.load( 'charaAni.js', function ( geometry, materials ) { var material = materials[ 0 ]; material.morphTargets = true;; var faceMaterial = new THREE.MeshFaceMaterial( materials ); morph = new THREE.MorphAnimMesh( geometry, faceMaterial ); morph.duration = 1000; // one second duration var s = 40 morph.scale.set( s, s, s ); morph.position.set( 0, 0, 0 ); morph.matrixAutoUpdate = false; morph.updateMatrix(); scene.add( morph ); morphs.push( morph ); } ); //グリッド planeGeometry = new THREE.PlaneGeometry( 1000, 1000, 10, 10 ); planeMaterial = new THREE.MeshBasicMaterial( { color: 0x000000, wireframe: true } ); planeMesh = new THREE.Mesh( planeGeometry, planeMaterial ); planeMesh.rotation.x = 90 * 2 * Math.PI / 360; //左に角度いれるとラジアンに変換 scene.add( planeMesh ); //ライティング var directionalLight = new THREE.DirectionalLight( 0xffffff, 3); directionalLight.position.set(0,0,3); scene.add( directionalLight ); //レンダラー renderer = new THREE.WebGLRenderer(); renderer.setSize( 640, 480 ); document.body.appendChild( renderer.domElement ); } function animate() { requestAnimationFrame( animate ); // animate morphs var delta = clock.getDelta(); if ( morphs.length ) { for ( var i = 0; i < morphs.length; i ++ ) morphs[ i ].updateAnimation( 600 * delta ); } render(); } function render() { renderer.render( scene, camera ); trackball.update(); } </script> </body> </html>
出力したモデルの読み込み部分と、animate関数の中身が前回とは違います。
どうやら、アニメーション専用の記述が必要そうです。
var clock = new THREE.Clock(); var morphs = []
グローバルとして使われる変数を先に宣言しておきます。変数clockに、three.jsの時間にかかわるオブジェクトを取得し、変数morphsは、配列として変数宣言します。二つとも後に使います。
// Json var loader = new THREE.JSONLoader(); loader.load( 'charaAni.js', function ( geometry, materials ) { var material = materials[ 0 ]; material.morphTargets = true;;
実は、このwebGLはスケルトンアニメーションではなく、モーフアニメーションで動いています。
マテリアルも同様にモーフの対象になりますが、今回はマテリアルのアニメーションはしていません。
なので、マテリアルのモーフのターゲットは一つのみ。という設定をしているのが25~26行目です。
「最初のマテリアルをそのまま維持しろ!」と命令しているわけです。
var faceMaterial = new THREE.MeshFaceMaterial( materials ); morph = new THREE.MorphAnimMesh( geometry, faceMaterial ); morph.duration = 1000; // one second duration
jsonによって出力されたすべてのマテリアルを取得し、ジオメトリーとくっつけて、オブジェクトを生成しています。ただし、前回と違いMorphAnimMeshというメソッドを使っています。モーフアニメーションさせるときはこれでオブジェクトを生成します。30行目のdurationプロパティに、1秒間を、何ミリ秒で表現するかを指定します。再生スピードの調整にも使えます。
var s = 40 morph.scale.set( s, s, s ); morph.position.set( 0, 0, 0 ); morph.matrixAutoUpdate = false; morph.updateMatrix(); scene.add( morph ); morphs.push( morph )
サイズ、位置を調整しています。matrixAutoUpdateとupdateMatrixで、モーフのアップデートを自動から手動に切り替えています。「モーフの読み込みは再描画ごとにやらなくてもいいよ、一度読み込んでしまえば、あとはそれを使い続けるよ」と言っています。あとは、シーンにオブジェクトを追加し、グローバル変数のmorphsにmorphを追加してあげます。こうすることでmorphsには、配列として複数のアニメーションポーズのモデルが格納され、後のanimate関数で使用できるようになるわけです。
// animate morphs var delta = clock.getDelta(); if ( morphs.length ) { for ( var i = 0; i < morphs.length; i ++ ) morphs[ i ].updateAnimation( 600 * delta );
clock.getDeltaで経過した秒数を取得します。68行目以降でモーフターゲットの数(morphsの配列)だけ、表示されるモデルを更新していく。という処理をします。どのポーズになるかは「morphs[ i ].updateAnimation( 600 * delta );」で決定され、経過時間×600ミリ秒のモーフポーズを表示します。ちょっと複雑すぎてよくわかりませんがそんな感じです。ちなみに600の数値を1200にすると倍速になります。
以上です。
次回は、各種CGソフトからBlenderへのアニメーション移植方法を解説します。