Fluid Water Simulation Alternativa3d 8

David Jones
@david3jones
avatar-davidejones

When a major release of the alternativa3d library comes out I slowly start to try recreating my previous tests and examples over to the new version to see how they work and learn a thing or 2 about the new system. I’ve recently taken the fluid water simulation for version 7 and set it up for version 8 which works a lot better with the standard material and lighting effects. To get it to work I had to create a Vertex class to assign the x y z values and then use version 8’s new geometry and streams to set the data back. fluid water Here is my document class

package 
{
    	import alternativa.engine3d.controllers.SimpleObjectController;
    	import alternativa.engine3d.core.Camera3D;
    	import alternativa.engine3d.core.Object3D;
    	import alternativa.engine3d.core.Resource;
    	import alternativa.engine3d.core.View;
    	import alternativa.engine3d.materials.StandardMaterial;
    	import alternativa.engine3d.resources.BitmapTextureResource;
    	import alternativa.engine3d.lights.*;
    	
    	import flash.display.Sprite;
    	import flash.display.Stage3D;
    	import flash.display.StageAlign;
    	import flash.display.StageScaleMode;
    	import flash.events.Event;
    	import flash.geom.Vector3D;
    	
    	import FluidPlane;
    	
    	[SWF(backgroundColor="#000000", frameRate="100", width="800", height="600")]
    	
    	public class test extends Sprite 
    	{
    		[Embed(source="465-diffuse.jpg")] static private const FluidDiffuse:Class;
    		[Embed(source="465-normal.jpg")] static private const FluidNormal:Class;
    		[Embed(source="465-bump.jpg")] static private const FluidSpec:Class;
    		
    		private var rootContainer:Object3D = new Object3D();
    		private var camera:Camera3D;
    		private var controller:SimpleObjectController;
    		private var fplane:FluidPlane;
    		private var stage3D:Stage3D;
    		private var dl2:DirectionalLight;
    		
    		public function test():void
    		{
    			//setup stage
    			stage.align = StageAlign.TOP_LEFT;
    			stage.scaleMode = StageScaleMode.NO_SCALE;
    			
    			camera = new Camera3D(0.1, 10000);
    			camera.view = new View(stage.stageWidth, stage.stageHeight);
    			addChild(camera.view);
    			addChild(camera.diagram);
    			camera.y = 100;
    			camera.z = 100;
    			camera.x = -50;
    			controller = new SimpleObjectController(stage, camera, 200);
    			controller.lookAt(new Vector3D(0,0,0));
    			rootContainer.addChild(camera);
    			
    			//setup material
    			var mat:StandardMaterial = new StandardMaterial(new BitmapTextureResource(new FluidDiffuse().bitmapData),new BitmapTextureResource(new FluidNormal().bitmapData),null,new BitmapTextureResource(new FluidSpec().bitmapData));
    			
    			dl2 = new DirectionalLight(0xFFFFFF);
                dl2.intensity = 0.5;
                dl2.lookAt(0,0,0);
    			dl2.rotationX = -2.26893;
                dl2.rotationY = 0;
                dl2.rotationZ = 0.698132;
                rootContainer.addChild(dl2);
    			
    			var al:AmbientLight = new AmbientLight(0xFFFFFF);
    			al.intensity = 0.5;
    			al.z = 100;
                rootContainer.addChild(al);
    			
    			//create fluidplane and apply material
    			fplane = new FluidPlane(camera);
    			fplane.setMaterialToAllSurfaces(mat);
    			rootContainer.addChild(fplane);
    						
    			stage3D = stage.stage3Ds[0];
    			stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContextCreate);
    			stage3D.requestContext3D();
    		}
    		
    		private function onContextCreate(e:Event):void {
    			for each (var resource:Resource in rootContainer.getResources(true)) {
    				resource.upload(stage3D.context3D);
    			}
    			
    			//start a splash
    			fplane.makeSplash(2);
    			
    			stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
    		}
    		
    		private function onEnterFrame(e:Event):void 
    		{	
    			controller.update();
    			camera.render(stage3D);
    			fplane.draw(stage3D);
    		}
    		
    		private function onResize(e:Event = null):void {
    			camera.view.width = stage.stageWidth;
    			camera.view.height = stage.stageHeight;
    		}
    	
    	}
    	
}
    

