threejs 物理引擎ammo自學

概念性的描述

概述
  • Ammo.js 使用Emscripten將 Bullet物理引擎 直接移植到JavaScript爱态。源代碼被直接翻譯成JavaScript秕岛,未進行人工重寫膘婶,因此功能與原始項目相同丸氛。
  • Bullet Physics是一個開源的物理模擬引擎,世界三大物理引擎之一(另外兩種是Havok和PhysX)井辜。
ammo引擎相關示例資源查看

官方網址
基于ammon.js的演示應用程序基類和3D物理演示绎谦。支持多種場景圖,包括Three.js和SceneJS

  1. 官網示例地址 - http://schteppe.github.io/ammo.js-demos/

  2. 物理引擎在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

小車移動

  1. 使用ammo引擎開發(fā)示例帖子地址 - 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

物理引擎基本綁定流程

創(chuàng)建一個帶物理屬性的模型的流程
ammo引擎 - 物理模型與圖形模型綁定 - 模型渲染更新
一些關鍵詞說明
  • mass -- 質量
  • inertia -- 慣性
    ...

模型的物理形狀

  • 學習的文檔來源: http://www.dwenzhao.cn/profession/netbuild/ammoegine.html
物理模型的形狀構成
  1. 球體形狀
  • 使用范圍: 任何球體使用的例子
  • 創(chuàng)建參數(shù): 球體碰撞形狀構造器纤怒,radius為球半徑
Ammo.btSphereShape( ballRadius )
  • 方法:
setMargin(margin) -- 設置碰撞形狀邊緣數(shù)
getMargin() -- 獲取碰撞形狀邊緣數(shù)
getRadius( ) -- 獲取球的半徑 
  1. 長方體形狀
  • 使用范圍: 用于盒子、箱子等規(guī)則物體
  • 創(chuàng)建參數(shù): 構造器破托,boxHalfExtents表示立方體盒子的半區(qū)域
Ammo.btBoxShape(btVector3 boxHalfExtents) 
  • 方法:
setMargin(margin)  -- 設置碰撞形狀邊緣數(shù)
getMargin()  -- 獲取碰撞形狀邊緣數(shù)
  1. 圓柱形狀
  • 使用范圍: 桿肪跋、金幣、石柱等都可以采用此類土砂,但碰撞計算量較大,不如膠囊
  • 創(chuàng)建參數(shù): 圓柱對象構造器谜洽,halfExtents為圓柱的半區(qū)域萝映,三維分量,第1和3維表示圓柱的長短半徑阐虚,第2維是長度
Ammo.btCylinderShape(btVector3 halfExtents) 
  • 方法:
getRadius( )  -- 獲取圓柱的半徑
  1. 膠囊形狀
  • 使用范圍: 碰撞計算量比圓柱小序臂,旗桿、鉛筆
  • 創(chuàng)建參數(shù): 膠囊碰撞形狀對象構造器实束,參數(shù)radius為兩端球面的半徑奥秆,height為中間圓柱的長度
Ammo.btCapsuleShape(float radius, float height) 
  • 方法:
getRadius( )  -- 獲取膠囊截面的半徑 
getHalfHeight( )  -- 獲取中間圓柱部分長度值的一半 
  1. 圓錐形狀
  • 使用范圍: 碰撞計算量比圓柱小,旗桿咸灿、鉛筆
  • 創(chuàng)建參數(shù): 圓錐碰撞形狀對象構造器,參數(shù)radius為圓錐的半徑,height為圓錐的高度
Ammo.btConeShape(float radius, float height) 
  • 方法:
getRadius( )  -- 獲取膠囊截面的半徑 
  1. 復合形狀
  • 復合形狀構造器
btCompoundShape() 
  • 方法:
//-- 向組合形狀中添加子形狀嚎花,localTransform為子形狀的變換龟再,shape為添加的子形狀
addChildShape ( btTransform localTransform, btCollisionShape shape)
//-- 從組合形狀中刪除指定的子形狀囊榜, childShapeindex為子形狀索引
removeChildShape( childShapeindex)
//-- 獲取當前組合形狀中子形狀的數(shù)量
getNumChildShapes()
//-- 獲取組合形狀中指定索引編號的子形狀,index為子形狀索引 
getChildShape(index)

