[練習]3D物理引擎 jiglibflash

2009-04-19_011913.jpg

jiglibflash是為Flash 3D開發的物理引擎,支援常見的3D引擎,包括PV3D、Away3D,由於寫起來是直接使用3D座標,所以撰寫方便,也支援不規則模形的物件,比我之前看過的WOW引擎功能多很多,但缺點還是太吃CPU資源

package {
import flash.display.Bitmap;
import flash.events.Event;
import flash.events.MouseEvent;

import jiglib.math.JNumber3D;
import jiglib.physics.PhysicsSystem;
import jiglib.physics.RigidBody;
import jiglib.physics.constraint.JConstraintWorldPoint;
import jiglib.plugin.papervision3d.Papervision3DPhysics;

import org.papervision3d.core.geom.renderables.Vertex3D;
import org.papervision3d.core.math.Number3D;
import org.papervision3d.core.math.Plane3D;
import org.papervision3d.core.utils.Mouse3D;
import org.papervision3d.events.InteractiveScene3DEvent;
import org.papervision3d.lights.PointLight3D;
import org.papervision3d.materials.BitmapMaterial;
import org.papervision3d.materials.ColorMaterial;
import org.papervision3d.materials.shadematerials.FlatShadeMaterial;
import org.papervision3d.materials.utils.MaterialsList;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.view.BasicView;
import org.papervision3d.view.layer.ViewportLayer;
import org.papervision3d.view.layer.util.ViewportLayerSortMode;
       /**
* 
* @author GD
* 
*/     
[SWF (width = "950", height = "500", frameRate = "30", backgroundColor = "0xFFFFFF")]
public class Main extends BasicView
{
private static const WORLD_WIDTH:uint = 950;

private var physics:Papervision3DPhysics;
private var pointLight:PointLight3D;

private var mouse3D:Mouse3D;
private var currentBody:RigidBody;
private var planeToDragOn:Plane3D;
private var dragConstraint:JConstraintWorldPoint

[Embed (source = "assets/floor.jpg")]
private var floorAsset:Class;

public function Main()
{
super(950, 500, true, true);

initPV3D();
initJiglib();

createFloor();
createBox(5);

stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);                    
startRendering();
}

private function initJiglib():void
{
//創銉物理world並指定元件要加入的scene
physics = new Papervision3DPhysics(scene, 8);   
}

private function initPV3D():void
{
pointLight = new PointLight3D();
pointLight.y = 1000;
pointLight.z = -800;
viewport.containerSprite.sortMode = ViewportLayerSortMode.INDEX_SORT;

Mouse3D.enabled = true;
mouse3D = viewport.interactiveSceneManager.mouse3D;

camera.z = -1200;
camera.y = 300;
camera.rotationX = 45;
}

private function createFloor():void
{
var colorMat:ColorMaterial = new ColorMaterial(0xCCCCCC);
var imageMat:BitmapMaterial = new BitmapMaterial(Bitmap(new floorAsset()).bitmapData);
var listMat:MaterialsList = new MaterialsList({all:colorMat, top:imageMat});

//createCube會創建物理的body跟實際的pv3d元件(會自動加入至pv3d scene)
var floorBody:RigidBody = physics.createCube(listMat, 1600, 1200, 10);

var floor3D:DisplayObject3D = physics.getMesh(floorBody);

//fix
floorBody.movable = false;
floorBody.moveTo(new JNumber3D(0, -300, 0));
floorBody.restitution = .8;
floorBody.friction = .2;

//重調整layer層次
viewport.getChildLayer(floor3D).layerIndex = 1;
}

private function createBox(num:uint):void
{
//重調整layer層次,在floor前,內部照z軸排序
var modelLayer:ViewportLayer = new ViewportLayer(viewport, null);

modelLayer.sortMode = ViewportLayerSortMode.Z_SORT;
modelLayer.layerIndex = 2;
viewport.containerSprite.addLayer(modelLayer);  

var cubeWidth:uint = 150;
var cubeHeight:uint = 150;
var cubeDepth:uint = 150;

for (var i:uint; i < num; i++)
{
var ranX:Number = Math.random() * 1200 - 600;
var ranY:Number = Math.random() * 500 + 500;
var ranZ:Number = Math.random() * 800 - 400;

var flatMat:FlatShadeMaterial = new FlatShadeMaterial(pointLight, Math.random() * 0x1000000, 0x111111);
var listMat:MaterialsList = new MaterialsList({all:flatMat});

var cube:RigidBody = physics.createCube(listMat, cubeWidth, cubeDepth, cubeHeight);
var cube3D:DisplayObject3D = physics.getMesh(cube);

cube.moveTo(new JNumber3D(ranX, ranY, ranZ));
modelLayer.addDisplayObject3D(cube3D);

flatMat.interactive = true;     
cube3D.addEventListener(InteractiveScene3DEvent.OBJECT_PRESS, mousePressHandler);
}
}

private function findBody(obj3D:DisplayObject3D):RigidBody
{
var bodys:Array = PhysicsSystem.getInstance().bodys;
var rigidBody:RigidBody;

for each (var body:RigidBody in bodys)
{
var skinObj:DisplayObject3D = physics.getMesh(body);
if (skinObj == obj3D)
{
rigidBody = body;
break;
}
}
return rigidBody;
}

private function mousePressHandler(event:InteractiveScene3DEvent):void
{
trace("press");
//創立constraint
var startPos:JNumber3D = new JNumber3D(mouse3D.x, mouse3D.y, mouse3D.z);
currentBody = findBody(event.displayObject3D);
planeToDragOn = new Plane3D(new Number3D(0, 0, -1), new Number3D(0, 0, -startPos.z));

var bodyPoint:JNumber3D = JNumber3D.sub(startPos, currentBody.currentState.position);
dragConstraint = new JConstraintWorldPoint(currentBody, bodyPoint, startPos);
PhysicsSystem.getInstance().addConstraint(dragConstraint);

stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
}

private function mouseUpHandler(evnet:MouseEvent):void
{
if (dragConstraint)
{
PhysicsSystem.getInstance().removeConstraint(dragConstraint);
dragConstraint = null;
currentBody.setActive();
stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
}
}

private function mouseMoveHandler(event:MouseEvent):void
{
var ray:Number3D = camera.unproject(viewport.containerSprite.mouseX, viewport.containerSprite.mouseY);
ray = Number3D.add(ray, new Number3D(camera.x, camera.y, camera.z));

var cameraVertex3D:Vertex3D = new Vertex3D(camera.x, camera.y, camera.z);
var rayVertex3D:Vertex3D = new Vertex3D(ray.x, ray.y, ray.z);
var intersectPoint:Vertex3D = planeToDragOn.getIntersectionLine(cameraVertex3D, rayVertex3D);

dragConstraint.worldPosition = new JNumber3D(intersectPoint.x, intersectPoint.y, intersectPoint.z);
}

override protected function onRenderTick(event:Event=null):void
{
physics.step();
super.onRenderTick(event);
}
}
}

jiglibflash google code:http://code.google.com/p/jiglibflash/

0 意見 :: [練習]3D物理引擎 jiglibflash