はりうすブログ (のすけのメモ)

湘南にある小さな会社 代表 ”のすけ”のブログです

babylon.js ステップ13 スプライト(Sprites)

babylon.js ステップ13はスプライトアニメーションです。

2Dではおなじみのこの技術。

もちろんbabylon.jsでも使えます


いきましょう!

2つのスプライト管理方法

スプライトは大量の2D画像を利用するため、パフォーマンス管理が重要です。

babylon.jsでは2つの管理方法があります

  • A uniform spritesheet (均一化されたスプライト)・・・SpriteManagerを利用
  • A packed spritesheet(パッケージされたスプライト)・・・SpritePackedManagerを利用

これらは、1枚のスプライトであってもManagerを使う必要があります。

スプライトマネージャー

f:id:hollywis:20200708221747p:plain

// 木の画像用のsprite managerの作成
var spriteManagerTrees = new BABYLON.SpriteManager("treesManager", "Assets/Palm-arecaceae.png", 2000, 800, scene);

treesManagerの部分は名前なのでユニークな名前を設定します。

「Assets/Palm-arecaceae.png」の木の画像を最大2000個作ることができる容量を確保します。

800の部分は画像のサイズに対応するセルサイズです。

最後に追加するsceneを設定します。

// プレイヤー用のsprite managerの作成
var spriteManagerPlayer = new BABYLON.SpriteManager("playerManager","Assets/Player.png", 2, {width: 64, height: 64}, scene);

上記では、セルサイズを[64x64]で設定しています。

f:id:hollywis:20200708221724p:plain

Picking(ピッキング)

次はピッキング(選択)を行います

完成図
https://www.babylonjs-playground.com/#9RI8CG#0

やり方

  • 必要なスプライトの選択をオンにします。 sprite.isPickable = true;
  • SpriteManagerがピッキングをサポートできるようにします。 spriteManager.isPickable = true;
// 選択されたスプライトを傾ける
var pickResult = scene.pickSprite(this.pointerX, this.pointerY);
if (pickResult.hit) {
    pickResult.pickedSprite.angle += 0.5;
}

sceneのpickSprite関数を使って、マウスポインタの選択を取得します。

そして、それがhit(衝突)している場合(ほぼ間違いなくhitしていますが)、スプライト画像を傾けます

multiPickSpriteを使用して、貫通系の複数選択も可能です

var pickResult = scene.multiPickSprite(this.pointerX, this.pointerY);
for (var i = 0; i < pickResult.length; i++) {
        pickResult[i].pickedSprite.angle += Math.PI / 4;
}

スプライトパックマネージャー(バージョン4.1から利用可能)

パックされたスプライトシートを用いる場合は、SpritePackedManagerを利用します

これは、JSONファイル(位置を含む)と画像ファイルが必要です。

// SpritePackedManager(名前,画像,インスタンス最大数,シーン)
var spm = new BABYLON.SpritePackedManager("spm", "pack1.png", 4, scene);

画像の例は次のような感じです。1枚の画像データに複数の画像を詰め込みます

f:id:hollywis:20200709010213p:plain

jsonファイルの中身はこんな感じで、その画像の始まりの座標と、横幅、縦幅でできています。

{   "frames": {
        "eye.png": {
            "frame": {"x":0,"y":148,"w":400,"h":400}
        },
        "redman.png": {
            "frame": {"x":0,"y":0,"w":55,"h":97}
            },
        "spot.png": {
            "frame": {"x":199,"y":0,"w":148,"h":148}
        },
        "triangle.png": {
            "frame": {"x":55,"y":0,"w":144,"h":72}
        }
    }
}

1枚の画像なのに、擬似的に複数の画像として扱うことができます。

var sprite = new BABYLON.Sprite("sprite", spm);
sprite.cellRef = "spot.png";

そして、このように該当画像を選んで使用できます

スプライトの設定

sprite.size = 0.3;  //大きさ
sprite.angle = Math.PI/4; //向き
sprite.invertU = -1; // 反射
sprite.width = 0.3; //幅
sprite.height = 0.4; //高さ
sprite.position.y = -0.3; //ポジション

スプライトアニメーション方法

スプライトの利点のアニメーションが簡単な事です。

