[ActionScript 3.0] Away3D 官网实例

  1 /*
  2 
  3 Dynamic tree generation and placement in a night-time scene
  4 
  5 Demonstrates:
  6 
  7 How to create a height map and splat map from scratch to use for realistic terrain
  8 How to use fratacl algorithms to create a custom tree-generating geometry primitive
  9 How to save GPU memory by cloning complex.
 10 
 11 Code by Rob Bateman & Alejadro Santander
 12 rob@infiniteturtles.co.uk
 13 http://www.infiniteturtles.co.uk
 14 Alejandro Santander
 15 http://www.lidev.com.ar/
 16 
 17 This code is distributed under the MIT License
 18 
 19 Copyright (c) The Away Foundation http://www.theawayfoundation.org
 20 
 21 Permission is hereby granted, free of charge, to any person obtaining a copy
 22 of this software and associated documentation files (the “Software”), to deal
 23 in the Software without restriction, including without limitation the rights
 24 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 25 copies of the Software, and to permit persons to whom the Software is
 26 furnished to do so, subject to the following conditions:
 27 
 28 The above copyright notice and this permission notice shall be included in
 29 all copies or substantial portions of the Software.
 30 
 31 THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 32 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 33 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 34 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 35 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 36 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 37 THE SOFTWARE.
 38 
 39 */
 40 
 41 package
 42 {
 43     
 44     import away3d.cameras.*;
 45     import away3d.containers.*;
 46     import away3d.controllers.*;
 47     import away3d.debug.*;
 48     import away3d.entities.*;
 49     import away3d.extrusions.*;
 50     import away3d.lights.*;
 51     import away3d.materials.*;
 52     import away3d.materials.lightpickers.*;
 53     import away3d.materials.methods.*;
 54     import away3d.primitives.*;
 55     import away3d.textures.*;
 56     import away3d.utils.*;
 57 
 58     import com.bit101.components.Label;
 59     
 60     import flash.display.*;
 61     import flash.events.*;
 62     import flash.filters.*;
 63     import flash.geom.*;
 64     import flash.ui.*;
 65     import flash.utils.*;
 66 
 67     import uk.co.soulwire.gui.*;
 68     
 69     
 70     [SWF(backgroundColor="#000000", frameRate="30", quality="LOW")]
 71     
 72     public class Advanced_FractalTreeDemo extends Sprite
 73     {
 74         //signature swf
 75         [Embed(source="/../embeds/signature.swf", symbol="Signature")]
 76         public var SignatureSwf:Class;
 77         
 78         //skybox
 79         [Embed(source="/../embeds/skybox/grimnight_posX.png")]
 80         private var EnvPosX:Class;
 81         [Embed(source="/../embeds/skybox/grimnight_posY.png")]
 82         private var EnvPosY:Class;
 83         [Embed(source="/../embeds/skybox/grimnight_posZ.png")]
 84         private var EnvPosZ:Class;
 85         [Embed(source="/../embeds/skybox/grimnight_negX.png")]
 86         private var EnvNegX:Class;
 87         [Embed(source="/../embeds/skybox/grimnight_negY.png")]
 88         private var EnvNegY:Class;
 89         [Embed(source="/../embeds/skybox/grimnight_negZ.png")]
 90         private var EnvNegZ:Class;
 91         
 92         //tree diffuse map
 93         [Embed (source="../embeds/tree/bark0.jpg")]
 94         public var TrunkDiffuse:Class;
 95         
 96         //tree normal map
 97         [Embed (source="../embeds/tree/barkNRM.png")]
 98         public var TrunkNormals:Class;
 99         
100         //tree specular map
101         [Embed (source="../embeds/tree/barkSPEC.png")]
102         public var TrunkSpecular:Class;
103         
104         //leaf diffuse map
105         [Embed (source="../embeds/tree/leaf4.jpg")]
106         public var LeafDiffuse:Class;
107         
108         //splat texture maps
109         [Embed(source="/../embeds/terrain/grass.jpg")]
110         private var Grass:Class;
111         [Embed(source="/../embeds/terrain/rock.jpg")]
112         private var Rock:Class;
113         
114         //engine variables
115         private var scene:Scene3D;
116         private var camera:Camera3D;
117         private var view:View3D;
118         private var awayStats:AwayStats;
119         private var cameraController:HoverController;
120         
121         //signature variables
122         private var Signature:Sprite;
123         private var SignatureBitmap:Bitmap;
124         
125         //light objects
126         private var moonLight:DirectionalLight;
127         private var cameraLight:PointLight;
128         private var skyLight:DirectionalLight;
129         private var lightPicker:StaticLightPicker;
130         private var fogMethod:FogMethod;
131         
132         //material objects
133         private var heightMapData:BitmapData;
134         private var blendBitmapData:BitmapData;
135         private var destPoint:Point = new Point();
136         private var blendTexture:BitmapTexture;
137         private var terrainMethod:TerrainDiffuseMethod;
138         private var terrainMaterial:TextureMaterial;
139         private var trunkMaterial:TextureMaterial;
140         private var leafMaterial:TextureMaterial;
141         private var cubeTexture:BitmapCubeTexture;
142         
143         //scene objects
144         private var terrain:Elevation;
145         private var tree:Mesh;
146         private var foliage:Mesh;
147         private var gui:SimpleGUI;
148         
149         //navigation variables
150         private var move:Boolean = false;
151         private var lastPanAngle:Number;
152         private var lastTiltAngle:Number;
153         private var lastMouseX:Number;
154         private var lastMouseY:Number;
155         private var tiltSpeed:Number = 2;
156         private var panSpeed:Number = 2;
157         private var distanceSpeed:Number = 1000;
158         private var tiltIncrement:Number = 0;
159         private var panIncrement:Number = 0;
160         private var distanceIncrement:Number = 0;
161         
162         //gui objects
163         private var treeCountLabel:Label;
164         private var polyCountLabel:Label;
165         private var terrainPolyCountLabel:Label;
166         private var treePolyCountLabel:Label;
167         
168         //tree configuration variables
169         private var treeLevel:uint = 10;
170         private var treeCount:uint = 25;
171         private var treeTimer:Timer;
172         private var treeDelay:uint = 0;
173         private var treeSize:Number = 1000;
174         private var treeMin:Number = 0.75;
175         private var treeMax:Number = 1.25;
176         
177         //foliage configuration variables
178         private var leafSize:Number = 300;
179         private var leavesPerCluster:uint = 5;
180         private var leafClusterRadius:Number = 400;
181         
182         //terrain configuration variables
183         private var terrainY:Number = -10000;
184         private var terrainWidth:Number = 200000;
185         private var terrainHeight:Number = 50000;
186         private var terrainDepth:Number = 200000;
187         
188         private var currentTreeCount:uint;
189         private var polyCount:uint;
190         private var terrainPolyCount:uint;
191         private var treePolyCount:uint;
192         private var clonesCreated:Boolean;
193         
194         public var minAperture:Number = 0.4;
195         public var maxAperture:Number = 0.5;
196         public var minTwist:Number = 0.3;
197         public var maxTwist:Number = 0.6;
198         
199         /**
200          * Constructor
201          */
202         public function Advanced_FractalTreeDemo()
203         {
204             init();
205         }
206         
207         /**
208          * Global initialise function
209          */
210         private function init():void
211         {
212             initEngine();
213             initLights();
214             initMaterials();
215             initObjects();
216             initGUI();
217             initListeners();
218         }
219         
220         /**
221          * Initialise the engine
222          */
223         private function initEngine():void
224         {
225             stage.scaleMode = StageScaleMode.NO_SCALE;
226             stage.align = StageAlign.TOP_LEFT;
227             
228             view = new View3D();
229             scene = view.scene;
230             camera = view.camera;
231             camera.lens.far = 1000000;
232             
233             //setup controller to be used on the camera
234             cameraController = new HoverController(camera, null, 0, 10, 25000, 0, 70);
235             
236             view.addSourceURL("srcview/index.html");
237             addChild(view);
238             
239             //add signature
240             Signature = Sprite(new SignatureSwf());
241             SignatureBitmap = new Bitmap(new BitmapData(Signature.width, Signature.height, true, 0));
242             stage.quality = StageQuality.HIGH;
243             SignatureBitmap.bitmapData.draw(Signature);
244             stage.quality = StageQuality.LOW;
245             addChild(SignatureBitmap);
246             
247             awayStats = new AwayStats(view);
248             addChild(awayStats);
249         }
250         
251         /**
252          * Initialise the lights
253          */
254         private function initLights():void
255         {
256             moonLight = new DirectionalLight();
257             moonLight.position = new Vector3D(3500, 4500, 10000); // Appear to come from the moon in the sky box.
258             moonLight.lookAt(new Vector3D(0, 0, 0));
259             moonLight.diffuse = 0.5;
260             moonLight.specular = 0.25;
261             moonLight.color = 0xFFFFFF;
262             scene.addChild(moonLight);
263             cameraLight = new PointLight();
264             cameraLight.diffuse = 0.25;
265             cameraLight.specular = 0.25;
266             cameraLight.color = 0xFFFFFF;
267             cameraLight.radius = 1000;
268             cameraLight.fallOff = 2000;
269             scene.addChild(cameraLight);
270             skyLight = new DirectionalLight();
271             skyLight.diffuse = 0.1;
272             skyLight.specular = 0.1;
273             skyLight.color = 0xFFFFFF;
274             scene.addChild(skyLight);
275             
276             lightPicker = new StaticLightPicker([moonLight, cameraLight, skyLight]);
277             
278             //create a global fog method
279             fogMethod = new FogMethod(0, 200000, 0x000000);
280         }
281         
282         /**
283          * Initialise the material
284          */
285         private function initMaterials():void
286         {
287             //create skybox texture
288             cubeTexture = new BitmapCubeTexture(Cast.bitmapData(EnvPosX), Cast.bitmapData(EnvNegX), Cast.bitmapData(EnvPosY), Cast.bitmapData(EnvNegY), Cast.bitmapData(EnvPosZ), Cast.bitmapData(EnvNegZ));
289             
290             //create tree material
291             trunkMaterial = new TextureMaterial(Cast.bitmapTexture(TrunkDiffuse));
292             trunkMaterial.normalMap = Cast.bitmapTexture(TrunkNormals);
293             trunkMaterial.specularMap = Cast.bitmapTexture(TrunkSpecular);
294             trunkMaterial.diffuseMethod = new BasicDiffuseMethod();
295             trunkMaterial.specularMethod = new BasicSpecularMethod();
296             trunkMaterial.addMethod(fogMethod);
297             trunkMaterial.lightPicker = lightPicker;
298             
299             //create leaf material
300             leafMaterial = new TextureMaterial(Cast.bitmapTexture(LeafDiffuse));
301             leafMaterial.addMethod(fogMethod);
302             leafMaterial.lightPicker = lightPicker;
303             
304             //create height map
305             heightMapData = new BitmapData(512, 512, false, 0x0);
306             heightMapData.perlinNoise(200, 200, 4, uint(1000*Math.random()), false, true, 7, true);
307             heightMapData.draw(createGradientSprite(512, 512, 1, 0));
308             
309             //create terrain diffuse method
310             blendBitmapData = new BitmapData(heightMapData.width, heightMapData.height, false, 0x000000);
311             blendBitmapData.threshold(heightMapData, blendBitmapData.rect, destPoint, ">", 0x444444, 0xFFFF0000, 0xFFFFFF, false);
312             blendBitmapData.applyFilter(blendBitmapData, blendBitmapData.rect, destPoint, new BlurFilter(16, 16, 3));
313             blendTexture = new BitmapTexture(blendBitmapData);
314             terrainMethod = new TerrainDiffuseMethod([Cast.bitmapTexture(Rock)], blendTexture, [20, 20]);
315 
316             //create terrain material
317             terrainMaterial = new TextureMaterial(Cast.bitmapTexture(Grass));
318             terrainMaterial.diffuseMethod = terrainMethod;
319             terrainMaterial.addMethod(new FogMethod(0, 200000, 0x000000)); //TODO: global fog method affects splats when updated
320             terrainMaterial.lightPicker = lightPicker;
321         }
322         
323         /**
324          * Initialise the scene objects
325          */
326         private function initObjects():void
327         {        
328             //create skybox.
329             scene.addChild(new SkyBox(cubeTexture));
330             
331             
332             
333             //create terrain
334             terrain = new Elevation(terrainMaterial, heightMapData, terrainWidth, terrainHeight, terrainDepth, 65, 65);
335             terrain.y = terrainY;
336             //terrain.smoothHeightMap();
337             scene.addChild(terrain);
338             
339             terrainPolyCount = terrain.geometry.subGeometries[0].vertexData.length/3;
340             polyCount += terrainPolyCount;
341         }
342         
343         /**
344          * Initialise the GUI
345          */
346         private function initGUI():void
347         {
348             gui = new SimpleGUI(this);
349             
350             gui.addColumn("Instructions");
351             var instr:String = "Click and drag to rotate camera.\n\n";
352             instr += "Arrows and WASD also rotate camera.\n\n";
353             instr += "Z and X zoom camera.\n\n";
354             instr += "Create a tree, then clone it to\n";
355             instr += "populate the terrain with trees.\n";
356             gui.addLabel(instr);
357             gui.addColumn("Tree");
358             gui.addSlider("minAperture", 0, 1, {label:"min aperture", tick:0.01});
359             gui.addSlider("maxAperture", 0, 1, {label:"max aperture", tick:0.01});
360             gui.addSlider("minTwist", 0, 1, {label:"min twist", tick:0.01});
361             gui.addSlider("maxTwist", 0, 1, {label:"max twist", tick:0.01});
362             gui.addButton("Generate Fractal Tree", {callback:generateTree, width:160});
363             gui.addColumn("Forest");
364             gui.addButton("Clone!", {callback:generateClones});
365             treeCountLabel = gui.addControl(Label, {text:"trees: 0"}) as Label;
366             polyCountLabel = gui.addControl(Label, {text:"polys: 0"}) as Label;
367             treePolyCountLabel = gui.addControl(Label, {text:"polys/tree: 0"}) as Label;
368             terrainPolyCountLabel = gui.addControl(Label, {text:"polys/terrain: 0"}) as Label;
369             gui.show();
370             
371             updateLabels();
372         }
373         
374         /**
375          * Initialise the listeners
376          */
377         private function initListeners():void
378         {
379             
380             addEventListener(Event.ENTER_FRAME, onEnterFrame);
381             view.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
382             view.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
383             stage.addEventListener(Event.RESIZE, onResize);
384             stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
385             stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
386             onResize();
387         }
388         
389         public function generateTree():void
390         {
391             if(tree) {
392                 currentTreeCount--;
393                 scene.removeChild(tree);
394                 tree = null;
395             }
396             
397             if(foliage) {
398                 scene.removeChild(foliage);
399                 foliage = null;
400             }
401             
402             createTreeShadow(0, 0);
403 
404             // Create tree.
405             var treeGeometry:FractalTreeRound = new FractalTreeRound(treeSize, 10, 3, minAperture, maxAperture, minTwist, maxTwist, treeLevel);
406             tree = new Mesh(treeGeometry, trunkMaterial);
407             tree.rotationY = 360*Math.random();
408             tree.y = terrain != null ? terrain.y + terrain.getHeightAt(tree.x, tree.z) : 0;
409             scene.addChild(tree);
410             
411             // Create tree leaves.
412             foliage = new Mesh(new Foliage(treeGeometry.leafPositions, leavesPerCluster, leafSize, leafClusterRadius), leafMaterial);
413             foliage.x = tree.x;
414             foliage.y = tree.y;
415             foliage.z = tree.z;
416             foliage.rotationY = tree.rotationY;
417             scene.addChild(foliage);
418             
419             // Count.
420             currentTreeCount++;
421             treePolyCount = tree.geometry.subGeometries[0].vertexData.length/3 + foliage.geometry.subGeometries[0].vertexData.length/3;
422             polyCount += treePolyCount;
423             updateLabels();
424         }
425         
426         public function generateClones():void
427         {
428             if(!tree || clonesCreated)
429                 return;
430             
431             // Start tree creation.
432             if(treeCount > 0) {
433                 treeTimer = new Timer(treeDelay, treeCount - 1);
434                 treeTimer.addEventListener(TimerEvent.TIMER, onTreeTimer);
435                 treeTimer.start();
436             }
437             
438             clonesCreated = true;
439         }
440         
441         private function createTreeShadow(x:Number, z:Number):void
442         {
443             // Paint on the terrain's shadow blend layer
444             var matrix:Matrix = new Matrix();
445             var dx:Number = (x/terrainWidth + 0.5)*512 - 8;
446             var dy:Number = (-z/terrainDepth + 0.5)*512 - 8;
447             matrix.translate(dx, dy);
448             var treeShadowBitmapData:BitmapData = new BitmapData(16, 16, false, 0x0000FF);
449             treeShadowBitmapData.draw(createGradientSprite(16, 16, 0, 1), matrix);
450             blendBitmapData.draw(treeShadowBitmapData, matrix, null, BlendMode.ADD);
451             
452             // Update the terrain.
453             blendTexture.bitmapData = blendBitmapData; // TODO: invalidation routine not active for blending texture
454         }
455         
456         private function createGradientSprite(width:Number, height:Number, alpha1:Number, alpha2:Number):Sprite
457         {
458             var gradSpr:Sprite = new Sprite();
459             var matrix:Matrix = new Matrix();
460             matrix.createGradientBox(width, height, 0, 0, 0);
461             gradSpr.graphics.beginGradientFill(GradientType.RADIAL, [0xFF000000, 0xFF000000], [alpha1, alpha2], [0, 255], matrix);
462             gradSpr.graphics.drawRect(0, 0, width, height);
463             gradSpr.graphics.endFill();
464             return gradSpr;
465         }
466         
467         private function updateLabels():void
468         {
469             treeCountLabel.text = "trees: " + currentTreeCount;
470             polyCountLabel.text = "polys: " + polyCount;
471             treePolyCountLabel.text = "polys/tree: " + treePolyCount;
472             terrainPolyCountLabel.text = "polys/terrain: " + terrainPolyCount;
473         }
474         
475         /**
476          * Navigation and render loop
477          */
478         private function onEnterFrame(event:Event):void
479         {
480             if (move) {
481                 cameraController.panAngle = 0.3*(stage.mouseX - lastMouseX) + lastPanAngle;
482                 cameraController.tiltAngle = 0.3*(stage.mouseY - lastMouseY) + lastTiltAngle;
483             }
484             
485             cameraController.panAngle += panIncrement;
486             cameraController.tiltAngle += tiltIncrement;
487             cameraController.distance += distanceIncrement;
488             
489             // Update light.
490             cameraLight.transform = camera.transform.clone();
491             
492             view.render();
493         }
494         
495         /**
496          * Key down listener for camera control
497          */
498         private function onKeyDown(event:KeyboardEvent):void
499         {
500             switch (event.keyCode) {
501                 case Keyboard.UP:
502                 case Keyboard.W:
503                     tiltIncrement = tiltSpeed;
504                     break;
505                 case Keyboard.DOWN:
506                 case Keyboard.S:
507                     tiltIncrement = -tiltSpeed;
508                     break;
509                 case Keyboard.LEFT:
510                 case Keyboard.A:
511                     panIncrement = panSpeed;
512                     break;
513                 case Keyboard.RIGHT:
514                 case Keyboard.D:
515                     panIncrement = -panSpeed;
516                     break;
517                 case Keyboard.Z:
518                     distanceIncrement = distanceSpeed;
519                     break;
520                 case Keyboard.X:
521                     distanceIncrement = -distanceSpeed;
522                     break;
523             }
524         }
525         
526         /**
527          * Key up listener for camera control
528          */
529         private function onKeyUp(event:KeyboardEvent):void
530         {
531             switch (event.keyCode) {
532                 case Keyboard.UP:
533                 case Keyboard.W:
534                 case Keyboard.DOWN:
535                 case Keyboard.S:
536                     tiltIncrement = 0;
537                     break;
538                 case Keyboard.LEFT:
539                 case Keyboard.A:
540                 case Keyboard.RIGHT:
541                 case Keyboard.D:
542                     panIncrement = 0;
543                     break;
544                 case Keyboard.Z:
545                 case Keyboard.X:
546                     distanceIncrement = 0;
547                     break;
548             }
549         }
550         
551         /**
552          * Mouse down listener for navigation
553          */
554         private function onMouseDown(event:MouseEvent):void
555         {
556             move = true;
557             lastPanAngle = cameraController.panAngle;
558             lastTiltAngle = cameraController.tiltAngle;
559             lastMouseX = stage.mouseX;
560             lastMouseY = stage.mouseY;
561             stage.addEventListener(Event.MOUSE_LEAVE, onStageMouseLeave);
562         }
563         
564         /**
565          * Mouse up listener for navigation
566          */
567         private function onMouseUp(event:MouseEvent):void
568         {
569             move = false;
570             stage.removeEventListener(Event.MOUSE_LEAVE, onStageMouseLeave);
571         }
572         
573         /**
574          * Mouse stage leave listener for navigation
575          */
576         private function onStageMouseLeave(event:Event):void
577         {
578             move = false;
579             stage.removeEventListener(Event.MOUSE_LEAVE, onStageMouseLeave);
580         }
581         
582         /**
583          * stage listener for resize events
584          */
585         private function onResize(event:Event = null):void
586         {
587             view.width = stage.stageWidth;
588             view.height = stage.stageHeight;
589             SignatureBitmap.y = stage.stageHeight - Signature.height;
590             awayStats.x = stage.stageWidth - awayStats.width;
591         }
592         
593         /**
594          * stage listener for resize events
595          */
596         private function onTreeTimer(event:TimerEvent):void
597         {
598             //create tree clone.
599             var treeClone:Mesh = tree.clone() as Mesh;
600             treeClone.x = terrainWidth*Math.random() - terrainWidth/2;
601             treeClone.z = terrainDepth*Math.random() - terrainDepth/2;
602             treeClone.y = terrain != null ? terrain.y + terrain.getHeightAt(treeClone.x, treeClone.z) : 0;
603             treeClone.rotationY = 360*Math.random();
604             treeClone.scale((treeMax - treeMin)*Math.random() + treeMin);
605             scene.addChild(treeClone);
606             
607             //create foliage clone.
608             var foliageClone:Mesh = foliage.clone() as Mesh;
609             foliageClone.x = treeClone.x;
610             foliageClone.y = treeClone.y;
611             foliageClone.z = treeClone.z;
612             foliageClone.rotationY = treeClone.rotationY;
613             foliageClone.scale(treeClone.scaleX);
614             scene.addChild(foliageClone);
615             
616             //create tree shadow clone.
617             createTreeShadow(treeClone.x, treeClone.z);
618             
619             //count.
620             currentTreeCount++;
621             polyCount += treePolyCount;
622             updateLabels();
623         }        
624         
625     }
626 }

 注:素材和实例可到官网下载。

------------------------------------------------------------------ Always put yourself in the other's shoes.If you feel that it hurts you,it probably hurts others,too.------------------------------------------------------------------
posted on 2015-11-27 11:11  晏过留痕  阅读(861)  评论(0编辑  收藏  举报