Away3D Bullet Physics 和MD2以及波浪

在Stage3D平台上,选择处理有关3D方面的内容时,Away3D是一把利器。Away3D对很多模型格式提供了强大的支持,并且它与其它的很多as3库可以很好的兼容。你会发现将Away3D和当前几大主流物理引擎(包括Bullet和JigLib,但不仅限于它们)联合起来会非常简单。Away3D利用它自己的接口然后通过Alchemy来使用C++,从而默认支持Bullet Physics。如果你对 JigLib 很熟悉的话,它通过一个相关插件的使用也可以支持Away3D。Bullet和JigLIb已经被广泛使用有一段时间了,并且它可以支持多种语言。它们允许开发人员给它们的模型添加物理现象,这就让我们创建竞赛类游戏,第一人称射击,弹珠游戏,发射愤怒的小鸟等等游戏成为可能。对开发人员来说,目前有很多可用的游戏引擎,例如Unity,Unreal Engine,Shivea,Cooper Cube,CubeEngine等等。这些引擎的功能都非常强大,使用它们,对于制作大多数的视频类游戏而言,根本没什么难度,虽然我很想知道这些引擎背后是怎么工作的。这些引擎除了CubeEngine和CooperCube之外,其它的价格都很昂贵。在这个demo里面,我将会给你演示如何去渲染一个MD2模型,使用三角形网格,利用一些基础的物理学知识,就可以创建一个波浪网格了,而不用使用纹理了。
看看这个三角形网格Demo  要花上几十秒来载入
    