均一なスプライトシートと(SpriteManager)を使用することです。

すべてのアニメーション画像を含む1つの大きな画像ファイルを次々にロードします。

マネージャーで指定したピクセルサイズは均一であることに注意してください。


たとえば、次のプレーヤーのスプライトシートでは、40以上のアクションを定義しています

f:id:hollywis:20200709011136p:plain

使い方:

// フレーム0からフレーム43までアニメーション化
// trueはループするかどうか
// 100はフレーム間の遅延時間
player.playAnimation(0, 43, true, 100);

実行例はこちら
https://www.babylonjs-playground.com/#9RI8CG

スプライトマップ

数千以上のアニメーションが必要な場合にはスプライトマップの利用を検討してください

spriteMapを利用すると情報をメモリに保存して高速な演算を可能にするようです。

var spriteMap = new BABYLON.SpriteMap(name, atlasJSON, spriteTexture, options, scene);

タイル表現に便利なスプライトマップタイル

マインクラフトの如く、同じサイズのタイルを使いたい場合にはスプライトマップタイルが便利です。

spriteMap.changeTiles(layerID, tileID, frameID)
  • layerID:システムのターゲットレイヤーの整数。
  • tileID:Vector2 | レイヤーのターゲットタイルのVector2 []。
  • frameID:変更するスプライトの整数フレームID。


タイル情報の保存やロード、アニメーション機能などもあります

spriteMap.saveTileMaps() // セーブ .tilemaps形式
spriteMap.saveTileMaps(url) //ロード


// アニメーション
spriteMap.addAnimationToTile(frameID, animationFrame, nextFrameID, animationFrameDisplayTiming, globalSpeed)

例はこちら
https://playground.babylonjs.com/#ARLADE

まとめ

スプライト表現について学びました。


babylon.jsでスプライト表現を行うためにはManagerを使う必要があり、全て同じピクセルの画像ならば、SpriteManagerで、異なるサイズの画像を扱うなら SpritePackedManagerを使います。


マネージャを定義したなら、Spriteインスタンスをnew BABYLON.Spriteで呼び出し
メッシュのように自由にサイズや位置などを設定できます。


また、アニメーションを使う場合にはplayAnimation関数でできました。


タイル表現には、SpriteMapが便利であることを学びました。


以上になります。

次回はパーティクル表現をやります!

babylon.js ステップ12 レイキャスト(Raycasts)

babylon.jsのチュートリアルシリーズ 12回目

今回はレイキャストをやっていきます

いきましょう!

レイキャストとは光線による衝突判定

前回の11回ではマウスの位置と、壁の衝突判定を行いましたが。

レイキャストは、光線(レーザー・)による衝突または、交差チェックを行う機能です。

FPSゲームの弾丸の軌道なんかはレイキャストで行います。


マウスクリックで、選択されたメッシュ情報を取得する方法(scene.pick)を使用しました。

一方レイキャストでは似たようなメソッド、 scene.pickWithRay() を使っていきます

光線と最初に接したメッシュの取得

光線と最初に接したメッシュの取得をやっていきます。

f:id:hollywis:20200708020632j:plain


真ん中に、光線を出力する赤い箱があります(箱はマウスで動かせる)

そして、その光線と接する可能性のある、青い箱が2つと緑の箱があります。


なお、奥の青い箱は、光線が届きません。

光線が当てられた箱は上に伸びていきます。


デモはこちら

https://www.babylonjs-playground.com/#KNE0O#84


まず、最初に光線の出力もとである赤い箱には、衝突検出をoffにする設定を入れます。赤い箱自体が衝突判定されてしまっては困りますので。

box.isPickable = false; 

次に、箱から出る光線のベクトルを定義します。その際,箱の位置()を差し引いて箱の原点origin(光線が始まる場所)からの方向を取得します。

// 赤い箱との方向ベクトル
var forward = new BABYLON.Vector3(0,0,1);        
forward = vecToLocal(forward, box);

// 箱の方向
var direction = forward.subtract(origin);
direction = BABYLON.Vector3.Normalize(direction);

vecToLocalは箱からの方向を取得する関数です。Normalizeは正規化(長さを1に)する作業です。

