JavaScript 的物理引擎对比

点击有惊喜


在本文中,我们将对比看一下当前三个非常流行的和一个目前还在开发中的JavaScript 物理引擎库,分别是: box2dweb,Ammo.js,JigLibJS 以及 Connon.js。我们会简短的介绍下每个 JS库,之后开始按照使用、性能和特征来评分。

不过运行其中任意一个库文件都是不带任何可视化效果的,这样很无趣,因此我们会设置一个小的环境来查看这些模拟运行的结果。由于 Three.js 的流行和使用简易,我使用它和它的 CanvasRenderer 来呈现结果。除了可以展示物体是如何交互的,Three.js 还可以提取出每个库中的场景信息。这里的场景由滑到地面的坡道组成;会有小球从以上场景中的任意位置上掉落到坡道上,再滑到地面上。

设置

我们的基础场景中使用了两个滑到地面的坡道。小球会从坡道上方的任意位置掉落,向下滚动,之后滚动到地面上。这个简单的场景可以高亮出这四个库文件的相似处和不同处。

[javascript] view plain copy
var viewport = document.getElementById( 'viewport' ), // The canvas element we're going to use 
renderer = new THREE.CanvasRenderer({ canvas: viewport }), // Create the renderer 
scene = new THREE.Scene, // Create the scene 
camera = new THREE.PerspectiveCamera( 35, 1, 1, 1000 );

renderer.setSize( viewport.clientWidth, viewport.clientHeight );

camera.position.set( -10, 30, -200 ); 
camera.lookAt( scene.position ); // Look at the center of the scene 
scene.add( camera );

function addLights() {

var ambientLight = new THREE.AmbientLight( 0x555555 );  
scene.add( ambientLight );  

var directionalLight = new THREE.DirectionalLight( 0xffffff );  
directionalLight.position.set( -.5, .5, -1.5 ).normalize();  
scene.add( directionalLight );  

}

function buildScene() {

var ramp_geometry= new THREE.CubeGeometry( 50, 2, 10 ),  
    material_red = new THREE.MeshLambertMaterial({ color: 0xdd0000, overdraw: true }),  
    material_green = new THREE.MeshLambertMaterial({ color: 0x00bb00, overdraw: true });  
  
var ramp_1 = new THREE.Mesh( ramp_geometry, material_red );  
ramp_1.position.set( -20, 25, 0 );  
ramp_1.rotation.z = -Math.PI / 28;  
scene.add( ramp_1 );  
  
var ramp_2 = new THREE.Mesh( ramp_geometry, material_red );  
ramp_2.position.set( 25, 5, 0 );  
ramp_2.rotation.z = Math.PI / 16;  
scene.add( ramp_2 );  
  
var floor = new THREE.Mesh(  
    new THREE.PlaneGeometry( 100, 50 ),  
    material_red  
);  
floor.position.y = -15;  
scene.add( floor );  

}

addLights(); 
buildScene(); 
renderer.render( scene, camera ); 
jsfiddle View: http://jsfiddle.net/chandlerprall/CXxH4/light/

box2dweb

box2dweb 是 C++ box2d 项目的一个分支,它在这次对比的4个库文件中独特之处在于它只能模拟二维场景。它所有的类都是命名空间的形式,这让代码有些难以阅读,所以建议创建你经常使用的本地变量。不要傻傻的认为 box2dweb 只能呈现 2D 的模拟就很弱了;它拥有的简单的 API 却蕴含了巨大的能量。box2dweb 拥有一个完整的约束机制(被称为连接器),它可以检测更多精确迅速移动的物体之间的连续碰撞,对于全部场景和独立对象都有许多配置选项。

使用 box2dweb 配合 b2ContactListener 检测碰撞非常简单。你可以单独使用4个碰撞状态的事件处理程序:BeginContact,EndContact,PreSolve和PostSolve。你也能够通过迭代world中每一步之后的接触列表来检测碰撞。
[javascript] view plain copy
var contactListener = new Box2D.Dynamics.b2ContactListener; 
contactListener.BeginContact = function( contact_details ) {

// `contact_details` can be used to determine which two  
// objects collided and in what way  

}; 
world.SetContactListener(contactListener);

