private var theta:Number = 0; private var buffer:Array = new Array(2); private var renderBuffer:int = 0; private var k1:Number; private var k2:Number; private var k3:Number; //Common private var range:int = 20; // play with tesselation 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 = range/2; private var waterYcenter:int= range/2; private var isPause:Boolean = false; //3D private var waterSurface:Plane; private var light:PointLight3D; public function Fluid2() { super(600, 400, false, false, "CAMERA3D"); preparePv3d(); prepareMath(); createObjects(); addListeners(); } public function preparePv3d():void { stage.quality = "LOW"; stage.scaleMode = "noScale"; stage.align = StageAlign.TOP_LEFT; camera.zoom = 5; addChild(new Stats()) // Mr.Doob Stats http://code.google.com/p/mrdoob/ } public function changeWaterMaterial(matIndex:uint):void { var material1:CompositeMaterial; var material2:ShadedMaterial; var envmapAsset:Class = getDefinitionByName("pat710.jpg") as Class; //"BlueSkies" by Michael Lambert http://www.filterforge.com/filters/710.html var envmapBitmapData:BitmapData = new envmapAsset(0, 0) as BitmapData; var waterShader:EnvMapShader; var waterBitmapMat:BitmapMaterial; var bumpmapAsset:Class; var bumpmapBitmapData:BitmapData; switch(matIndex) { case 1: material1 = new CompositeMaterial(); material1.addMaterial(new ColorMaterial(0x0000fff, 1)); var wireframe:WireframeMaterial = new WireframeMaterial(0x9b85f9, 1); wireframe.doubleSided = true; material1.addMaterial(wireframe); waterSurface.material = material1; makeSplash(30); // play with splash height break; case 2: bumpmapAsset = getDefinitionByName("bump465.jpg") as Class; bumpmapBitmapData = new bumpmapAsset(0,0) as BitmapData; waterShader = new EnvMapShader(light, envmapBitmapData, envmapBitmapData,0,bumpmapBitmapData); waterBitmapMat = new BitmapAssetMaterial("diffuse465.jpg"); //"poolwater" by DrEvil http://www.filterforge.com/filters/465.html material2 = new ShadedMaterial(waterBitmapMat, waterShader); waterSurface.material = material2; makeSplash(30); break; case 3: bumpmapAsset = getDefinitionByName("bump465.jpg") as Class; bumpmapBitmapData = new bumpmapAsset(0,0) as BitmapData; waterShader = new EnvMapShader(light, envmapBitmapData, envmapBitmapData,0,bumpmapBitmapData); waterBitmapMat = new BitmapAssetMaterial("pat2192.jpg"); //"Aqua Absolute" by Zephos http://www.filterforge.com/filters/2192.html material2 = new ShadedMaterial(waterBitmapMat, waterShader); waterSurface.material = material2; makeSplash(30); break; case 4: bumpmapAsset = getDefinitionByName("bump4141.jpg") as Class; bumpmapBitmapData = new bumpmapAsset(0,0) as BitmapData; waterShader = new EnvMapShader(light, envmapBitmapData, envmapBitmapData,0,bumpmapBitmapData); waterBitmapMat = new BitmapAssetMaterial("diffuse4141.jpg"); // "Sea Water" by Constantin Malkov http://www.filterforge.com/filters/4141.html material2 = new ShadedMaterial(waterBitmapMat, waterShader); waterSurface.material = material2; makeSplash(30); break; } waterSurface.material.doubleSided = true; } public function createObjects():void { light = new PointLight3D(false, false); waterSurface = new Plane(new MaterialObject3D(), 1200, 1200, waterSegsX, waterSegsY); changeWaterMaterial(1); waterSurface.material.doubleSided = true; waterSurface.rotationX = -90; scene.addChild(waterSurface); camera.lookAt(waterSurface); trace("vertices: ", waterSurface.geometry.vertices.length, "faces: ", waterSurface.geometry.faces.length) } public function prepareMath():void { 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():void { 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):void { populateBuffer(); buffer[renderBuffer][waterXcenter][waterYcenter].y = splashHeight; } public function addListeners():void { addEventListener(Event.ENTER_FRAME, onEnterFrame); stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler); } 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; } public function onEnterFrame(event:Event):void { light.copyPosition(camera); 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.geometry.vertices[verCounter].z = buffer[renderBuffer][x][z].y * 3; verCounter++; } } evaluate(); for each(var face:Triangle3D in waterSurface.geometry.faces) face.createNormal(); for each(var vertex:Vertex3D in waterSurface.geometry.vertices) vertex.calculateNormal(); } rotateCamera(); singleRender(); } private function rotateCamera():void{ var x:Number = (stage.mouseX - stage.stageWidth/2) / 4; camera.moveLeft(x); var y:Number = (stage.mouseY - stage.stageHeight/2) / 6; camera.moveDown(y); if (camera.y > 1000 || camera.y < -200) camera.moveDown(-y); } public function keyUpHandler(e:KeyboardEvent):void { if (isChar(e.charCode, "1")) changeWaterMaterial(1); else if(isChar(e.charCode, "2")) changeWaterMaterial(2); else if (isChar(e.charCode, "3")) changeWaterMaterial(3); else if (isChar(e.charCode, "4")) changeWaterMaterial(4); else if (isChar(e.charCode, "0")) if(isPause == false) isPause = true; else isPause = false; } private function isChar(code:Number, str:String):Boolean{ if(code == str.charCodeAt()) return true; return false; }
For speed comparison i make it (just geometry) fluid on Away3D, i done equal FPS on both engines.
UPD:
18.03.2008. 20:03
Hi Axey.
I am a author of 'miscellaneous'(http://yamasv.blog92.fc2.com/).
A lot of people came to my blog via your introduction.
Thank you very much.
Really nice work :)
nice job! but it's look like Away3D not fully complete, so i add some effect at Away3D also add Polygonal Array3 ,here
http://sleepydesign.blogspot.com/2008/04/away3d-fluid-with-polygonal.html
hope you like it ;)
Hello, is good, all this is very good, but they are one thing that worries me.
Which serves all this, if the computer can not move it?
Neither the most powerful computer can't calculate a water source maded in flash.
I wait the day when flash may access the all power of the PC graphics card.
Until then all this will not serve for nothing.
:(((((
nice job,thank you
great job... could you give us the bump4141.jpg and diffuse4141.jpg images please? I can't understand the difference...
thanks!
hey i tried to recreate this in alternativa3d, http://davidejones.com/blog/actionscript3/fluid-water-simulation-alternativa3d-7/
Write a comment
* = required field