模型的物理屬性配置以及受力方法

btRigidBody - 剛體 - 運動的方法
  1. 為剛體設置摩擦力
btRigidBody實例.setFriction(數(shù)字)
  1. 獲取剛體的加速度
btRigidBody實例.getAngularVelocity()
  1. 剛體設置線速度 - 使物體朝著某個坐標線性運動過去
  • 先坐標變化亥宿,再使用setLinearVelocity卸勺,移動物體過去
//-- 三維向量
const pos = new THREE.Vector3(1,1,1);
//-- 設置(x,y,z)、三維中每個值乘以14
pos.multiplyScalar( 14 );
btRigidBody實例.setLinearVelocity( new Ammo.btVector3( pos ) );
  1. 獲取線速度
btRigidBody實例.getLinearVelocity()

線性速度實際使用過程中

  • 為剛體添加摩擦力
  • 通過Vector3上的copy方法烫扼,獲取上一時刻的坐標信息曙求,賦值給Vector3的實例pos
  • 通過Vector3上的multiplyScalar方法,將pos坐標信息(x,y,z)乘以某個數(shù)值
  • 通過給 剛體實例.setLinearVelocity( new Ammo.btVector3( pos.x, pos.y, pos.z ) ) 給剛體添加速度
  • 通過getLinearVelocity查看實例的線性速度返回字符串格式為 - {"hy":8466696}
  • 通過getAngularVelocity獲取了加速度映企,發(fā)現(xiàn)值略比getLinearVelocity大一點 - {"hy":8466712}
  1. 添加一個外力 - 參數(shù)(應用的力, 施加力的位置 )
  • 參照cannon物理引擎悟狱,從空間中的一個特殊點對剛體施加力(不一定在剛體的表面)
  • 如: 自然中的風
btRigidBody實例.applyForce(btVector3格式作用力, btVector3格式坐標點)
  1. 添加一個剛體局部坐標系中的力
btRigidBody實例.applyCentralLocalForce(btVector3格式坐標點)

物理世界啟動與渲染配置

物理世界啟動
  1. 物理世界的類型
  • 為了模擬不同材質的物體,物理世界也對應出了不同的分支


    物理世界的種類構成
  1. 物理世界的配置
  • 創(chuàng)建物理世界卑吭,需要傳入不同參數(shù)芽淡,定制化其效果
  • 剛體世界 示例代碼:
//完全碰撞檢測算法
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);
普通剛體物理世界
  1. 物理世界中 碰撞參數(shù)與物理世界之間的對應關系


    碰撞算法與物理世界

    | 碰撞算法 | 物理世界 |
    | btDefaultCollisionConfiguration | btDiscreteDynamicsWorld |
    | btSoftBodyRigidBodyCollisionConfiguration | btSoftRigidDynamicsWorld |

  2. 既支持剛體也支持軟體的物理世界配置
    基本代碼:

//-- 物理世界變量
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();

        //-- 創(chuàng)建一個支持軟體、剛體的物理世界
    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 ) );
}
物理世界的渲染
  • 說明:
    模型配置了物理碰撞屬性抚岗,在物理世界里就擁有了運動軌跡或杠,可以實時查看位置

*知識點:

  • 獲取運動狀態(tài)信息:
    通過btTransform類:變換類
    該類由位置和方向組合而成,用來表示剛體的變換宣蔚,如平移向抢、旋轉等

  • 通過剛體的getMotionState獲取剛體形狀
    getMotionState() - 獲取剛體的形狀,返回值為獲取的形狀指針

  • 通過剛體形狀的getWorldTransform( btTransform實例transformAux1 )獲得最新的transformAux1信息

  • 通過transformAux1的getOrigin()獲取網格模型的位置坐標

  • 通過transformAux1的getRotation()獲取網格模型的旋轉角度

  • 渲染網格的最新位置與渲染姿態(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;

//-- 啟動物理世界
initPhysics();
animate();
function initPhysics() {
        ...
        //-- 創(chuàng)建一個支持軟體胚委、剛體的物理世界
    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 ) );

    //-- 剛體運動監(jiān)測對象
    transformAux1 = new Ammo.btTransform();
}

