はじめに
前回に引き続き、WebGL/HTML5ゲームエンジンである
PlayCanvasを触っていこうと思います。
PlayCanvasは、デスクトップとモバイルブラウザ向けに作られた
PLAYCANVAS
WebGL/HTML5ゲームエンジンです。豊富な機能を揃えた3Dエンジンと
クラウドホスティングされた開発環境およびツールセットを備えています。
導入及び基本理解については前回記事をご参照ください。
今回はTweenも使うのでtween.js
を事前に下記リンクから
プロジェクトに導入しておきます。
(新規script作成後、全文コピペして貼り付ければOKです)
playcanvas-tween
Particle(パーティクル)
PlayCanvasのComponentにParticleというものが存在します。
このParticleを利用すれば、そこそこ見栄えの良いエフェクトが
簡単に作成可能です。
下記のデモもParticleで作成したものです。

先ほど説明した通り、ParticleもComponentの1つなので
簡単に追加して編集化が可能です。
下記画像の通り、HIERARCHY上で追加するで編集できます。

Particleのパラメータは大量にあるので、
パラメータに関する説明は省略します。
プロジェクトを公開するので、細かい設定に関しては
下記ご参照ください。
Effectデモプロジェクト
Tween
PlayCanvasにはTweenライブラリが用意されています。
これを使うことで現在の値から指定した値へ
アニメーションを行うことができます。
【参考リンク】:チュートリアル – Vue.jsでPlayCanvas製3Dモデルビュワーサイトを作る 4/6
任意のパラメータをTweenで変化させれば、
よりリッチなエフェクトが作成可能です。
今回解説するTweenの利用例は下記GIFのように
Particle(Entity)の大きさとPoint Lightの明るさが連動するサンプルです。
(球体を置いて明るさの変化を分かり易くしています)

コード
var FireEffect = pc.createScript('fireEffect');
FireEffect.attributes.add('firePointLightEntity', {type: 'entity', title: 'Fire Point Light Entity'});
FireEffect.attributes.add('fireEntity', {type: 'entity', title: 'Fire Entity'});
FireEffect.prototype.initialize = function() {
//大きさ変更するパラメータの初期値
defaultFireSize = new pc.Vec3().copy(this.fireEntity.getLocalScale());
defaultFirePointLightRange = this.firePointLightEntity.light.range;
defaultFirePointLightIntensity = this.firePointLightEntity.light.intensity;
this.fireTween();
};
FireEffect.prototype.fireTween = function(){
//Scriptのインスタンスを保持
var self = this;
//すべての変化に影響するランダムな値
0 ~ 1
var randomFloat = getRandomInt(0,10) * 0.1;
//変化にかける時間
var randomDuration = getRandomInt(1,2) * 0.25;
//==================
// 火の大きさ
//==================
//実行中のTween停止
if(tweenFireSize){ tweenFireSize.stop(); }
//大きさの変化領域
var randomSize = randomFloat * 0.5;
//今のサイズ var currentScale = new pc.Vec3().copy(this.fireEntity.getLocalScale());
//単発でTween実行
var tweenFireSize = this.app
.tween(currentScale).to({x: defaultFireSize.x + randomSize, y: defaultFireSize.y + randomSize, z: 1 }, randomDuration, pc.SineOut)
.yoyo(true)
.on('update', function (dt) {
//毎フレームサイズをセットして更新
self.fireEntity.setLocalScale(currentScale);
})
.start();
//==================
// 炎直下ライトの範囲
//==================
//実行中のTween停止
if(tweenLightRange){ tweenLightRange.stop(); }
//レンジの変化領域
var randomRange = randomFloat * 0.1;
//単発でTween実行
var tweenLightRange = this.app
.tween(this.firePointLightEntity.light).to({range: defaultFirePointLightRange + randomRange}, randomDuration, pc.SineOut)
.yoyo(true)
.start();
//==================
// 炎直下ライトの明るさ
//==================
//実行中のTween停止
if(tweenLightIntensity){ tweenLightIntensity.stop(); }
//明るさの変化領域
var randomIntensity = randomFloat * 0.5;
//単発でTween実行
var tweenLightIntensity = this.app
.tween(this.firePointLightEntity.light)
.to({intensity: defaultFirePointLightIntensity + randomIntensity}, randomDuration, pc.SineOut)
.yoyo(true)
.on('complete', function () {
//再帰的に実行
self.fireTween();
})
.start();
};
//ランダムな数字生成
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return (Math.floor(Math.random() * (max-min)) + min);
}
tween.jsの基本的な使い方については
ライブラリのREADMEの通りなので割愛します。
行っている処理としては、ランダムに生成した数字を
・炎(Entity)の大きさ
・Point Lightの明るさ
・Point Lightの照らす範囲
上記それぞれを変化させるTweenに渡して変化のタイミングを合わせています。
さらに、変化量はそれぞれで細かく調整しています。
【参考リンク】:【PlayCanvas(JavaScript)】ランダムな値をTweenに渡してループさせる
LightとShadow
LightとShadowの関係で少し苦労した点がありました。
Light ComponentにCast Shadowsというパラメータがあります。

これをオンにすれば、Lightから出た光は
Modelを持つEntityの影を描画します。
しかし、このままでは1つ問題をはらんでいます。
下記GIFをご覧ください。

何が問題かというと、Lightの明るさが影に全く影響を及ぼさないことです。
これは自然界の光と影の関係においてはありえません。
Lightが明るくなれば、影も比例して薄く(明るく)ならないといけません。
解決策としては、影を落とすLightと照らすLightをそれぞれ用意することです。
お好みの明るさに調節したら全く同じものをもう一つ用意します。

そして、片方のCast Shadowsだけオンにします。

ちゃんと明るさに応じて影の濃さも変化するようになりました。
おわりに
PlayCanvasで簡単な絵作りに挑戦してみました。
動作も軽く、簡単なものを作るなら扱いやすいので
なかなか可能性を感じさせるゲームエンジンでした。
参考リンク、拝借した素材
Explosion Particle Effect
Jiggly Bubble Free