Fluid Water Simulation Alternativa3d 8
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. 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
Comments
Comments are currently closed