最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

Three.js 進(jìn)階之旅:物理效果-碰撞和聲音

2023-06-29 22:00 作者:unlexx  | 我要投稿


聲明:本文涉及圖文和模型素材僅用于個(gè)人學(xué)習(xí)、研究和欣賞,請(qǐng)勿二次修改、非法傳播、轉(zhuǎn)載、出版、商用、及進(jìn)行其他獲利行為。


摘要

本文內(nèi)容主要匯總?cè)绾卧?Three.js?創(chuàng)建的?3D?世界中添加物理效果,使其更加真實(shí)。所謂物理效果指的是對(duì)象會(huì)有重力,它們可以相互碰撞,施加力之后可以移動(dòng),而且通過(guò)鉸鏈和滑塊還可以在移動(dòng)過(guò)程中在對(duì)象上施加約束。?通過(guò)本文的閱讀,你將學(xué)習(xí)到如何使用?Cannon.js?在?Three.js?中創(chuàng)建一個(gè)?3D?物理世界,并在物理世界更新對(duì)象、聯(lián)系材質(zhì)、施加外力、處理多個(gè)物體中添加物體之間的碰撞效果,通過(guò)檢測(cè)碰撞激烈程度來(lái)添加撞擊聲音等。



效果

本文最終將實(shí)現(xiàn)如下所示的效果,點(diǎn)擊?DAT.GUI?中創(chuàng)建立方體????和球體????的按鈕,對(duì)應(yīng)的物體將在擁有重力的三維世界中墜落,物體與地面及物體與物體之間發(fā)生碰撞時(shí)可以產(chǎn)生與碰撞強(qiáng)度匹配的撞擊音頻???,點(diǎn)擊重置按鈕,創(chuàng)建的物體將被清除。

打開(kāi)以下鏈接,在線預(yù)覽效果,大屏訪問(wèn)效果更佳。

  • ??????在線預(yù)覽地址:https://dragonir.github.io/physics-cannon

本專欄系列代碼托管在?Github?倉(cāng)庫(kù)【threejs-odessey】,后續(xù)所有目錄也都將在此倉(cāng)庫(kù)中更新。

???代碼倉(cāng)庫(kù)地址:git@github.com:dragonir/threejs-odessey.git


原理

在專欄之前的原理和示例學(xué)習(xí)中,我們已經(jīng)可以使用光照、陰影、Raycaster?等特性生成一些簡(jiǎn)單的物理效果,但是如果需要實(shí)現(xiàn)像物體張力、摩擦力、拉伸、反彈等物理效果時(shí),我們可以使用一些專業(yè)的物理特性開(kāi)源庫(kù)來(lái)實(shí)現(xiàn)。

為了實(shí)現(xiàn)物理效果,我們將在?Three.js?中創(chuàng)建一個(gè)物理世界,它純粹是理論性質(zhì)的,我們無(wú)法直接看到它,但是在其中,三維物體將產(chǎn)生掉落、碰撞、摩擦、滑動(dòng)等物理特性。具體原理是當(dāng)我們?cè)?Three.js?中創(chuàng)建一個(gè)網(wǎng)格模型時(shí),同時(shí)會(huì)將其添加到物理世界中,在每一幀渲染任何內(nèi)容之前我們會(huì)告訴物理世界如何自行更新,然后我們將獲取物理世界中更新的位移和旋轉(zhuǎn)坐標(biāo)數(shù)據(jù),將其應(yīng)用到?Three.js?三維網(wǎng)格中。

庫(kù)

已經(jīng)有很多功能完備的物理特性庫(kù),我們就沒(méi)必要重復(fù)造輪子了。物理特性庫(kù)可以分為?2D?庫(kù)和?3D?庫(kù),雖然我們是使用?Three.js?開(kāi)發(fā)三維功能,但是有些?2D庫(kù)?在三維世界中同樣是適用的而且它們的性能會(huì)更好,如果我們需要開(kāi)發(fā)的物理功能是碰撞類的,則可以使用?2D?庫(kù),比如Ouigo Let's play就是一個(gè)使用?2D?庫(kù)開(kāi)發(fā)的優(yōu)秀示例。下面是一些常用的物理特性庫(kù)。

