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

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

技術ポートフォリオ

なんとなく自分の技術ポートフォリオをまとめてみました

重点科目はJS系、その他の言語は重点項目ではないので一旦排除しています。

  • Lv15までは守
  • Lv100までは破
  • Lv100以上は離の領域

総合力: Lv50 (システム開発歴10年ほど)

  • Nuxt.js : Lv10
  • Vue.js:Lv15
  • Firebase総合力:Lv5
  • Firebase FireStore:Lv15
  • Firebase Authentication:Lv10
  • Firebase Storage:Lv5
  • Firebase Functions:Lv10
  • Pixi.js,Three.js,babylon.js:Lv5~Lv10
  • サーバー構築 Lv20
  • システム設計 Lv35

守:ツールを十分に理解するフェーズ

【テーマ】通常の利用方法の範囲で忠実に実行する。2年くらいの利用実績。

課題
・Nuxt.js、Vue.jsのレベルを15まであげる
・Firebaseの総合力をレベルを15まで


破:基本理解が一定レベルを超え、ツールの垣根超えて縦横無尽に利用できるフェーズ

【テーマ】
ツールではなく根源的な法則の理解(基本の積み重ね)


・ほぼ入り口にはいっている。様々なライブラリを取り込み組み合わせて利用できるようになって来た

 現在レベル50
 →外部のJSライブラリをどんどん取り入れ、Lv15まで理解し、その後複合させて独自のシステムに昇華させるフェーズ


勉強: 破レベルの先輩コードに触れ学ぶ!
TODO:
  ティラノスクリプトソースコードを読む
  Pixi.jsソースコードを読む
  Three.jsのソースコードを読む
  普段使ってるOSSで不満に思ったことを書き留めておく

離:独自のフレームワークを生み出すレベル

【テーマ】
融通無碍の境地。

基本を全て押さえ、組み合わせもでき
かつムリなくシンプルに纏める、納める事ができる技術

2・6・2

『自己満曲線』に入ってないか定期的にチェックする。
・リリース
→体感としてLv70くらいを目指していた。
・フォーカス
→Lv1000を目指す事。

nuxt.js のSSRデバッグ方法 by Jetbrain

こちらの記事が参考になりました。
ありがとうございます。

k-sasaki.net


asyncDataのデバッグを諦めてconsole.logで頑張っていたところ

これで、デバッグできるようになりました!

f:id:hollywis:20200729112828p:plain

こんな感じで、ブレークポイントを入れたい場所に

「debugger;」

と書けばchromeのDevツールでブレークされます。

Jetbrain最高です。

babylon.js ステップ15 環境設定

ステップ15は環境設定です。

今までは無機質な虚無空間でしたが、ここで遂に空が登場します。

そうする事で、見栄えのする3D空間が完成します


いきましょう!!

f:id:hollywis:20200711204337j:plain


背景色の変更

シーンの背景色を変更するプロパティを使う事で簡単に、背景色を設定できます

  • scene.clearColor - 背景を変更する関数
scene.clearColor = new BABYLON.Color3(0.5, 0.8, 0.5);

Color3型をnewして色を設定できます

f:id:hollywis:20200711205002p:plain

アンビエントカラーの変更

次のプロパティを使うとアンビエントカラーを設定できます

scene.ambientColor = new BABYLON.Color3(0.3, 0.3, 0.3);

clearColorの設定方法と同じように見えますが、アンビエントカラーについては、ambientColorシーンアイテムの最終的な色を決定するためにかなりの数の計算で使用されています。

主に、メッシュとの組み合わせて使用​​され、メッシュマテリアルのStandardMaterial.ambientColor によって最終的なアンビエントカラーが決まるようです。

スカイボックス

f:id:hollywis:20200711221127j:plain

美しい完璧な空を作りたいと思いませんか?

それを簡単に実現したのがスカイボックスです。

このボックスの中にカメラを設置すれば、あたかも広大な空の中にいるような演出ができます。

作り方は次の通り

まずは箱を作ります。

var skybox = BABYLON.Mesh.CreateBox("skyBox", 100.0, scene);
var skyboxMaterial = new BABYLON.StandardMaterial("skyBox", scene);
skyboxMaterial.backFaceCulling = false;
skyboxMaterial.disableLighting = true;
skybox.material = skyboxMaterial;

さらにinfiniteDistanceプロパティを設定します。

 skybox.infiniteDistance = true;

これによって、スカイボックスがカメラの位置に追随するため、カメラがスカイボックスから出てしまうことはなくなります。