获取游戏源代码
多重碰撞Demo
  • package
  • {
  •         //Away3D lib
  •         import away3d.animators.VertexAnimator;
  •         import away3d.cameras.Camera3D;
  •         import away3d.cameras.lenses.PerspectiveLens;
  •         import away3d.containers.ObjectContainer3D;
  •         import away3d.containers.View3D;
  •         import away3d.core.base.Object3D;
  •         import away3d.core.base.SubGeometry;
  •         import away3d.debug.AwayStats;
  •         import away3d.entities.Mesh;
  •         import away3d.events.AssetEvent;
  •         import away3d.events.LoaderEvent;
  •         import away3d.extrusions.Elevation;
  •         import away3d.extrusions.SkinExtrude;
  •         import away3d.library.AssetLibrary;
  •         import away3d.library.assets.AssetType;
  •         import away3d.lights.PointLight;
  •         import away3d.loaders.Loader3D;
  •         import away3d.loaders.misc.AssetLoaderContext;
  •         import away3d.loaders.parsers.MD2Parser;
  •         import away3d.loaders.parsers.OBJParser;
  •         import away3d.materials.BitmapFileMaterial;
  •         import away3d.materials.BitmapMaterial;
  •         import away3d.materials.ColorMaterial;
  •         import away3d.materials.DefaultMaterialBase;
  •         import away3d.materials.methods.EnvMapDiffuseMethod;
  •         import away3d.materials.methods.FogMethod;
  •         import away3d.materials.utils.CubeMap;
  •         import away3d.primitives.Cube;
  •         import away3d.primitives.Plane;
  •         import away3d.primitives.SkyBox;
  •         import away3d.primitives.Sphere;

  •         // physics lib 
  •         import awayphysics.collision.dispatch.AWPCollisionObject;
  •         import awayphysics.collision.shapes.*;
  •         import awayphysics.collision.shapes.AWPSphereShape;
  •         import awayphysics.data.AWPCollisionFlags;
  •         import awayphysics.debug.AWPDebugDraw;
  •         import awayphysics.dynamics.*;
  •         import awayphysics.dynamics.vehicle.*;
  •         import awayphysics.events.AWPEvent;

  •         import flash.display.Bitmap;
  •         import flash.display.BitmapData;
  •         import flash.display.Sprite;
  •         import flash.display.StageAlign;
  •         import flash.display.StageScaleMode;
  •         import flash.events.Event;
  •         import flash.events.KeyboardEvent;
  •         import flash.geom.Matrix3D;
  •         import flash.geom.Vector3D;
  •         import flash.net.URLRequest;
  •         import flash.ui.Keyboard;





  •         [SWF(width="1280", height="720", frameRate="60", backgroundColor="0x000000")]
  •         public class LoaderOBJTest extends Sprite
  •         {
  •                 private var _view : View3D;
  •                 private var _loader : Loader3D;
  •                 private var _light : PointLight;
  •                 private var _mesh : Mesh;
  •                 public var camera:Camera3D;
  •                 public var plane:Plane;
  •                 public var waveCycle:Number =5;
  •                 public var threeSixtyRads:Number = 360 * (Math.PI / 180);
  •                 private var _speed:Number = 1;
  •                 public var extrude:SkinExtrude;
  •                 private var isRenderable:Boolean = false;
  •                 [Embed(source="assets/shipwreck/water.jpg")] private var WaterImage:Class;
  •                 [Embed(source="assets/shipwreck/waterM.jpg")] private var WaterImageM:Class;
  •                 [Embed(source="assets/test/Ratamahatta.jpg")] private var Oger:Class;
  •                 private var oger:Bitmap = new Oger();
  •                 private var waterBitmap:Bitmap = new WaterImage();
  •                 private var waterBitmapM:Bitmap = new WaterImageM();
  •                 private var wave:Number = 0;
  •                 //private var _camController : HoverDragController;
  •                 private var _count : Number = 0;
  •                 protected static const MOVESPEED:Number = 100;
  •                 protected static const TURNSPEED:Number = 90;
  •                 protected var forward:Boolean = false;
  •                 protected var backward:Boolean = false;
  •                 protected var turnLeft:Boolean = false;
  •                 protected var turnRight:Boolean = false;
  •                 public var elevate:Elevation;
  •                 private var _cubeMap : CubeMap;
  •                 [Embed(source="assets/skybox/px.jpg")]
  •                 private var EnvPosX:Class;
  •                 [Embed(source="assets/skybox/py.jpg")]
  •                 private var EnvPosY:Class;
  •                 [Embed(source="assets/skybox/pz.jpg")]
  •                 private var EnvPosZ:Class;
  •                 [Embed(source="assets/skybox/nx.jpg")]
  •                 private var EnvNegX:Class;
  •                 [Embed(source="assets/skybox/ny.jpg")]
  •                 private var EnvNegY:Class;
  •                 [Embed(source="assets/skybox/nz.jpg")]
  •                 private var EnvNegZ:Class;

  •                 private var island:ObjectContainer3D;
  •                 private var mylight:PointLight;
  •                 private var _timeScale : Number = 3;
  •                 private var sphereContainer:ObjectContainer3D;
  •                 private var sphereCollider:Mesh;
  •                 private var physicsWorld : AWPDynamicsWorld;
  •                 private var debugDraw:AWPDebugDraw;
  •                 private var _sphereShape : AWPSphereShape;
  •                 public var sphereArr:Array = new Array();

  •                 // speed up or slow down physics
  •                 private var timeStep : Number = 0.2 / 60;
  •                 //private var timeStep : Number = 1 / 60;


  •                 public function LoaderOBJTest()
  •                 {
  •                         _view = new View3D();
  •                         _view.antiAlias = 4;
  •                         this.addChild(_view);
  •                         _light = new PointLight();
  •                         _light.x = 15000;
  •                         _light.z = 15000;
  •                         _light.color = 0xffddbb;
  •                         _view.scene.addChild(_light);
  •                         _view.camera.x = 800;
  •                         _view.camera.y = 220;
  •                         _view.camera.rotationY = -90;
  •                         _view.camera.z = 8;
  •                         camera = _view.camera;
  •                         camera.lens = new PerspectiveLens();
  •                         camera.lens.far = 5000;


  •                         addChild(new AwayStats(_view));
  •                         initMesh();

  •                         addEventListener(Event.ENTER_FRAME, onEnterFrame);
  •                         _view.mouseEnabled = true;
  •                         this.addEventListener(Event.ENTER_FRAME, handleEnterFrame);
  •                         this.stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
  •                         this.stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
  •                         stage.scaleMode = StageScaleMode.NO_SCALE;
  •                         stage.align = StageAlign.TOP_LEFT;
  •                         stage.addEventListener(Event.RESIZE, onStageResize);

  •                         _cubeMap = new CubeMap( new EnvPosX().bitmapData, new EnvNegX().bitmapData,
  •                                 new EnvPosY().bitmapData, new EnvNegY().bitmapData,
  •                                 new EnvPosZ().bitmapData, new EnvNegZ().bitmapData);

  •                         _view.scene.addChild(new SkyBox(_cubeMap));

  •                         var tex : BitmapData = new BitmapData(512, 512, false, 0);
  •                         tex.perlinNoise(25, 25, 8, 1, false, true, 7, true);
  •                         var fog : FogMethod = new FogMethod(1500, 0x808080);






  •                 }

  •                 private function onStageResize(event : Event) : void
  •                 {
  •                         _view.width = stage.stageWidth;
  •                         _view.height = stage.stageHeight;
  •                 }

  •                 private function initMesh() : void
  •                 {
  •                         Loader3D.enableParser(OBJParser);
  •                         _loader = new Loader3D();
  •                         _loader.load(new URLRequest('assets/shipwreck/shipwreck.obj'), new OBJParser());
  •                         _loader.addEventListener(LoaderEvent.RESOURCE_COMPLETE, onSceneResourceComplete);

  •                         var waterMaterial:BitmapMaterial = new BitmapMaterial(waterBitmap.bitmapData);
  •                         waterMaterial.bothSides = true;
  •                         plane = new Plane(waterMaterial, 7000, 7000, 100, 100);
  •                         plane.y = 135;
  •                         plane.rotationX = 90;
  •                         plane.segmentsW = 100;
  •                         plane.segmentsH = 100;

  •                         // init the physics world
  •                         physicsWorld = AWPDynamicsWorld.getInstance();
  •                         physicsWorld.initWithDbvtBroadphase();
  •                         physicsWorld.collisionCallbackOn = true;


  •                         _view.scene.addChild(plane);


  •                 }

  •                 private function onAssetRetrieved(event : AssetEvent) : void
  •                 {
  •                         if (event.asset.assetType == AssetType.MESH) {
  •                                 var pmaterial : DefaultMaterialBase;


  •                                 _mesh = Mesh(event.asset);
  •                                 _mesh.scaleX = 0.4;
  •                                 _mesh.scaleY = 0.4;
  •                                 _mesh.scaleZ = 0.4;
  •                                 _mesh.y = 185;
  •                                 _mesh.x = 65;
  •                                 _mesh.z = 8;
  •                                 _view.scene.addChild(_mesh);

  •                                 pmaterial = DefaultMaterialBase(_mesh.material);
  •                                 var ogerMaterial:BitmapMaterial = new BitmapMaterial(new Oger().bitmapData);
  •                                 _mesh.material = ogerMaterial;


  •                         }
  •                         else if (event.asset.assetType == AssetType.ANIMATOR) {
  •                                 var controller : VertexAnimator = VertexAnimator(event.asset);
  •                                 controller.play("stand");
  •                                 controller.timeScale = _timeScale;
  •                         }
  •                         //debugDraw = new AWPDebugDraw(_view, physicsWorld); 
  •                         //debugDraw.debugMode = AWPDebugDraw.DBG_DrawCollisionShapes;

  •                 }

  •                 private function onSceneResourceComplete(event : LoaderEvent) : void
  •                 {
  •                         island=ObjectContainer3D(event.target);

  •                         island.y = -180;
  •                         island.scaleX = 2;
  •                         island.scaleY = 2;
  •                         island.scaleZ = 2;
  •                         var mesh:Mesh=Mesh(island.getChildAt(0));
  •                         _view.scene.addChild(island);

  •                         mylight = new PointLight();
  •                         _view.scene.addChild(mylight);
  •                         mylight.color = 0xffffff;
  •                         mylight.y = 2000;
  •                         mylight.z = -1000;

  •                         var materia:ColorMaterial = new ColorMaterial(0xeeee00);
  •                         materia.lights=[mylight];
  •                         materia.bothSides = true;
  •                         var sceneShape : AWPBvhTriangleMeshShape = new AWPBvhTriangleMeshShape(mesh.geometry);
  •                         var sceneBody : AWPRigidBody = new AWPRigidBody(sceneShape, mesh, 0);

  •                         // you can debug the collision event below
  •                         sceneBody.addEventListener(AWPEvent.COLLISION_ADDED, worldCollisionAdded);
  •                         physicsWorld.addRigidBody(sceneBody);

  •                         //create rigid bogies
  •                         //loop through and try different tests 
  •                         for(var i:int = 0; i < 1; i++){

  •                                 /*_sphereShape = new AWPSphereShape(40);
  •                                 var sphere : Sphere = new Sphere(materia, 40);
  •                                 sphere.position = camera.position;

  •                                 var body : AWPRigidBody = new AWPRigidBody(_sphereShape, sphere, 2);
  •                                 //body.position = camera.position;                
  •                                 body.ccdSweptSphereRadius = 0.5;
  •                                 body.ccdMotionThreshold = 0.5;
  •                                 body.gravity = new Vector3D(0.005, 0.005, 0.005, 0.005);
  •                                 sphereArr[i] = body;
  •                                 body.position = camera.position;
  •                                 body.x = -140; //- 10  + (i*5);
  •                                 body.y = 400;
  •                                 body.z =  (i * 10 + 80) + 100;


  •                                 _view.scene.addChild(sphere);
  •                                 //body.addEventListener(AWPEvent.COLLISION_ADDED, worldCollisionAdded);
  •                                 physicsWorld.addRigidBody(sphereArr[i]);*/

  •                                 var boxShape : AWPBoxShape = new AWPBoxShape(600, 600, 600);
  •                                 var cube:Cube = new Cube(materia, 200, 200, 200);

  •                                 var body:AWPRigidBody = new AWPRigidBody(boxShape, cube, 1);
  •                                 body.friction = .9;
  •                                 //body.position = new Vector3D(-140, 500, (i * 10 + 80) + 100);
  •                                 body.x = -140; //- 10  + (i*5);
  •                                 body.y = 800;
  •                                 body.z =  (i * 10 + 80) + 100;
  •                                 _view.scene.addChild(cube);
  •                                 physicsWorld.addRigidBody(body);



  •                                 //trace(body.position.x);
  •                                 //trace(camera.position.x);
  •                         }



  •                         AssetLibrary.enableParser(MD2Parser);
  •                         AssetLibrary.addEventListener(AssetEvent.ASSET_COMPLETE, onAssetRetrieved);
  •                         AssetLibrary.load(new URLRequest('assets/test/tris.md2'));

  •                 }

  •                 private function worldCollisionAdded(event : AWPEvent) : void {
  •                         trace(event);
  •                 }

  •                 private function keyDownHandler(event:KeyboardEvent):void {
  •                         if (event.keyCode == 38)
  •                         {
  •                                 this.forward = true;
  •                         }
  •                         else if (event.keyCode == 40)
  •                         {
  •                                 this.backward = true;
  •                         }
  •                         else if (event.keyCode == 39)
  •                         {
  •                                 this.turnRight = true;
  •                         }
  •                         else if (event.keyCode == 37)
  •                         {
  •                                 this.turnLeft = true;
  •                         }

  •                 }

  •                 private function keyUpHandler(event:KeyboardEvent):void {
  •                         if (event.keyCode == 38)
  •                         {
  •                                 this.forward = false;
  •                         }
  •                         else if (event.keyCode == 40)
  •                         {
  •                                 this.backward = false;
  •                         }
  •                         else if (event.keyCode == 39)
  •                         {
  •                                 this.turnRight = false;
  •                         }
  •                         else if (event.keyCode == 37)
  •                         {
  •                                 this.turnLeft = false;
  •                         }

  •                 }

  •                 private function incrementWave():void {
  •                         waveCycle += _speed; // angle in radians
  •                         var v:Vector.<Number> = SubGeometry(plane.geometry.subGeometries[0]).vertexData;
  •                         var i:int;
  •                         // manipulate the Z component of each vertex
  •                         for (i = 2; i < v.length; i += 3) {
  •                                 // multiply by the sine of the x coordinate, plus offset for animation (normalized to be 0-360 degrees)
  •                                 v[i] = Math.sin(((v[i - 2] + waveCycle) / 100) * (threeSixtyRads * 1) )  * 2;
  •                                 // add harmonic from Y frequency
  •                                 v[i] += Math.sin(((v[i - 1] + waveCycle) / 100) * (threeSixtyRads * 1) )  * 1;
  •                         }

  •                         SubGeometry(plane.geometry.subGeometries[0].updateVertexData(v));

  •                 }

  •                 private function handleEnterFrame(e : Event) : void
  •                 {        


  •                         incrementWave();

  •                         if (this.forward)
  •                                 _view.camera.moveForward(MOVESPEED * .05);
  •                         else if (this.backward)
  •                                 _view.camera.moveBackward(MOVESPEED * .05);

  •                         if (this.turnLeft)
  •                                 _view.camera.rotationY -= TURNSPEED * .05;
  •                         else if (this.turnRight)
  •                                 _view.camera.rotationY += TURNSPEED * .05;


  •                                 isRenderable = true;



  •                 }                

  •                 private function onEnterFrame(ev : Event) : void
  •                 {
  •                         _count += .003;
  •                         _light.x = Math.sin(_count) * 150000;
  •                         _light.y = 1000;
  •                         _light.z = Math.cos(_count) * 150000;
  •                         physicsWorld.step(timeStep);
  •                         try{
  •                         //debugDraw.debugDrawWorld();
  •                         }catch(e:Error){

  •                                 trace(e);
  •                         }
  •                         _view.render();
  •                 }
  •         }
  • }