對(duì)于?3D?物理庫(kù),主要有以下三個(gè):

  • Ammo.js

  • 官網(wǎng):http://schteppe.github.io/ammo.js-demos/

  • 倉(cāng)庫(kù):https://github.com/kripken/ammo.js/

  • 文檔:https://github.com/kripken/ammo.js/#readme

  • Bullet?一個(gè)使用?C++?編寫(xiě)的物理引擎的?JavaScript?直接移植

  • 包比較重量級(jí),當(dāng)前仍然由社區(qū)更新維護(hù)

  • Cannon.js

  • 官網(wǎng):https://schteppe.github.io/cannon.js/

  • 倉(cāng)庫(kù):https://github.com/schteppe/cannon.js

  • 文檔:http://schteppe.github.io/cannon.js/docs/

  • 比?Ammo.js?更加輕量級(jí),使用起來(lái)更舒服

  • 主要由一個(gè)開(kāi)發(fā)者維護(hù),已經(jīng)多年未更新,有一個(gè)維護(hù)的?fork?是?cannon-es

  • Oimo.js

  • 官網(wǎng):https://lo-th.github.io/Oimo.js/

  • 倉(cāng)庫(kù):https://github.com/lo-th/Oimo.js

  • 文檔:http://lo-th.github.io/Oimo.js/docs.html

  • 比?Ammo.js?輕量且更容易入手

  • 主要由一個(gè)開(kāi)發(fā)者維護(hù),已經(jīng)有兩年沒(méi)有更新

對(duì)于?2D?物理庫(kù),有很多,下面列出了比較流行的幾個(gè):

  • Matter.js

  • 官網(wǎng):https://brm.io/matter-js/

  • 倉(cāng)庫(kù):https://github.com/liabru/matter-js

  • 文檔:https://brm.io/matter-js/docs/

  • 主要由一個(gè)開(kāi)發(fā)者維護(hù),目前仍在更新中

  • P2.js

  • 官網(wǎng):https://schteppe.github.io/p2.js/

  • 倉(cāng)庫(kù):https://github.com/schteppe/p2.js

  • 文檔:http://schteppe.github.io/p2.js/docs/

  • 主要由一個(gè)開(kāi)發(fā)者維護(hù),已經(jīng)有2年沒(méi)有更新

  • Planck.js

  • 官網(wǎng):https://piqnt.com/planck.js/

  • 倉(cāng)庫(kù):https://github.com/shakiba/planck.js

  • 文檔:https://github.com/shakiba/planck.js/tree/master/docs

  • 主要由一個(gè)開(kāi)發(fā)者維護(hù),目前仍在更新中

  • Box2D.js

  • 官網(wǎng):http://kripken.github.io/box2d.js/demo/webgl/box2d.html

  • 倉(cāng)庫(kù):https://github.com/kripken/box2d.js/

  • 文檔:無(wú)

  • 主要由一個(gè)開(kāi)發(fā)者維護(hù),目前仍在更新中

本文內(nèi)容及示例將使用?Cannon.js?庫(kù),因?yàn)樗菀桌斫夂褪褂?,?duì)于其他庫(kù),使用原理基本上是一樣的,大家感興趣的話可以自行嘗試。

Cannon.js

Cannon.js?是一個(gè)?3D?物理引擎,通過(guò)為物體賦予真實(shí)的物理屬性的方式來(lái)計(jì)算運(yùn)動(dòng)、旋轉(zhuǎn)和碰撞檢測(cè)。Cannon.js?相較于其他常見(jiàn)的物理引擎來(lái)說(shuō),比較輕量級(jí)而且完全通過(guò)?JavaScript?來(lái)實(shí)現(xiàn)。主要有以下特性:

  • 剛體動(dòng)力學(xué)

  • 離散碰撞檢測(cè)

  • 接觸、摩擦和恢復(fù)

  • 點(diǎn)到點(diǎn)約束、鉸鏈約束、鎖緊裝置約束等

  • Gauss-Seidel?約束求解器與孤島分割算法

  • 碰撞過(guò)濾

  • 剛體休眠

  • 實(shí)驗(yàn)性?SPH?流體支持

  • 各種形狀和碰撞算法