skyboxMaterial.disableLighting = true;

ボックスに対するすべての光の反射を削除します


次に、空のテクスチャを内側に貼り付けます。

skyboxMaterial.reflectionTexture = new BABYLON.CubeTexture("textures/skybox", scene);
skyboxMaterial.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE;

なお、設定している/skyboxディレクトリには6つの面に対するテクスチャが入っていて、適切な名前設定の必要があります

f:id:hollywis:20200711221500p:plain

  • 「skybox_nx.jpg」(左)
  • 「skybox_ny.jpg」(下)
  • 「skybox_nz.jpg」(背面)
  • 「skybox_px.jpg」(右)
  • 「skybox_py.jpg 」(上)
  • 「skybox_pz.jpg」(前)

そして、これらのテクスチャは合わせると継ぎ目なくつながっている必要があります。

あとどうやらjpgだけ対応していますpngを設定したらエラーになりました

f:id:hollywis:20200711221653p:plain

スカイボックステクスチャは、空だけのテクスチャである必要は なく。

建物、丘、山、木、湖、惑星、星などざまざまです。

f:id:hollywis:20200711221144p:plain

スカイボックスとGoogleで検索すると様々なテクスチャがあるかと思います。

そのほか、ddsファイルを利用する方法もあります

skyboxMaterial.reflectionTexture = new BABYLON.CubeTexture("/assets/textures/SpecularHDR.dds", scene)

最後に、レンダリング順序を設定します

skybox.renderingGroupId = 0;

// Some other mesh
myMesh.renderingGroupId = 1;

スカイボックスの設定renderingGroupIdを0にして、他のすべてのレンダリング可能なオブジェクトを0より大きくします。

スカイボックスの自動生成方法

var envTexture = new BABYLON.CubeTexture("/assets/textures/SpecularHDR.dds", scene);
scene.createDefaultSkybox(envTexture, true, 1000);

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

スカイボックス用の画像を自分で生成する方法

1枚のパノラマ画像からスカイボックス用の6面の画像にする事をキューブマップ(cubemap)と呼びます。

そんなキューブマップをやってくれる便利なツールがありました


こちらのパノラマ画像のキューブマップ変換機が便利そうです
christinayan01.jp

名前の命名規則は、それぞれ次のように変更します

l ->「nx」(左)
d ->「ny」(下)
b ->「nz」(背面)
r ->「px」(右)
u ->「py 」(上)
f ->「pz」(前)


Fog霧

f:id:hollywis:20200711221235p:plain

フォグはかなり高度な効果なのですが、Babylon.jsのフォグは最大限に簡素化されています。

まず、次のようにフォグモードを定義します。

scene.fogMode = BABYLON.Scene.FOGMODE_EXP;

モードは次の4種類

  • BABYLON.Scene.FOGMODE_NONE -デフォルト無効
  • BABYLON.Scene.FOGMODE_EXP -フォグ密度は指数関数に従
  • BABYLON.Scene.FOGMODE_EXP2 -上記と同じですが高速
  • BABYLON.Scene.FOGMODE_LINEAR -フォグ密度は線形関数に従う


EXPまたはEXP2の場合には密度を設定できます

scene.fogDensity = 0.01;

それ以外の場合には、位置を設定できます

scene.fogStart = 20.0;
scene.fogEnd = 60.0;

すべてのモードで色を設定できます

scene.fogColor = new BABYLON.Color3(0.9, 0.9, 0.85);

デモはこちら
https://www.babylonjs-playground.com/#7G0IQW

まとめ

環境設定として背景色やスカイボックス、霧の使い方を学びました。

これで解像度の高い空ができるかと思います

babylon.js ステップ14 パーティクル表現

babylon.js を覚えようシリーズ ステップ14はパーティクル表現です。

Three.jsでは自作で頑張るわけですが、babylon.jsではパーティクルシステムが備わっていますので、簡単にパーティクル表現が可能です

いきましょう!


f:id:hollywis:20200709105939p:plain

パーティクルの作り方

パーティクルシステム

パーティクルシステムを用いたパーティクル表現の例はこちらです。

コード中に説明を追加していますので順番にみていきましょう


コード例は以下です。