そして、取得した単位ベクトルから任意の長さの光線を作成します。

var ray = new BABYLON.Ray(origin, direction, length);

最後に、接触した箱(mesh)の接触点を取得します

var hit = scene.pickWithRay(ray);

あとは、衝突したメッシュのyを増やしてあげれば良いです

if (hit.pickedMesh) {
   hit.pickedMesh.scaling.y  += 0.01;
}

Predicate関数を使用したレイキャスト

予め、衝突判定するメッシュを定義するための関数を作ることができます。

// boxとbox2は衝突判定をしない,それ以外はする
function predicate(mesh){
  if (mesh == box2 || mesh == box){
    return false;
  }
  return true;
}

そして、pickWithRayの時に、Predicateを渡してあげます。こうすることで、個別にxxx.isPickable = false; のおような設定を省略できます。

scene.pickWithRay(ray, predicate);

例はこちら。手前の青い箱のPickableをfalseにしているので、後ろの箱に衝突判定があります

https://www.babylonjs-playground.com/#KNE0O#18


マルチピック

scene.multiPickWithRay光線を最初の障害物で停止させたくない場合は、次のように使用できます。

https://www.babylonjs-playground.com/#KNE0O#19


f:id:hollywis:20200708024443j:plain

 var hits = scene.multiPickWithRay(ray);

hit算出をmultiPickWithRayに変えることで、貫通する衝突判定が可能です。

multiPickWithRayの戻り値は配列になっていることに注意してください.


そのほかRayクラスを直接利用することで、ここのメッシュの交差判定をしたり

Ray.intersectsMesh(mesh, fastCheck) → PickingInfo

ローカルスペースへ変更したりできます

Ray.Transform(ray, matrix) → Ray

Picking Ray

カメラから無限遠に向かって、衝突判定(照準)することができます。

そのためにはcreatePickingRay関数を使います。

前の11ステップでは壁との衝突判定を行いましたが、任意のメッシュの場合にはこちらの方が便利そうです。

例はこちら

https://playground.babylonjs.com/#AC8XPN

デバッグ用のRayHelper

デバッグ用に光線に色をつけることができます。

BABYLON.RayHelper.CreateAndShow(ray, scene, new BABYLON.Color3(1, 1, 0.1));

例はこちら

https://www.babylonjs-playground.com/#ZHDBJ#48

まとめ

pickWithRay() を使って光線的な衝突を検出し、そこから衝突したメッシュを取得することができました。

また、multiPickWithRay()を使えば貫通する光線を用いて一度に複数の衝突も取得できました。


また、カメラからの照準(選択)する方法としてcreatePickingRay()を用いる方法を学びました。

以上です!

長かったですが、これで衝突判定系は終わりです。

次回は2D表現のスプライトいっみます

babylon.js ステップ11 画面クリックとの衝突判定 (Picking Collisions)

babylon.js チュートリアル ステップ11 は画面クリックとのコリジョンです。

コリジョンシリーズの3回目です。

いきましょう!

f:id:hollywis:20200630012048p:plain

3Dオブジェクトのクリック(hit)を検出

壁を表す平面と、銃創の絵が描かれた平面の2つを作成して、壁への衝突を検出し、衝突している場合は、そこに銃槍を刻むシーンをやってみます。


まず、クリックイベントで「pick」関数を使用して座標を取得します

//クリックイベント検出
window.addEventListener("click", function () {
   // pickでポインタ情報を取得する
   var pickResult = scene.pick(scene.pointerX, scene.pointerY);
});

pickResultオブジェクトは、主に4つの情報で構成されています。

  • hit (ブール値):クリックがシーン内のオブジェクトにヒットした場合はtrue。
  • distance (float):アクティブなカメラとヒットの間の距離(メッシュにヒットしなかった場合は無限)
  • pickedMesh (BABYLON.Mesh):オブジェクトにヒットしたメッシュ。hitしてない場合はnull
  • pickedPoint (BABYLON.Vector3):クリックしたVector3型で返す。hitしてない場合はnull

ヒットした情報を用いて銃槍の位置をずらす

pickResultを用いて