Cannon-es

Cannon.js?庫(kù)已經(jīng)多年沒(méi)有更新了,但是另一庫(kù)?Cannon-es?克隆了原倉(cāng)庫(kù)并致力于長(zhǎng)期更新維護(hù)新的倉(cāng)庫(kù),可以像下面這樣安裝并使用,Cannon-es?用法和?Cannon.js?用法是完全一致的。

  • Git?倉(cāng)庫(kù):https://github.com/pmndrs/cannon-es

  • NPM?地址:https://www.npmjs.com/package/cannon-es



實(shí)現(xiàn)

???本文示例及相關(guān)教程翻譯并整理自?three.js journey?相關(guān)課程。

開(kāi)始

安裝并引入



初始化場(chǎng)景是一個(gè)平面????和一個(gè)球體???,為了更好觀察物理特性,已經(jīng)開(kāi)啟了陰影效果。

我們可以使用?WebGL?創(chuàng)建一個(gè)無(wú)重力的太空?qǐng)鼍?,但是為了模擬地球環(huán)境????,就需要添加重力,在?Cannon.js?中可以通過(guò)修改?gravity?屬性值來(lái)實(shí)現(xiàn),它是一個(gè)?Cannon.js Vec3?值,和?Three.js?中的?Vector3?一樣,它包含?x、yz?屬性且擁有一個(gè)?set(...)?方法



我們使用?-9.82?作為重力的?y?值,是因?yàn)樗?strong>地球的重力系數(shù),如果你想讓物理墜落的更慢或者想創(chuàng)建一個(gè)火星重力環(huán)境????,就可以把它改為其他數(shù)值。

基礎(chǔ)

世界

首先,我們需要?jiǎng)?chuàng)建一個(gè)?Cannon.js?世界:



對(duì)象

我們?cè)趫?chǎng)景中已經(jīng)創(chuàng)建了一個(gè)球體,現(xiàn)在來(lái)在?Cannon.js?世界中創(chuàng)建一個(gè)球體。為了實(shí)現(xiàn)它,我們首先必須創(chuàng)建一個(gè)剛體Body,剛體是一種簡(jiǎn)單的對(duì)象,可以墜落和其他剛體產(chǎn)生碰撞。創(chuàng)建剛提前,我們首先需要決定剛體的形狀,有很多形狀可選,比如?Box、Cylinder、Plane?等,我們創(chuàng)建一個(gè)和?Three.js?中球體相同半徑的球狀剛體



然后,創(chuàng)建一個(gè)初始化?mass?質(zhì)量及?position?位置的?Body?剛體:



最后,我們通過(guò)?addBody(...)?方法將創(chuàng)建的剛體添加到世界中:



此時(shí)查看頁(yè)面可以看到?jīng)]有任何效果,我們還需要更新?Cannon.js?世界和?Three.js?球體坐標(biāo)。為更新物理世界world,我們必須使用時(shí)間步長(zhǎng)step(...)方法。

更新

現(xiàn)在需要實(shí)現(xiàn)更新?Cannon.js?世界和?Three.js?場(chǎng)景。此時(shí)我們需要使用?step(...)?方法,為了使其生效,必須提供一個(gè)固定時(shí)間步長(zhǎng)、自上次調(diào)用函數(shù)以來(lái)經(jīng)過(guò)的時(shí)間、以及每個(gè)函數(shù)調(diào)用可執(zhí)行的最大固定步驟數(shù)作為參數(shù)。



  • dt:固定時(shí)間戳,要使用的固定時(shí)間步長(zhǎng)

  • [timeSinceLastCalled]:自上次調(diào)用函數(shù)以來(lái)經(jīng)過(guò)的時(shí)間

  • [maxSubSteps=10]:每個(gè)函數(shù)調(diào)用可執(zhí)行的最大固定步驟數(shù)

