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

第18回2つのビットマップをパーティクルにしてアニメーションさせる

前回の第17回ロゴがパーティクルで弾けるアニメーションでは、ロゴひとつをパーティクルにしてアニメーションさせた第17回サンプル1Away3D 15/03/13: Exploding a logo using particles⁠。今回は、ロゴの画像をもうひとつ加えたい図1⁠。複数ならいくつでも同じなのだから、ふたつといわず必要な数(4つ)読み込めばよいと思われるかもしれない。けれど、数が複数になると、アニメーションもそれに合わせて変えなければならないところが出てくる。まずは、2つで修正すべき点を絞った方が進めやすい。

図1 2つのブラウザのロゴがパーティクルになって弾ける
図1 2つのブラウザのロゴがパーティクルになって弾ける

2つのロゴがパーティクルで弾けるアニメーションを動かす

アニメーションの調整は後回しにして、とにかくふたつのロゴからつくったパーティクルのアニメーションを動かしたい。第1に、読み込む素材のビットマップファイルが2つになるので、URLを配列に入れて扱う。使うFirefoxロゴのファイルとして、awayjs-examplesの中のbin/assets/firefox.pngをassetsフォルダに納めた図2⁠。リスナーを定める関数(setListeners())は、以下のように変数(assetsURLs)の配列からfor文でそれぞれのURLの画像を読み込む。

図2 Firefoxロゴの画像ファイル
図2 Firefoxロゴの画像ファイル
// var assetsURL = "assets/chrome.png";
var assetsURLs = [
  "assets/chrome.png",
  "assets/firefox.png"
];

function setListeners() {
  var count = assetsURLs.length;

  AssetLibrary.addEventListener(LoaderEvent.RESOURCE_COMPLETE, onResourceComplete);
  // AssetLibrary.load(new URLRequest(assetsURL));
  for (var i = 0; i < count; i++) {
    AssetLibrary.load(new URLRequest(assetsURLs[i]));
  }
}

第2に、リスナー関数(onResourceComplete())が読み込んだ画像からつくったBitmapDataオブジェクト(bitmapData)は、これも配列の新たな変数(bitmapDatas)に納める。パーティクルをつくる処理は2つのオブジェクトがつくられてからなので、配列エレメントが2つできたことをif条件で確かめた。

// var bitmapData;
var bitmapDatas = new Array(assetsURLs.length);

function onResourceComplete(eventObject) {

  // bitmapData = Cast.bitmapData(asset);
  var bitmapData = Cast.bitmapData(asset);
  switch (eventObject.url) {
    case assetsURLs[0]:
      bitmapDatas[0] = bitmapData;
      break;
    case assetsURLs[1]:
      bitmapDatas[1] = bitmapData;
      break;
  }
  if (bitmapDatas[0] && bitmapDatas[1]) {
    var colorGeometry = createParticles();
    startParticleAnimation(colorGeometry);
  }
}