var createScene = function () {
    var scene = new BABYLON.Scene(engine);

    // ライトやカメラなど環境セッティング
    var light0 = new BABYLON.PointLight("Omni", new BABYLON.Vector3(-10, 7, -10), scene);
    var camera = new BABYLON.ArcRotateCamera("ArcRotateCamera", 1, 0.8, 20, new BABYLON.Vector3(0, 0, 0), scene);
    camera.attachControl(canvas, true);

    // パーティクルの吹き出し口のオブジェクト作成
    var fountain = BABYLON.Mesh.CreateBox("foutain", 1.0, scene);

    // 地面作成
    var ground = BABYLON.Mesh.CreatePlane("ground", 50.0, scene);
    ground.position = new BABYLON.Vector3(0, -15, 0);
    ground.rotation = new BABYLON.Vector3(Math.PI / 2, 0, 0);

    ground.material = new BABYLON.StandardMaterial("groundMat", scene);
    ground.material.backFaceCulling = false;
    ground.material.diffuseColor = new BABYLON.Color3(0.3, 0.3, 1);

    // パーティクルシステムの作成
    var particleSystem = new BABYLON.ParticleSystem("particles", 2000, scene);

    //パーティクルに貼るテクスチャ定義
    particleSystem.particleTexture = new BABYLON.Texture("textures/flare.png", scene);

    // パーティクルの出る(emit:放出)ポイントをVector3で定義 mn~maxで定義可能
    particleSystem.emitter = fountain; // the starting object, the emitter
    particleSystem.minEmitBox = new BABYLON.Vector3(-1, 0, 0); // Starting all from
    particleSystem.maxEmitBox = new BABYLON.Vector3(1, 0, 0); // To...

    // パーティクルの色 2種類と消えゆくときの色
    particleSystem.color1 = new BABYLON.Color4(0.7, 0.8, 1.0, 1.0);
    particleSystem.color2 = new BABYLON.Color4(0.2, 0.5, 1.0, 1.0);
    particleSystem.colorDead = new BABYLON.Color4(0, 0, 0.2, 0.0);

    // パーティクル ランダムで min〜maxに
    particleSystem.minSize = 0.1;
    particleSystem.maxSize = 0.5;

    // パーティクルのライフタイム設定 ランダムでmin~max
    particleSystem.minLifeTime = 0.3;
    particleSystem.maxLifeTime = 1.5;

    // 放出(emit)率
    particleSystem.emitRate = 1500;

    // ブレンドモード : BLENDMODE_ONEONE, or BLENDMODE_STANDARD
    particleSystem.blendMode = BABYLON.ParticleSystem.BLENDMODE_ONEONE;

    // 重力設定
    particleSystem.gravity = new BABYLON.Vector3(0, -9.81, 0);

    // エミット(放出)後のパーティクルの方向
    particleSystem.direction1 = new BABYLON.Vector3(-7, 8, 3);
    particleSystem.direction2 = new BABYLON.Vector3(7, 8, -3);

    // 角速度(ラジアン)
    particleSystem.minAngularSpeed = 0;
    particleSystem.maxAngularSpeed = Math.PI;

    // スピード
    particleSystem.minEmitPower = 1;
    particleSystem.maxEmitPower = 3;
    particleSystem.updateSpeed = 0.005;

    // Particle Systemをスタート
    particleSystem.start();

    // 吹き出すアニメーション
    var keys = [];
    var animation = new BABYLON.Animation("animation", "rotation.x", 30, BABYLON.Animation.ANIMATIONTYPE_FLOAT,
                                                                    BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);
    // アニメーション設定 フレーム0, valueは拡大率 "1"
    keys.push({
        frame: 0,
        value: 0
    });

    // フレーム50, 拡大率 "0.2"
    keys.push({
        frame: 50,
        value: Math.PI
    });

    // フレーム 100, 拡大率 "1"
    keys.push({
        frame: 100,
        value: 0
    });

    // アニメーションスタート
    animation.setKeys(keys);
    fountain.animations.push(animation);
    scene.beginAnimation(fountain, 0, 100, true);

    return scene;
}

動いている例はこちら
www.babylonjs-playground.com


解説

この部分で パーティクルシステム(Particle System)を作成しています

    // パーティクルシステムの作成
    var particleSystem = new BABYLON.ParticleSystem("particles", 2000, scene);

    //パーティクルに貼るテクスチャ定義
    particleSystem.particleTexture = new BABYLON.Texture("textures/flare.png", scene);

    // パーティクルの出るポイントをVector3で定義 mn~maxで定義可能
    particleSystem.emitter = fountain; // the starting object, the emitter
    particleSystem.minEmitBox = new BABYLON.Vector3(-1, 0, 0); // Starting all from
    particleSystem.maxEmitBox = new BABYLON.Vector3(1, 0, 0); // To...

2000というのは、表示可能な最大数の設定値です。