???關(guān)于時(shí)間步長(zhǎng)原理,可查看此文章

在動(dòng)畫(huà)函數(shù)中,我們希望以?60fps?運(yùn)行,因此將第一個(gè)參數(shù)設(shè)置為?1/60,這個(gè)設(shè)置在更高或更低幀率的情況下都能以相同速度運(yùn)行;對(duì)于第二個(gè)參數(shù),我們需要計(jì)算自上一幀以來(lái)經(jīng)過(guò)了多少時(shí)間,通過(guò)將前一幀的?elapsedTime?減去當(dāng)前?elapsedTime?來(lái)獲得,不要直接使用?Clock?類中的?getDelta()?方法,因?yàn)闊o(wú)法得到預(yù)期的結(jié)果還會(huì)弄亂內(nèi)部邏輯;第三個(gè)迭代參數(shù),可以隨便設(shè)置一個(gè)值,運(yùn)行體驗(yàn)是否絲滑并不重要。



此時(shí)查看頁(yè)面,看起來(lái)仍然沒(méi)有變化,但實(shí)際上物理世界中的球體剛體?sphereBody?正在不斷下墜,可以通過(guò)如下的打印日志????可以觀察到。


現(xiàn)在我們需要使用物理世界的?sphereBody?剛體坐標(biāo)來(lái)更新?Three.js?中的球體,可以使用如下兩種方法實(shí)現(xiàn)該功能:



???copy方法在 Vector2、Vector3、Euler、Quaternion 甚至 Material、Object3D、Geometry 等類中都是可用的。

此時(shí)就能看到小球????墜落的效果,但是它直接穿過(guò)了地面,因?yàn)楝F(xiàn)在僅在?Three.js?場(chǎng)景中添加了地面,而沒(méi)有在?Cannon.js?物理世界中創(chuàng)建地面的剛體。

現(xiàn)在我們使用平面形狀?Plane?來(lái)創(chuàng)建地面剛體,地面不應(yīng)該受到物理世界重力的影響而下沉,它應(yīng)該是保持靜止不動(dòng)的,我們可以通過(guò)如下方法將?mass?設(shè)置為?0?來(lái)實(shí)現(xiàn):


此時(shí)你會(huì)發(fā)現(xiàn)小球????墜落的方向變了,并不是我們預(yù)期的結(jié)果,它應(yīng)該落到地面上。因?yàn)槲锢硎澜缰刑砑拥钠矫媸敲嫦蛳鄼C(jī)????的,我們需要像在?Three.js?中旋轉(zhuǎn)平面一樣對(duì)它進(jìn)行旋轉(zhuǎn)。在?Cannon.js?中,我們只能使用四元數(shù)?Quaternion?來(lái)對(duì)剛體進(jìn)行旋轉(zhuǎn),可以通過(guò)?setFromAxisAngle(...)?方法:

  • 第一個(gè)參數(shù)是旋轉(zhuǎn)軸

  • 第二個(gè)參數(shù)是角度

現(xiàn)在可以看到小球????從高處下落并且停在地面上,因?yàn)榈孛媸庆o止不動(dòng)的,因此我們不需要使用?Cannon.js?中的地面來(lái)更新?Three.js?中的地面。

聯(lián)系材質(zhì)

從上圖可以觀察到,小球????墜落到地面后并沒(méi)有反復(fù)彈跳,我們可以通過(guò)修改設(shè)置?Cannon.js?中的?Material?和?ContactMaterial?來(lái)添加摩擦和彈跳效果。