连接器可以以不同的方式来约束对象,可以让目标进行类似铰链和滑动的单方向动作,以及模拟贴附到绳子上的运动。另外还有其他许多种类的配置。要让连接器按照你想要的方式工作,我们需要一点点测试,一旦你找到诀窍之后想要操作和增加新的joints就变得非常非常快。作为示例,我们创建一个公转的连接器,通俗的说法就是一个铰链。box2dweb 中所有连接器有两个部分组成,并且在 world 中都有一个位置。不过摩擦连接器只需要一个部分。获取更多可用连接器和不同配置选项的细节可以查看Box2D 手册或者在线的 Box2D 连接器教程。
[javascript] view plain copy
var body_a = world.CreateBody( bodyDef_A ).CreateFixture( fixDef ); 
var body_b = world.CreateBody( bodyDef_B ).CreateFixture( fixDef ); 
var jointDef = new Box2D.Dynamics.Joints.b2RevoluteJointDef; 
jointDef.Initialize(

body_a.GetBody(),           // Body A  
body_b.GetBody(),           // Body B  
body_b.GetBody().GetWorldCenter() // Anchor location in world   
        // coordinates,in this case it's the center of body B  

); 
var joint = world.CreateJoint( jointDef );

最后想要看到 box2dweb 演示还需要一个步骤:在一步模拟之后如何更新你的场景,例如在游戏中更新一个图形。Javascript 中的 world 对象有一个可以返回场景中第一个目标的方法,被称作 GetBodyList。利用GetBody后你可以重复调用body.getNext() 直到GetNext方法返回null,这样可以处理场景中剩下的目标。正如你所见到每一个部分,你可以更新关联的图像对象或者其他任何你需要关联的。你还可以使用对象定义的 userData 属性在你创建对象的时候附加到每一个对象中。userData 通常包含了几何目标的位置和简单旋转的参考。

概述:

性能:我从见过box2dweb 场景运行缓慢,除非设置不佳。反而是游戏逻辑和实际图像渲染通常是对 FPS 的影响最大。
特色:Box2D 永远不会用来做3D 的工作,因为大多数“缺少”的特性其实并不是缺少,它们就是不在 3D 环境下运行生效而已。如果你只在二维的环境,这个库应该拥有你需要的一切。
可用性:API非常简单,虽然有时候在命名空间的不同部分里想要找到一些对象有点困难。而且 Box2D 的手册也不太透彻,因为你需要通过flash节点的文档来查找以及在网上搜索具体的主题文档。
总结:这是一个不需要复杂设置就能够使用的强大引擎,也没有学习的弯路。如果你只需要二维的物理引擎,你只要选择 box2dweb。
浏览器支持:Chrome,Firefox,IE9,Safari,Opera

[javascript] view plain copy
// Create some local variables for convenience 
var state = false, // true when the simulation is running

  
b2Vec2 = Box2D.Common.Math.b2Vec2,  
    b2BodyDef = Box2D.Dynamics.b2BodyDef,  
    b2Body = Box2D.Dynamics.b2Body,  
    b2FixtureDef = Box2D.Dynamics.b2FixtureDef,  
    b2Fixture = Box2D.Dynamics.b2Fixture,  
    b2World = Box2D.Dynamics.b2World,  
    b2MassData = Box2D.Collision.Shapes.b2MassData,  
    b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape,  
    b2CircleShape = Box2D.Collision.Shapes.b2CircleShape,  
    b2DebugDraw = Box2D.Dynamics.b2DebugDraw,  
      
viewport = document.getElementById( 'viewport' ), // The canvas element we're going to use  
  
// If your computer supports it, switch to the WebGLRenderer for a much smoother experience  
// most of the lag and jittering you see in the simulation is from the CanvasRenderer, not the physics  
renderer = new THREE.CanvasRenderer({ canvas: viewport }), // Create the renderer  
//renderer = new THREE.WebGLRenderer({ canvas: viewport }), // Create the renderer  
  
scene = new THREE.Scene, // Create the scene  
camera = new THREE.PerspectiveCamera( 35, 1, 1, 1000 ),  
  
ball_geometry = new THREE.SphereGeometry( 3 ), // Create the ball geometry with a radius of `3`  
ball_material = new THREE.MeshLambertMaterial({ color: 0x0000ff, overdraw: true }), // Balls will be blue  
  
large_ball_geometry = new THREE.SphereGeometry( 4 ), // Create the ball geometry with a radius of `4`  
large_ball_material = new THREE.MeshLambertMaterial({ color: 0x00ff00, overdraw: true }), // Large balls are be green  
  
time_last_run, // used to calculate simulation delta  
  
world, // This will hold the box2dweb objects  
bodyDef = new b2BodyDef, // `bodyDef` will describe the type of bodies we're creating  
  
// Create a fixture definition  
//  `density` represents kilograms per meter squared.  
//        a denser object will have greater mass  
//    `friction` describes the friction between two objects  
//    `restitution` is how much "bounce" an object will have  
//        "0.0" is no restitution, "1.0" means the object won't lose velocity  
fixDef = new b2FixtureDef;  

点击有惊喜


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值