//-- 添加網格模型挟鸠,掛載物理外形到自定義屬性physicsBody
function addRigidMass(){
    ...
    //-- 創(chuàng)建一個與網格幾何模型形狀發(fā)相似的物理幾何模型
    const body = new Ammo.btRigidBody( rbInfo );
    threeObject.userData.physicsBody = body;
    ...
    //-- 添加網格模型到場景
    scene.add( threeObject );
    //-- 有質量的物體會參與碰撞,將其添加到一個數(shù)組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 ) {
            //-- 獲取物理世界中的運動姿態(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待整理的方法

  1. set - 設置系列
* getLinearVelocity - 獲取線性速度
* setLinearVelocity - 設置線性速度
* setLinearFactor - 設置線性系數(shù)
* getAngularVelocity - 獲取角速度
* setAngularVelocity - 設置角速度
* setAngularFactor- 設置角度系數(shù)
* setCenterOfMassTransform - 設置質心變化
* setSleepingThresholds - ?
* setDamping - 設置阻尼
* setFriction - 設置摩擦力
* setRollingFriction - 設置滾動摩擦
* setAnisotropicFriction - 設置異性摩擦
* setMassProps - 設置道具質量
* setMotionState - 設置運動狀態(tài)
* setGravity - 設置重力
* setContactProcessingThreshold - ?
* setActivationState - 設置激活狀態(tài)
* setRestitution - ?
* setCollisionFlags - 設置碰撞標記
* setCollisionShape - 設置碰撞形狀
* setWorldTransform - 設置世界變化
* setCcdMotionThreshold - ?
* setCcdSweptSphereRadius - ?
* setUserIndex - 設置使用者索引
* setUserPointer - 設置用戶坐標

待學習

http://schteppe.github.io/ammo.js-demos/ - ammo引擎官方
https://juejin.cn/post/7200039970575941693 - 物理引擎差異文章( 優(yōu)先看!!! )
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 - 發(fā)射子彈與指定碰撞地點
http://threejs.org/examples/physics_ammo_break.html - 物理屬性

未完待續(xù)....

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市营袜,隨后出現(xiàn)的幾起案子撒顿,更是在濱河造成了極大的恐慌,老刑警劉巖连茧,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件核蘸,死亡現(xiàn)場離奇詭異巍糯,居然都是意外死亡,警方通過查閱死者的電腦和手機客扎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門祟峦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人徙鱼,你說我怎么就攤上這事宅楞。” “怎么了袱吆?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵厌衙,是天一觀的道長。 經常有香客問我绞绒,道長婶希,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任蓬衡,我火速辦了婚禮喻杈,結果婚禮上,老公的妹妹穿的比我還像新娘狰晚。我一直安慰自己筒饰,他們只是感情好,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布壁晒。 她就那樣靜靜地躺著瓷们,像睡著了一般。 火紅的嫁衣襯著肌膚如雪秒咐。 梳的紋絲不亂的頭發(fā)上谬晕,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音携取,去河邊找鬼固蚤。 笑死,一個胖子當著我的面吹牛歹茶,可吹牛的內容都是我干的。 我是一名探鬼主播你弦,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼惊豺,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了禽作?” 一聲冷哼從身側響起尸昧,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎旷偿,沒想到半個月后烹俗,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體爆侣,經...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年幢妄,在試婚紗的時候發(fā)現(xiàn)自己被綠了兔仰。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡蕉鸳,死狀恐怖乎赴,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情潮尝,我是刑警寧澤榕吼,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站勉失,受9級特大地震影響羹蚣,放射性物質發(fā)生泄漏。R本人自食惡果不足惜乱凿,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一顽素、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧告匠,春花似錦戈抄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至戚哎,卻和暖如春裸诽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背型凳。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工丈冬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人甘畅。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓埂蕊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親疏唾。 傳聞我的和親對象是個殘疾皇子蓄氧,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內容