一個(gè)?Material?僅僅是一個(gè)類,你可以用它創(chuàng)建一種材質(zhì)并命名后將它關(guān)聯(lián)到?Body?剛體上,對(duì)于場(chǎng)景中所有的材質(zhì),都可以通過(guò)此方法進(jìn)行創(chuàng)建。比如,假設(shè)世界中的所有物體都是塑料材質(zhì)的,此時(shí)你只需創(chuàng)建一種材質(zhì)即可,可以將它命名為?default?或?plastic;如果場(chǎng)景中地面和小球是不同材質(zhì)的,就需要根據(jù)它們的類型創(chuàng)建多種材質(zhì)。下面我們?yōu)槭纠械膬深愇矬w分別創(chuàng)建名為混凝土?concrete?和 塑料?plastic?的材質(zhì):



接下來(lái),我們使用創(chuàng)建的兩種材質(zhì)來(lái)創(chuàng)建聯(lián)系材質(zhì)?ContactMaterial,它是兩種材質(zhì)的組合,包含對(duì)象碰撞時(shí)的屬性。然后使用?addContactMaterial(...)?方法將它添加到世界中:



  • 前兩個(gè)參數(shù)是材質(zhì)

  • 第三個(gè)參數(shù)是碰撞屬性對(duì)象,包含摩擦系數(shù)和恢復(fù)系數(shù),兩者的默認(rèn)值均為?0.3

接著我們將創(chuàng)建好的?Material?應(yīng)用到?Body?上,可以在實(shí)例化主體時(shí)直接傳遞材質(zhì),也可以在實(shí)例化之后使用材質(zhì)屬性傳遞材質(zhì)?,F(xiàn)在可以看到小球????下落后在停止之前會(huì)返回彈跳多次:


場(chǎng)景中一般會(huì)有多種材質(zhì)?Materials?的物體,為每種兩兩組合創(chuàng)建?ContactMaterial?會(huì)費(fèi)時(shí)費(fèi)解,為了簡(jiǎn)化這一操作,我們來(lái)使用一種默認(rèn)材質(zhì)來(lái)替換創(chuàng)建聯(lián)系材質(zhì)時(shí)的兩種材質(zhì),并將它應(yīng)用到所有剛體上:


可以觀察到效果是相同的?;蛘呶覀冎苯釉O(shè)置世界的默認(rèn)聯(lián)系材質(zhì)defaultContactMaterial?屬性,然后移除?sphereBody?和?floorBody?的?material?屬性,這樣世界中的所有材質(zhì)就都是相同的默認(rèn)材質(zhì)。



施加外力

對(duì)一個(gè)剛體?Body?有以下幾種施加外力的方法:

  • applyForce(force, worldPoint):從空間中的一個(gè)特殊點(diǎn)對(duì)剛體施加力(不一定在剛體的表面),比如就像風(fēng)推動(dòng)所有物體一樣,或微弱但突然的力推向多米諾骨牌,或者像強(qiáng)烈且突然的力把憤怒的小鳥(niǎo)推向城堡一樣。

  • force:力的大小?Vec3

  • worldPoint:施加力的世界點(diǎn)?Vec3

  • applyImpulse:類似于?applyForce,但它不是因?yàn)樵黾訉?dǎo)致加速度改變,而是直接作用于加速度。

  • applyLocalForce(force, localPoint):與?applyForce?相同,但是坐標(biāo)系是剛體的局部坐標(biāo),即?(0, 0, 0)?將是剛體的中點(diǎn),從物體的內(nèi)部施力。

  • force:要應(yīng)用的力向量?Vec3

  • localPoint:剛體中中要施加力的局部點(diǎn)?Vec3

  • applyLocalImpulse:與?applyImpulse?相同,但是坐標(biāo)系是剛體的局部坐標(biāo),即從物體的內(nèi)部施力。

現(xiàn)在我們使用?applyLocalForce(...)?來(lái)為小球剛體?sphereBody?開(kāi)始時(shí)施加一個(gè)小沖擊力:



可以看到小球????向右彈跳并滾動(dòng)。