and here is the revised fluid plane class.

// A conversion of the papervision and away3d example
// http://exey.ru/blog/home/fluid-simulation-pv3d-and-away3d
    
package
{
    	import alternativa.engine3d.primitives.Plane;
    	import alternativa.engine3d.materials.Material;
    	import flash.geom.Vector3D;
    	import alternativa.engine3d.core.Camera3D;
    	import alternativa.engine3d.core.VertexAttributes;
    	import flash.display.Stage3D;
    
    	public class FluidPlane extends Plane
    	{
    		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;
    
    		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 = range/2;
    		private var waterYcenter:int= range/2;
    		private var isPause:Boolean = false;
    		
    		private var camera:Camera3D;
    		private var vertices:Vector. = new Vector.();
    		private var verts:Vector. = new Vector.();
    
    		public function FluidPlane(camera:Camera3D,width:Number = 100, length:Number = 100, widthSegments:uint = 1, lengthSegments:uint = 1, twoSided:Boolean = true, reverse:Boolean = false, bottom:Material = null, top:Material = null)
    		{
    			this.camera = camera;
    			widthSegments = waterSegsX;
    			lengthSegments = waterSegsY;
    			super(width, length, widthSegments, lengthSegments, twoSided, reverse, bottom, top);
    			
    			setupVertices();
    			prepareMath();
    		}
    		
    		private function setupVertices():void
    		{
    			verts =  this.geometry.getAttributeValues(VertexAttributes.POSITION);
    			var x:int = 0;
    			for(var i:int = 0; i < verts.length/3; i++)
    			{
    				var v:Vertex = new Vertex();
    				v.x = verts[i + x]; x++;
    				v.y = verts[i + x]; x++;
    				v.z = verts[i + x];
    				this.vertices.push(v);
    			}
    		}
    		
    		private function resaveVertices():void
    		{
    			this.verts = new Vector.();
    			for(var i:int = 0; i < this.vertices.length; i++)
    			{
    				this.verts.push(this.vertices[i].x);
    				this.verts.push(this.vertices[i].y);
    				this.verts.push(this.vertices[i].z);
    			}
    		}
    		
    		public function draw(stage3D:Stage3D):void
    		{			
    			theta += 0.05;
    			var verCounter:uint = 0;
    			for(var x:int = 0 ; x < waterSegsXreal ; x++){
    				for(var z:int = 0 ; z < waterSegsYreal ; z++){
    					this.vertices[verCounter].z = buffer[renderBuffer][x][z].y * 3;
    					verCounter++;
    				}
    			}
    			evaluate();
    			
    			resaveVertices();
    			
                this.geometry.setAttributeValues(VertexAttributes.POSITION, verts);
    			this.geometry.calculateNormals();
    			this.geometry.calculateTangents(0);
    			this.calculateBoundBox();
                this.geometry.upload(stage3D.context3D);
    		}
    		
    		
    		public function makeSplash(splashHeight:int):void 
    		{
    			populateBuffer();
    			buffer[renderBuffer][waterXcenter][waterYcenter].y = splashHeight; 
    		}
    		
    		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 Vector3D(j,0,k));
    					a.push(aa);
    				}
    				buffer[i] = a;
    			}
    		}
    		
    		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:Vector3D = (Vector3D)(buffer[renderBuffer][j + 1][i]);
    					var currentP:Vector3D = (Vector3D)(buffer[renderBuffer][j - 1][i]);
    					((Vector3D)(prev[i])).y = k1*((Vector3D)(crnt[i])).y + k2*((Vector3D)(prev[i])).y + k3*(((Vector3D)(crnt[i+1])).y + ((Vector3D)(crnt[i-1])).y + currentN.y + currentP.y);
    				}
    			}
    			renderBuffer = 1-renderBuffer;
    		}
    		
    	}
}
    
import flash.geom.Vector3D;
class Vertex extends Object
{
    
    	public var x:Number;
    	public var y:Number;
    	public var z:Number;
    
    	function Vertex()
    	{
    		return;
    	}
}

You can download the source files here or see the demo here

Downloads

Comments

    Comments are currently closed