// もしクリックが壁にhitした場合、ぶつかった画像の位置を更新する
if (pickResult.hit) {
   impact.position.x = pickResult.pickedPoint.x;
   impact.position.y = pickResult.pickedPoint.y;
}

デモ

完成したデモはこちら
https://www.babylonjs-playground.com/#NU4F6Y


次回は,FPSなどで使えるレイキャスト(Raycasts)やっていきます

babylon.js ステップ10 メッシュの交差衝突判定 (Intersect Collisions - mesh)

f:id:hollywis:20200620221236p:plain

メッシュ同士が、それぞれ衝突を検出する方法をやります

いきましょう!!

説明

衝突検出の2つの方法を紹介します。

  1. 2つのメッシュが接触しているときに衝突イベントを発生させる方法
  1. メッシュと1点間の接触を検出する方法

2つのメッシュが接触しているときに衝突イベントを発生させる方法


intersectsMesh()を使うことで、対象との交差(衝突)判定を行うことが出来ます

コードは次の通り

// 平面(plan1)とballoon1との交差判定
if (balloon1.intersectsMesh(plan1, false)) {
  balloon1.material.emissiveColor = new BABYLON.Color4(1, 0, 0, 1);
} else {
  balloon1.material.emissiveColor = new BABYLON.Color4(1, 1, 1, 1);
}


バビロンエンジンでは、交差判定を効率よく行うために
オブジェクトの周囲に下図のように境界ボックス(バウンティングボックス)を作成し、

このボックスと衝突するメッシュの間の交差をテストします。

f:id:hollywis:20200620221905p:plain


また、より詳細に接触を検出したい場合には第二引数をtrueにすることで、

バウンティングボックスをメッシュにより近くし、

交差判定を正確にすることが出来ます。

ただ、この操作は計算負荷が高くなるようです。


左が、falseの例、右がtrueの例です。

f:id:hollywis:20200620222143p:plain

このタイプのバウンディングボックスは、メッシュをある角度に回転させる場合に特に役立ちます。

メッシュと1点間の接触を検出する方法

特定の1点との接触判定をする方法が、intersectsPoint()です。


使用方法は次の通り

var pointToIntersect = new BABYLON.Vector3(10, -5, 0);
if (balloon3.intersectsPoint(pointToIntersect)){
  balloon3.material.emissiveColor = new BABYLON.Color4(1, 0, 0, 1);
}

デモはこちらです

ボールと接触すると赤色になります

https://www.babylonjs-playground.com/#KQV9SA

まとめ

babylon.jsでは衝突判定ようの便利な関数があり

オブジェクト間ではintersectsMesh()


オブジェクトと点ではintersectsPoint()を使うことで衝突判定を行う方法を紹介しました。


次回はマウスとの衝突判定です!

babylon.js ステップ9 カメラとメッシュの衝突判定&重力 (Cameras, Mesh Collisions and Gravity)

babylon.js を覚えようステップ9は衝突判定と重力制御です!


いやー、重力とか楽しそうですね。


メッシュだけでなく、カメラにも設定できるようです。


いきましょう!!

説明

f:id:hollywis:20200620210628j:plain

FPSFirst Person Shooter)ゲームをプレイしたことがありますか?

この回では、そのFPS的なカメラの動きをシミュレートします。

カメラは床にあり、地面と衝突しており、シーン内のオブジェクトと衝突している可能性がありますね

では、このFPS的な設定をしていきましょう!

1.重力の設定

シーンにグラビティ(重力)ベクトルをVector3型で設定します。

scene.gravity = new BABYLON.Vector3(0, -9.81, 0);

古典的には、yに重力加速度9.8を下向き(負)に設定すると良いです。

カメラへの適用は、applyGravityプロパティをtrue設定します

camera.applyGravity = true; 

2.楕円体を定義する

次の重要なステップは、カメラの周りに楕円体を定義することらしいです。

この楕円体はプレーヤーの幅(プレイヤーサイズ)を表します。

外部のメッシュがこの楕円体に接触すると衝突イベントが発生し、カメラがこのメッシュに近づきすぎないようにすることで、カメラがメッシュにめり込まないようにします。
f:id:hollywis:20200620211011p:plain

babylon.jsカメラの楕円体プロパティのデフォルトはサイズ(0.5、1、0.5)ですが、

