效果演示
项目使用说明
源码如下
/*
Particle explosions in Away3D using the OpenFL and Haxe logos
Demonstrates:
How to split images into particles.
How to share particle geometries and animation sets between meshes and animators.
How to manually update the playhead of a particle animator using the update() function.
Code by Rob Bateman & Liao Cheng
rob@infiniteturtles.co.uk
http://www.infiniteturtles.co.uk
liaocheng210@126.com
This code is distributed under the MIT License
Copyright (c) The Away Foundation http://www.theawayfoundation.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the “Software”), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
package;
import openfl.display.*;
import openfl.events.*;
import openfl.geom.*;
import openfl.utils.*;
import openfl.Lib;
import away3d.animators.*;
import away3d.animators.data.*;
import away3d.animators.nodes.*;
import away3d.cameras.*;
import away3d.containers.*;
import away3d.controllers.*;
import away3d.core.base.*;
import away3d.debug.*;
import away3d.entities.*;
import away3d.lights.*;
import away3d.materials.*;
import away3d.materials.lightpickers.*;
import away3d.primitives.*;
import away3d.tools.helpers.*;
import away3d.utils.*;
import openfl.Vector;
class Main extends Sprite {
private static inline var PARTICLE_SIZE:Int = 3;
private static inline var NUM_ANIMATORS:Int = 4;
// engine variables
private var scene:Scene3D;
private var camera:Camera3D;
private var view:View3D;
private var cameraController:HoverController;
// light variables
private var greenLight:PointLight;
private var orangeLight:PointLight;
// private var whitelight:DirectionalLight;
// private var direction:Vector3D = new Vector3D();
private var lightPicker:StaticLightPicker;
// data variables
private var bluePoints:Vector<Vector3D> = new Vector<Vector3D>();
private var whitePoints:Vector<Vector3D> = new Vector<Vector3D>();
private var blueSeparation:Int;
private var whiteSeparation:Int;
// material objects
private var whiteMaterial:ColorMaterial;
private var blueMaterial:ColorMaterial;
// particle objects
private var blueGeometry:ParticleGeometry;
private var whiteGeometry:ParticleGeometry;
private var blueAnimationSet:ParticleAnimationSet;
private var whiteAnimationSet:ParticleAnimationSet;
// scene objects
private var blueParticleMesh:Mesh;
private var whiteParticleMesh:Mesh;
private var blueAnimators:Vector<ParticleAnimator>;
private var whiteAnimators:Vector<ParticleAnimator>;
// navigation variables
private var angle:Float = 0;
private var move:Bool = false;
private var lastPanAngle:Float;
private var lastTiltAngle:Float;
private var lastMouseX:Float;
private var lastMouseY:Float;
/**
* Constructor
*/
public function new() {
super();
init();
}
/**
* Global initialise function
*/
private function init():Void {
initEngine();
initLights();
initMaterials();
initParticles();
initObjects();
initListeners();
}
/**
* Initialise the engine
*/
private function initEngine():Void {
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
scene = new Scene3D();
camera = new Camera3D();
view = new View3D();
view.scene = scene;
view.camera = camera;
// setup controller to be used on the camera
cameraController = new HoverController(camera, null, 225, 10, 1000);
addChild(view);
addChild(new AwayStats(view));
}
/**
* Initialise the lights
*/
private function initLights():Void {
// create a green point light
greenLight = new PointLight();
greenLight.color = 0x00FF00;
greenLight.ambient = 1;
greenLight.fallOff = 600;
greenLight.radius = 100;
greenLight.specular = 2;
scene.addChild(greenLight);
// create a blue pointlight
orangeLight = new PointLight();
orangeLight.color = 0xFF9900;
orangeLight.fallOff = 600;
orangeLight.radius = 100;
orangeLight.specular = 2;
scene.addChild(orangeLight);
// create a lightpicker for the green and blue light
lightPicker = new StaticLightPicker([greenLight, orangeLight]);
}
/**
* Initialise the materials
*/
private function initMaterials():Void {
// setup the blue particle material
blueMaterial = new ColorMaterial(0x24AFC4);
blueMaterial.alphaPremultiplied = true;
blueMaterial.bothSides = true;
blueMaterial.lightPicker = lightPicker;
// setup the white particle material
whiteMaterial = new ColorMaterial(0xFFFFFF, 0.2);
whiteMaterial.alphaPremultiplied = true;
whiteMaterial.bothSides = true;
whiteMaterial.lightPicker = lightPicker;
}
/**
* Initialise the particles
*/
private function initParticles():Void {
var bitmapData:BitmapData;
var point:Vector3D;
// create blue and white point vectors for the OpenFL image
bitmapData = Cast.bitmapData("assets/openfl.png");
for (i in 0...bitmapData.width) {
for (j in 0...bitmapData.height) {
point = new Vector3D(PARTICLE_SIZE * (i - bitmapData.width / 2 - 100), PARTICLE_SIZE * (-j + bitmapData.height / 2));
if (((bitmapData.getPixel32(i, j) >> 24) & 0xff) == 0)
whitePoints.push(point);
else
bluePoints.push(point);
}
}
// define where one logo stops and another starts
blueSeparation = bluePoints.length;
whiteSeparation = whitePoints.length;
// create blue and white point vectors for the Haxe image
bitmapData = Cast.bitmapData("assets/haxe.png");
for (i in 0...bitmapData.width) {
for (j in 0...bitmapData.height) {
point = new Vector3D(PARTICLE_SIZE * (i - bitmapData.width / 2 + 100), PARTICLE_SIZE * (-j + bitmapData.height / 2));
if (((bitmapData.getPixel32(i, j) >> 24) & 0xff) == 0)
whitePoints.push(point);
else
bluePoints.push(point);
}
}
var numBlue:Int = bluePoints.length;
var numWhite:Int = whitePoints.length;
// setup the base geometry for one particle
var plane:PlaneGeometry = new PlaneGeometry(PARTICLE_SIZE, PARTICLE_SIZE, 1, 1, false);
// combine them into a list
var blueGeometrySet:Vector<Geometry> = new Vector<Geometry>();
for (i in 0...numBlue)
blueGeometrySet.push(plane);
var whiteGeometrySet:Vector<Geometry> = new Vector<Geometry>();
for (i in 0...numWhite)
whiteGeometrySet.push(plane);
// generate the particle geometries
blueGeometry = ParticleGeometryHelper.generateGeometry(blueGeometrySet);
whiteGeometry = ParticleGeometryHelper.generateGeometry(whiteGeometrySet);
// define the blue particle animations and init function
blueAnimationSet = new ParticleAnimationSet(true);
blueAnimationSet.addAnimation(new ParticleBillboardNode());
blueAnimationSet.addAnimation(new ParticleBezierCurveNode(ParticlePropertiesMode.LOCAL_STATIC));
blueAnimationSet.addAnimation(new ParticlePositionNode(ParticlePropertiesMode.LOCAL_STATIC));
blueAnimationSet.initParticleFunc = initblueParticleFunc;
// define the white particle animations and init function
whiteAnimationSet = new ParticleAnimationSet();
whiteAnimationSet.addAnimation(new ParticleBillboardNode());
whiteAnimationSet.addAnimation(new ParticleBezierCurveNode(ParticlePropertiesMode.LOCAL_STATIC));
whiteAnimationSet.addAnimation(new ParticlePositionNode(ParticlePropertiesMode.LOCAL_STATIC));
whiteAnimationSet.initParticleFunc = initWhiteParticleFunc;
}
/**
* Initialise the scene objects
*/
private function initObjects():Void {
// initialise animators vectors
blueAnimators = new Vector<ParticleAnimator>(NUM_ANIMATORS, true);
whiteAnimators = new Vector<ParticleAnimator>(NUM_ANIMATORS, true);
// create the blue particle mesh
blueParticleMesh = new Mesh(blueGeometry, blueMaterial);
// create the white particle mesh
whiteParticleMesh = new Mesh(whiteGeometry, whiteMaterial);
for (i in 0...NUM_ANIMATORS) {
// clone the blue particle mesh
blueParticleMesh = cast blueParticleMesh.clone();
blueParticleMesh.rotationY = 45 * (i - 1);
scene.addChild(blueParticleMesh);
// clone the white particle mesh
whiteParticleMesh = cast whiteParticleMesh.clone();
whiteParticleMesh.rotationY = 45 * (i - 1);
scene.addChild(whiteParticleMesh);
// create and start the blue particle animator
blueAnimators[i] = new ParticleAnimator(blueAnimationSet);
blueParticleMesh.animator = blueAnimators[i];
scene.addChild(blueParticleMesh);
// create and start the white particle animator
whiteAnimators[i] = new ParticleAnimator(whiteAnimationSet);
whiteParticleMesh.animator = whiteAnimators[i];
scene.addChild(whiteParticleMesh);
}
}
/**
* Initialise the listeners
*/
private function initListeners():Void {
addEventListener(Event.ENTER_FRAME, onEnterFrame);
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
stage.addEventListener(Event.RESIZE, onResize);
onResize();
}
/**
* Initialiser function for blue particle properties
*/
private function initblueParticleFunc(properties:ParticleProperties):Void {
properties.startTime = 0;
properties.duration = 1;
var degree1:Float = Math.random() * Math.PI * 2;
var degree2:Float = Math.random() * Math.PI * 2;
var r:Float = 500;
if (properties.index < blueSeparation)
properties.nodes[ParticleBezierCurveNode.BEZIER_END_VECTOR3D] = new Vector3D(200 * PARTICLE_SIZE, 0, 0);
else
properties.nodes[ParticleBezierCurveNode.BEZIER_END_VECTOR3D] = new Vector3D(-200 * PARTICLE_SIZE, 0, 0);
properties.nodes[ParticleBezierCurveNode.BEZIER_CONTROL_VECTOR3D] = new Vector3D(r * Math.sin(degree1) * Math.cos(degree2),
r * Math.cos(degree1) * Math.cos(degree2), 2 * r * Math.sin(degree2));
properties.nodes[ParticlePositionNode.POSITION_VECTOR3D] = bluePoints[properties.index];
}
/**
* Initialiser function for white particle properties
*/
private function initWhiteParticleFunc(properties:ParticleProperties):Void {
properties.startTime = 0;
properties.duration = 1;
var degree1:Float = Math.random() * Math.PI * 2;
var degree2:Float = Math.random() * Math.PI * 2;
var r:Float = 500;
if (properties.index < whiteSeparation)
properties.nodes[ParticleBezierCurveNode.BEZIER_END_VECTOR3D] = new Vector3D(200 * PARTICLE_SIZE, 0, 0);
else
properties.nodes[ParticleBezierCurveNode.BEZIER_END_VECTOR3D] = new Vector3D(-200 * PARTICLE_SIZE, 0, 0);
properties.nodes[ParticleBezierCurveNode.BEZIER_CONTROL_VECTOR3D] = new Vector3D(r * Math.sin(degree1) * Math.cos(degree2),
r * Math.cos(degree1) * Math.cos(degree2), r * Math.sin(degree2));
properties.nodes[ParticlePositionNode.POSITION_VECTOR3D] = whitePoints[properties.index];
}
/**
* Navigation and render loop
*/
private function onEnterFrame(event:Event):Void {
// update the camera position
cameraController.panAngle += 0.2;
// update the particle animator playhead positions
var time:Int;
for (i in 0...NUM_ANIMATORS) {
time = Std.int(1000 * (Math.sin(Lib.getTimer() / 5000 + Math.PI * i / 4) + 1));
blueAnimators[i].update(time);
whiteAnimators[i].update(time);
}
if (move) {
cameraController.panAngle = 0.3 * (stage.mouseX - lastMouseX) + lastPanAngle;
cameraController.tiltAngle = 0.3 * (stage.mouseY - lastMouseY) + lastTiltAngle;
}
// update the light positions
angle += Math.PI / 180;
greenLight.x = Math.sin(angle) * 600;
greenLight.z = Math.cos(angle) * 600;
orangeLight.x = Math.sin(angle + Math.PI) * 600;
orangeLight.z = Math.cos(angle + Math.PI) * 600;
view.render();
}
/**
* Mouse down listener for navigation
*/
private function onMouseDown(event:MouseEvent):Void {
lastPanAngle = cameraController.panAngle;
lastTiltAngle = cameraController.tiltAngle;
lastMouseX = stage.mouseX;
lastMouseY = stage.mouseY;
move = true;
stage.addEventListener(Event.MOUSE_LEAVE, onStageMouseLeave);
}
/**
* Mouse up listener for navigation
*/
private function onMouseUp(event:MouseEvent):Void {
move = false;
stage.removeEventListener(Event.MOUSE_LEAVE, onStageMouseLeave);
}
/**
* Mouse stage leave listener for navigation
*/
private function onStageMouseLeave(event:Event):Void {
move = false;
stage.removeEventListener(Event.MOUSE_LEAVE, onStageMouseLeave);
}
/**
* stage listener for resize events
*/
private function onResize(event:Event = null):Void {
view.width = stage.stageWidth;
view.height = stage.stageHeight;
}
}