概念性的描述
概述
- Ammo.js 使用Emscripten將 Bullet物理引擎 直接移植到JavaScript。源代碼被直接翻譯成JavaScript,未進(jìn)行人工重寫,因此功能與原始項(xiàng)目相同。
- Bullet Physics是一個(gè)開源的物理模擬引擎,世界三大物理引擎之一(另外兩種是Havok和PhysX)。
ammo引擎相關(guān)示例資源查看
官方網(wǎng)址
基于ammon.js的演示應(yīng)用程序基類和3D物理演示。支持多種場(chǎng)景圖,包括Three.js和SceneJS
官網(wǎng)示例地址 -
http://schteppe.github.io/ammo.js-demos/物理引擎在github上的地址 -
https://github.com/kripken/ammo.js/#readme
注:
- github地址下載的demo比ammo官網(wǎng)demo多一些
- 這是來(lái)自Bullet的HelloWorld.cpp,翻譯成JavaScript。該目錄中的其他示例可能也很有用。特別請(qǐng)參閱中的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

※ 網(wǎng)格體積 - ammo.js-main/examples/webgl_demo_softbody_volume2/index.html - (渲染很卡)

※ 建立地形 - ammo.js-main/examples/webgl_demo_terrain/index.html

※ 射線測(cè)試 - ammo.js-main/examples/webgl_demo_test_ray/index.html

※ 小車移動(dòng) - ammo.js-main/examples/webgl_demo_vehicle/index.html

- 使用ammo引擎開發(fā)示例帖子地址 -
https://juejin.cn/post/6985033373857579045- (推薦!)
-
一個(gè)3d球體在平臺(tái)移動(dòng),涉及物理控制、移動(dòng)端搖桿適配、場(chǎng)景內(nèi)物品、交互鏡頭使用....
項(xiàng)目截圖
其他物理引擎
3D引擎
- cannon引擎官網(wǎng)地址 -
https://pmndrs.github.io/cannon-es/
2D引擎
- matter -
https://brm.io/matter-js/docs/ - p2 -
https://github.com/schteppe/p2.js#demos
物理引擎基本綁定流程
創(chuàng)建一個(gè)帶物理屬性的模型的流程