値を変更すると、調整された軸に応じて、背が高く、大きく、小さく、薄くなります。

次の例では、カメラの楕円体をデフォルトの楕円体よりも少し大きくします。

//カメラの周りに楕円を定義 (e.g. your player's size)
camera.ellipsoid = new BABYLON.Vector3(1, 1, 1);

カメラの楕円体はオフセット(Offset)され、常に視点が楕円体の上にあります。

camera.ellipsoidOffsetプロパティを更新することにより、この動作を制御できます。

計算は次のようになります。

finalPosition = position - vec3(0, ellipsoid.y, 0) + ellipsoidOffset

衝突を適用する(Apply collision)

最後のステップとして、シーン内の衝突の検知をすることを宣言します。

// Enable Collisions
scene.collisionsEnabled = true;
camera.checkCollisions = true;

そして、どのメッシュがカメラと衝突するか設定出来ます。

これはとても便利ですね!Three.jsではなかった設定です。

ground.checkCollisions = true;
box.checkCollisions = true;


以上です!!

demoはこちら
https://www.babylonjs-playground.com/#4HUQQ

カメラは地面と衝突するまで落ちます。

また、ボックスに近づくとカメラがボックスに衝突します。

メッシュオブジェクトとメッシュオブジェクトの衝突

mesh.ellipsoidプロパティ

mesh.moveWithCollisions(velocity)関数

を使用して、メッシュでも同じことを行うこともできる。


この関数は、指定された速度でメッシュを移動させ、現在のメッシュとcheckCollisionsがアクティブになっているすべてのメッシュとの間に衝突がないかどうかをチェックします。


mesh.ellipsoidOffsetを使用して、メッシュ上で楕円体の中心を移動することもできます(デフォルトでは、楕円体はメッシュの中心にあります)。

var speedCharacter = 8;
var gravity = 0.15;
var character = ここにメッシュを設定;

character.ellipsoid = new BABYLON.Vector3(0.5, 1.0, 0.5); //楕円を定義
character.ellipsoidOffset = new BABYLON.Vector3(0, 1.0, 0); //楕円オフセットを設定(上にずらす)

var forwards = new BABYLON.Vector3(parseFloat(Math.sin(character.rotation.y)) / speedCharacter, gravity, parseFloat(Math.cos(character.rotation.y)) / speedCharacter);
forwards.negate();

character.moveWithCollisions(forwards); //衝突判定ありの前進

// または

var backwards = new BABYLON.Vector3(parseFloat(Math.sin(character.rotation.y)) / speedCharacter, -gravity, parseFloat(Math.cos(character.rotation.y)) / speedCharacter);

character.moveWithCollisions(backwards); // 衝突判定ありの後進

ArcRotateCameraでの衝突

ArcRotateCameraでも衝突をチェックすることができますが、、、

障害物に沿ってスライドする代わりに、衝突が追加されてもこのカメラは移動しません。


衝突を有効にするには、camera.checkCollisions = trueを呼び出します。


次のコードで衝突半径を定義できます。

camera.collisionRadius = new BABYLON.Vector3(0.5, 0.5, 0.5)

まとめ

重力を設定する方法は、シーンに設定して、カメラのapplyGravityをtrueにするだけという。

ものすごく簡単に重力が設定できることを紹介しました。

Three.jsではもう少し複雑ですよね。


また、衝突判定には楕円を対象物の周りに作ってmoveWithCollisionsで移動させることで衝突判定が出来ます。

お次はメッシュの衝突判定をより詳しくいきます!


hollywis.hatenablog.com

babylon.js ステップ8 アニメーション(Animations)

babylon.js でのステップも8個目!!

今回はアニメーションです!

アニメーションは、メッシュに動きを与えて見栄えがするシーンを作成出来ます。

いきましょう!

アニメーションの2つの方法

アニメーション方法には2つあります。

  1. 予めアニメーションの動きのキーフレームを定義する方法
  1. 実行時にアニメーションを適用されるようにプロパティを随時変更する方法

キーフレームアニメーション

まず環境を作ります

シーン、ライト、カメラを設定してから、箱を一個置いてみます。