そして第3に、パーティクルをつくる関数(createParticles())が、BitmapDataデータオブジェクトの配列(bitmapDatas)から順に取り出したエレメントからパーティクルの情報をつくる(setParticlesData()関数の呼出し⁠⁠。これらの手を加えると、とりあえずエラーなくアニメーションは動く。

function createParticles() {
  var count = bitmapDatas.length;

  // setParticlesData(bitmapData, PARTICLE_SIZE, colorValues, colorPoints);
  for (var i = 0; i < count; i++) {
    setParticlesData(bitmapDatas[i], PARTICLE_SIZE, colorValues, colorPoints);

  }

  // var count = colorPoints.length;
  count = colorPoints.length;
  for (var j = 0; j < count; j++) {

  }

}

ここまでのスクリプトは以下のコード1にまとめた。もっとも、はじめに注意したとおり、アニメーションとしてはまったくいただけない。ChromeとFirefoxのロゴが合体してしまう図3⁠。これは、2つのロゴのアニメーションの行き先が同じ位置になっているためだ。ロゴごとにアニメーションを変えてやらなければならない。

図3 2つのロゴが合体してしまう
図3 2つのロゴが合体してしまう
コード1 2つの画像ファイルからパーティクルのアニメーションをつくって動かす
var LoaderEvent = require("awayjs-core/lib/events/LoaderEvent");
var ColorTransform = require("awayjs-core/lib/geom/ColorTransform");
var Vector3D = require("awayjs-core/lib/geom/Vector3D");
var AssetLibrary = require("awayjs-core/lib/library/AssetLibrary");
var URLRequest = require("awayjs-core/lib/net/URLRequest");
var RequestAnimationFrame = require("awayjs-core/lib/utils/RequestAnimationFrame");
var View = require("awayjs-display/lib/containers/View");
var HoverController = require("awayjs-display/lib/controllers/HoverController");
var Mesh = require("awayjs-display/lib/entities/Mesh");
var PointLight = require("awayjs-display/lib/entities/PointLight");
var StaticLightPicker = require("awayjs-display/lib/materials/lightpickers/StaticLightPicker");
var PrimitivePlanePrefab = require("awayjs-display/lib/prefabs/PrimitivePlanePrefab");
var Cast = require("awayjs-display/lib/utils/Cast");
var ParticleAnimationSet = require("awayjs-renderergl/lib/animators/ParticleAnimationSet");
var ParticleAnimator = require("awayjs-renderergl/lib/animators/ParticleAnimator");
var ParticlePropertiesMode = require("awayjs-renderergl/lib/animators/data/ParticlePropertiesMode");
var ParticleBillboardNode = require("awayjs-renderergl/lib/animators/nodes/ParticleBillboardNode");
var ParticleBezierCurveNode = require("awayjs-renderergl/lib/animators/nodes/ParticleBezierCurveNode");
var ParticleInitialColorNode = require("awayjs-renderergl/lib/animators/nodes/ParticleInitialColorNode");
var ParticlePositionNode = require("awayjs-renderergl/lib/animators/nodes/ParticlePositionNode");
var DefaultRenderer = require("awayjs-renderergl/lib/DefaultRenderer");
var ParticleGeometryHelper = require("awayjs-renderergl/lib/utils/ParticleGeometryHelper");
var MethodMaterial = require("awayjs-methodmaterials/lib/MethodMaterial");
var MethodRendererPool = require("awayjs-methodmaterials/lib/pool/MethodRendererPool");
var PARTICLE_SIZE = 2;
var view;
var cameraController;
var light;
var assetsURLs = [
  "assets/chrome.png",
  "assets/firefox.png"
];
var bitmapDatas = new Array(assetsURLs.length);
var colorValues = [];
var colorPoints = [];
var colorMaterial;
var colorAnimationSet;
var colorAnimator;
var timer;
var time = 0;
function initialize() {
  var lightPicker = createLights();
  view = createView(window.innerWidth, window.innerHeight, 0x0);
  cameraController = setupCameraController(view.camera, 1000, 225, 10);
  colorMaterial = createMaterial(lightPicker, true);
  setListeners();
}
function createView(width, height, backgroundColor) {
  var defaultRenderer = new DefaultRenderer(MethodRendererPool);
  var view = new View(defaultRenderer);
  view.width = width;
  view.height = height;
  view.backgroundColor = backgroundColor;
  return view;
}
function setupCameraController(camera, distance, panAngle, tiltAngle) {
  var cameraController = new HoverController(camera);
  cameraController.distance = distance;
  cameraController.panAngle = panAngle;
  cameraController.tiltAngle = tiltAngle;
  return cameraController;
}
function createLights() {
  light = createPointLight(0xFFFFFF, 1, 600, 100, 2);
  return new StaticLightPicker([light]);
}
function createPointLight(color, ambient, fallOff, radius, specular) {
  var light = new PointLight();
  light.color = color;
  light.ambient = ambient;
  light.fallOff = fallOff;
  light.radius = radius;
  light.specular = specular;
  return light;
}
function createMaterial(lightPicker, bothSides) {
  var material = new MethodMaterial();
  material.bothSides = bothSides;
  material.lightPicker = lightPicker;
  return material;
}
function onResourceComplete(eventObject) {
  var asset = eventObject.assets[0];
  var bitmapData = Cast.bitmapData(asset);
  switch (eventObject.url) {
    case assetsURLs[0]:
      bitmapDatas[0] = bitmapData;
      break;
    case assetsURLs[1]:
      bitmapDatas[1] = bitmapData;
      break;
  }
  if (bitmapDatas[0] && bitmapDatas[1]) {
    var colorGeometry = createParticles();
    startParticleAnimation(colorGeometry);
  }
}
function createParticles() {
  var count = bitmapDatas.length;
  colorAnimationSet = createColorAnimationSet(initColorParticle);
  for (var i = 0; i < count; i++) {
    setParticlesData(bitmapDatas[i], PARTICLE_SIZE, colorValues, colorPoints);
  }
  var primitive = new PrimitivePlanePrefab(PARTICLE_SIZE, PARTICLE_SIZE, 1, 1, false);
  var geometry = primitive.geometry;
  var colorGeometrySet = [];
  count = colorPoints.length;
  for (var j = 0; j < count; j++) {
    colorGeometrySet[j] = geometry;
  }
  var colorGeometry = ParticleGeometryHelper.generateGeometry(colorGeometrySet);
  return colorGeometry;
}
function setParticlesData(bitmapData, size, colorValues, colorPoints) {
  var bitmapWidth = bitmapData.width;
  var bitmapHeight = bitmapData.height;
  for (var i = 0; i < bitmapWidth; i++) {
    for (var j = 0; j < bitmapHeight; j++) {
      var point = new Vector3D(size * (i - bitmapWidth / 2), size * ( -j + bitmapHeight / 2));
      var color = bitmapData.getPixel32(i, j);
        var rgbColor = getRgbComponents(color);
        rgbColor.scaleBy(1 / 255);
        colorValues.push(rgbColor);
        colorPoints.push(point);
    }
  }
}
function getRgbComponents(rgbColor) {
  var rgbVector = new Vector3D();
  rgbVector.x = (rgbColor & 0xff0000) >> 16;
  rgbVector.y = (rgbColor & 0xff00) >> 8;
  rgbVector.z = rgbColor & 0xff;
  return rgbVector;
}
function createColorAnimationSet(initParticleFunc) {
  var LOCAL_STATIC = ParticlePropertiesMode.LOCAL_STATIC;
  var colorAnimationSet = new ParticleAnimationSet();
  colorAnimationSet.addAnimation(new ParticleBillboardNode());
  colorAnimationSet.addAnimation(new ParticleBezierCurveNode(LOCAL_STATIC));
  colorAnimationSet.addAnimation(new ParticlePositionNode(LOCAL_STATIC));
  colorAnimationSet.addAnimation(new ParticleInitialColorNode(LOCAL_STATIC, true, false, new ColorTransform(0, 1, 0, 1)));
  colorAnimationSet.initParticleFunc = initParticleFunc;
  return colorAnimationSet;
}
function startParticleAnimation(colorGeometry) {
  var scene = view.scene;
  var colorParticleMesh = new Mesh(colorGeometry, colorMaterial);
  var animator = new ParticleAnimator(colorAnimationSet);
  colorAnimator = animator;
  colorParticleMesh.animator = animator;
  scene.addChild(colorParticleMesh);
}
function setListeners() {
  var count = assetsURLs.length;
  timer = new RequestAnimationFrame(render);
  timer.start();
  AssetLibrary.addEventListener(LoaderEvent.RESOURCE_COMPLETE, onResourceComplete);
  for (var i = 0; i < count; i++) {
    AssetLibrary.load(new URLRequest(assetsURLs[i]));
  }
}
function initColorParticle(properties) {
  var BEZIER_END_VECTOR3D = ParticleBezierCurveNode.BEZIER_END_VECTOR3D;
  var index = properties.index;
  var endPoint = new Vector3D();
  var rgb = colorValues[index];
  properties.startTime = 0;
  properties.duration = 1;
  properties[BEZIER_END_VECTOR3D] = endPoint;
  properties[ParticleInitialColorNode.COLOR_INITIAL_COLORTRANSFORM] = new ColorTransform(rgb.x, rgb.y, rgb.z, 1);
  properties[ParticleBezierCurveNode.BEZIER_CONTROL_VECTOR3D] = getRandomVector3D(100);
  properties[ParticlePositionNode.POSITION_VECTOR3D] = colorPoints[index];
}
function getRandomVector3D(radius) {
  var angle0 = Math.random() * Math.PI * 2;
  var angle1 = Math.random() * Math.PI * 2;
  var x = radius * Math.cos(angle0) * Math.cos(angle1);
  var y = radius * Math.cos(angle0) * Math.sin(angle1);
  var z = radius * Math.sin(angle0);
  return new Vector3D(x, y, z);
}
function render(deltaTime) {
  time += deltaTime;
  if (colorAnimator) {
    var _time = 1000 * (Math.sin(time / 5000) + 1);
    colorAnimator.update(_time);
  }
  view.render();
}

2つのロゴのアニメーションを変える

パーティクルのアニメーションの行き先は、ParticleBezierCurveNodeを用いてベジエ曲線で定めた。パーティクルの色や座標はピクセル単位で、それぞれ配列(colorValuesとcolorPoints)に納めている。これらの配列を入れ子にして、ロゴごとに分けることも考えられる。

けれど、パーティクルを初期化するときに行き先座標を定めさえすれば、その後のアニメーションでどのロゴの値かはとくに知らなくて済む。そこで、色や座標の値をエレメントに加えたとき、2つのロゴが切り替わるインデックスを別の変数(colorSeparations)にとっておくことにした。ロゴの数は増えるので、この変数も配列にしておく。インデックスを得るのは、パーティクルをつくる関数(createParticles())になる。

var colorSeparations = [];

function createParticles() {
  var count = bitmapDatas.length;

  for (var i = 0; i < count; i++) {
    setParticlesData(bitmapDatas[i], PARTICLE_SIZE, colorValues, colorPoints);
    colorSeparations[i] = colorPoints.length;
  }

}

そして、パーティクルを初期化する関数(initColorParticle())だ。引数(properties)に受け取るParticlePropertiesオブジェクトのParticleProperties.indexプロパティで今初期設定しているパーティクルのインデックス(index)がわかる。配列(colorSeparations)にとっておいたロゴの切り替わるインデックスとの大小を見比べて、アニメーションの行き先(endPoint)のx座標を変えた。

function initColorParticle(properties) {
  var BEZIER_END_VECTOR3D = ParticleBezierCurveNode.BEZIER_END_VECTOR3D;

  var size = 300 * PARTICLE_SIZE;
  var index = properties.index;
  var endPoint = new Vector3D();

  if (index < colorSeparations[0]) {
    endPoint.x = size;
  } else {
    endPoint.x = -size;
  }
  properties[BEZIER_END_VECTOR3D] = endPoint;

  // properties[ParticleBezierCurveNode.BEZIER_CONTROL_VECTOR3D] = getRandomVector3D(100);
  properties[ParticleBezierCurveNode.BEZIER_CONTROL_VECTOR3D] = getRandomVector3D(500);

}

もうひとつ、2つのロゴでアニメーションのタイミングもずらすことにしよう。前回解説したとおり、このコードではAnimatorBase.update()メソッドに総経過時間を渡して、パーティクルのいつの状態を表示するのかを決めている。この経過時間をロゴごとに変えれば、アニメーションの動きも異なってくる。そのためには、ParticleAnimatorオブジェクトをロゴごとに定めなければならない。そこで、オブジェクトを新たな配列の変数(colorAnimators)に納める。

パーティクルのアニメーションを定める関数(startParticleAnimation())には、2つ目の引数にParticleAnimatorオブジェクトの数(numAnimators)を加えた。Mesh.animatorプロパティを定めるMeshオブジェクトも、ロゴごとにつくる。ただし、設定は同じでよいのでMesh.clone()メソッドによる複製(colorParticleMesh)を用いた。

// var colorAnimator;
var colorAnimators;

function onResourceComplete(eventObject) {

  if (bitmapDatas[0] && bitmapDatas[1]) {

    // startParticleAnimation(colorGeometry);
    startParticleAnimation(colorGeometry, assetsURLs.length);
  }
}

// function startParticleAnimation(colorGeometry) {
function startParticleAnimation(colorGeometry, numAnimators) {

  colorAnimators = new Array(numAnimators);
  // var colorParticleMesh = new Mesh(colorGeometry, colorMaterial);
  var _colorParticleMesh = new Mesh(colorGeometry, colorMaterial);
  var animator = new ParticleAnimator(colorAnimationSet);
  // colorAnimator = animator;
  for (var i = 0; i < numAnimators; i++) {
    var colorParticleMesh = _colorParticleMesh.clone();
    var animator = new ParticleAnimator(colorAnimationSet);
    colorAnimators[i] = animator;
    colorParticleMesh.animator = animator;

  }
}

そして、描画を更新する関数(render())で、三角関数のsinにより導く経過時間(_time)の周期を2つのロゴの間でπ/4(= 45度)ずらした。これで2つのロゴのアニメーションは軌道が変わるとともに、その周期にも差が生じる。2つのロゴのパーティクルは異なる動きになる。

function render(deltaTime) {

    var count = colorAnimators.length;
    // var _time = 1000 * (Math.sin(time / 5000) + 1);
    for (var i = 0; i < count; i++) {
      var _time = 1000 * (Math.sin(time / 5000 + Math.PI * i / 4) + 1);
      colorAnimators[i].update(_time);
    }
  }

}