現(xiàn)在我們使用?applyForce(...)?方法來(lái)施加一點(diǎn)風(fēng)力????,因?yàn)轱L(fēng)是永久性的,因此在更新?World?之前,我們需要將這種力施加到每一幀。要正確應(yīng)用此力,受力點(diǎn)應(yīng)該是小球的位置?sphereBody.position


處理多個(gè)物體

對(duì)一個(gè)或兩個(gè)物體添加物理效果比較簡(jiǎn)單,但是為很多個(gè)物體都按上述方法添加就會(huì)非常復(fù)雜,我們需要添加一個(gè)自動(dòng)化處理方法。

自動(dòng)處理函數(shù)

首先,移除或注釋掉?Cannon.js?世界和?Three.js?中的球體,還有動(dòng)畫(huà)函數(shù)?tick()?中球體的設(shè)置,然后創(chuàng)建一個(gè)?createSphere?方法來(lái)生成小球:



接著使用如下方法來(lái)創(chuàng)建一個(gè)小球????,其中?position?參數(shù)不必是?Three.js?中的?Vector3?或者?Cannon.js?中的?Vec3,只需使用?x, y ,z?即可:



可以看到地面頂部的創(chuàng)建的小球,但是由于我們移除了將?Cannon.js?世界中小球的?position?拷貝到?Three.js?中的方法,現(xiàn)在的小球暫時(shí)沒(méi)有物理下墜效果

使用一個(gè)對(duì)象數(shù)組

為了使批量創(chuàng)建的小球得到更新,我們使用一個(gè)數(shù)組?objectsToUpdate?在創(chuàng)建函數(shù)中保存它們:



然后在動(dòng)畫(huà)方法?tick()?中批量將小球的?body.position?拷貝到?mesh.position



此時(shí),批量創(chuàng)建的小球????也有物理效果了。

添加Dat.GUI

為了方便調(diào)試,我們給頁(yè)面按如下方式添加?Dat.GUI?調(diào)試工具,并添加一個(gè)?createSphere?來(lái)在場(chǎng)景中創(chuàng)建多個(gè)小球:


優(yōu)化

因?yàn)?Three.js?網(wǎng)格?Mesh?的?geometry?和?material?都是一樣的,我們應(yīng)該將其移出?createSphere?方法,由于我們使用?radius?來(lái)創(chuàng)建幾何體的,為了兼容之前的方法,我們可以按如下方式將?SphereGeometry?半徑設(shè)置為?1,并使用?scale?來(lái)調(diào)整幾何體的大小,得到的結(jié)果和上面是一致的,但是性能得以提升



添加立方體

現(xiàn)在我們使用相同的流程添加一個(gè)創(chuàng)建立方體????的方法?createBox,其中傳入的參數(shù)將是?width,height,depth,position。需要注意的是,Cannon.js?中創(chuàng)建Box?與?Three.js?創(chuàng)建?Box?不同,在?Three.js?中,創(chuàng)建幾何體BoxBufferGeometry?只需要直接提供立方體的寬高深就行,但是在Cannon.js中,它是根據(jù)立方體對(duì)角線距離的一半來(lái)計(jì)算生成形狀,因此其寬高深必須乘以0.5。



先移除創(chuàng)建小球的方法,頁(yè)面運(yùn)行可以得到如下的結(jié)果:

現(xiàn)在可以創(chuàng)建隨機(jī)的立方體了,但是看起來(lái)有點(diǎn)奇怪不太逼真是不是?因?yàn)榱⒎襟w掉下來(lái)后沒(méi)有翻轉(zhuǎn),原因是?Three.js?中的網(wǎng)格沒(méi)有像?Cannon.js?中的剛體一樣旋轉(zhuǎn),在球體的示例中我們沒(méi)有發(fā)現(xiàn)是因?yàn)闊o(wú)論球體是否旋轉(zhuǎn)都是和原來(lái)一樣的,而在立方體中不一樣。我們可以通過(guò)如下將剛體的?quaternion?屬性拷貝到網(wǎng)格的?quaternion?屬性來(lái)實(shí)現(xiàn),就像之前拷貝位置屬性?position?一樣:



現(xiàn)在立方體????墜落時(shí)的旋轉(zhuǎn)也正常了。


性能優(yōu)化

Broadphase ?

測(cè)試物體之間的碰撞時(shí),一種方法是檢測(cè)一個(gè)剛體與另外所有其他剛體之間的碰撞,雖然這一操作很容易實(shí)現(xiàn),但是非常耗費(fèi)性能。此時(shí)就需要?Broadphase,它會(huì)在測(cè)試之前對(duì)剛體進(jìn)行粗略的分類,想象一下,兩堆相距很遠(yuǎn)的立方體,為什么要用一堆立方體來(lái)測(cè)試另一堆立方體之間的碰撞關(guān)系能,它們相距很遠(yuǎn),不會(huì)發(fā)生碰撞,因此就沒(méi)必要測(cè)試來(lái)耗費(fèi)性能。

在?Cannon.js?中共有?3?種?Broadphase?算法:

  • NaiveBroadphase:測(cè)試每個(gè)剛體與其他所有剛體之間的碰撞,默認(rèn)算法。

  • GridBroadphase: 使用四邊形柵格覆蓋?world,僅針對(duì)同一柵格或相鄰柵格中的其他剛體進(jìn)行碰撞測(cè)試。

  • SAPBroadphase:掃描剪枝算法,在多個(gè)步驟的任意軸上測(cè)試剛體。

NaiveBroadphase?是默認(rèn)檢測(cè)方法,但是推薦使用?SAPBroadphase?算法,雖然這種算法有時(shí)可能會(huì)產(chǎn)生檢測(cè)不會(huì)發(fā)生碰撞的錯(cuò)誤,但是它的檢測(cè)速度非???。通過(guò)如下方式,簡(jiǎn)單設(shè)置?world.broadphase?屬性即可修改碰撞檢測(cè)算法:



Sleep ??

即使我們使用改進(jìn)的?Broadphase?碰撞檢測(cè)算法,有可能所有的剛體都會(huì)被檢測(cè),即使是那些不再發(fā)生移動(dòng)的剛體。此時(shí)我們可以使用稱為?Sleep?的特性,當(dāng)剛體的速度逐漸變小不再發(fā)生移動(dòng),它就會(huì)進(jìn)入睡眠狀態(tài),此時(shí)就不會(huì)對(duì)它進(jìn)行碰撞檢測(cè),除非使用代碼讓其施加一個(gè)足夠的力再次運(yùn)動(dòng)或有其它的剛體擊中它??梢酝ㄟ^(guò)對(duì)?world?設(shè)置?allowSleep?屬性為?true?來(lái)實(shí)現(xiàn):



你也可以使用?sleepSpeedLimitsleepTimeLimit?屬性對(duì)睡眠速度和時(shí)間進(jìn)行詳細(xì)設(shè)置,但是一般不會(huì)改變默認(rèn)值。

事件

可以對(duì)剛體的事件進(jìn)行監(jiān)聽(tīng),比如你想在物體發(fā)生碰撞時(shí)播放呻吟或者在射擊游戲中檢測(cè)是否命中敵人等情況下是非常有用的。你可以在剛體上監(jiān)聽(tīng)?colidesleep、wakeup?等事件。

現(xiàn)在,我們來(lái)實(shí)現(xiàn)一下當(dāng)場(chǎng)景中的小球????和立方體????互相之間發(fā)生碰撞時(shí)播放聲音????的功能。首先在?JavaScript?中創(chuàng)建音頻,并添加一個(gè)方法來(lái)播放它。

???有些瀏覽器比如?Chrome?默認(rèn)會(huì)靜音????除非用戶與頁(yè)面發(fā)生交互,例如點(diǎn)擊任意區(qū)域,所以不要擔(dān)心首次加載時(shí)不播放聲音的問(wèn)題


然后在創(chuàng)建立方體方法?createBox?中調(diào)用:


此時(shí),當(dāng)立方體????撞擊到地面或相互碰撞時(shí)可以聽(tīng)到撞擊聲音???,看起來(lái)似乎是正確的,但是當(dāng)添加多個(gè)立方體時(shí),我們會(huì)聽(tīng)到很多立方體之間相互撞擊的聲音是一樣的,而現(xiàn)實(shí)中的聲音應(yīng)該是根據(jù)聲音隨著立方體之間的撞擊程度而不同,撞擊程度足夠小的話就聽(tīng)不到聲音。為了獲取撞擊的強(qiáng)度,我們需要獲取撞擊信息,可以通過(guò)如下給?playHitSound?方法添加參數(shù)?collision?的方式來(lái)獲取撞擊信息:



然后在創(chuàng)建球體的方法?createSphere?中同樣調(diào)用播放撞擊音頻方法:



移除物體

當(dāng)頁(yè)面上添加過(guò)多物體時(shí),我們可以通過(guò)在?Dat.GUI?添加一個(gè)重置按鈕來(lái)移除已添加的物體,通過(guò)遍歷?objectsToUpdate?數(shù)組,將每個(gè)數(shù)組項(xiàng)對(duì)應(yīng)的的?object.body?從 物理世界?world?中移除,將?object.mesh?從?Three.js?場(chǎng)景中移除,并清除?collide?碰撞事件的?eventListener



總結(jié)

本文中主要包含的知識(shí)點(diǎn)包括:

  • Three.js?中添加物理效果基本原理

  • 常用?3D?與?2D?物理物理引擎匯總

  • Cannon.js?與?Cannon-es?安裝與引用

  • 物理世界創(chuàng)建、對(duì)象更新、聯(lián)系材質(zhì)、施加外力、處理多個(gè)物體

  • 碰撞事件監(jiān)聽(tīng)、音頻添加

  • 性能優(yōu)化、物理世界移除物體等

想了解其他前端知識(shí)或其他未在本文中詳細(xì)描述的Web 3D開(kāi)發(fā)技術(shù)相關(guān)知識(shí),可閱讀我往期的文章。如果有疑問(wèn)可以在評(píng)論中留言,如果覺(jué)得文章對(duì)你有幫助,不要忘了一鍵三連哦 ??。



附錄

  • [1].??? Three.js 打造繽紛夏日3D夢(mèng)中情島

  • [2].??? Three.js 實(shí)現(xiàn)炫酷的賽博朋克風(fēng)格3D數(shù)字地球大屏

  • [3].??? Three.js 實(shí)現(xiàn)2022冬奧主題3D趣味頁(yè)面,含冰墩墩

  • [4].??? Three.js 實(shí)現(xiàn)3D開(kāi)放世界小游戲:阿貍的多元宇宙

  • [5].??? 掘金1000粉!使用Three.js實(shí)現(xiàn)一個(gè)創(chuàng)意紀(jì)念頁(yè)面

  • 【Three.js 進(jìn)階之旅】系列專欄訪問(wèn) ??

  • 更多往期【3D】專欄訪問(wèn) ??

  • 更多往期【前端】專欄訪問(wèn) ??

參考

  • [1].?three.js journey(https://threejs-journey.com/)

  • [2].?threejs.org(https://threejs.org)



Three.js 進(jìn)階之旅:物理效果-碰撞和聲音的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
县级市| 宜黄县| 福建省| 布尔津县| 海南省| 宁城县| 赣州市| 衡阳县| 芒康县| 德清县| 宜春市| 襄汾县| 大方县| 双流县| 阳高县| 曲阳县| 囊谦县| 健康| 平南县| 万盛区| 西充县| 临猗县| 鱼台县| 阿克| 呼和浩特市| 凯里市| 历史| 西充县| 北宁市| 福清市| 汶川县| 高淳县| 玉屏| 安达市| 阿勒泰市| 孟津县| 宜春市| 桂平市| 谢通门县| 冷水江市| 比如县|