Away3D TypeScriptではじめる3次元表現

第12回 パーティクルのアニメーションを加える

この記事を読むのに必要な時間:およそ 12 分

前回の第11回Away3D TypeScriptが2015年3月13日付でビルドを改めたでは,最新のライブラリを使って床の平面に石畳のテクスチャを貼った(再掲第11回図2)⁠カメラはマウスドラッグで周囲を回る。今回から,お題にしたAnimating particles simulating fireの本論となるパーティクルをつくり始める。パーティクルは仕込みが多く,目に見える動きがなかなか確かめられない。今回,アニメーションを試すのは本稿の終わりのほうになる。しばしご辛抱のうえ,おつき合いいただきたい。

第11回 図2 床の平面に石畳のテクスチャが貼られた(再掲)

第11回 図2 床の平面に石畳のテクスチャが貼られた(再掲)

パーティクルのオブジェクトを加える

炎のパーティクルは,床の中心から描く円周上に置こう。パーティクルのオブジェクトをつくる関数(createParticles())はつぎのように定める。引数は,炎の数と炎から立ち上るパーティクル数,炎の平面上の位置を定める中心からの半径と垂直座標,および3次元空間のシーン(View.sceneプロパティ)だ。そして戻り値として,炎のオブジェクトが入った配列を返す。

createParticles(炎の数, パーティクル数, 炎の位置の半径, 炎の垂直座標, シーン)

このパーティクルをつくる関数(createParticles())は,以下の抜書きのように初期設定の関数(initialize())から呼び出す。そして,戻り値の炎のオブジェクトの配列は変数(fireObjects)に納めた。また,少しだけコードを手直しする。StaticLightPickerオブジェクトは初期設定の関数でつくって変数(lightPicker)に納め,床をつくる関数(createPlane())にはそのオブジェクトを引数として渡すことにした。そして,最後の引数である垂直位置は,今回のお題に合うよう少し引上げている(-300から-20へ)⁠

// var DefaultMaterialManager = require("awayjs-display/lib/managers/DefaultMaterialManager");

var lightPicker;

var fireObjects;

var particleMaterial;
function initialize() {

  lightPicker = new StaticLightPicker([directionalLight]);
  // plane = createPlane(800, 800, directionalLight, -300);
  plane = createPlane(800, 800, lightPicker, -20);
  fireObjects = createParticles(3, 500, 300, 5, scene);

}

function createPlane(width, height, light, y) {
  var material = new MethodMaterial();   // DefaultMaterialManager.getDefaultTexture());

  // material.lightPicker = new StaticLightPicker([light]);
  material.lightPicker = light;

}

なお,MethodMaterial()コンストラクタには,とくに引数は渡さなくてよい※1)⁠したがって,平面をつくる関数(createPlane())でもコンストラクタから引数を省き,require()関数によるDefaultMaterialManagerクラスの読込みも除いた。

パーティクルをつくる関数(createParticles())の中身は以下のとおりだ。もととなる小さな平面のひながたは,PrimitivePlanePrefab()コンストラクタでつくる。渡す第3および第4引数は,x軸方向とyまたはz軸方向それぞれのセグメント数で,デフォルト値は1だ。第5引数は,面の(法線ベクトルの)向きをy軸に合わせるかどうかのブール値で,デフォルト値がtruefalseはz軸に向ける。

パーティクルは平面で,同じものをたくさんつくる。そこで,いちいちPrefabBase.getNewObject()メソッドは用いず,幾何学情報のGeometryオブジェクト(geometry)PrimitivePrefabBase.geometryプロパティで得る。これとMethodMaterialオブジェクト(material)を後述のMesh()コンストラクタに渡せば,パーティクルの平面オブジェクトはつくれる。

パーティクルに用いるGeometryオブジェクトは,パーティクルと同じ数(numParticles)だけ配列(geometrySet)に加えた。炎のオブジェクトをつくる関数(getFireObjects())は別に定めて呼び出し,でき上がったオブジェクトの配列(fireObjects)を受け取って返す。

function createParticles(numFires, numParticles, radius, y, scene) {

  var primitive = new PrimitivePlanePrefab(10, 10, 1, 1, false);
  var geometry = primitive.geometry;
  var material = particleMaterial = new MethodMaterial(); 
  var geometrySet = [];
  for (var i = 0; i < numParticles; i++) {
    geometrySet[i] = geometry;
  }
  var fireObjects = getFireObjects(geometrySet, numFires, material, animationSet, radius, y, scene);
  return fireObjects;
}