function createScene() {
  //Here... your basic scene as before: [scene, light, camera]

  //Create a box
  var box1 = BABYLON.Mesh.CreateBox("Box1", 10.0, scene);
  box1.position.x = -20;

アニメーションオブジェクトを定義します。
(GSAPみたいなトゥイーン的な方法ですね)

// new BABYLON.Animation(名前,変更対象(例:xの大きさ),値の型,動作タイプ);
var animationBox = new BABYLON.Animation("myAnimation", "scaling.x", 30, BABYLON.Animation.ANIMATIONTYPE_FLOAT, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);

値の型は次の設定値があります

  • BABYLON.Animation.ANIMATIONTYPE_FLOAT
  • BABYLON.Animation.ANIMATIONTYPE_VECTOR2
  • BABYLON.Animation.ANIMATIONTYPE_VECTOR3
  • BABYLON.Animation.ANIMATIONTYPE_QUATERNION
  • BABYLON.Animation.ANIMATIONTYPE_MATRIX
  • BABYLON.Animation.ANIMATIONTYPE_COLOR3


動作タイプには次の設定があります

  • BABYLON.Animation.ANIMATIONLOOPMODE_RELATIVE・・・以前の値を使いインクリメントしてループ
  • BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE・・・初期値にリセットしてループ
  • BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT・・・最後の値をキープしてループ


動作モードについてもう少し捕捉すると

次のように アニメーションキーを設定するとして

// 配列にキーフレームを設定(フレームは昇順でpushしないとならない!)
var keys = []; 

//キーフレーム 0で, スケールを1
  keys.push({
    frame: 0,
    value: 1
  });

  //キーフレーム20で, スケールを0.2
  keys.push({
    frame: 20,
    value: 0.2
  });

  //キーフレーム 100で, スケールを1
  keys.push({
    frame: 100,
    value: 1
  });

Vector2、Vector3、Quaternionの場合は、キーにinTangent値とoutTangent値を設定します

var keys = []; 

  keys.push({
    frame: 0,
    value: BABYLON.Vector3.Zero(),
    outTangent: new BABYLON.Vector3(1, 0, 0)
  });

  keys.push({
    frame: 20,
    inTangent: new BABYLON.Vector3(1, 0, 0),
    value: new BABYLON.Vector3(1, 1, 1),
    outTangent: new BABYLON.Vector3(-1, 0, 0)
  });

  keys.push({
    frame: 100,
    inTangent: new BABYLON.Vector3(-1, 0, 0),
    value: BABYLON.Vector3.Zero()
  });

そして、定義したアニメーション配列をアニメオブジェクトに設定します

animationBox.setKeys(keys);

そして、このアニメーションを箱に紐付けます

box1.animations = [];
box1.animations.push(animationBox);

そして、実行コマンド(beginAnimation)でアニメーションが起動します

// 箱をキーフレーム0から100まで実行!
scene.beginAnimation(box1, 0, 100, true);

キーフレームを入れ替えて逆に実行も可能!

scene.beginAnimation(box1, 100, 0, true);


beginAnimationには、そのほかスピード設定などなど、いろいろ設定できるのドキュメントを確認してみてくださいな

アニメーションを止める方法

実行した後に

var newAnimation = scene.beginAnimation(box1, 0, 100, true);

pauseで止められます

newAnimation.pause();

そのほか、restart(),stop(),reset()もあります

終了を待って同期処理をする

promises を使って同期実行が出来ます

var anim = scene.beginAnimation(box1, 0, 100, false);

console.log("before");
await anim.waitAsync();
console.log("after");

例はこちら
https://www.babylonjs-playground.com/#HZBCXR

CreateAndStartAnimation関数

AbstractMeshオブジェクトの場合には、

StartとEndを設定することでアニメーションを定義出来ます。

BABYLON.Animation.CreateAndStartAnimation('boxscale', box1, 'scaling.x', 30, 120, 1.0, 1.5);

アニメーションのブレンド

f:id:hollywis:20200620162648p:plain
歩いている状態から走る状態へのなめらかな遷移など、アニメーションのブレンドが出来ます!

enableBlending = true を設定

例はこちら
https://www.babylonjs-playground.com/#2BLI9T#174

f:id:hollywis:20200620162742p:plain

アニメーションの重みを設定してブレンド

Babylon.js 3.2以降では、ブレンドを特定の重みでアニメーションを開始できます。

重さを用いたアニメーションはscene.beginWeightedAnimationAPIを使用します。

// 停止 重み 1.0
// scene.beginWeightedAnimation(対象,開始フレーム,終了フレーム,重み,ループ(true/false),(スピード),(終了後の処理),(アニメート設定))
var idleAnim = scene.beginWeightedAnimation(skeleton, 0, 89, 1.0, true);
// 歩き 重み 0
var walkAnim = scene.beginWeightedAnimation(skeleton, 90, 124, 0, true);
// 走り 重み 0
var runAnim = scene.beginWeightedAnimation(skeleton, 125, 146, 0, true);


重みは0から1.0の間をとります。-1を設定するとモードがオフになります。

例はこちら
https://www.babylonjs-playground.com/#IQN716#9

イージング機能

アニメーションにイージングを追加出来ます

イージングチートシート
Easing Functions Cheat Sheet

適用できる関数はこちら

  • BABYLON.CircleEase()
  • BABYLON.BackEase(amplitude)
  • BABYLON.BounceEase(bounces, bounciness)
  • BABYLON.CubicEase()
  • BABYLON.ElasticEase(oscillations, springiness)
  • BABYLON.ExponentialEase(exponent)
  • BABYLON.PowerEase(power)
  • BABYLON.QuadraticEase()
  • BABYLON.QuarticEase()
  • BABYLON.QuinticEase()
  • BABYLON.SineEase()
  • BABYLON.BezierCurveEase()


EasingModeプロパティを使用して、イージング関数の動作の変更もできます。
つまり、アニメーションの補間方法を変更できます。EasingModeに指定できる値は3つあります。

  • BABYLON.EasingFunction.EASINGMODE_EASEIN :補間は、イージング関数に関連付けられた数式に従います。
  • BABYLON.EasingFunction.EASINGMODE_EASEOUT :補間は、100%補間からイージング関数に関連付けられた数式の出力を引いたものに従います。
  • BABYLON.EasingFunction.EASINGMODE_EASEINOUT :補間では、アニメーションの前半にEaseInを使用し、後半にEaseOutを使用します。

補完ベジェの自作も出来ます

// 例
var bezierEase = new BABYLON.BezierCurveEase(0.32, -0.73, 0.69, 1.59);

設定例はこちら
https://www.babylonjs-playground.com/#8ZNVGR

複雑なアニメーション

複雑なアニメーションでは、アニメーションの各フレーム(ティック)ごとにすべてを選択できます。

ゲームのような複雑なアニメーションを設定する場合は、こちらを使います。

requestAnimationFrameを使うわけですがbabylon.jsでは便利なregisterBeforeRenderが用意されています

scene.registerBeforeRender(function () {
  //Your code here
});

例はこちら
https://playground.babylonjs.com/#YJVTI6

まとめ

アニメーションには、予め動きを定義できる

「キーフレームアニメーション」

「複雑なアニメーション」

の2つがありました。



「キーフレームアニメーション」には、かなり細かい設定が可能なプロパティが多く用意されており、予定調和可能な映画やCMのような表現で活躍すると思います。

また、ゲームのような動きが予測出来ないような場合には「複雑なアニメーション」をregisterBeforeRender関数を利用して実行します。


お次はコリジョン(衝突)判定

いきましょう

hollywis.hatenablog.com

babylon.js ステップ7 ライティング

f:id:hollywis:20200620154902j:plain


babylon.js ステップ7 ライティングです。

3D表現はライティングが無いと始まりません。

ライディングの無い空間はただの暗黒です。

暗黒の空間に一条の光として、ライトを設置します。

ライトと言っても、太陽のような環境光もあります。

いきましょう!

ライトの種類

4種類のライトあります

  1. ポイントライト(Point Light)
  2. 指向性ライト(Directional Light)
  3. スポットライト(Spot LIghe)
  4. 半球ライト(HemiLight)

ポイントライト/点光源(Point Light)

ポイントライトは、ワールドスペース内の一意のポイント(点)にから発光されるライトです。

光はこのポイントからあらゆる方向に放出されます。

ポイントライトの分かりやすい例は、裸電球です。

ちょっと上(y軸を多め)に置くとメッシュ全体を照らせます。

var light = new BABYLON.PointLight("pointLight", new BABYLON.Vector3(1, 10, 1), scene);


例はこちら
https://www.babylonjs-playground.com/#20OAV9

指向性ライト/平行光源(Directional Light)

指向性ライト/平行光源は、方向によって定義される特殊な光です。

光は、指定された方向のあらゆる場所から放出され、無限の範囲を持ちます。

指向性ライトの例としては、太陽からの十分に遠い惑星があったとして

その惑星に対して、並行な光が降り注ぐと思うのですが、そんな感じです。

下方向に光を当てると、オブジェクトの上部が明るくなります。

var light = new BABYLON.DirectionalLight("DirectionalLight", new BABYLON.Vector3(0, -1, 0), scene);

例はこちら
https://www.babylonjs-playground.com/#20OAV9#1

スポットライト(Spot LIghe)

スポットライトは、単一の点から一方向に円錐状に放出されます。

方向、角度、および指数を設定出来ます。

値は、位置、照らす方向で光の円錐を定義します。

照射角は、ラジアンで、スポットライトの円錐ビームのサイズ(照明のフィールド)を定義し、

指数は、距離(距離)に伴う光の減衰の速度を定義します。

// new BABYLON.SpotLight(名前, 位置, 照らす方向, 照射角, 光の減衰, scene);
var light = new BABYLON.SpotLight("spotLight", new BABYLON.Vector3(0, 30, -10), new BABYLON.Vector3(0, -1, 0), Math.PI / 3, 2, scene);

例はこちら
https://www.babylonjs-playground.com/#20OAV9#3

半球ライト(HemiLight)

半球ライトは、環境光をシミュレートします。

半球の光は、通常は上空に向かう方向によって定義されます。

ただし、次に説明する色の設定をすることで、より完全な効果が得られる。

var light = new BABYLON.HemisphericLight("HemiLight", new BABYLON.Vector3(0, 1, 0), scene);

例はこちら
https://www.babylonjs-playground.com/#20OAV9#5

色の設定

色に影響を与えるライトには、3つのプロパティがあります。

  • 拡散反射光(diffuse )・・・ベースの反射光 4種類のライトすべてに適用
  • 鏡面反射光(specular)・・・ハイライト 4種類のライトすべてに適用
  • 地面光(groundColor)・・・地面からの反射光。半球ライトにのみ適用


地面光(groundColor)の例はこちら

地面からの反射光が緑だと想定して、gtoundColorが適用されています

https://www.babylonjs-playground.com/#20OAV9#6

ライトのオン、オフ、または調光

これでオフ

light.setEnabled(false);

これでオン

light.setEnabled(true);

intensityを設定することで調光できる

light0.intensity = 0.5;
light1.intensity = 2.4;

ポイントライトとスポットライトの場合、rangeプロパティを使用してライトが到達する距離を設定できます

light.range = 100;

ライティングへのテクスチャの適用

テクスチャへ拡散色を定義するとよい(拡散はオブジェクトに基本色を与えます)。

拡散色の例としては、大聖堂内部の光の効果をシミュレートする場合、ステンドグラスを通過する様々な光は色がついて地面に投影されます。

これは、プロジェクターからの光やなどの光の効果にも当てはまります。

これを再現するためには、SpotLightを用いて、projectionTextureプロパティを適用します。

f:id:hollywis:20200620154802p:plain

var spotLight = new BABYLON.SpotLight("spot02", new BABYLON.Vector3(30, 40, 30),
        new BABYLON.Vector3(-1, -2, -1), 1.1, 16, scene);
spotLight.projectionTexture = new BABYLON.Texture("textures/stainedGlass.png", scene);

まとめ

ライトには4つの種類がありました。

ポイントライト(Point Light)、指向性ライト(Directional Light)、スポットライト(Spot LIghe)、半球ライト(HemiLight)

さらには、ライトの反射光に色の設定する方法とテクスチャを適用する方法も説明しました。

次回はアニメーション!!
hollywis.hatenablog.com