概念性的描述
概述
- Ammo.js 使用Emscripten将 Bullet物理引擎 直接移植到JavaScript。源代码被直接翻译成JavaScript,未进行人工重写,因此功能与原始项目相同。
- Bullet Physics是一个开源的物理模拟引擎,世界三大物理引擎之一(另外两种是Havok和PhysX)。
ammo引擎相关示例资源查看
官方网址
基于ammon.js的演示应用程序基类和3D物理演示。支持多种场景图,包括Three.js和SceneJS
官网示例地址 -
http://schteppe.github.io/ammo.js-demos/
物理引擎在github上的地址 -
https://github.com/kripken/ammo.js/#readme
注:
- github地址下载的demo比ammo官网demo多一些
- 这是来自Bullet的HelloWorld.cpp,翻译成JavaScript。该目录中的其他示例可能也很有用。特别请参阅中的WebGL
示例演示目录 -ammo.js-main/examples
※ 下落的盒子 - ammo.js-main/examples/webgl_demo/ammo.wasm.html
※ 彩色的墙 - ammo.js-main/examples/webgl_demo_gimpact_chain/index.html
※ 柔软的布料 - ammo.js-main/examples/webgl_demo_softbody_cloth/index.html
※ 绳子 - ammo.js-main/examples/webgl_demo_softbody_rope/index.html
※ 网格体积 - ammo.js-main/examples/webgl_demo_softbody_volume2/index.html
- (渲染很卡)
※ 建立地形 - ammo.js-main/examples/webgl_demo_terrain/index.html
※ 射线测试 - ammo.js-main/examples/webgl_demo_test_ray/index.html
※ 小车移动 - ammo.js-main/examples/webgl_demo_vehicle/index.html
- 使用ammo引擎开发示例帖子地址 -
https://juejin.cn/post/6985033373857579045
- (推荐!)
-
一个3d球体在平台移动,涉及物理控制、移动端摇杆适配、场景内物品、交互镜头使用....
其他物理引擎
3D引擎
- cannon引擎官网地址 -
https://pmndrs.github.io/cannon-es/
2D引擎
- matter -
https://brm.io/matter-js/docs/
- p2 -
https://github.com/schteppe/p2.js#demos
物理引擎基本绑定流程
创建一个带物理属性的模型的流程
一些关键词说明
- mass -- 质量
- inertia -- 惯性
...
模型的物理形状
- 学习的文档来源:
http://www.dwenzhao.cn/profession/netbuild/ammoegine.html
物理模型的形状构成
- 球体形状
- 使用范围: 任何球体使用的例子
- 创建参数: 球体碰撞形状构造器,radius为球半径
Ammo.btSphereShape( ballRadius )
- 方法:
setMargin(margin) -- 设置碰撞形状边缘数
getMargin() -- 获取碰撞形状边缘数
getRadius( ) -- 获取球的半径
- 长方体形状
- 使用范围: 用于盒子、箱子等规则物体
- 创建参数: 构造器,boxHalfExtents表示立方体盒子的半区域
Ammo.btBoxShape(btVector3 boxHalfExtents)
- 方法:
setMargin(margin) -- 设置碰撞形状边缘数
getMargin() -- 获取碰撞形状边缘数
- 圆柱形状
- 使用范围: 杆、金币、石柱等都可以采用此类,但碰撞计算量较大,不如胶囊
- 创建参数: 圆柱对象构造器,halfExtents为圆柱的半区域,三维分量,第1和3维表示圆柱的长短半径,第2维是长度
Ammo.btCylinderShape(btVector3 halfExtents)
- 方法:
getRadius( ) -- 获取圆柱的半径
- 胶囊形状
- 使用范围: 碰撞计算量比圆柱小,旗杆、铅笔
- 创建参数: 胶囊碰撞形状对象构造器,参数radius为两端球面的半径,height为中间圆柱的长度
Ammo.btCapsuleShape(float radius, float height)
- 方法:
getRadius( ) -- 获取胶囊截面的半径
getHalfHeight( ) -- 获取中间圆柱部分长度值的一半
- 圆锥形状
- 使用范围: 碰撞计算量比圆柱小,旗杆、铅笔
- 创建参数: 圆锥碰撞形状对象构造器,参数radius为圆锥的半径,height为圆锥的高度
Ammo.btConeShape(float radius, float height)
- 方法:
getRadius( ) -- 获取胶囊截面的半径
- 复合形状
- 复合形状构造器
btCompoundShape()
- 方法:
//-- 向组合形状中添加子形状,localTransform为子形状的变换,shape为添加的子形状
addChildShape ( btTransform localTransform, btCollisionShape shape)
//-- 从组合形状中删除指定的子形状, childShapeindex为子形状索引
removeChildShape( childShapeindex)
//-- 获取当前组合形状中子形状的数量
getNumChildShapes()
//-- 获取组合形状中指定索引编号的子形状,index为子形状索引
getChildShape(index)
模型的物理属性配置以及受力方法
btRigidBody - 刚体 - 运动的方法
- 为刚体设置摩擦力
btRigidBody实例.setFriction(数字)
- 获取刚体的加速度
btRigidBody实例.getAngularVelocity()
- 刚体设置线速度 - 使物体朝着某个坐标线性运动过去
- 先坐标变化,再使用setLinearVelocity,移动物体过去
//-- 三维向量
const pos = new THREE.Vector3(1,1,1);
//-- 设置(x,y,z)、三维中每个值乘以14
pos.multiplyScalar( 14 );
btRigidBody实例.setLinearVelocity( new Ammo.btVector3( pos ) );
- 获取线速度
btRigidBody实例.getLinearVelocity()
线性速度实际使用过程中
- 为刚体添加摩擦力
- 通过Vector3上的copy方法,获取上一时刻的坐标信息,赋值给Vector3的实例pos
- 通过Vector3上的multiplyScalar方法,将pos坐标信息(x,y,z)乘以某个数值
- 通过给 刚体实例.setLinearVelocity( new Ammo.btVector3( pos.x, pos.y, pos.z ) ) 给刚体添加速度
- 通过getLinearVelocity查看实例的线性速度返回字符串格式为 -
{"hy":8466696}
- 通过getAngularVelocity获取了加速度,发现值略比getLinearVelocity大一点 -
{"hy":8466712}
- 添加一个外力 - 参数(应用的力, 施加力的位置 )
- 参照cannon物理引擎,从空间中的一个特殊点对刚体施加力(不一定在刚体的表面)
- 如: 自然中的风
btRigidBody实例.applyForce(btVector3格式作用力, btVector3格式坐标点)
- 添加一个刚体局部坐标系中的力
btRigidBody实例.applyCentralLocalForce(btVector3格式坐标点)
物理世界启动与渲染配置
物理世界启动
- 物理世界的类型
-
为了模拟不同材质的物体,物理世界也对应出了不同的分支
- 物理世界的配置
- 创建物理世界,需要传入不同参数,定制化其效果
- 刚体世界 示例代码:
//完全碰撞检测算法
let collisionConfiguration = new Ammo.btDefaultCollisionConfiguration();
// 重叠对/碰撞的调度计算
let dispatcher = new Ammo.btCollisionDispatcher(collisionConfiguration);
// 所有可能碰撞对的宽相位碰撞检测列表
let broadphase = new Ammo.btDbvtBroadphase();
// 使物体正确地交互,考虑重力、力、碰撞等
let solver = new Ammo.btSequentialImpulseConstraintSolver();
physicsWorld = new Ammo.btDiscreteDynamicsWorld( dispatcher, broadphase, solver, collisionConfiguration);
-
物理世界中 碰撞参数与物理世界之间的对应关系
| 碰撞算法 | 物理世界 |
| btDefaultCollisionConfiguration | btDiscreteDynamicsWorld |
| btSoftBodyRigidBodyCollisionConfiguration | btSoftRigidDynamicsWorld | 既支持刚体也支持软体的物理世界配置
基本代码:
//-- 物理世界变量
const gravityConstant = - 9.8;
//-- 启动物理世界
initPhysics();
function initPhysics() {
//-- 设置物理引擎的碰撞类型 - 软体与刚体碰撞
const collisionConfiguration = new Ammo.btSoftBodyRigidBodyCollisionConfiguration();
//-- dispatcher为碰撞检测算法分配器引用
const dispatcher = new Ammo.btCollisionDispatcher( collisionConfiguration );
//-- 为碰撞粗测算法接口
const broadphase = new Ammo.btDbvtBroadphase();
//-- 配置约束解决器 - (序列脉冲约束解决器)
//-- 使物体正确地交互,考虑重力、力、碰撞等
const solver = new Ammo.btSequentialImpulseConstraintSolver();
//-- 配置约束解决器 - (软体约束解决器)
const softBodySolver = new Ammo.btDefaultSoftBodySolver();
//-- 创建一个支持软体、刚体的物理世界
physicsWorld = new Ammo.btSoftRigidDynamicsWorld( dispatcher, broadphase, solver, collisionConfiguration, softBodySolver );
//-- 设置物理世界的重力
physicsWorld.setGravity( new Ammo.btVector3( 0, gravityConstant, 0 ) );
physicsWorld.getWorldInfo().set_m_gravity( new Ammo.btVector3( 0, gravityConstant, 0 ) );
}
物理世界的渲染
- 说明:
模型配置了物理碰撞属性,在物理世界里就拥有了运动轨迹,可以实时查看位置
*知识点:
获取运动状态信息:
通过btTransform类:变换类
该类由位置和方向组合而成,用来表示刚体的变换,如平移、旋转等通过刚体的getMotionState获取
刚体形状
getMotionState()
- 获取刚体的形状,返回值为获取的形状指针通过
刚体形状
的getWorldTransform( btTransform实例transformAux1 )获得最新的transformAux1信息通过transformAux1的getOrigin()获取网格模型的位置坐标
通过transformAux1的getRotation()获取网格模型的旋转角度
渲染网格的最新位置与渲染姿态
ms.getWorldTransform( transformAux1 );
const p = transformAux1.getOrigin();
const q = transformAux1.getRotation();
objThree.position.set( p.x(), p.y(), p.z() );
objThree.quaternion.set( q.x(), q.y(), q.z(), q.w() );
- 示例代码:
//-- 物理世界变量
const gravityConstant = - 9.8;
let transformAux1;
//-- 启动物理世界
initPhysics();
animate();
function initPhysics() {
...
//-- 创建一个支持软体、刚体的物理世界
physicsWorld = new Ammo.btSoftRigidDynamicsWorld( dispatcher, broadphase, solver, collisionConfiguration, softBodySolver );
//-- 设置物理世界的重力
physicsWorld.setGravity( new Ammo.btVector3( 0, gravityConstant, 0 ) );
physicsWorld.getWorldInfo().set_m_gravity( new Ammo.btVector3( 0, gravityConstant, 0 ) );
//-- 刚体运动监测对象
transformAux1 = new Ammo.btTransform();
}
//-- 添加网格模型,挂载物理外形到自定义属性physicsBody
function addRigidMass(){
...
//-- 创建一个与网格几何模型形状发相似的物理几何模型
const body = new Ammo.btRigidBody( rbInfo );
threeObject.userData.physicsBody = body;
...
//-- 添加网格模型到场景
scene.add( threeObject );
//-- 有质量的物体会参与碰撞,将其添加到一个数组rigidBodies中
//-- 源码中如果mass为0,则为地板类型刚体,不参与运动计算
if ( mass > 0 ) {
rigidBodies.push( threeObject );
}
//-- 添加物理模型到物理世界
physicsWorld.addRigidBody( body );
}
function animate() {
//-- 渲染
const deltaTime = clock.getDelta();
//-- 渲染物理世界
updatePhysics( deltaTime );
renderer.render( scene, camera );
requestAnimationFrame( animate );
}
function updatePhysics( deltaTime ) {
// Step world
physicsWorld.stepSimulation( deltaTime, 10 );
//-- rigidBodies为带有自定义属性
for ( let i = 0, il = rigidBodies.length; i < il; i ++ ) {
const objThree = rigidBodies[ i ];
const objPhys = objThree.userData.physicsBody;
//-- 通过物理模型,获取刚体的形状
const ms = objPhys.getMotionState();
if ( ms ) {
//-- 获取物理世界中的运动姿态
ms.getWorldTransform( transformAux1 );
const p = transformAux1.getOrigin();
const q = transformAux1.getRotation();
objThree.position.set( p.x(), p.y(), p.z() );
objThree.quaternion.set( q.x(), q.y(), q.z(), q.w() );
}
}
}
ammo.wasm.js待整理的方法
- set - 设置系列
* getLinearVelocity - 获取线性速度
* setLinearVelocity - 设置线性速度
* setLinearFactor - 设置线性系数
* getAngularVelocity - 获取角速度
* setAngularVelocity - 设置角速度
* setAngularFactor- 设置角度系数
* setCenterOfMassTransform - 设置质心变化
* setSleepingThresholds - ?
* setDamping - 设置阻尼
* setFriction - 设置摩擦力
* setRollingFriction - 设置滚动摩擦
* setAnisotropicFriction - 设置异性摩擦
* setMassProps - 设置道具质量
* setMotionState - 设置运动状态
* setGravity - 设置重力
* setContactProcessingThreshold - ?
* setActivationState - 设置激活状态
* setRestitution - ?
* setCollisionFlags - 设置碰撞标记
* setCollisionShape - 设置碰撞形状
* setWorldTransform - 设置世界变化
* setCcdMotionThreshold - ?
* setCcdSweptSphereRadius - ?
* setUserIndex - 设置使用者索引
* setUserPointer - 设置用户坐标
待学习
http://schteppe.github.io/ammo.js-demos/
- ammo引擎官方
https://juejin.cn/post/7200039970575941693
- 物理引擎差异文章( 优先看!!! )
https://juejin.cn/post/7095621578976657421
- 动画
https://www.cnblogs.com/lxiang/archive/2012/09/13/2683220.html
- ApplyForce、ApplyImpulse、SetLinearVelocity
https://pmndrs.github.io/cannon-es/docs/classes/Trimesh.html
- 模型添加碰撞形状
http://threejs.org/examples/index.html#physics_ammo_volume
- 官方示例软体模型与刚体模型
http://threejs.org/examples/physics_ammo_instancing.html
- 发射子弹与指定碰撞地点
http://threejs.org/examples/physics_ammo_break.html
- 物理属性
未完待续....