前回の第12回
![第12回 図2 のろしのように立ち上るパーティクル(再掲) 第12回 図2 のろしのように立ち上るパーティクル(再掲)](/assets/images/design/serial/01/away3d-typescript/0012/thumb/TH800_002.png)
パーティクルの動きにランダムな広がりを与える
始めに、
function FireObject(mesh, animator) {
this.strength = 0;
this.mesh = mesh;
this.animator = animator;
}
FireObject.prototype.startAnimation = function() {
this.animator.start();
};
前回のコードのアニメーションがのろしのようにしか見えないのは、
getVector3D(距離, xz平面の角度, xy平面の角度)
2つの角度のうちのひとつは、
P(r cosθcosω, r cosθsinω, r sinθ)
![図1 3次元座標を原点からの距離と2平面との角度から求める 図1 3次元座標を原点からの距離と2平面との角度から求める](/assets/images/design/serial/01/away3d-typescript/0013/thumb/TH800_001r.png)
距離と2つの角度からVector3Dオブジェクトを返す関数
function initParticle(prop) {
var PIx2 = Math.PI * 2;
var radian0 = Math.random() * PIx2;
var radian1 = Math.random() * PIx2;
var velocityVector = getVector3D(15, radian0, radian1);
prop[ParticleVelocityNode.VELOCITY_VECTOR3D] = velocityVector;
}
function getVector3D(radius, angleXY, angleXZ) {
var sinXY = Math.sin(angleXY);
var cosXY = Math.cos(angleXY);
var sinXZ = Math.sin(angleXZ);
var cosXZ = Math.cos(angleXZ);
var vector = new Vector3D(radius * cosXY * cosXZ, radius * cosXY * sinXZ, radius * sinXY);
return vector;
}
パーティクルにローカルなプロパティを定めるには、
function createParticles(numFires, numParticles, radius, y, scene) {
var GLOBAL = ParticlePropertiesMode.GLOBAL;
var animations = [
new ParticleBillboardNode(),
new ParticleVelocityNode(GLOBAL, new Vector3D(0, 80, 0)),
new ParticleVelocityNode(ParticlePropertiesMode.LOCAL_STATIC)
];
}
ParticlePropertiesModeクラスの定数 | モード |
---|---|
GLOBAL | グローバルなプロパティ |
LOCAL_ | ローカルな静的プロパティ |
LOCAL_ | ローカルな動的プロパティ |
これで、
![図2 パーティクルに広がる動きが加わった 図2 パーティクルに広がる動きが加わった](/assets/images/design/serial/01/away3d-typescript/0013/thumb/TH800_002.png)
さらに、
new ParticleScaleNode(モード, cycleDurationの使用, cyclePhaseの使用, 最小伸縮率, 最大伸縮率)
var ParticleScaleNode = require("awayjs-renderergl/lib/animators/nodes/ParticleScaleNode");
function createParticles(numFires, numParticles, radius, y, scene) {
var GLOBAL = ParticlePropertiesMode.GLOBAL;
var animations = [
new ParticleBillboardNode(),
new ParticleScaleNode(GLOBAL, false, false, 2.5, 0.5),
new ParticleVelocityNode(GLOBAL, new Vector3D(0, 80, 0)),
new ParticleVelocityNode(ParticlePropertiesMode.LOCAL_STATIC)
];
}
![図3 パーティクルの大きさがまちまちになった 図3 パーティクルの大きさがまちまちになった](/assets/images/design/serial/01/away3d-typescript/0013/thumb/TH800_003.png)
パーティクルごとに異なる動きを加えて広がるようにし、
var LoaderEvent = require("awayjs-core/lib/events/LoaderEvent");
var TimerEvent = require("awayjs-core/lib/events/TimerEvent");
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 Timer = require("awayjs-core/lib/utils/Timer");
var View = require("awayjs-display/lib/containers/View");
var DirectionalLight = require("awayjs-display/lib/entities/DirectionalLight");
var Mesh = require("awayjs-display/lib/entities/Mesh");
var StaticLightPicker = require("awayjs-display/lib/materials/lightpickers/StaticLightPicker");
var PrimitivePlanePrefab = require("awayjs-display/lib/prefabs/PrimitivePlanePrefab");
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 ParticleScaleNode = require("awayjs-renderergl/lib/animators/nodes/ParticleScaleNode");
var ParticleVelocityNode = require("awayjs-renderergl/lib/animators/nodes/ParticleVelocityNode");
var DefaultRenderer = require("awayjs-renderergl/lib/DefaultRenderer");
var MethodMaterial = require("awayjs-methodmaterials/lib/MethodMaterial");
var MethodRendererPool = require("awayjs-methodmaterials/lib/pool/MethodRendererPool");
var HoverController = require("awayjs-display/lib/controllers/HoverController");
var ParticleGeometryHelper = require("awayjs-renderergl/lib/utils/ParticleGeometryHelper");
var view;
var plane;
var cameraController;
var lightPicker;
var timer;
var planeDiffuse = "assets/floor_diffuse.jpg";
var lastMouseX;
var lastMouseY;
var lastPanAngle;
var lastTiltAngle;
var fireObjects;
var particleMaterial;
function initialize() {
var directionalLight = createDirectionalLight(0.25, 0xFFFFFF);
view = createView(240, 180, 0x0);
var scene = view.scene;
lightPicker = new StaticLightPicker([directionalLight]);
plane = createPlane(800, 800, lightPicker, -20);
fireObjects = createParticles(3, 500, 300, 5, scene);
scene.addChild(plane);
cameraController = setupCameraController(view.camera, 1000, 0, 90, 45, 20);
AssetLibrary.addEventListener(LoaderEvent.RESOURCE_COMPLETE, onResourceComplete);
AssetLibrary.load(new URLRequest(planeDiffuse));
document.onmousedown = startDrag;
timer = new RequestAnimationFrame(render);
timer.start();
var fireTimer = new Timer(1000, fireObjects.length);
fireTimer.addEventListener(TimerEvent.TIMER, startFire);
fireTimer.start();
}
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 createPlane(width, height, light, y) {
var material = new MethodMaterial();
var plane = new PrimitivePlanePrefab(width, height).getNewObject();
plane.material = material;
material.lightPicker = light;
plane.y = y;
return plane;
}
function createParticles(numFires, numParticles, radius, y, scene) {
var GLOBAL = ParticlePropertiesMode.GLOBAL;
var animations = [
new ParticleBillboardNode(),
new ParticleScaleNode(GLOBAL, false, false, 2.5, 0.5),
new ParticleVelocityNode(GLOBAL, new Vector3D(0, 80, 0)),
new ParticleVelocityNode(ParticlePropertiesMode.LOCAL_STATIC)
];
var animationSet = getParticleAnimationSet(animations, initParticle);
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;
}
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;
}
function getParticleAnimationSet(animations, initParticleFunc) {
var animationSet = new ParticleAnimationSet(true, true);
var count = animations.length;
for (var i = 0; i < count; i++) {
animationSet.addAnimation(animations[i]);
}
animationSet.initParticleFunc = initParticleFunc;
return animationSet;
}
function createAnimationParticle(particleGeometry, material, animationSet, fireObjects) {
var mesh = new Mesh(particleGeometry, material);
var animator = new ParticleAnimator(animationSet);
mesh.animator = animator;
fireObjects.push(new FireObject(mesh, animator));
return mesh;
}
function initParticle(prop) {
var PIx2 = Math.PI * 2;
var radian0 = Math.random() * PIx2;
var radian1 = Math.random() * PIx2;
var velocityVector = getVector3D(15, radian0, radian1);
prop.startTime = Math.random() * 5;
prop.duration = Math.random() * 4 + 0.1;
prop[ParticleVelocityNode.VELOCITY_VECTOR3D] = velocityVector;
}
function getVector3D(radius, angleXY, angleXZ) {
var sinXY = Math.sin(angleXY);
var cosXY = Math.cos(angleXY);
var sinXZ = Math.sin(angleXZ);
var cosXZ = Math.cos(angleXZ);
var vector = new Vector3D(radius * cosXY * cosXZ, radius * cosXY * sinXZ, radius * sinXY);
return vector;
}
function startFire(eventObject) {
var fireTimer = eventObject.target;
var count = fireTimer.currentCount;
var fireObject = fireObjects[count - 1];
fireObject.startAnimation();
if (count >= fireTimer.repeatCount) {
fireTimer.removeEventListener(TimerEvent.TIMER, startFire);
}
}
function createDirectionalLight(ambient, color) {
var light = new DirectionalLight();
light.ambient = ambient;
light.color = color;
return light;
}
function setupCameraController(camera, distance, minTiltAngle, maxTiltAngle, panAngle, tiltAngle) {
var cameraController = new HoverController(camera);
cameraController.distance = distance;
cameraController.minTiltAngle = minTiltAngle;
cameraController.maxTiltAngle = maxTiltAngle;
cameraController.panAngle = panAngle;
cameraController.tiltAngle = tiltAngle;
return cameraController;
}
function onResourceComplete(eventObject) {
var assets = eventObject.assets;
var material;
var count = assets.length;
var url = eventObject.url;
for (var i = 0; i < count; i++) {
var asset = assets[i];
switch (url) {
case (planeDiffuse):
material = plane.material;
material.texture = asset;
break;
}
}
}
function render(timeStamp) {
view.render();
}
function startDrag(eventObject) {
lastMouseX = eventObject.clientX;
lastMouseY = eventObject.clientY;
lastPanAngle = cameraController.panAngle;
lastTiltAngle = cameraController.tiltAngle;
document.onmousemove = drag;
document.onmouseup = stopDrag;
}
function drag(eventObject) {
cameraController.panAngle = 0.5 * (eventObject.clientX - lastMouseX) + lastPanAngle;
cameraController.tiltAngle = 0.3 * (eventObject.clientY - lastMouseY) + lastTiltAngle;
}
function stopDrag(eventObject) {
document.onmousemove = null;
document.onmouseup = null;
}
パーティクルのカラーをアニメーションさせる
つぎに、
new ParticleColorNode(モード, 乗数データの使用, オフセットデータの使用, cycleDurationの使用, cyclePhaseの使用, 初めの色, 終わりの色)
ParticleNodeBaseのサブクラスのコンストラクタ | ノードの役割 |
---|---|
ParticleBillboardNode() | パーティクルの角度をつねにカメラに向ける。 |
ParticleScaleNode(モード, usesCycleの使用, usesPhaseの使用, 最小伸縮率, 最大伸縮率) | パーティクルアニメーションが時間の中でどう伸縮するかを定める。 |
ParticleVelocityNode(モード, 速度ベクトル) | パーティクルアニメーションが始まるときの速度を定める。 |
ParticleColorNode(モード, 乗数データの使用, オフセットデータの使用, usesCycleの使用, usesPhaseの使用, 初めの色, 終わりの色) | パーティクルアニメーションの間に色がどう変わるかを定める。 |
ColorTransformオブジェクトは、
もとの色×乗数 + オフセット
![図4 Flash Professional CCの[カラー効果] 図4 Flash Professional CCの[カラー効果]](/assets/images/design/serial/01/away3d-typescript/0013/thumb/TH800_004.png)
ColorTransform()コンストラクタに渡す引数はつぎのように、
new ColorTransform(乗数赤, 乗数緑, 乗数青, 乗数アルファ, オフセット赤, オフセット緑, オフセット青, オフセットアルファ)
もうひとつ、
![図5 Fireworks CS6の[ブレンドモード]で[加法]を選ぶと重なりが明るくなる 図5 Fireworks CS6の[ブレンドモード]で[加法]を選ぶと重なりが明るくなる](/assets/images/design/serial/01/away3d-typescript/0013/thumb/TH193_00501.png)
![図5 Fireworks CS6の[ブレンドモード]で[加法]を選ぶと重なりが明るくなる 図5 Fireworks CS6の[ブレンドモード]で[加法]を選ぶと重なりが明るくなる](/assets/images/design/serial/01/away3d-typescript/0013/thumb/TH193_00502.png)
アニメーションさせるカラーの初めと終わりを定めるColorTransformオブジェクトは、
ParticleColorNode()コンストラクタの第1引数はParticlePropertiesMode.
var BlendMode = require("awayjs-core/lib/data/BlendMode");
var ColorTransform = require("awayjs-core/lib/geom/ColorTransform");
var ParticleColorNode = require("awayjs-renderergl/lib/animators/nodes/ParticleColorNode");
function createParticles(numFires, numParticles, radius, y, scene) {
var GLOBAL = ParticlePropertiesMode.GLOBAL;
var startColor = new ColorTransform(0, 0, 0, 1, 0xFF, 0x33, 0x01);
var endColor = new ColorTransform(0, 0, 0, 1, 0x99);
var animations = [
new ParticleBillboardNode(),
new ParticleScaleNode(GLOBAL, false, false, 2.5, 0.5),
new ParticleVelocityNode(GLOBAL, new Vector3D(0, 80, 0)),
new ParticleColorNode(GLOBAL, true, true, false, false, startColor, endColor),
new ParticleVelocityNode(ParticlePropertiesMode.LOCAL_STATIC)
];
var material = particleMaterial = new MethodMaterial();
material.blendMode = BlendMode.ADD;
}
パーティクルの初めの色と加算
![図6 パーティクルは黄色から赤に移り変わる 図6 パーティクルは黄色から赤に移り変わる](/assets/images/design/serial/01/away3d-typescript/0013/thumb/TH800_00601.png)
![図6 パーティクルは黄色から赤に移り変わる 図6 パーティクルは黄色から赤に移り変わる](/assets/images/design/serial/01/away3d-typescript/0013/thumb/TH800_00602.png)
var BlendMode = require("awayjs-core/lib/data/BlendMode");
var LoaderEvent = require("awayjs-core/lib/events/LoaderEvent");
var TimerEvent = require("awayjs-core/lib/events/TimerEvent");
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 Timer = require("awayjs-core/lib/utils/Timer");
var View = require("awayjs-display/lib/containers/View");
var DirectionalLight = require("awayjs-display/lib/entities/DirectionalLight");
var Mesh = require("awayjs-display/lib/entities/Mesh");
var StaticLightPicker = require("awayjs-display/lib/materials/lightpickers/StaticLightPicker");
var PrimitivePlanePrefab = require("awayjs-display/lib/prefabs/PrimitivePlanePrefab");
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 ParticleScaleNode = require("awayjs-renderergl/lib/animators/nodes/ParticleScaleNode");
var ParticleVelocityNode = require("awayjs-renderergl/lib/animators/nodes/ParticleVelocityNode");
var ParticleColorNode = require("awayjs-renderergl/lib/animators/nodes/ParticleColorNode");
var DefaultRenderer = require("awayjs-renderergl/lib/DefaultRenderer");
var MethodMaterial = require("awayjs-methodmaterials/lib/MethodMaterial");
var MethodRendererPool = require("awayjs-methodmaterials/lib/pool/MethodRendererPool");
var HoverController = require("awayjs-display/lib/controllers/HoverController");
var ParticleGeometryHelper = require("awayjs-renderergl/lib/utils/ParticleGeometryHelper");
var view;
var plane;
var cameraController;
var lightPicker;
var timer;
var planeDiffuse = "assets/floor_diffuse.jpg";
var lastMouseX;
var lastMouseY;
var lastPanAngle;
var lastTiltAngle;
var fireObjects;
var particleMaterial;
function initialize() {
var directionalLight = createDirectionalLight(0.25, 0xFFFFFF);
view = createView(240, 180, 0x0);
var scene = view.scene;
lightPicker = new StaticLightPicker([directionalLight]);
plane = createPlane(800, 800, lightPicker, -20);
fireObjects = createParticles(3, 500, 300, 5, scene);
scene.addChild(plane);
cameraController = setupCameraController(view.camera, 1000, 0, 90, 45, 20);
AssetLibrary.addEventListener(LoaderEvent.RESOURCE_COMPLETE, onResourceComplete);
AssetLibrary.load(new URLRequest(planeDiffuse));
document.onmousedown = startDrag;
timer = new RequestAnimationFrame(render);
timer.start();
var fireTimer = new Timer(1000, fireObjects.length);
fireTimer.addEventListener(TimerEvent.TIMER, startFire);
fireTimer.start();
}
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 createPlane(width, height, light, y) {
var material = new MethodMaterial();
var plane = new PrimitivePlanePrefab(width, height).getNewObject();
plane.material = material;
material.lightPicker = light;
plane.y = y;
return plane;
}
function createParticles(numFires, numParticles, radius, y, scene) {
var GLOBAL = ParticlePropertiesMode.GLOBAL;
var startColor = new ColorTransform(0, 0, 0, 1, 0xFF, 0x33, 0x01);
var endColor = new ColorTransform(0, 0, 0, 1, 0x99);
var animations = [
new ParticleBillboardNode(),
new ParticleScaleNode(GLOBAL, false, false, 2.5, 0.5),
new ParticleVelocityNode(GLOBAL, new Vector3D(0, 80, 0)),
new ParticleColorNode(GLOBAL, true, true, false, false, startColor, endColor),
new ParticleVelocityNode(ParticlePropertiesMode.LOCAL_STATIC)
];
var animationSet = getParticleAnimationSet(animations, initParticle);
var primitive = new PrimitivePlanePrefab(10, 10, 1, 1, false);
var geometry = primitive.geometry;
var material = particleMaterial = new MethodMaterial();
var geometrySet = [];
material.blendMode = BlendMode.ADD;
for (var i = 0; i < numParticles; i++) {
geometrySet[i] = geometry;
}
var fireObjects = getFireObjects(geometrySet, numFires, material, animationSet, radius, y, scene);
return fireObjects;
}
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;
}
function getParticleAnimationSet(animations, initParticleFunc) {
var animationSet = new ParticleAnimationSet(true, true);
var count = animations.length;
for (var i = 0; i < count; i++) {
animationSet.addAnimation(animations[i]);
}
animationSet.initParticleFunc = initParticleFunc;
return animationSet;
}
function createAnimationParticle(particleGeometry, material, animationSet, fireObjects) {
var mesh = new Mesh(particleGeometry, material);
var animator = new ParticleAnimator(animationSet);
mesh.animator = animator;
fireObjects.push(new FireObject(mesh, animator));
return mesh;
}
function initParticle(prop) {
var PIx2 = Math.PI * 2;
var radian0 = Math.random() * PIx2;
var radian1 = Math.random() * PIx2;
var velocityVector = getVector3D(15, radian0, radian1);
prop.startTime = Math.random() * 5;
prop.duration = Math.random() * 4 + 0.1;
prop[ParticleVelocityNode.VELOCITY_VECTOR3D] = velocityVector;
}
function getVector3D(radius, angleXY, angleXZ) {
var sinXY = Math.sin(angleXY);
var cosXY = Math.cos(angleXY);
var sinXZ = Math.sin(angleXZ);
var cosXZ = Math.cos(angleXZ);
var vector = new Vector3D(radius * cosXY * cosXZ, radius * cosXY * sinXZ, radius * sinXY);
return vector;
}
function startFire(eventObject) {
var fireTimer = eventObject.target;
var count = fireTimer.currentCount;
var fireObject = fireObjects[count - 1];
fireObject.startAnimation();
if (count >= fireTimer.repeatCount) {
fireTimer.removeEventListener(TimerEvent.TIMER, startFire);
}
}
function createDirectionalLight(ambient, color) {
var light = new DirectionalLight();
light.ambient = ambient;
light.color = color;
return light;
}
function setupCameraController(camera, distance, minTiltAngle, maxTiltAngle, panAngle, tiltAngle) {
var cameraController = new HoverController(camera);
cameraController.distance = distance;
cameraController.minTiltAngle = minTiltAngle;
cameraController.maxTiltAngle = maxTiltAngle;
cameraController.panAngle = panAngle;
cameraController.tiltAngle = tiltAngle;
return cameraController;
}
function onResourceComplete(eventObject) {
var assets = eventObject.assets;
var material;
var count = assets.length;
var url = eventObject.url;
for (var i = 0; i < count; i++) {
var asset = assets[i];
switch (url) {
case (planeDiffuse):
material = plane.material;
material.texture = asset;
break;
}
}
}
function render(timeStamp) {
view.render();
}
function startDrag(eventObject) {
lastMouseX = eventObject.clientX;
lastMouseY = eventObject.clientY;
lastPanAngle = cameraController.panAngle;
lastTiltAngle = cameraController.tiltAngle;
document.onmousemove = drag;
document.onmouseup = stopDrag;
}
function drag(eventObject) {
cameraController.panAngle = 0.5 * (eventObject.clientX - lastMouseX) + lastPanAngle;
cameraController.tiltAngle = 0.3 * (eventObject.clientY - lastMouseY) + lastTiltAngle;
}
function stopDrag(eventObject) {
document.onmousemove = null;
document.onmouseup = null;
}
パーティクルにテクスチャを与える
パーティクルにテクスチャを与えて、
![図7 パーティクルの素材に与えるPNG画像 図7 パーティクルの素材に与えるPNG画像](/assets/images/design/serial/01/away3d-typescript/0013/007.png)
var planeDiffuse = "assets/floor_diffuse.jpg";
var imageParticle = "assets/blue.png";
function initialize() {
// AssetLibrary.addEventListener(LoaderEvent.RESOURCE_COMPLETE, onResourceComplete);
// AssetLibrary.load(new URLRequest(planeDiffuse));
loadAsset(planeDiffuse);
loadAsset(imageParticle);
}
function loadAsset(url) {
AssetLibrary.addEventListener(LoaderEvent.RESOURCE_COMPLETE, onResourceComplete);
AssetLibrary.load(new URLRequest(url));
}
そして、
function onResourceComplete(eventObject) {
var assets = eventObject.assets;
var material;
var count = assets.length;
var url = eventObject.url;
for (var i = 0; i < count; i++) {
var asset = assets[i];
switch (url) {
case (planeDiffuse):
material = plane.material;
material.texture = asset;
break;
case (imageParticle):
particleMaterial.texture = asset;
break;
}
}
}
![図8 パーティクルに柔らかな円形のテクスチャが与えられた 図8 パーティクルに柔らかな円形のテクスチャが与えられた](/assets/images/design/serial/01/away3d-typescript/0013/thumb/TH800_008.png)
var BlendMode = require("awayjs-core/lib/data/BlendMode");
var LoaderEvent = require("awayjs-core/lib/events/LoaderEvent");
var TimerEvent = require("awayjs-core/lib/events/TimerEvent");
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 Timer = require("awayjs-core/lib/utils/Timer");
var View = require("awayjs-display/lib/containers/View");
var DirectionalLight = require("awayjs-display/lib/entities/DirectionalLight");
var Mesh = require("awayjs-display/lib/entities/Mesh");
var StaticLightPicker = require("awayjs-display/lib/materials/lightpickers/StaticLightPicker");
var PrimitivePlanePrefab = require("awayjs-display/lib/prefabs/PrimitivePlanePrefab");
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 ParticleScaleNode = require("awayjs-renderergl/lib/animators/nodes/ParticleScaleNode");
var ParticleVelocityNode = require("awayjs-renderergl/lib/animators/nodes/ParticleVelocityNode");
var ParticleColorNode = require("awayjs-renderergl/lib/animators/nodes/ParticleColorNode");
var DefaultRenderer = require("awayjs-renderergl/lib/DefaultRenderer");
var MethodMaterial = require("awayjs-methodmaterials/lib/MethodMaterial");
var MethodRendererPool = require("awayjs-methodmaterials/lib/pool/MethodRendererPool");
var HoverController = require("awayjs-display/lib/controllers/HoverController");
var ParticleGeometryHelper = require("awayjs-renderergl/lib/utils/ParticleGeometryHelper");
var view;
var plane;
var cameraController;
var lightPicker;
var timer;
var planeDiffuse = "assets/floor_diffuse.jpg";
var imageParticle = "assets/blue.png";
var lastMouseX;
var lastMouseY;
var lastPanAngle;
var lastTiltAngle;
var fireObjects;
var particleMaterial;
function initialize() {
var directionalLight = createDirectionalLight(0.25, 0xFFFFFF);
view = createView(240, 180, 0x0);
var scene = view.scene;
lightPicker = new StaticLightPicker([directionalLight]);
plane = createPlane(800, 800, lightPicker, -20);
fireObjects = createParticles(3, 500, 300, 5, scene);
scene.addChild(plane);
cameraController = setupCameraController(view.camera, 1000, 0, 90, 45, 20);
loadAsset(planeDiffuse);
loadAsset(imageParticle);
document.onmousedown = startDrag;
timer = new RequestAnimationFrame(render);
timer.start();
var fireTimer = new Timer(1000, fireObjects.length);
fireTimer.addEventListener(TimerEvent.TIMER, startFire);
fireTimer.start();
}
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 createPlane(width, height, light, y) {
var material = new MethodMaterial();
var plane = new PrimitivePlanePrefab(width, height).getNewObject();
plane.material = material;
material.lightPicker = light;
plane.y = y;
return plane;
}
function createParticles(numFires, numParticles, radius, y, scene) {
var GLOBAL = ParticlePropertiesMode.GLOBAL;
var startColor = new ColorTransform(0, 0, 0, 1, 0xFF, 0x33, 0x01);
var endColor = new ColorTransform(0, 0, 0, 1, 0x99);
var animations = [
new ParticleBillboardNode(),
new ParticleScaleNode(GLOBAL, false, false, 2.5, 0.5),
new ParticleVelocityNode(GLOBAL, new Vector3D(0, 80, 0)),
new ParticleColorNode(GLOBAL, true, true, false, false, startColor, endColor),
new ParticleVelocityNode(ParticlePropertiesMode.LOCAL_STATIC)
];
var animationSet = getParticleAnimationSet(animations, initParticle);
var primitive = new PrimitivePlanePrefab(10, 10, 1, 1, false);
var geometry = primitive.geometry;
var material = particleMaterial = new MethodMaterial();
var geometrySet = [];
material.blendMode = BlendMode.ADD;
for (var i = 0; i < numParticles; i++) {
geometrySet[i] = geometry;
}
var fireObjects = getFireObjects(geometrySet, numFires, material, animationSet, radius, y, scene);
return fireObjects;
}
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;
}
function getParticleAnimationSet(animations, initParticleFunc) {
var animationSet = new ParticleAnimationSet(true, true);
var count = animations.length;
for (var i = 0; i < count; i++) {
animationSet.addAnimation(animations[i]);
}
animationSet.initParticleFunc = initParticleFunc;
return animationSet;
}
function createAnimationParticle(particleGeometry, material, animationSet, fireObjects) {
var mesh = new Mesh(particleGeometry, material);
var animator = new ParticleAnimator(animationSet);
mesh.animator = animator;
fireObjects.push(new FireObject(mesh, animator));
return mesh;
}
function initParticle(prop) {
var PIx2 = Math.PI * 2;
var radian0 = Math.random() * PIx2;
var radian1 = Math.random() * PIx2;
var velocityVector = getVector3D(15, radian0, radian1);
prop.startTime = Math.random() * 5;
prop.duration = Math.random() * 4 + 0.1;
prop[ParticleVelocityNode.VELOCITY_VECTOR3D] = velocityVector;
}
function getVector3D(radius, angleXY, angleXZ) {
var sinXY = Math.sin(angleXY);
var cosXY = Math.cos(angleXY);
var sinXZ = Math.sin(angleXZ);
var cosXZ = Math.cos(angleXZ);
var vector = new Vector3D(radius * cosXY * cosXZ, radius * cosXY * sinXZ, radius * sinXY);
return vector;
}
function startFire(eventObject) {
var fireTimer = eventObject.target;
var count = fireTimer.currentCount;
var fireObject = fireObjects[count - 1];
fireObject.startAnimation();
if (count >= fireTimer.repeatCount) {
fireTimer.removeEventListener(TimerEvent.TIMER, startFire);
}
}
function createDirectionalLight(ambient, color) {
var light = new DirectionalLight();
light.ambient = ambient;
light.color = color;
return light;
}
function setupCameraController(camera, distance, minTiltAngle, maxTiltAngle, panAngle, tiltAngle) {
var cameraController = new HoverController(camera);
cameraController.distance = distance;
cameraController.minTiltAngle = minTiltAngle;
cameraController.maxTiltAngle = maxTiltAngle;
cameraController.panAngle = panAngle;
cameraController.tiltAngle = tiltAngle;
return cameraController;
}
function loadAsset(url) {
AssetLibrary.addEventListener(LoaderEvent.RESOURCE_COMPLETE, onResourceComplete);
AssetLibrary.load(new URLRequest(url));
}
function onResourceComplete(eventObject) {
var assets = eventObject.assets;
var material;
var count = assets.length;
var url = eventObject.url;
for (var i = 0; i < count; i++) {
var asset = assets[i];
switch (url) {
case (planeDiffuse):
material = plane.material;
material.texture = asset;
break;
case (imageParticle):
particleMaterial.texture = asset;
break;
}
}
}
function render(timeStamp) {
view.render();
}
function startDrag(eventObject) {
lastMouseX = eventObject.clientX;
lastMouseY = eventObject.clientY;
lastPanAngle = cameraController.panAngle;
lastTiltAngle = cameraController.tiltAngle;
document.onmousemove = drag;
document.onmouseup = stopDrag;
}
function drag(eventObject) {
cameraController.panAngle = 0.5 * (eventObject.clientX - lastMouseX) + lastPanAngle;
cameraController.tiltAngle = 0.3 * (eventObject.clientY - lastMouseY) + lastTiltAngle;
}
function stopDrag(eventObject) {
document.onmousemove = null;
document.onmouseup = null;
}
さて次回は、
距離と2つの角度から3次元空間の座標を求める
数学に興味のある読者向けに、
P(r cosθ, r sinθ)
すると、
OPz = QP = r sinθ
OQ = r cosθ
OPx = OQ cosω = r cosθcosω
OPy = OQ sinω = r cosθsinω
したがって、
![図9 3次元座標を原点からの距離と2平面との角度から三角関数で導く 図9 3次元座標を原点からの距離と2平面との角度から三角関数で導く](/assets/images/design/serial/01/away3d-typescript/0013/thumb/TH800_009.png)