一些關(guān)鍵詞說(shuō)明
- mass -- 質(zhì)量
- inertia -- 慣性
...
模型的物理形狀
- 學(xué)習(xí)的文檔來(lái)源:
http://www.dwenzhao.cn/profession/netbuild/ammoegine.html
物理模型的形狀構(gòu)成
- 球體形狀
- 使用范圍: 任何球體使用的例子
- 創(chuàng)建參數(shù): 球體碰撞形狀構(gòu)造器,radius為球半徑
Ammo.btSphereShape( ballRadius )
- 方法:
setMargin(margin) -- 設(shè)置碰撞形狀邊緣數(shù)
getMargin() -- 獲取碰撞形狀邊緣數(shù)
getRadius( ) -- 獲取球的半徑
- 長(zhǎng)方體形狀
- 使用范圍: 用于盒子、箱子等規(guī)則物體
- 創(chuàng)建參數(shù): 構(gòu)造器,boxHalfExtents表示立方體盒子的半?yún)^(qū)域
Ammo.btBoxShape(btVector3 boxHalfExtents)
- 方法:
setMargin(margin) -- 設(shè)置碰撞形狀邊緣數(shù)
getMargin() -- 獲取碰撞形狀邊緣數(shù)
- 圓柱形狀
- 使用范圍: 桿、金幣、石柱等都可以采用此類,但碰撞計(jì)算量較大,不如膠囊
- 創(chuàng)建參數(shù): 圓柱對(duì)象構(gòu)造器,halfExtents為圓柱的半?yún)^(qū)域,三維分量,第1和3維表示圓柱的長(zhǎng)短半徑,第2維是長(zhǎng)度
Ammo.btCylinderShape(btVector3 halfExtents)
- 方法:
getRadius( ) -- 獲取圓柱的半徑
- 膠囊形狀
- 使用范圍: 碰撞計(jì)算量比圓柱小,旗桿、鉛筆
- 創(chuàng)建參數(shù): 膠囊碰撞形狀對(duì)象構(gòu)造器,參數(shù)radius為兩端球面的半徑,height為中間圓柱的長(zhǎng)度
Ammo.btCapsuleShape(float radius, float height)
- 方法:
getRadius( ) -- 獲取膠囊截面的半徑
getHalfHeight( ) -- 獲取中間圓柱部分長(zhǎng)度值的一半
- 圓錐形狀
- 使用范圍: 碰撞計(jì)算量比圓柱小,旗桿、鉛筆
- 創(chuàng)建參數(shù): 圓錐碰撞形狀對(duì)象構(gòu)造器,參數(shù)radius為圓錐的半徑,height為圓錐的高度
Ammo.btConeShape(float radius, float height)
- 方法:
getRadius( ) -- 獲取膠囊截面的半徑
- 復(fù)合形狀
- 復(fù)合形狀構(gòu)造器
btCompoundShape()
- 方法:
//-- 向組合形狀中添加子形狀,localTransform為子形狀的變換,shape為添加的子形狀
addChildShape ( btTransform localTransform, btCollisionShape shape)
//-- 從組合形狀中刪除指定的子形狀, childShapeindex為子形狀索引
removeChildShape( childShapeindex)
//-- 獲取當(dāng)前組合形狀中子形狀的數(shù)量
getNumChildShapes()
//-- 獲取組合形狀中指定索引編號(hào)的子形狀,index為子形狀索引
getChildShape(index)
模型的物理屬性配置以及受力方法
btRigidBody - 剛體 - 運(yùn)動(dòng)的方法
- 為剛體設(shè)置摩擦力
btRigidBody實(shí)例.setFriction(數(shù)字)
- 獲取剛體的加速度
btRigidBody實(shí)例.getAngularVelocity()
- 剛體設(shè)置線速度 - 使物體朝著某個(gè)坐標(biāo)線性運(yùn)動(dòng)過(guò)去
- 先坐標(biāo)變化,再使用setLinearVelocity,移動(dòng)物體過(guò)去
//-- 三維向量
const pos = new THREE.Vector3(1,1,1);
//-- 設(shè)置(x,y,z)、三維中每個(gè)值乘以14
pos.multiplyScalar( 14 );
btRigidBody實(shí)例.setLinearVelocity( new Ammo.btVector3( pos ) );
- 獲取線速度
btRigidBody實(shí)例.getLinearVelocity()
線性速度實(shí)際使用過(guò)程中
- 為剛體添加摩擦力
- 通過(guò)Vector3上的copy方法,獲取上一時(shí)刻的坐標(biāo)信息,賦值給Vector3的實(shí)例pos
- 通過(guò)Vector3上的multiplyScalar方法,將pos坐標(biāo)信息(x,y,z)乘以某個(gè)數(shù)值
- 通過(guò)給 剛體實(shí)例.setLinearVelocity( new Ammo.btVector3( pos.x, pos.y, pos.z ) ) 給剛體添加速度
- 通過(guò)getLinearVelocity查看實(shí)例的線性速度返回字符串格式為 -
{"hy":8466696} - 通過(guò)getAngularVelocity獲取了加速度,發(fā)現(xiàn)值略比getLinearVelocity大一點(diǎn) -
{"hy":8466712}
- 添加一個(gè)外力 - 參數(shù)(應(yīng)用的力, 施加力的位置 )
- 參照cannon物理引擎,從空間中的一個(gè)特殊點(diǎn)對(duì)剛體施加力(不一定在剛體的表面)
- 如: 自然中的風(fēng)
btRigidBody實(shí)例.applyForce(btVector3格式作用力, btVector3格式坐標(biāo)點(diǎn))
- 添加一個(gè)剛體局部坐標(biāo)系中的力
btRigidBody實(shí)例.applyCentralLocalForce(btVector3格式坐標(biāo)點(diǎn))
物理世界啟動(dòng)與渲染配置
物理世界啟動(dòng)
- 物理世界的類型
-
為了模擬不同材質(zhì)的物體,物理世界也對(duì)應(yīng)出了不同的分支
物理世界的種類構(gòu)成
- 物理世界的配置
- 創(chuàng)建物理世界,需要傳入不同參數(shù),定制化其效果
- 剛體世界 示例代碼:
//完全碰撞檢測(cè)算法
let collisionConfiguration = new Ammo.btDefaultCollisionConfiguration();
// 重疊對(duì)/碰撞的調(diào)度計(jì)算
let dispatcher = new Ammo.btCollisionDispatcher(collisionConfiguration);
// 所有可能碰撞對(duì)的寬相位碰撞檢測(cè)列表
let broadphase = new Ammo.btDbvtBroadphase();
// 使物體正確地交互,考慮重力、力、碰撞等
let solver = new Ammo.btSequentialImpulseConstraintSolver();
physicsWorld = new Ammo.btDiscreteDynamicsWorld( dispatcher, broadphase, solver, collisionConfiguration);