炎のオブジェクトをつくって,配列に入れて返す関数(getFireObjects())はつぎのように定める。第1引数はGeometryオブジェクトを納めた配列,第3引数にはパーティクルに用いる素材オブジェクトを渡す。第4引数のアニメーションの定めについては,後で改めて説明する。他の引数は,この関数を呼び出す前掲のパーティクルをつくる関数(createParticles())が受け取った値だ。

getFireObjects(幾何情報の配列, 炎の数, 表面素材, アニメーションセット, 炎の位置の半径, 炎の垂直座標, シーン)

炎のオブジェクトの配列をつくる関数(getFireObjects())が受け取ったGeometryオブジェクトの配列(geometrySet)は,ParticleGeometryHelper.generateGeometry()メソッドに渡してParticleGeometryオブジェクト(particleGeometry)を得る。ひとつひとつの炎のオブジェクト(mesh)は別の関数(createAnimationParticle())でつくり,床の平面の中心から定められた半径(radius)の円周上に等間隔(anglePerFire)で並べたうえで,3次元空間のシーン(scene)に加えた。

var ParticleGeometryHelper = require("awayjs-renderergl/lib/utils/ParticleGeometryHelper");

function getFireObjects(geometrySet, numFires, material, animationSet, radius, y, scene) {
  var fireObjects = [];
  var particleGeometry = ParticleGeometryHelper.generateGeometry(geometrySet);
  var anglePerFire = Math.PI * 2 / numFires;
  for (var i = 0; i < numFires; i++) {
    var mesh = createAnimationParticle(particleGeometry, material, animationSet, fireObjects);
    var angle = i * anglePerFire;
    mesh.x = radius * Math.sin(angle);
    mesh.z = radius * Math.cos(angle);
    mesh.y = y;
    scene.addChild(mesh);
  }
  return fireObjects;
}

炎のオブジェクトをつくって返す関数(createAnimationParticle())は,Meshクラスのコンストラクタに幾何情報(particleGeometry)と素材オブジェクト(material)を引数に渡して,まずMeshオブジェクトにする。そして,このMeshオブジェクト(mesh)と後述するアニメーションのオブジェクト(animator)を渡した炎のオブジェクトがつくられて,関数の引数に受け取った配列(fireObjects)に納められる。関数の戻り値はMeshオブジェクトだ。なお,配列は参照が渡されるので,炎のオブジェクトは前掲呼出し側の関数(getFireObjects())の変数(fireObjects)に加えられることになる。

var Mesh = require("awayjs-display/lib/entities/Mesh");

function createAnimationParticle(particleGeometry, material, animationSet, fireObjects) {
  var mesh = new Mesh(particleGeometry, material);

  fireObjects.push(new FireObject(mesh, animator));
  return mesh;
}

アニメーションさせる炎のオブジェクトは,以下のクラス(FireObject)で定めたコード1)⁠コンストラクタの引数は,つぎのようにMeshオブジェクト(mesh)とパーティクルのアニメーションを定めたParticleAnimatorオブジェクト(animator)(ParticleAnimatorオブジェクトは後述)⁠クラスに加えたメソッド(startAnimation())については後ほど説明する。なお,JavaScriptでクラスをどのように定義するかは,⁠HTML5のCanvasでつくるダイナミックな表現―CreateJSを使う」第17回簡単なクラスを定義するを参照してほしい。

new FireObject(Meshオブジェクト, ParticleAnimatorオブジェクト)

コード1 アニメーションさせる炎を定めたクラス

function FireObject(mesh, animator) {
  this.strength = 0;
  this.mesh = mesh;
  this.animator = animator;
}
FireObject.prototype.startAnimation = function() {
  this.animator.start();
};
※1
MethodMaterial()コンストラクタの引数にデフォルトのテクスチャ(BitmapTextureオブジェクト)を渡してもとくに問題はない。だが,お題のAnimating particles simulating fireでは引数を与えていないので,それに合わせた。

著者プロフィール

野中文雄(のなかふみお)

ソフトウェアトレーナー,テクニカルライター,オーサリングエンジニア。上智大学法学部卒,慶応義塾大学大学院経営管理研究科修士課程修了(MBA)。独立系パソコン販売会社で,総務・人事,企画,外資系企業担当営業などに携わる。その後,マルチメディアコンテンツ制作会社に転職。ソフトウェアトレーニング,コンテンツ制作などの業務を担当する。2001年11月に独立。Web制作者に向けた情報発信プロジェクトF-siteにも参加する。株式会社ロクナナ取締役(非常勤)。

URLhttp://www.FumioNonaka.com/

著書

コメント

コメントの記入