package { /** * ... * @author Exey Panteleev * Math by Yamasv http://yamasv.blog92.fc2.com/blog-entry-85.html */ import flash.display.Sprite; import flash.events.Event; import flash.events.KeyboardEvent; import flash.display.StageAlign; import flash.display.StageQuality; import net.hires.utils.Stats; import away3d.core.scene.View3D; import away3d.core.math.Number3D; import away3d.core.material.WireColorMaterial; import away3d.objects.LineSegment; import away3d.objects.Plane; import away3d.objects.Sphere; [SWF(backgroundColor="#222015", frameRate="60", width="600", height="400")] public class Fluid2 extends Sprite { //Math private var theta:Number = 0; private var buffer:Array = new Array(); private var renderBuffer:int = 0; private var k1:Number; private var k2:Number; private var k3:Number; //Common private var range:int = 20; private var waterSegsX:int = range; private var waterSegsY:int = range; private var waterSegsXreal:int = waterSegsX+1; private var waterSegsYreal:int = waterSegsY+1; private var waterXcenter:int = waterSegsX/2; private var waterYcenter:int= waterSegsY/2; private var isPause:Boolean = false; //Away3D public var view:View3D; private var waterSurface:Plane; private var waterMat:WireColorMaterial; public function Fluid2() { prepareAway3d(); prepareMath(); createObjects(); addListeners(); } private function prepareAway3d() { stage.quality = "LOW"; stage.scaleMode = "noScale"; stage.align = StageAlign.TOP_LEFT; view = new View3D(); view.x = 300; view.y = 200; addChild(view); view.camera.z = 1800; stage.addChild( new Stats() ); // MrDoob Stats http://code.google.com/p/mrdoob/ } private function changeWaterMaterial(matIndex:uint) { var material1:WireColorMaterial; switch(matIndex) { case 1: material1 = new WireColorMaterial(0x0000ff, {wirecolor: 0x9b85f9}); waterSurface.material = material1; makeSplash(30); break; } } private function createObjects() { waterSurface = new Plane( { width:1200, height:1200, segmentsW:waterSegsX, segmentsH:waterSegsY } ); changeWaterMaterial(1); //waterSurface.rotationX = -90; waterSurface.back = waterMat; view.scene.addChild(waterSurface); trace("vertices: ", waterSurface.vertices.length, "faces: ", waterSurface.faces.length) } private function addListeners() { addEventListener(Event.ENTER_FRAME, onEnterFrame); stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler); } public function prepareMath() { populateBuffer(); trace(buffer[0].length, buffer[1].length) var d:Number = 1; var t:Number = 0.1; var c:Number = 2.1; var mu:Number = 0.001; var f1:Number = c*c*t*t/(d*d); var f2:Number = 1/(mu*t+2); k1 = (4 - 8*f1)*f2; k2 = (mu*t-2)*f2; k3 = 2 * f1 * f2; } public function populateBuffer() { var x:int,y:int,z:int; // 3-d displacement will be stored in the array(2*w*h) for(var i:int = 0 ; i < 2; i++){ var a:Array = new Array(); for(var j:int = 0 ; j < waterSegsYreal; j++){ var aa:Array = new Array(); for(var k:int = 0 ; k < waterSegsXreal; k++) aa.push(new Number3D(j,0,k)); a.push(aa); } buffer[i] = a; } } public function makeSplash(splashHeight:int) { populateBuffer(); buffer[renderBuffer][waterXcenter][waterYcenter].y = splashHeight; } private function evaluate():void{ for(var j:int = 1 ; j < waterSegsYreal-1; j++){ var crnt:Array = buffer[renderBuffer][j]; var prev:Array = buffer[1-renderBuffer][j]; for (var i:int = 1 ; i < waterSegsXreal-1; i++) { // trace(j, i); var currentN:Number3D = (Number3D)(buffer[renderBuffer][j + 1][i]); var currentP:Number3D = (Number3D)(buffer[renderBuffer][j - 1][i]); ((Number3D)(prev[i])).y = k1*((Number3D)(crnt[i])).y + k2*((Number3D)(prev[i])).y + k3*(((Number3D)(crnt[i+1])).y + ((Number3D)(crnt[i-1])).y + currentN.y + currentP.y); } } renderBuffer = 1-renderBuffer; } private function onEnterFrame(event:Event):void { //light.copyPosition(camera); // trace( buffer[renderBuffer][1][0]); if(!isPause){ theta += 0.05; var verCounter:uint = 0; for(var x:int = 0 ; x < waterSegsXreal ; x++){ for(var z:int = 0 ; z < waterSegsYreal ; z++){ waterSurface.vertices[verCounter].y = buffer[renderBuffer][x][z].y * 3; verCounter++; } } evaluate(); } rotateCamera(); view.render(); } private function rotateCamera():void{ // Move camera based on mouse position var x:Number = (stage.mouseX - stage.stageWidth/2); view.camera.moveLeft(x); var y:Number = (stage.mouseY - stage.stageHeight/2); view.camera.moveDown(y); if (view.camera.y > 1000 || view.camera.y < -200) view.camera.moveDown(-y); view.camera.lookAt(waterSurface.position); } public function keyUpHandler(e:KeyboardEvent) { if (isChar(e.charCode, "1")) changeWaterMaterial(1); else if (isChar(e.charCode, "0")) if(isPause == false) isPause = true; else isPause = false; } private function isChar(code:Number, str:String){ if(code == str.charCodeAt()) return true; return false; } } }