away3d 4.0加入特效系统后,做比较炫的特效已经不是什么难事,away3d官方已经基于内置的particle system做了几个挺炫的粒子特效,需要的可以查看github中实例源码。这个传送门特效且作为away3d 粒子系统练手的的另一个实例。
简单说下,这个特效由三个独立的部分组成,转动的符文圆盘、向上发射的半透明光及不断从符文盘向上浮动的颗粒。效果图如下:
废话不说,直接上代码解释。
首先,必须准备三个部分的纹理和材质了。分别是符文圆盘、光辉、浮动粒子的纹理,在本教程最后提供的源码里有相应的纹理。
[Embed(source="../assets/pan.png")] public var panTexture:Class; [Embed(source="../assets/light.png")] public var lightTexture:Class; [Embed(source="../assets/blueball.png")] public var blueballTexture:Class;
材质拆分成五个部分,分别对应五种不同的粒子mesh。简单说为什么有五种,因为:1圆盘+3光辉+1浮动粒子串。粒子对应的五种material、mesh、animator等的声明如下,它们之间的关系我们将在后面代码解释。
//materials private var matPan:TextureMaterial; private var matLight1:TextureMaterial; private var matLight2:TextureMaterial; private var matLight3:TextureMaterial; private var matBall:TextureMaterial; //particle objects private var particleAnimationSet1:ParticleAnimationSet; private var particleAnimationSet2:ParticleAnimationSet; private var particleAnimationSet3:ParticleAnimationSet; private var particleAnimationSet4:ParticleAnimationSet; private var particleAnimationSet5:ParticleAnimationSet; private var particleGeometry1:ParticleGeometry; private var particleGeometry2:ParticleGeometry; private var particleGeometry3:ParticleGeometry; private var particleGeometry4:ParticleGeometry; private var particleGeometry5:ParticleGeometry; // scene objects private var particleMesh1:Mesh; private var particleMesh2:Mesh; private var particleMesh3:Mesh; private var particleMesh4:Mesh; private var particleMesh5:Mesh; private var animator1:ParticleAnimator; private var animator2:ParticleAnimator; private var animator3:ParticleAnimator; private var animator4:ParticleAnimator; private var animator5:ParticleAnimator;
接着就是初始化引擎了,为了便于理解,采用跟官方一样的方法,顺便贴出代码。
//engine variables private var scene:Scene3D; private var camera:Camera3D; private var view:View3D; private var cameraController:HoverController; //signature variables private var Signature:Sprite; private var SignatureBitmap:Bitmap; //navigation variables private var _move:Boolean = false; private var _lastPanAngle:Number; private var _lastTiltAngle:Number; private var _lastMouseX:Number; private var _lastMouseY:Number; /** * 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, 255, 50, 300, 5); view.addSourceURL("srcview/index.html"); addChild(view); //add signature Signature = Sprite(new SignatureSwf()); SignatureBitmap = new Bitmap(new BitmapData(Signature.width, Signature.height, true, 0)); stage.quality = StageQuality.HIGH; SignatureBitmap.bitmapData.draw(Signature); stage.quality = StageQuality.LOW; addChild(SignatureBitmap); addChild(new AwayStats(view)); }
引擎准备完后就是进入主题了,开始制作各种粒子。away3d中的生成粒子有几个步骤:
1、定义粒子需要的几何体集合,比如该教程中传送门的转动圆盘需要1个plane, 浮动的粒子需要50个plane来表现;
2、根据几何体几何,生成粒子需要的ParticleGeometry;
3、根据ParticleGeometry、Material,生成粒子mesh;
4、定义particleAnimationSet。粒子中的动作节点分为局部静态动作、局部动态动作还有全局动作,一个particleAnimationSet可以添加以上多种类型的不同动作节点;进一步了解动作细节,点击查看官方文档。
5、根据particleAnimationSet定义ParticleAnimator,并把ParticleAnimator装到粒子mesh上。
6、设置粒子的start time,duration time, delay time及局部动作属性。
文字太抽象,下面是直观的代码:
/** * 初始化粒子材质 */ private function initMaterials():void { matPan = new TextureMaterial(Cast.bitmapTexture(panTexture)); matBall = new TextureMaterial(Cast.bitmapTexture(blueballTexture)); matLight1 = new TextureMaterial(Cast.bitmapTexture(lightTexture)); matLight2 = new TextureMaterial(Cast.bitmapTexture(lightTexture)); matLight3 = new TextureMaterial(Cast.bitmapTexture(lightTexture)); matPan.bothSides = true; matPan.smooth = true; matPan.repeat = true; matPan.alphaBlending = true; matPan.specularColor = 0xFF1161D9; matPan.ambientColor = 0xFF1161D9; matLight1.bothSides = true; matLight1.smooth = true; matLight1.alphaBlending = true; matLight2.bothSides = true; matLight2.smooth = true; matLight2.alphaBlending = true; matLight3.bothSides = true; matLight3.smooth = true; matLight3.alphaBlending = true; matBall.bothSides = true; matBall.repeat = true; matBall.smooth = true; matBall.alphaBlending = true; } /** * 初始化粒子 */ private function initParticles():void { // 设置所有粒子的particleGeometry var ball:Geometry = new PlaneGeometry(3,3,1,1,false); var light1:Geometry = new CylinderGeometry(50,30,200,16,1,false,false,true); var light2:Geometry = new CylinderGeometry(55,30,180,16,1,false,false,true); var light3:Geometry = new CylinderGeometry(60,30,160,16,1,false,false,true); var pan:Geometry = new PlaneGeometry(65,65,1,1); var ballGeoSet:Vector.<Geometry> = new Vector.<Geometry>(); var light1GeoSet:Vector.<Geometry> = new Vector.<Geometry>(); var light2GeoSet:Vector.<Geometry> = new Vector.<Geometry>(); var light3GeoSet:Vector.<Geometry> = new Vector.<Geometry>(); var panGeoSet:Vector.<Geometry> = new Vector.<Geometry>(); // particle ball for (var i:int = 0; i < 40; i++) { ballGeoSet.push(ball); } particleGeometry1 = ParticleGeometryHelper.generateGeometry(ballGeoSet); particleAnimationSet1 = new ParticleAnimationSet(true, true, false); particleAnimationSet1.addAnimation(new ParticleBillboardNode()); particleAnimationSet1.addAnimation(new ParticleVelocityNode(ParticlePropertiesMode.GLOBAL, new Vector3D(0,30,0))); particleAnimationSet1.addAnimation(new ParticleColorNode(ParticlePropertiesMode.GLOBAL,true,true,false,false,new ColorTransform(), new ColorTransform(1,1,1,0))); particleAnimationSet1.addAnimation(new ParticlePositionNode(ParticlePropertiesMode.LOCAL_STATIC)); particleAnimationSet1.addAnimation(new ParticleOscillatorNode(ParticlePropertiesMode.LOCAL_STATIC)); particleAnimationSet1.addAnimation(new ParticleVelocityNode(ParticlePropertiesMode.LOCAL_STATIC)); particleAnimationSet1.initParticleFunc = initBallParticleProperties; // light 1 light1GeoSet.push(light1); particleGeometry2 = ParticleGeometryHelper.generateGeometry(light1GeoSet); particleAnimationSet2 = new ParticleAnimationSet(true, true, false); particleAnimationSet2.addAnimation(new ParticlePositionNode(ParticlePropertiesMode.GLOBAL, new Vector3D(0,100,0))); particleAnimationSet2.addAnimation(new ParticleRotationalVelocityNode(ParticlePropertiesMode.GLOBAL, new Vector3D(0,1,0,25))); particleAnimationSet2.addAnimation(new ParticleColorNode(ParticlePropertiesMode.GLOBAL,true,true,false, false,new ColorTransform(1,1,1,0.2), new ColorTransform(1,1,1,0.2))); particleAnimationSet2.initParticleFunc = initLightParticleProperties; // light 2 light2GeoSet.push(light2); particleGeometry3 = ParticleGeometryHelper.generateGeometry(light2GeoSet); particleAnimationSet3 = new ParticleAnimationSet(true, true, false); particleAnimationSet3.addAnimation(new ParticlePositionNode(ParticlePropertiesMode.GLOBAL, new Vector3D(0,90,0))); particleAnimationSet3.addAnimation(new ParticleRotationalVelocityNode(ParticlePropertiesMode.GLOBAL, new Vector3D(0,1,0,25))); particleAnimationSet3.addAnimation(new ParticleColorNode(ParticlePropertiesMode.GLOBAL,true,true,false, false,new ColorTransform(1,1,1,0.2), new ColorTransform(1,1,1,0.2))); particleAnimationSet3.initParticleFunc = initLightParticleProperties; // light 3 light3GeoSet.push(light3); particleGeometry4 = ParticleGeometryHelper.generateGeometry(light3GeoSet); particleAnimationSet4 = new ParticleAnimationSet(true, true, false); particleAnimationSet4.addAnimation(new ParticlePositionNode(ParticlePropertiesMode.GLOBAL, new Vector3D(0,90,0))); particleAnimationSet4.addAnimation(new ParticleRotationalVelocityNode(ParticlePropertiesMode.GLOBAL, new Vector3D(0,1,0,25))); particleAnimationSet4.addAnimation(new ParticleColorNode(ParticlePropertiesMode.GLOBAL,true,true,false, false,new ColorTransform(1,1,1,0.2), new ColorTransform(1,1,1,0.2))); particleAnimationSet4.initParticleFunc = initLightParticleProperties; // pan panGeoSet.push(pan); particleGeometry5 = ParticleGeometryHelper.generateGeometry(panGeoSet); particleAnimationSet5 = new ParticleAnimationSet(true, true, false); particleAnimationSet5.addAnimation(new ParticleRotationalVelocityNode(ParticlePropertiesMode.GLOBAL, new Vector3D(0,1,0,8))); particleAnimationSet5.initParticleFunc = initPanParticleProperties; } /** * 初始化场景 */ private function initObjects():void { particleMesh1 = new Mesh(particleGeometry1, matBall); particleMesh2 = new Mesh(particleGeometry2, matLight1); particleMesh3 = new Mesh(particleGeometry3, matLight2); particleMesh4 = new Mesh(particleGeometry4, matLight3); particleMesh5 = new Mesh(particleGeometry5, matPan); scene.addChild(particleMesh1); scene.addChild(particleMesh2); scene.addChild(particleMesh3); scene.addChild(particleMesh4); scene.addChild(particleMesh5); animator1 = new ParticleAnimator(particleAnimationSet1); animator2 = new ParticleAnimator(particleAnimationSet2); animator3 = new ParticleAnimator(particleAnimationSet3); animator4 = new ParticleAnimator(particleAnimationSet4); animator5 = new ParticleAnimator(particleAnimationSet5); particleMesh1.animator = animator1; particleMesh2.animator = animator2; particleMesh3.animator = animator3; particleMesh4.animator = animator4; particleMesh5.animator = animator5; animator1.start(); animator2.start(); animator3.start(); animator4.start(); animator5.start(); } /** * 初始化浮动粒子属性 */ private function initBallParticleProperties(properties:ParticleProperties):void { properties.startTime = Math.random()*4.1; properties.duration = 3; var degree1:Number = Math.random() * Math.PI ; var degree2:Number = Math.random() * Math.PI; var r1:Number = Math.random()*15; var r2:Number = Math.random()*20 +10; properties[ParticlePositionNode.POSITION_VECTOR3D] = new Vector3D(r1*Math.sin(degree1), 0 , r1*Math.cos(degree1)); properties[ParticleOscillatorNode.OSCILLATOR_VECTOR3D] = new Vector3D(r2*Math.sin(degree2), 0 , r2*Math.cos(degree2), Math.random()*4+2); properties[ParticleVelocityNode.VELOCITY_VECTOR3D] = new Vector3D(0,Math.random()*100,0); } /** * 初始化光辉属性 */ private function initLightParticleProperties(properties:ParticleProperties):void { properties.startTime = 1; properties.duration = 10; } /** * 初始化符文转盘属性 */ private function initPanParticleProperties(properties:ParticleProperties):void { properties.startTime = 1; properties.duration = 1; }