-
物理世界中 碰撞參數(shù)與物理世界之間的對(duì)應(yīng)關(guān)系
碰撞算法與物理世界
| 碰撞算法 | 物理世界 |
| btDefaultCollisionConfiguration | btDiscreteDynamicsWorld |
| btSoftBodyRigidBodyCollisionConfiguration | btSoftRigidDynamicsWorld | 既支持剛體也支持軟體的物理世界配置
基本代碼:
//-- 物理世界變量
const gravityConstant = - 9.8;
//-- 啟動(dòng)物理世界
initPhysics();
function initPhysics() {
//-- 設(shè)置物理引擎的碰撞類型 - 軟體與剛體碰撞
const collisionConfiguration = new Ammo.btSoftBodyRigidBodyCollisionConfiguration();
//-- dispatcher為碰撞檢測(cè)算法分配器引用
const dispatcher = new Ammo.btCollisionDispatcher( collisionConfiguration );
//-- 為碰撞粗測(cè)算法接口
const broadphase = new Ammo.btDbvtBroadphase();
//-- 配置約束解決器 - (序列脈沖約束解決器)
//-- 使物體正確地交互,考慮重力、力、碰撞等
const solver = new Ammo.btSequentialImpulseConstraintSolver();
//-- 配置約束解決器 - (軟體約束解決器)
const softBodySolver = new Ammo.btDefaultSoftBodySolver();
//-- 創(chuàng)建一個(gè)支持軟體、剛體的物理世界
physicsWorld = new Ammo.btSoftRigidDynamicsWorld( dispatcher, broadphase, solver, collisionConfiguration, softBodySolver );
//-- 設(shè)置物理世界的重力
physicsWorld.setGravity( new Ammo.btVector3( 0, gravityConstant, 0 ) );
physicsWorld.getWorldInfo().set_m_gravity( new Ammo.btVector3( 0, gravityConstant, 0 ) );
}
物理世界的渲染
- 說(shuō)明:
模型配置了物理碰撞屬性,在物理世界里就擁有了運(yùn)動(dòng)軌跡,可以實(shí)時(shí)查看位置
*知識(shí)點(diǎn):
獲取運(yùn)動(dòng)狀態(tài)信息:
通過(guò)btTransform類:變換類
該類由位置和方向組合而成,用來(lái)表示剛體的變換,如平移、旋轉(zhuǎn)等通過(guò)剛體的getMotionState獲取
剛體形狀
getMotionState()- 獲取剛體的形狀,返回值為獲取的形狀指針通過(guò)
剛體形狀的getWorldTransform( btTransform實(shí)例transformAux1 )獲得最新的transformAux1信息通過(guò)transformAux1的getOrigin()獲取網(wǎng)格模型的位置坐標(biāo)
通過(guò)transformAux1的getRotation()獲取網(wǎng)格模型的旋轉(zhuǎn)角度
渲染網(wǎng)格的最新位置與渲染姿態(tài)
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;
//-- 啟動(dòng)物理世界
initPhysics();
animate();
function initPhysics() {
...
//-- 創(chuàng)建一個(gè)支持軟體、剛體的物理世界
physicsWorld = new Ammo.btSoftRigidDynamicsWorld( dispatcher, broadphase, solver, collisionConfiguration, softBodySolver );
//-- 設(shè)置物理世界的重力
physicsWorld.setGravity( new Ammo.btVector3( 0, gravityConstant, 0 ) );
physicsWorld.getWorldInfo().set_m_gravity( new Ammo.btVector3( 0, gravityConstant, 0 ) );
//-- 剛體運(yùn)動(dòng)監(jiān)測(cè)對(duì)象
transformAux1 = new Ammo.btTransform();
}
//-- 添加網(wǎng)格模型,掛載物理外形到自定義屬性physicsBody
function addRigidMass(){
...
//-- 創(chuàng)建一個(gè)與網(wǎng)格幾何模型形狀發(fā)相似的物理幾何模型
const body = new Ammo.btRigidBody( rbInfo );
threeObject.userData.physicsBody = body;
...
//-- 添加網(wǎng)格模型到場(chǎng)景
scene.add( threeObject );
//-- 有質(zhì)量的物體會(huì)參與碰撞,將其添加到一個(gè)數(shù)組rigidBodies中
//-- 源碼中如果mass為0,則為地板類型剛體,不參與運(yùn)動(dòng)計(jì)算
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;
//-- 通過(guò)物理模型,獲取剛體的形狀
const ms = objPhys.getMotionState();
if ( ms ) {
//-- 獲取物理世界中的運(yùn)動(dòng)姿態(tài)
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 - 設(shè)置系列
* getLinearVelocity - 獲取線性速度
* setLinearVelocity - 設(shè)置線性速度
* setLinearFactor - 設(shè)置線性系數(shù)
* getAngularVelocity - 獲取角速度
* setAngularVelocity - 設(shè)置角速度
* setAngularFactor- 設(shè)置角度系數(shù)
* setCenterOfMassTransform - 設(shè)置質(zhì)心變化
* setSleepingThresholds - ?
* setDamping - 設(shè)置阻尼
* setFriction - 設(shè)置摩擦力
* setRollingFriction - 設(shè)置滾動(dòng)摩擦
* setAnisotropicFriction - 設(shè)置異性摩擦
* setMassProps - 設(shè)置道具質(zhì)量
* setMotionState - 設(shè)置運(yùn)動(dòng)狀態(tài)
* setGravity - 設(shè)置重力
* setContactProcessingThreshold - ?
* setActivationState - 設(shè)置激活狀態(tài)
* setRestitution - ?
* setCollisionFlags - 設(shè)置碰撞標(biāo)記
* setCollisionShape - 設(shè)置碰撞形狀
* setWorldTransform - 設(shè)置世界變化
* setCcdMotionThreshold - ?
* setCcdSweptSphereRadius - ?
* setUserIndex - 設(shè)置使用者索引
* setUserPointer - 設(shè)置用戶坐標(biāo)
待學(xué)習(xí)
http://schteppe.github.io/ammo.js-demos/ - ammo引擎官方
https://juejin.cn/post/7200039970575941693 - 物理引擎差異文章( 優(yōu)先看!!! )
https://juejin.cn/post/7095621578976657421 - 動(dòng)畫
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 - 發(fā)射子彈與指定碰撞地點(diǎn)
http://threejs.org/examples/physics_ammo_break.html - 物理屬性
未完待續(xù)....


