Author: Max Pellizzaro
Date: May 11th 2008
version: 3.0.2
With tutorial will teach you on how to model a balnket (or a net) using WOW. I have seen on the WOW's official web site three nice demos on using a cloth, and I just want to do it with Sandy.
In this tutorial we will model a squared net hanging from the four vertex of the net, as you can see from the picture below.
The main class has been named Example033.
In this section we report the AS code as a reference, and it will be explained in the next paragraph.
package
{
import flash.utils.*;
import flash.display.Sprite;
import flash.events.*;
import flash.ui.*;
import flash.media.Sound;
//wow engine
import fr.seraf.wow.primitive.*;
import fr.seraf.wow.constraint.*;
import fr.seraf.wow.core.WOWEngine;
import fr.seraf.wow.core.data.WVector;
import fr.seraf.wow.math.*;
// Sandy
import sandy.core.Scene3D;
import sandy.core.data.*;
import sandy.core.scenegraph.*;
import sandy.materials.*;
import sandy.materials.attributes.*;
import sandy.primitive.*;
import sandy.events.*;
public class Example033 extends Sprite
{
private var wow:WOWEngine;
private var net:Plane3D;
private var arrayWSphere:Array = new Array();
private var arrayWConstraint:Array = new Array();
private var scene:Scene3D;
private var camera:Camera3D;
public function Example033()
{
//create an instance of the physic engine
wow=new WOWEngine();
// SELECTIVE is better for dealing with lots of little particles colliding,
wow.collisionResponseMode = wow.SELECTIVE;
// gravity -- particles of varying masses are affected the same
wow.addMasslessForce (new WVector(0,1,0));
var plane01:WOWPlane = new WOWPlane();
plane01.setPosition (0,60,0);
plane01.elasticity=0.1;
plane01.friction=0.0;
//wow.addParticle (plane01);
// Sandy code
camera = new Camera3D( 600, 600 );
camera.z = -200;
camera.y = 50;
camera.lookAt (0,0,0);
var root:Group = createScene();
scene = new Scene3D( "scene", this, camera, root );
scene.light.setDirection(100, -350, 0);
addEventListener ( Event.ENTER_FRAME, enterFrameHandler );
stage.addEventListener (MouseEvent.MOUSE_MOVE, mouseMovedHandler);
}
private function createScene ():Group
{
// Create the root Group
var g:Group = new Group();
net = new Plane3D( "theNet", 100, 100, 9, 9, Plane3D.ZX_ALIGNED, "quad" );
net.y = 10;
net.enableBackFaceCulling = false;
var materialAttr01:MaterialAttributes = new MaterialAttributes(
new LightAttributes( true, 0.01),
new LineAttributes(1, 0xFFFFFF, 1)
);
var material01:Material = new ColorMaterial( 0x990000, 1, materialAttr01 );
material01.lightingEnable = false;
var app01:Appearance = new Appearance( material01 );
net.appearance = app01;
// vertex of the pshere
for (var i=0; i<net.geometry.aVertex.length; i++){
var sphere:WSphere = null;
if(i==0 || i==9 || i==90 || i==99)
sphere = new WSphere(net.geometry.aVertex[i].x,
-net.geometry.aVertex[i].y,
net.geometry.aVertex[i].z,
1,true);
else
sphere = new WSphere(net.geometry.aVertex[i].x,
-net.geometry.aVertex[i].y,
net.geometry.aVertex[i].z,
1,false,0.01,0.1,0);
arrayWSphere[i] = sphere;
wow.addParticle (arrayWSphere[i]);
}
for (var j=0; j<net.geometry.aEdges.length; j++){
arrayWConstraint[j] =new WSpringConstraint(
arrayWSphere[net.geometry.aEdges[j].vertexId1],
arrayWSphere[net.geometry.aEdges[j].vertexId2],
1);
wow.addConstraint(arrayWConstraint[j]);
}
/*
// let's add constraints to the net
var k = 0;
for (var k1=0; k1<=90; k1=k1+10){
for (var j1=0; j1<4; j1++){
arrayWConstraint[k] =new WSpringConstraint(
arrayWSphere[k1+j1],
arrayWSphere[k1+j1+1],
1);
wow.addConstraint(arrayWConstraint[k]);
k++;
}
}
for (var k2=0; k2<=9; k2++){
for (var j2=0; j2<=40; j2=j2+10){
arrayWConstraint[k] =new WSpringConstraint(
arrayWSphere[k2+j2],
arrayWSphere[k2+j2+10],
1);
wow.addConstraint(arrayWConstraint[k]);
k++;
}
}
for (var k3=9; k3<=99; k3=k3+10){
for (var j3=0; j3<4; j3++){
arrayWConstraint[k] =new WSpringConstraint(
arrayWSphere[k3-j3],
arrayWSphere[k3-j3-1],
1);
wow.addConstraint(arrayWConstraint[k]);
k++;
}
}
for (var k4=90; k4<=99; k4++){
for (var j4=0; j4<=30; j4=j4+10){
arrayWConstraint[k] =new WSpringConstraint(
arrayWSphere[k4-j4],
arrayWSphere[k4-j4-10],
1);
wow.addConstraint(arrayWConstraint[k]);
k++;
}
}
for (var k5=0; k5<=90; k5=k5+10){
arrayWConstraint[k] =new WSpringConstraint(
arrayWSphere[4+k5],
arrayWSphere[5+k5],
1);
wow.addConstraint(arrayWConstraint[k]);
k++;
}
for (var k7=0; k7<=90; k7=k7+10){
arrayWConstraint[k] =new WSpringConstraint(
arrayWSphere[5+k7],
arrayWSphere[4+k7],
1);
wow.addConstraint(arrayWConstraint[k]);
k++;
}
for (var k6=0; k6<=9; k6++){
arrayWConstraint[k] =new WSpringConstraint(
arrayWSphere[40+k6],
arrayWSphere[50+k6],
1);
wow.addConstraint(arrayWConstraint[k]);
k++;
}
for (var k8=0; k8<=9; k8++){
arrayWConstraint[k] =new WSpringConstraint(
arrayWSphere[50+k8],
arrayWSphere[40+k8],
1);
wow.addConstraint(arrayWConstraint[k]);
k++;
}
*/
g.addChild ( net );
return g;
}
private function mouseMovedHandler (event:MouseEvent):void{
net.pan=-(event.stageX-600/2)/10;
net.tilt=-(event.stageY-600/2)/10;
}
private function enterFrameHandler ( event : Event ):void
{
//run the engine once
wow.step ();
for (var i=0; i<net.geometry.aVertex.length; i++){
net.geometry.aVertex[i].x = arrayWSphere[i].px;
net.geometry.aVertex[i].y = -arrayWSphere[i].py;
net.geometry.aVertex[i].z = arrayWSphere[i].pz;
}
scene.render ();
}
}
}
Before examining the code we need to explain what we need to model and how to do it.
The idea behind the model of the net is to model each intersection of the net as a single sphere, and to use springs for every edges linking each intersection of the net. So now let’s examine the code.
This task is pretty easy to do, is it the same one as the previuos tutorial
//create an instance of the physic engine wow=new WOWEngine(); // SELECTIVE is better for dealing with lots of little particles colliding, wow.collisionResponseMode = wow.SELECTIVE;
For this tutorial we need to model a lot of WOW objects:
let's model the intersection of the net (and for of them are fixed):
for (var i=0; i<net.geometry.aVertex.length; i++){ var sphere:WSphere = null; if(i==0 || i==9 || i==90 || i==99) sphere = new WSphere(net.geometry.aVertex[i].x, -net.geometry.aVertex[i].y, net.geometry.aVertex[i].z, 1,true); else sphere = new WSphere(net.geometry.aVertex[i].x, -net.geometry.aVertex[i].y, net.geometry.aVertex[i].z, 1,false,0.01,0.1,0); arrayWSphere[i] = sphere; wow.addParticle (arrayWSphere[i]); }
Let's now mode the Springs, one for each edge:
for (var j=0; j<net.geometry.aEdges.length; j++){ arrayWConstraint[j] =new WSpringConstraint( arrayWSphere[net.geometry.aEdges[j].vertexId1], arrayWSphere[net.geometry.aEdges[j].vertexId2], 1); wow.addConstraint(arrayWConstraint[j]); }
This is the easy part, since by now you know that far better than me…
camera = new Camera3D( 600, 600 ); camera.z = -200; camera.y = 50; camera.lookAt (0,0,0); var root:Group = createScene(); scene = new Scene3D( "scene", this, camera, root ); scene.light.setDirection(100, -350, 0);
We just need one Sandy object: a plabe3D, tha in fact we have already used when creating the WOW object since we have looped on the Sandy object vertex and edges in order to model WOW spheres and WOW springs.
net = new Plane3D( "theNet", 100, 100, 9, 9, Plane3D.ZX_ALIGNED, "quad" ); net.y = 10; net.enableBackFaceCulling = false;
This task is prety easy too… we just need to loop between Sandy vertex and WOW spheres.
for (var i=0; i<net.geometry.aVertex.length; i++){ net.geometry.aVertex[i].x = arrayWSphere[i].px; net.geometry.aVertex[i].y = -arrayWSphere[i].py; net.geometry.aVertex[i].z = arrayWSphere[i].pz; }
This is it! Let’s see our result now.
Let's see our first output.
Looking at this result I was not too happy, because I wanted to see a simmetric net! So I have digged to see how to make it simmetric and I have found out that the order of the spring was impostant. When you define a Sping you need to specify the two edges of the sping. If you have a net with 6 edges, you should specify 3 spring in one direction and 3 spring in the other direction. I have places this “simmetric” code in comment in the above code example, and here is the result !!