さらに、パーティクルシステムには、パーティクルが見えるようにするためのテクスチャと、開始点からのパーティクルの位置と広がりを設定する「エミッタ(emitter)」も必要です。

パーティクルのスタート

particleSystem.start();


パーティクルの停止

particleSystem.stop();


リセット方法

particleSystem.reset()


もし遅延起動させたい場合には

particleSystem.startDelay = 3000;

なんてこともできます。

タイマーを設定して、自動的に勝手に止めることもできます

particleSystem.targetStopDuration = 5; //自動停止
particleSystem.disposeOnStop = true; //パーティクルシステムを破棄し、メモリを開放

パーティクルのテクスチャマスク

f:id:hollywis:20200709121020p:plain

particleSystem.textureMask = new BABYLON.Color4(0.1, 0.8, 0.8, 1.0);

テクスチャにマスクを適用して、一部の色をフィルタリングしたり、アルファチャネルの一部をフィルタリングしたりすることもできます。

パーティクルエミッタ

パーティクルエミッタはメッシュだけでなく、任意のVector3でもOKです。

particleSystem.emitter = new BABYLON.Vector3(-1, 2, 3);

これで任意の点から、パーティクルを放出できます。

ローカル空間

エミッタがメッシュのとき、isLocal設定で、パーティクルをメッシュの座標系に依存させることができます。

particleSystem.isLocal = true

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

場所と広がり

f:id:hollywis:20200709122843p:plain

minEmit maxEmitを設定することで、放出場所を設定します。

particleSystem.minEmitBox = new BABYLON.Vector3(-2, -3, 4); 
particleSystem.maxEmitBox = new BABYLON.Vector3(4, 2, 3); 


シンプルな例がこちら

ただテクスチャを貼ったパーティクルを数個だし、漂流して消えます。

 var createScene = function () {
    var scene = new BABYLON.Scene(engine);

    // Setup environment
    var light0 = new BABYLON.PointLight("Omni", new BABYLON.Vector3(0, 2, 8), scene);
    var camera = new BABYLON.ArcRotateCamera("ArcRotateCamera", 1, 0.8, 20, new BABYLON.Vector3(0, 0, 0), scene);
    camera.attachControl(canvas, true);

    // Create a particle system
    var particleSystem = new BABYLON.ParticleSystem("particles", 2000, scene);

    //Texture of each particle
    particleSystem.particleTexture = new BABYLON.Texture("textures/flare.png", scene);

    // Where the particles come from
    particleSystem.emitter = new BABYLON.Vector3(0, 0, 0); // the starting object, the emitter
    particleSystem.minEmitBox = new BABYLON.Vector3(-0.5, -0.5, -0.5); // Starting all from
    particleSystem.maxEmitBox = new BABYLON.Vector3(0.5, 0.5, 0.5); // To...

    // Start the particle system
    particleSystem.start();

    return scene;
}

ライフタイム

パーティクルの生存期間を設定できます

// Life time of each particle (random between...)
particleSystem.minLifeTime = 0.3;
particleSystem.maxLifeTime = 1.5;

また、高度な設定方法もあります。

system.targetStopDuration = 0.5など停止が決まっているとき

particleSystem.addLifeTimeGradient(0, 0.5); //初期のパーティクルはLife time 0.5
particleSystem.addLifeTimeGradient(1, 0); // 最後のパーティクルはLife time 0

第一引数の0は、最初。1は終わりの時を意味します。

乱数をとりたい場合

particleSystem.addLifeTimeGradient(0, 0.5, 0.8);
particleSystem.addLifeTimeGradient(1.0, 0, 0.1);

このように,第二引数と第三引数の間で乱数をとります

サイズ

// Size of each particle (random between...)
particleSystem.minSize = 0.1;
particleSystem.maxSize = 0.5;

このような書き方もできる

// Scale of each particle (random between...)
particleSystem.minScaleX = 0.1;
particleSystem.maxScaleX = 0.5;

particleSystem.minScaleY = 0.2;
particleSystem.maxScaleY = 0.4;

時間経過を反映した場合(要:targetStopDuration)

particleSystem.addStartSizeGradient(0, 10);
particleSystem.addStartSizeGradient(1.0, 500);

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

particleSystem.color1 = new BABYLON.Color4(0.7, 0.8, 1.0, 1.0);
particleSystem.color2 = new BABYLON.Color4(0.2, 0.5, 1.0, 1.0);
particleSystem.colorDead = new BABYLON.Color4(0, 0, 0.2, 0.0);


グラデーションもできます