复制代码
你会发现三角形网格用在地形以及其它复杂的几何体上会体现出完美的效果。你可以把这个demo当做一个预先的压力测试。让我们对浏览器狠一点吧,donkey punch it,让它以一个很高的帧速做极值计算。如果你看unity 博客文档的话,你将会看到他们对多边形计数的建议。

Unity的对多边形计算的建议:
你应该使用多少个多边形取决于你所要求的质量以及你所选择的平台。在移动平台上,300到1500这之间的任何一个数值可以选作三角形的个数,而在桌面平台上你可以选择500到6000之间的任何一个数值。如果你想在屏幕上显示更多的人物角色或者想让你的游戏能在老的机子上运行,那么你将要为每一个角色减少相应的多边形数量。举个例子:Half  Life 2中的人物角色每一个角色使用了数值在2500到5000之间这么多个三角形。在PS3或者Xbox 360 上运行的Next-gen  AAA游戏一般每个人物角色使用5000到7000个三角形。- http://unity3d.com/support/documentation/printable.html

iPhone上的Stage3D的FTIC Demos(这里的视频由于找了好久,一直显示不出来,所以这里给出地址,大家自己去看吧!)
视频地址: http://www.youtube.com/embed/c1w_5ghL91o

上面的听起来可能像是使用了很多的三角形,但是当你进行开发的时候你可以很快学会使用它们。我们将先特意不管多边形的计数。这样我们就可以真正地看到他的运行原理。所以简而言之,这个demo可能不是在每个浏览器中都能运行的很完美。现在所有你可以看到的就是一个demo,这个demo基于一个alpha软件以及一个来自adobe的测试版的sdk。这些都是不断变化的。所以这是前沿技术而不是最前沿技术。你可以设置重力,碰撞等等。有一件事你要铭记在心,那就是即使这个demo是应用在web上的,谁说你不能对它进行稍微的修改,通过AIR来让它运行在移动设备上呢?AIR支持Stage3D,所以如果你想花点时间的话,你可以收集一个基于这个代码例子的第一人称射击或者一个弹珠类游戏。我也将马上给你展示怎样通过 threeJS 来使用JigLib和Bullet( AmmoJS )。这个项目中的代码将会告诉你怎么样去利用JigLib和Bullet。我也通过将代码放到github上来使大家能更便捷地使用这些代码,所以如果你把这些代码当做模板,那么你可以用它来做任何你想做的东西。
我也想说明几个案例分析。我喜欢专注于一些在安卓系统上运行的新的3d多人角色扮演类游戏。案例一是由dvidearts开发的 Earth and Legend 。这个角色扮演游戏是一个真正的有趣的互动角色扮演游戏,这个游戏让我想起了Fable。如果你站在技术立场上来观察它的话,除了一些明显的东西之外,你还可以发现一些内在的东西。明显的部分是成为了移动设备上的一款出色的游戏,聪明地使用了android游戏资源API,吸引人的任务,高度的实用性与充满乐趣的游戏设置相结合,还有漂亮的游戏场景。内在的部分是下列的场景用法,很少的多边形数,聪明的模型创建。DvideArts对场景进行了拆分,这样的话每个场景就会有几个动态的怪物出现。场景中的拆分用到了加载器。这些加载器展现给使用者的是一张精细的图,在这同时加载器在后台进行 垃圾回收 。也要注意摄像机/用户玩家,在主窗口中他们不能有一个超过大约180度的视角。这个策略帮助他们克服了在视窗中对复杂几何图形以及纹理使用的需要,同时节省了实时渲染时间。他们的树木很少带有分支以及地形(三角形网格的多边形计数很低)。这就给游戏提供了一个精心制作的游戏场景,并且你可以使用高帧速来制作一个优秀的游戏。你的模型要是动态的。考虑到那些住院病人作为玩家,你也应该通过一个UI来增加物理效果。就我自己而言,,我喜欢他们的用户控件,使用一个虚拟的操纵杆来进行旋转并且让UI来控制场景的方向。为了能正确地完成这些功能,最后你将必须开发出不同的工具以及了解设备的限制。为了准确地知道任何一个限制,你将要将限制放到你的工具中进行测试,看哪种工具可以正常运行。

