初めまして。 html5、javascript、flashなどのクライアント開発を
メインに担当しております、 菅家(@KA_ka_YY)と申します。
アプリコンテストというイベントにて
WebGLを使用した野球盤ゲームを作成しました。
その際利用したThree.js(WebGLのjavascriptライブラリ)を用いた
WebGLの使用方法を紹介させていただこうと思います。
インデックス
- (1)レンダリング
- (2)アニメーション制御
- (3)テクスチャ変更
(4)ゲームに反映
(5)使用ツール
(1)レンダリング
まずは Blender というフリーの3Dモデリングソフトで
以下のようなキャラクターを作りました。
(Blenderでのモデリング方法については割愛させていただきます。)
そして、Three.js用にjson形式で書き出してくれるプラグインを使用して書き出します。
次に、Three.jsの準備です。
※バージョンによりインターフェースが違う場合がございます。
今回はバージョンr47を使用しました。
Three.js以外に使用するライブラリは次の通りです。
(シーン、カメラ、ライト、表示オブジェクト、レンダラーなど)
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のパスを渡します。
//書き出した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++;
}
以上でアニメーションは終わりです。