threejs 物理引擎ammo自學(xué)

概念性的描述

概述
  • 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

  1. 官網(wǎng)示例地址 - http://schteppe.github.io/ammo.js-demos/

  2. 物理引擎在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 - (渲染很卡)

網(wǎng)格體積

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

建立地形

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

射線測(cè)試

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

小車移動(dòng)

  1. 使用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è)帶物理屬性的模型的流程
ammo引擎 - 物理模型與圖形模型綁定 - 模型渲染更新
一些關(guān)鍵詞說(shuō)明
  • mass -- 質(zhì)量
  • inertia -- 慣性
    ...

模型的物理形狀

  • 學(xué)習(xí)的文檔來(lái)源: http://www.dwenzhao.cn/profession/netbuild/ammoegine.html
物理模型的形狀構(gòu)成
  1. 球體形狀
  • 使用范圍: 任何球體使用的例子
  • 創(chuàng)建參數(shù): 球體碰撞形狀構(gòu)造器,radius為球半徑
Ammo.btSphereShape( ballRadius )
  • 方法:
setMargin(margin) -- 設(shè)置碰撞形狀邊緣數(shù)
getMargin() -- 獲取碰撞形狀邊緣數(shù)
getRadius( ) -- 獲取球的半徑 
  1. 長(zhǎng)方體形狀
  • 使用范圍: 用于盒子、箱子等規(guī)則物體
  • 創(chuàng)建參數(shù): 構(gòu)造器,boxHalfExtents表示立方體盒子的半?yún)^(qū)域
Ammo.btBoxShape(btVector3 boxHalfExtents) 
  • 方法:
setMargin(margin)  -- 設(shè)置碰撞形狀邊緣數(shù)
getMargin()  -- 獲取碰撞形狀邊緣數(shù)
  1. 圓柱形狀
  • 使用范圍: 桿、金幣、石柱等都可以采用此類,但碰撞計(jì)算量較大,不如膠囊
  • 創(chuàng)建參數(shù): 圓柱對(duì)象構(gòu)造器,halfExtents為圓柱的半?yún)^(qū)域,三維分量,第1和3維表示圓柱的長(zhǎng)短半徑,第2維是長(zhǎng)度
Ammo.btCylinderShape(btVector3 halfExtents) 
  • 方法:
getRadius( )  -- 獲取圓柱的半徑
  1. 膠囊形狀
  • 使用范圍: 碰撞計(jì)算量比圓柱小,旗桿、鉛筆
  • 創(chuàng)建參數(shù): 膠囊碰撞形狀對(duì)象構(gòu)造器,參數(shù)radius為兩端球面的半徑,height為中間圓柱的長(zhǎng)度
Ammo.btCapsuleShape(float radius, float height) 
  • 方法:
getRadius( )  -- 獲取膠囊截面的半徑 
getHalfHeight( )  -- 獲取中間圓柱部分長(zhǎng)度值的一半 
  1. 圓錐形狀
  • 使用范圍: 碰撞計(jì)算量比圓柱小,旗桿、鉛筆
  • 創(chuàng)建參數(shù): 圓錐碰撞形狀對(duì)象構(gòu)造器,參數(shù)radius為圓錐的半徑,height為圓錐的高度
Ammo.btConeShape(float radius, float height) 
  • 方法:
getRadius( )  -- 獲取膠囊截面的半徑 
  1. 復(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)的方法
  1. 為剛體設(shè)置摩擦力
btRigidBody實(shí)例.setFriction(數(shù)字)
  1. 獲取剛體的加速度
btRigidBody實(shí)例.getAngularVelocity()
  1. 剛體設(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 ) );
  1. 獲取線速度
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}
  1. 添加一個(gè)外力 - 參數(shù)(應(yīng)用的力, 施加力的位置 )
  • 參照cannon物理引擎,從空間中的一個(gè)特殊點(diǎn)對(duì)剛體施加力(不一定在剛體的表面)
  • 如: 自然中的風(fēng)
btRigidBody實(shí)例.applyForce(btVector3格式作用力, btVector3格式坐標(biāo)點(diǎn))
  1. 添加一個(gè)剛體局部坐標(biāo)系中的力
btRigidBody實(shí)例.applyCentralLocalForce(btVector3格式坐標(biāo)點(diǎn))

物理世界啟動(dòng)與渲染配置

物理世界啟動(dòng)
  1. 物理世界的類型
  • 為了模擬不同材質(zhì)的物體,物理世界也對(duì)應(yīng)出了不同的分支


    物理世界的種類構(gòu)成
  1. 物理世界的配置
  • 創(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);
普通剛體物理世界
  1. 物理世界中 碰撞參數(shù)與物理世界之間的對(duì)應(yīng)關(guān)系


    碰撞算法與物理世界

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

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

//-- 物理世界變量
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待整理的方法

  1. 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ù)....

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容