particleSystem.addColorGradient(0, new BABYLON.Color4(1, 1, 1, 0));
||>


開始時、終了時設定あり
>||
particleSystem.addColorGradient(0, new BABYLON.Color4(1, 1, 1, 0));
particleSystem.addColorGradient(1.0, new BABYLON.Color4(1, 1, 1, 1));

ブレンドモード

BLENDMODE_ONEONEがデフォルトであり、blendMode指定されていない場合に使用されます。

  • BLENDMODE_ONEONE -色は結果に影響を与えるアルファなしで追加されます
  • BLENDMODE_STANDARD- カラーは、パーティクルのアルファを使用して追加されます(つまり、カラー(1-アルファ)+パーティクルカラーアルファ)
  • BLENDMODE_ADD -色が追加されますが、粒子の色のみが粒子のアルファを使用します(つまり、色+ particleColor *アルファ)

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

  • BLENDMODE_MULTIPLY-色が乗算され、(1-アルファ)に追加されます(つまり、色*パーティクルカラー+ 1-アルファ)

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

  • BLENDMODE_MULTIPLYADD- BLENDMODE_MULTIPLY後に BLENDMODE_ADD

例はこちら(スペースキーを押すと爆発表現のパーティクルが放出されます)
https://www.babylonjs-playground.com/#VS5XS7#0

rate

rateは1秒あたりのパーティクルの放出数を設定します

f:id:hollywis:20200709125218p:plain

後ほど、設定値を手動設定もできます

particleSystem.manualEmitCount = 300;


時間経過を考慮したGradient設定もできます

particleSystem.addEmitRateGradient(0, 10);
particleSystem.addEmitRateGradient(1.0, 500);

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

放出方向

2つの方向を指定できます。

一方向のみを指定した場合、パーティクルは指定された一般的な方向にランダムに放出されます。

2つ指定されている場合、パーティクルは2つの方向の間を移動します。

particleSystem.direction1 = new BABYLON.Vector3(-7, 8, 3);
particleSystem.direction2 = new BABYLON.Vector3(7, 8, -3);

重力

//Set the gravity of all particles (not necessarily down)
particleSystem.gravity = new BABYLON.Vector3(0, -9.81, 0);

回転

パーティクルのZ軸を中心として、角速度の範囲をラジアン/秒で定義できます。

particleSystem.minAngularSpeed = 0;
particleSystem.maxAngularSpeed = Math.PI;

次のように初期回転角度も定義できます

particleSystem.minInitialRotation = 0;
particleSystem.maxInitialRotation = Math.PI;

速度

放出するパーティクルのパワーと全体的なモーション速度の範囲を定義できます

0.01がデフォルト。(更新が速い=アニメーションが速い)

particleSystem.minEmitPower = 1;
  particleSystem.maxEmitPower = 3;
  particleSystem.updateSpeed = 0.005;

Gradient設定で徐々に速度を変えることもできます

詳しくは例をどうぞ
https://www.babylonjs-playground.com/#3W04PW#0は

速度リミット

時間の経過に伴う速度の制限を定義できます。

制限に達した場合、速度に係数が適用されます。

particleSystem.addLimitVelocityGradient(0, 0.5);
particleSystem.addLimitVelocityGradient(1.0, 3);

例はこちら

https://www.babylonjs-playground.com/#9GBBPM#2

抗力係数

空気摩擦をシミュレートするために使用されます。

たとえば、ドラッグ係数が0.8に設定されている場合、粒子の方向の20%だけが粒子の位置に追加されます。

particleSystem.addDragGradient(0, 0.5);
particleSystem.addDragGradient(1.0, 3);

例はこちら

https://www.babylonjs-playground.com/#BDW3BF#0

整列

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

このようんy軸を揃えて整列させると

system.billboardMode = BABYLON.ParticleSystem.BILLBOARDMODE_Y;

こんな感じで湯気を表現できる
https://www.babylonjs-playground.com/#B9HKG0#0

ノイズテクスチャ

なんかいろいろできるっぽいです

https://www.babylonjs-playground.com/#R1JWLA#3

まとめ

パーティクルシステムを用いて、様々なパーティクル表現を学びました。

パーティクルのエミッタ(放出元)の設定や、パーティクルの放出方向、色、ブレンドモード、速度、数、重力設定などなど、事細かに設定できることがわかりました。

ここでは紹介しませんでしたがパフォーマンスに問題がある際には、WebGL2を用いたパーティクル作成機能などもあるので、ドキュメントを読んでみてください。


次回は、環境設定に入ります

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)やっていきます