スクリプトは以下のコード2にまとめた。これで2つのロゴのパーティクルの動く先が変わり、タイミングもずれる。あわせて、jsdo.itにサンプル1のコードを掲げたので確かめてほしい。アニメーションには、まだ気になるところがあるかもしれない。それは次回に譲ろう。もちろん、ロゴの数も増やしたい。

サンプル1 Away3D 15/03/13: Exploding two logos using particles
サンプル1 Away3D 15/03/13: Exploding two logos using particles
 クリックでjsdo.itサイトのサンプルが開く
コード2 ふたつのロゴのパーティクルが異なるアニメーションで動く
var LoaderEvent = require("awayjs-core/lib/events/LoaderEvent");
var ColorTransform = require("awayjs-core/lib/geom/ColorTransform");
var Vector3D = require("awayjs-core/lib/geom/Vector3D");
var AssetLibrary = require("awayjs-core/lib/library/AssetLibrary");
var URLRequest = require("awayjs-core/lib/net/URLRequest");
var RequestAnimationFrame = require("awayjs-core/lib/utils/RequestAnimationFrame");
var View = require("awayjs-display/lib/containers/View");
var HoverController = require("awayjs-display/lib/controllers/HoverController");
var Mesh = require("awayjs-display/lib/entities/Mesh");
var PointLight = require("awayjs-display/lib/entities/PointLight");
var StaticLightPicker = require("awayjs-display/lib/materials/lightpickers/StaticLightPicker");
var PrimitivePlanePrefab = require("awayjs-display/lib/prefabs/PrimitivePlanePrefab");
var Cast = require("awayjs-display/lib/utils/Cast");
var ParticleAnimationSet = require("awayjs-renderergl/lib/animators/ParticleAnimationSet");
var ParticleAnimator = require("awayjs-renderergl/lib/animators/ParticleAnimator");
var ParticlePropertiesMode = require("awayjs-renderergl/lib/animators/data/ParticlePropertiesMode");
var ParticleBillboardNode = require("awayjs-renderergl/lib/animators/nodes/ParticleBillboardNode");
var ParticleBezierCurveNode = require("awayjs-renderergl/lib/animators/nodes/ParticleBezierCurveNode");
var ParticleInitialColorNode = require("awayjs-renderergl/lib/animators/nodes/ParticleInitialColorNode");
var ParticlePositionNode = require("awayjs-renderergl/lib/animators/nodes/ParticlePositionNode");
var DefaultRenderer = require("awayjs-renderergl/lib/DefaultRenderer");
var ParticleGeometryHelper = require("awayjs-renderergl/lib/utils/ParticleGeometryHelper");
var MethodMaterial = require("awayjs-methodmaterials/lib/MethodMaterial");
var MethodRendererPool = require("awayjs-methodmaterials/lib/pool/MethodRendererPool");
var PARTICLE_SIZE = 2;
var view;
var cameraController;
var light;
var assetsURLs = [
  "assets/chrome.png",
  "assets/firefox.png"
];
var colorSeparations = [];
var bitmapDatas = new Array(assetsURLs.length);
var colorValues = [];
var colorPoints = [];
var colorMaterial;
var colorAnimationSet;
var colorAnimators;
var timer;
var time = 0;
function initialize() {
  var lightPicker = createLights();
  view = createView(window.innerWidth, window.innerHeight, 0x0);
  cameraController = setupCameraController(view.camera, 1000, 225, 10);
  colorMaterial = createMaterial(lightPicker, true);
  setListeners();
}
function createView(width, height, backgroundColor) {
  var defaultRenderer = new DefaultRenderer(MethodRendererPool);
  var view = new View(defaultRenderer);
  view.width = width;
  view.height = height;
  view.backgroundColor = backgroundColor;
  return view;
}
function setupCameraController(camera, distance, panAngle, tiltAngle) {
  var cameraController = new HoverController(camera);
  cameraController.distance = distance;
  cameraController.panAngle = panAngle;
  cameraController.tiltAngle = tiltAngle;
  return cameraController;
}
function createLights() {
  light = createPointLight(0xFFFFFF, 1, 600, 100, 2);
  return new StaticLightPicker([light]);
}
function createPointLight(color, ambient, fallOff, radius, specular) {
  var light = new PointLight();
  light.color = color;
  light.ambient = ambient;
  light.fallOff = fallOff;
  light.radius = radius;
  light.specular = specular;
  return light;
}
function createMaterial(lightPicker, bothSides) {
  var material = new MethodMaterial();
  material.bothSides = bothSides;
  material.lightPicker = lightPicker;
  return material;
}
function onResourceComplete(eventObject) {
  var asset = eventObject.assets[0];
  var bitmapData = Cast.bitmapData(asset);
  switch (eventObject.url) {
    case assetsURLs[0]:
      bitmapDatas[0] = bitmapData;
      break;
    case assetsURLs[1]:
      bitmapDatas[1] = bitmapData;
      break;
  }
  if (bitmapDatas[0] && bitmapDatas[1]) {
    var colorGeometry = createParticles();
    startParticleAnimation(colorGeometry, assetsURLs.length);
  }
}
function createParticles() {
  var count = bitmapDatas.length;
  colorAnimationSet = createColorAnimationSet(initColorParticle);
  for (var i = 0; i < count; i++) {
    setParticlesData(bitmapDatas[i], PARTICLE_SIZE, colorValues, colorPoints);
    colorSeparations[i] = colorPoints.length;
  }
  var primitive = new PrimitivePlanePrefab(PARTICLE_SIZE, PARTICLE_SIZE, 1, 1, false);
  var geometry = primitive.geometry;
  var colorGeometrySet = [];
  count = colorPoints.length;
  for (var j = 0; j < count; j++) {
    colorGeometrySet[j] = geometry;
  }
  var colorGeometry = ParticleGeometryHelper.generateGeometry(colorGeometrySet);
  return colorGeometry;
}
function setParticlesData(bitmapData, size, colorValues, colorPoints) {
  var bitmapWidth = bitmapData.width;
  var bitmapHeight = bitmapData.height;
  for (var i = 0; i < bitmapWidth; i++) {
    for (var j = 0; j < bitmapHeight; j++) {
      var point = new Vector3D(size * (i - bitmapWidth / 2), size * ( -j + bitmapHeight / 2));
      var color = bitmapData.getPixel32(i, j);
        var rgbColor = getRgbComponents(color);
        rgbColor.scaleBy(1 / 255);
        colorValues.push(rgbColor);
        colorPoints.push(point);
    }
  }
}
function getRgbComponents(rgbColor) {
  var rgbVector = new Vector3D();
  rgbVector.x = (rgbColor & 0xff0000) >> 16;
  rgbVector.y = (rgbColor & 0xff00) >> 8;
  rgbVector.z = rgbColor & 0xff;
  return rgbVector;
}
function createColorAnimationSet(initParticleFunc) {
  var LOCAL_STATIC = ParticlePropertiesMode.LOCAL_STATIC;
  var colorAnimationSet = new ParticleAnimationSet();
  colorAnimationSet.addAnimation(new ParticleBillboardNode());
  colorAnimationSet.addAnimation(new ParticleBezierCurveNode(LOCAL_STATIC));
  colorAnimationSet.addAnimation(new ParticlePositionNode(LOCAL_STATIC));
  colorAnimationSet.addAnimation(new ParticleInitialColorNode(LOCAL_STATIC, true, false, new ColorTransform(0, 1, 0, 1)));
  colorAnimationSet.initParticleFunc = initParticleFunc;
  return colorAnimationSet;
}
function startParticleAnimation(colorGeometry, numAnimators) {
  var scene = view.scene;
  colorAnimators = new Array(numAnimators);
  var _colorParticleMesh = new Mesh(colorGeometry, colorMaterial);
  for (var i = 0; i < numAnimators; i++) {
    var colorParticleMesh = _colorParticleMesh.clone();
    var animator = new ParticleAnimator(colorAnimationSet);

    colorAnimators[i] = animator;
    colorParticleMesh.animator = animator;
    scene.addChild(colorParticleMesh);
  }
}
function setListeners() {
  var count = assetsURLs.length;
  timer = new RequestAnimationFrame(render);
  timer.start();
  AssetLibrary.addEventListener(LoaderEvent.RESOURCE_COMPLETE, onResourceComplete);
  for (var i = 0; i < count; i++) {
    AssetLibrary.load(new URLRequest(assetsURLs[i]));
  }
}
function initColorParticle(properties) {
  var BEZIER_END_VECTOR3D = ParticleBezierCurveNode.BEZIER_END_VECTOR3D;
  var size = 300 * PARTICLE_SIZE;
  var index = properties.index;
  var endPoint = new Vector3D();
  var rgb = colorValues[index];
  properties.startTime = 0;
  properties.duration = 1;
  if (index < colorSeparations[0]) {
    endPoint.x = size;
  } else {
    endPoint.x = -size;
  }
  properties[BEZIER_END_VECTOR3D] = endPoint;
  properties[ParticleInitialColorNode.COLOR_INITIAL_COLORTRANSFORM] = new ColorTransform(rgb.x, rgb.y, rgb.z, 1);
  properties[ParticleBezierCurveNode.BEZIER_CONTROL_VECTOR3D] = getRandomVector3D(500);
  properties[ParticlePositionNode.POSITION_VECTOR3D] = colorPoints[index];
}
function getRandomVector3D(radius) {
  var angle0 = Math.random() * Math.PI * 2;
  var angle1 = Math.random() * Math.PI * 2;
  var x = radius * Math.cos(angle0) * Math.cos(angle1);
  var y = radius * Math.cos(angle0) * Math.sin(angle1);
  var z = radius * Math.sin(angle0);
  return new Vector3D(x, y, z);
}
function render(deltaTime) {
  time += deltaTime;
  if (colorAnimators) {
    var count = colorAnimators.length;
    for (var i = 0; i < count; i++) {
      var _time = 1000 * (Math.sin(time / 5000 + Math.PI * i / 4) + 1);
      colorAnimators[i].update(_time);
    }
  }
  view.render();
}

おすすめ記事

記事・ニュース一覧