我曾注意到用于JigLib和Bullet上的三角形网格可能会出现一点点错误。记住尽管使用一个更大的多边形计数以及一个更紧凑的网格可能可以解决这个问题,但是这样做会增加场景资源消耗以及内存消耗。Away3D团队在支持Bullet上下了很大的功夫,也就有了现在的Away3D了。bullet库可以很好地支持Away3D,而适用于threeJS  jiglib的库相对于ammoJS而言是有争议的。

你怎样才能使用这些代码呢?如果你想尽你可能地对这些代码进行改进,那么这非常好。创建一个容器,然后让一个MD2模型成为它的一个子对象。 容器 用于碰撞是非常棒的,尽管你可以访问到三角形网格,你不会用它来实现你的MD2模型碰撞,你将会很少使用它,因为它有点资源大户的味道但事实上它也确实是这样,因为它保存着你的应用程序每一秒的计算的数值。我不久将会演示相类似的例子。

Stage3D对开发者而言是非常棒的。我们可以使用我们熟悉的工具,并且喜欢快速创建移动应用程序。说实在的,为什么开发人员在意Flash Player支持移动设备吗?我们怎么在web上快速地赚钱?我个人宁愿创建一个应用程序,这个应用程序被下载了100,000次,并且它要价$99。Adobe的新版AIR非常棒,它增加了很多的3d的东西,这就使得开发应用程序变得更简单了。这也需要你用时间来考虑 启动平台 ,因为它将可以转换成很多的应用程序类型然后你就可以对这个应用程序进行改进,学习这些代码例子。这些代码例子很有帮助哦!

两篇优秀的有关物理学的Stage3D参考文献:
http://blog.muzerly.com/
http://savagelook.com/blog/

引擎:

http://www.ambiera.com/coppercube/
http://unity3d.com/
http://www.stonetrip.com/
http://www.unrealengine.com/
http://cubeengine.com/



链接:

http://www.fitc.ca/  -> its for the cool kids
https://github.com/away3d/away3d-core-fp11
https://github.com/away3d/awayphysics-core-fp11
http://www.jiglibflash.com/blog/
http://blog.muzerly.com/?tag=jiglib  
http://www.youtube.com/watch?v=c1w_5ghL91o&hd=1
http://flashdaily.net/post/13740 ... -content-running-on  
http://labs.adobe.com/technologies/airlaunchpad/
https://www.youtube.com/watch?v= ... ure=player_embedded
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值