1 pixel|サイバーエージェント公式クリエイターズブログ

サイバーエージェントのクリエイターの取り組みを紹介するオフィシャルブログです。最新技術への挑戦やサービス誕生の裏話、勉強会やイベントのレポートなどCAクリエイターの情報が満載です。


Theme:

初めまして。 html5、javascript、flashなどのクライアント開発を
メインに担当しております、 菅家(@KA_ka_YY)と申します。

 

インデックス

  • (1)レンダリング
  • (2)アニメーション制御
  • (3)テクスチャ変更
    (4)ゲームに反映
    (5)使用ツール
 

(1)レンダリング

まずは Blender というフリーの3Dモデリングソフトで
以下のようなキャラクターを作りました。
(Blenderでのモデリング方法については割愛させていただきます。)

モデル

そして、Three.js用にjson形式で書き出してくれるプラグインを使用して書き出します。

次に、Three.jsの準備です。
※バージョンによりインターフェースが違う場合がございます。
 今回はバージョンr47を使用しました。


Three.js以外に使用するライブラリは次の通りです。

手始めに基本的に必要なオブジェクトを設定します。
(シーン、カメラ、ライト、表示オブジェクト、レンダラーなど)

//描画用のdom
container = document.getElementById('container');

windowHalfX = container.clientWidth * 0.5;
//パースペクティブカメラを指定
camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.y = -500;
camera.position.z = 3000;

//シーンの作成
scene = new THREE.Scene();

//ディレクショナルライトを指定
light = new THREE.DirectionalLight(0xffffff,2); // 光源の色, 強さ
light.position.set(0, 0, 1).normalize();
//ライトをシーンに追加
scene.add(light);

//レンダラ生成
renderer = new THREE.WebGLRenderer({antialias : true});
renderer.setSize(container.clientWidth, container.clientHeight);

次に、
Three.jsにはJSONLoaderというクラスが用意されているので
引数に先ほど書き出したjsonのパスを渡します。


var loader = new THREE.JSONLoader();
//書き出したjsonのパスを指定する
loader.load("./three/macho_batter.js", createScene);

/**
 * jsonのロード後のコールバック関数
 **/

function createScene(geometry) {
   for (var i=0; i < geometry.materials.length; i++){
        geometry.materials[i].shading = THREE.SmoothShading;
        geometry.materials[i].morphTargets = true;
    };
    mesh = new THREE.Mesh(geometry, material);
    var material = new THREE.MeshFaceMaterial();
    mesh = new THREE.Mesh(geometry, material);
    mesh.position.y = -container.clientHeight;
    mesh.scale.x = mesh.scale.y = mesh.scale.z = 250;
    scene.add(mesh);
    console.log('material',material)
    console.log('mesh',mesh)
}


描画されれば成功です!



(2)アニメーション(スキンメッシュアニメーション)制御

再びBlenderでキャラクターにスキンメッシュアニメーションを設定していきます。
「バットの構え」のモーションと「スウィング」のモーションを作成し、
タイムライン上で0~10が「バットの構え」、11~26が「バットをスウィング」とします。

 


この状態で先ほどと同様にjsonデータを書き出し直します。

今度はThree.jsでアニメーションを設定して行きます。
meshオブジェクト内のmorphTargetInfluencesに任意の値を入れて
renderer.render(scene, camera);を実行するとその値のタイムライン上の描画になるわけですが、

まあ、ややこしいことは省きまして下記ソースのfunctionを定義し、

gotoAndPlay( 開始フレーム, 終了フレーム, 終了までの間隔値, ループの有無, コールバック );

で、アニメーションするようになります。


/**
 * @from int 開始タイムライン
 * @to int 最期のタイムライン
 * @duration 終了までの間隔値 値が大きいほどゆっくりになる。
 * @roop boolean アニメーションをループさせるか
 * @callback roopがfalseの時、第二引数(to)のタイムラインに来た時に実行される関数
 */
function gotoAndPlay(from, to, duration, roop, callback){
   var keyframes = to - from;
   var interpolation =  duration / keyframes;
   var lastKeyframe = 0;
   var currentKeyframe = 0;
   var _count = 0;
   for(var i = 0; i < mesh.morphTargetInfluences.length; i++) {
     mesh.morphTargetInfluences[i] = 0;
   }
   if(roop)
      _stop = false;
   render = function(){
     var time = _count % duration;
     if(time == duration -1 && !roop) {
       if(callback!=undefined){
           _stop = true;
       callback();
       } 
    }else{
       var keyframe = Math.floor(time / interpolation) + from;
       if(keyframe != currentKeyframe) {
           mesh.morphTargetInfluences[lastKeyframe] = 0;
           mesh.morphTargetInfluences[currentKeyframe] = 1;
           mesh.morphTargetInfluences[keyframe] = 0;
           lastKeyframe = currentKeyframe;
           currentKeyframe = keyframe;
       }
       mesh.morphTargetInfluences[keyframe] =
           (time % interpolation ) / interpolation;
       mesh.morphTargetInfluences[lastKeyframe] =
           1 - mesh.morphTargetInfluences[keyframe];

       //meshのy軸を回転させる
       mesh.rotation.y+=0.005;

       //描画を更新
       renderer.render(scene, camera);
       _count++;
       _stop = false;
     }
   };
}

/**
* enterframe
* アニメーションレンダリング
*/
function enterframe() {
    requestAnimationFrame(enterframe);
    render();
    stats.update();
}


つまり、タイムライン操作をすることで
任意のアニメーションに切り替えることができます。

では、通常時は「バット構え」の状態で、キーボードの「A」を押すことで、
「スウィング」するようにしてみたいと思います。

/**
 * 「A」ボタンを押したとき
 */
 document.addEventListener("keydown", function(e){
     if(e.keyCode==65){
         swing();
     }
 }, false);

 /**
  * バット構え
  */
 function kamae(){
      gotoAndPlay(0,10,100,true);
 }

 /**
  * バットをスイング
  */
 function swing(){
    //第5引数には構えの関数を入れる。
   //スイングが終了後にかまえのアニメーションに戻る。
     gotoAndPlay(10,26,100,false,kamae);
}

です。

さらに、ロード時に「バットの構え」のアニメーションが行われるように
createScene関数内に下記を追記します。

//バット構えアニメーションの指定
kamae();

//アニメーションレンダリング
enterframe();


(3)テクスチャ変更

今回ゲームには反映しなかったのですが、
mesh.geometry.materials[0].mapにあるイメージオブジェクトをTHREE.ImageUtils.loadTextureクラスで置き換えることで、
テクスチャを変更できます。

var _btn = document.getElementById('changeTexture');
_btn.addEventListener('click',changeTexture);
var _textureCount = 0;

/**
* テクスチャーを切り替える
*/
function changeTexture(){
    if(_textureCount%2==1){
        mesh.geometry.materials[0].map = new THREE.ImageUtils.loadTexture("/three/macho1.png");
    if(_textureCount%2==0){
        mesh.geometry.materials[0].map = new THREE.ImageUtils.loadTexture("/three/macho2.png");
    _textureCount++;
}


以上でアニメーションは終わりです。

(4)ゲームに反映

上記の方法で、数種類のキャラクターにピッチングなどのアニメーションを設定して野球盤ゲームを作成しました。

ハチャメヂャーリーグ



(5)使用ツール&参考ページ

いいね!した人  |  リブログ(0)

1pixelさんの読者になろう

ブログの更新情報が受け取れて、アクセスが簡単になります

最近の画像つき記事  もっと見る >>
ページトップへ戻る