国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Three.js】第二十一章 Physics 物理

這篇具有很好參考價(jià)值的文章主要介紹了【Three.js】第二十一章 Physics 物理。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

介紹

物理是WebGL可以添加到項(xiàng)目體驗(yàn)中最酷的功能之一。人們喜歡真實(shí)物理感的物體,看到它們碰撞、倒塌、墜落和彈跳,就像我的作品集一樣: https: //bruno-simon.com/
有很多方法可以將物理功能添加到您的項(xiàng)目中,這取決于您想要實(shí)現(xiàn)的目標(biāo)。您可以使用一些數(shù)學(xué)和解決方案(例如Raycaster)來創(chuàng)建自己的物理學(xué)

理論

這個(gè)想法很簡單。我們將創(chuàng)建一個(gè)物理世界。這個(gè)物理世界是純理論的。在這個(gè)物理世界上,東西會產(chǎn)生掉落、碰撞、摩擦、滑動(dòng)等等交互。
當(dāng)我們創(chuàng)建一個(gè) Three.js 網(wǎng)格時(shí),我們還將在物理世界中創(chuàng)建該網(wǎng)格的一個(gè)物理版本。如果我們在 Three.js 中創(chuàng)建一個(gè) Box,我們也會在物理世界中創(chuàng)建一個(gè)Box框。
然后,在每一幀上,在渲染任何東西之前,我們告訴物理世界進(jìn)行自我更新;我們獲取物理對象的坐標(biāo)(位置和旋轉(zhuǎn))并將它們應(yīng)用于相應(yīng)的 Three.js 網(wǎng)格。
就是這么簡單的原理。這里最困難的是將我們的代碼組織成一個(gè)合理的結(jié)構(gòu)。這是一個(gè)完全和原本文件路徑分開的路徑部分。每個(gè)開發(fā)人員都會有自己的習(xí)慣,這也取決于你想做什么以及你想把這個(gè)物理世界變得多復(fù)雜。
首先,我們將簡單地創(chuàng)建球體和盒子。

物理功能依賴庫

物理功能有多個(gè)可用的庫。首先,您必須決定是需要 3D 庫還是 2D 庫。雖然您可能認(rèn)為它必須是一個(gè) 3D 庫,因?yàn)?Three.js 完全是關(guān)于 3D 的,但您可能錯(cuò)了。2D 庫通常性能更高,如果您可以總結(jié) 2D 碰撞的物理經(jīng)驗(yàn),則最好使用 2D 庫。
舉一個(gè)例子是如果你想創(chuàng)建一個(gè)類似??彈球游戲。球可以在墻上碰撞和彈跳,您就可以使用 2D 庫將所有東西投影到二維平面上。您可以將球設(shè)計(jì)成物理世界中的圓圈,而墻壁是簡單的矩形。事實(shí)上,這么做您將無法通過擊球底部來使球跳過其他球。
像這樣完成的項(xiàng)目的一個(gè)很好的例子是Merci Michel的Ouigo Let’s play。他們使用了 2D 物理庫,因?yàn)槊總€(gè)碰撞和動(dòng)畫都可以在 2D 空間中表示。

3D物理

對于 3D 物理,主要有三個(gè)庫:

ammo.js
  • 網(wǎng)站: http: //schteppe.github.io/ammo.js-demos/
  • Git 存儲庫:https://github.com/kripken/ammo.js/
  • 文檔:無文檔
  • Bullet 的直接 JavaScript 端口(用 C++ 編寫的物理引擎)
  • 體積大有點(diǎn)重
  • 社區(qū)仍然在更新
cannon.js
  • 網(wǎng)站: https: //schteppe.github.io/cannon.js/
  • Git 存儲庫: https: //github.com/schteppe/cannon.js
  • 文檔: http: //schteppe.github.io/cannon.js/docs/
  • 比 Ammo.js 更輕
  • 比 Ammo.js 更容易實(shí)現(xiàn)
  • 主要由一名開發(fā)人員維護(hù)
  • 多年未更新
  • 有一個(gè)維護(hù)的叉子
Oimo.js
  • 網(wǎng)站: https: //lo-th.github.io/Oimo.js/
  • Git 存儲庫:https://github.com/lo-th/Oimo.js
  • 文檔:http://lo-th.github.io/Oimo.js/docs.html
  • 比 Ammo.js 更輕
  • 比 Ammo.js 更容易實(shí)現(xiàn)
  • 主要由一名開發(fā)人員維護(hù)
  • 2年沒更新了

2D物理

對于 2D 物理,有很多庫,但這里是最流行的:

matter.js
  • 網(wǎng)站: https: //brm.io/matter-js/
  • Git 存儲庫: https: //github.com/liabru/matter-js
  • 文檔: https: //brm.io/matter-js/docs/
  • 主要由一名開發(fā)人員維護(hù)
  • 還是有點(diǎn)更新
P2.js
  • 網(wǎng)站: https: //schteppe.github.io/p2.js/
  • Git 存儲庫: https: //github.com/schteppe/p2.js
  • 文檔: http: //schteppe.github.io/p2.js/docs/
  • 主要由一名開發(fā)人員維護(hù)(與 Cannon.js 相同)
  • 2年沒更新了
planck.js
  • 網(wǎng)站: https: //piqnt.com/planck.js/
  • Git 存儲庫: https: //github.com/shakiba/planck.js
  • 文檔: https: //github.com/shakiba/planck.js/tree/master/docs
  • 主要由一名開發(fā)人員維護(hù)
  • 現(xiàn)在還在更新
Box2D.js
  • 網(wǎng)站:http://kripken.github.io/box2d.js/demo/webgl/box2d.html
  • Git 存儲庫: https: //github.com/kripken/box2d.js/
  • 文檔:無文檔
  • 主要由一名開發(fā)人員維護(hù)(與 Ammo.js 相同)
  • 現(xiàn)在還在更新

我們不會在本課中使用 2D 庫,但 2D 庫代碼與 3D 庫代碼非常相似。主要區(qū)別在于您必須更新的軸。
已經(jīng)有嘗試將 Three.js 與Physijs等庫結(jié)合起來的解決方案。盡管如此,我們不會使用這些已經(jīng)做好封裝的現(xiàn)成解決方案,我們要手動(dòng)結(jié)合物理庫來獲得更好的學(xué)習(xí)體驗(yàn)并更好地理解內(nèi)部運(yùn)行的邏輯。
雖然 Ammo.js 是最常用的庫,尤其是在 Three.js中,正如您在示例中看到的那樣,我們將選擇 Cannon.js。這個(gè)庫在我們的項(xiàng)目中實(shí)現(xiàn)起來更舒服,也更容易使用。

導(dǎo)入 Cannon.js

要將 Cannon.js 添加到我們的項(xiàng)目中,我們首先需要添加依賴項(xiàng)。
在您的終端的項(xiàng)目文件夾中,運(yùn)行此命令npm install --save cannon。
我們現(xiàn)在可以使用經(jīng)典的 JavaScript 在我們的 JavaScript 中import導(dǎo)入 Cannon.js :

import CANNON from 'cannon'

我們需要的一切都在CANNON變量中可用。

設(shè)置

我們的啟動(dòng)器由平面上的一個(gè)球體組成,并且出于美學(xué)原因已經(jīng)啟用了陰影。
【Three.js】第二十一章 Physics 物理,javascript,開發(fā)語言,ecmascript

基礎(chǔ)

世界

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

/**
 * Physics
 */
const world = new CANNON.World()

現(xiàn)在我們獲得了一個(gè),感覺在沒有重力漂浮在太空中的 WebGL 體驗(yàn)感,讓我們增加重力腳踏實(shí)地。您可以使用Cannon.js Vec3 的 gravity屬性更改重力。
**Cannon.js **Vec3就像 Three.js Vector3一樣。它也有**x**、**y****z**屬性,還有一個(gè)**set(...)**方法:

world.gravity.set(0, - 9.82, 0)

我們把第二個(gè)參數(shù)值 改為 - 9.82 是因?yàn)椋?code>- 9.82它是地球上的重力常數(shù),但如果您想讓物體下落得更慢或者如果您的場景發(fā)生在火星上,您可以使用其他重力值。

目的

因?yàn)槲覀兊膱鼍爸幸呀?jīng)有了一個(gè)球體,所以讓我們在 Cannon.js World中也創(chuàng)建一個(gè)球體。
為此,我們必須創(chuàng)建一個(gè)Body。Body是會掉落的并與其他物體碰撞的。
在我們創(chuàng)建一個(gè)Body之前,我們必須決定一個(gè)形狀。有許多可用的基本形狀,如Box、Cylinder、Plane等。我們將選擇一個(gè)與 Three.js 球體具有相同半徑的Sphere :

const sphereShape = new CANNON.Sphere(0.5)

然后我們可以創(chuàng)建我們的body并指定質(zhì)量和位置:

const sphereBody = new CANNON.Body({
    mass: 1,
    position: new CANNON.Vec3(0, 3, 0),
    shape: sphereShape
})

最后,我們可以將Body 通過addBody(...)添加到世界中:

world.addBody(sphereBody)

現(xiàn)在頁面里什么都沒有發(fā)生,因?yàn)槲覀內(nèi)匀恍枰挛覀兊?Cannon.js 世界并相應(yīng)地更新我們的 Three.js 球體。

更新 Cannon.js 世界和 Three.js 場景

要更新我們的world世界,我們必須使用step(...). 該方法底層的代碼很難理解,我們不會在本課中對其進(jìn)行解釋,但您可以在本文中找到更多相關(guān)信息。
要讓它工作,您必須提供一個(gè)固定的時(shí)間步長、自上一步以來經(jīng)過了多少時(shí)間,以及世界world可以應(yīng)用多少次迭代來趕上潛在的延遲。
我們不會解釋什么是時(shí)間步長,但我們希望體驗(yàn)以 60fps 的速度運(yùn)行,所以我們將使用1 / 60來表示. 別擔(dān)心,在幀率更高和更低的設(shè)備上,體驗(yàn)將以相同的速度運(yùn)行。
迭代次數(shù)由你決定,但體驗(yàn)是否流暢就沒那么重要了。
對于三角洲時(shí)間,它有點(diǎn)復(fù)雜。我們需要計(jì)算自上一幀以來經(jīng)過了多少時(shí)間。不要使用Clock類中的getDelta()方法。你不會得到預(yù)期的結(jié)果,而且你會搞亂類的內(nèi)部邏輯。
為了獲得正確的增量時(shí)間,我們需要從前一幀elapsedTime減去當(dāng)前幀elapsedTime獲得:

const clock = new THREE.Clock()
let oldElapsedTime = 0

const tick = () =>
{
    const elapsedTime = clock.getElapsedTime()
    const deltaTime = elapsedTime - oldElapsedTime
    oldElapsedTime = elapsedTime

    // ...
}

我們終于可以更新我們的世界了:

const tick = () =>
{
    // ...

    // Update physics
    world.step(1 / 60, deltaTime, 3)
}

似乎沒有任何東西在移動(dòng)。其實(shí)現(xiàn)實(shí)是我們的sphereBody正在無限的墮入深淵,只是因?yàn)橄鄼C(jī)一直跟著物體墜落所以你難以發(fā)現(xiàn),你可以通過在更新world世界后記錄它的位置來看到:

world.step(1 / 60, deltaTime, 3)
    console.log(sphereBody.position.y)

我們現(xiàn)在需要做的是使用sphereBody坐標(biāo)更新我們的sphere。 Three.js 有兩種方法可以做到這一點(diǎn)。您可以單獨(dú)更新每個(gè)position屬性:

sphere.position.x = sphereBody.position.x
    sphere.position.y = sphereBody.position.y
    sphere.position.z = sphereBody.position.z

或者您可以使用以下方法將所有屬性作為一個(gè)復(fù)制copy(...)

sphere.position.copy(sphereBody.position)

copy(...)在許多類中可用,例如Vector2、Vector3、Euler、Quaternion,甚至類如Material、Object3D、Geometry等。
【Three.js】第二十一章 Physics 物理,javascript,開發(fā)語言,ecmascript
你最終應(yīng)該看到你的項(xiàng)目中球體正在自由落體。問題是我們的球體似乎從地板上掉了下來。這是因?yàn)樵摰匕宕嬖谟?Three.js 場景中,但不存在于 Cannon.js 世界中。
我們可以使用Plane形狀簡單地添加一個(gè)新的Body,但我們不希望我們的地板受到重力影響而掉落。換句話說,我們希望我們的地板是靜態(tài)的。要使Body靜態(tài),請將其設(shè)置為:mass = 0

const floorShape = new CANNON.Plane()
const floorBody = new CANNON.Body()
floorBody.mass = 0
floorBody.addShape(floorShape)
world.addBody(floorBody)

【Three.js】第二十一章 Physics 物理,javascript,開發(fā)語言,ecmascript
如您所見,這次我們的做法大不相同。我們創(chuàng)建了一個(gè)沒有參數(shù)的Body ,然后我們設(shè)置了這些參數(shù)。結(jié)果是一樣的,我們這樣做的唯一原因是為了上課講解。一件有趣的事情是您可以創(chuàng)建一個(gè)由多個(gè)Shapes組成的Body。它對于復(fù)雜但堅(jiān)固的物體很有用。
您應(yīng)該看到球體朝一個(gè)方向(可能朝向相機(jī))跳躍。這不是預(yù)期的結(jié)果。原因是我們的地板plane默認(rèn)正對著相機(jī)。我們需要像在 Three.js 中旋轉(zhuǎn)地板一樣旋轉(zhuǎn)它讓他轉(zhuǎn)到離開相機(jī)的區(qū)域。
使用 Cannon.js 進(jìn)行旋轉(zhuǎn)比使用 Three.js 稍微困難一些,因?yàn)槟仨毷褂肣uaternion來實(shí)現(xiàn)。有多種旋轉(zhuǎn)Body的方法,但必須使用其quaternion屬性。我們將使用setFromAxisAngle(...)方法旋轉(zhuǎn)body.
第一個(gè)參數(shù)是一個(gè)軸。您可以將其想象成穿過身體的一根線。第二個(gè)參數(shù)是角度。這是你圍繞這條線旋轉(zhuǎn)身體的角度。

floorBody.quaternion.setFromAxisAngle(new CANNON.Vec3(- 1, 0, 0), Math.PI * 0.5)

【Three.js】第二十一章 Physics 物理,javascript,開發(fā)語言,ecmascript

我們將軸設(shè)置為負(fù)軸(相對于相機(jī)的左側(cè))穿過身體的線,并將x角度設(shè)置為(四分之一圓)。Math.PI * 0.5
您現(xiàn)在應(yīng)該看到球體下落然后停在地板上。
我們不需要用 Cannon.js 地板更新 Three.js 地板,因?yàn)檫@個(gè)對象不會再移動(dòng)了。

ContactMaterial 關(guān)聯(lián)材料

如您所見,球落地后基本不會彈跳。這是默認(rèn)行為,我們可以使用Material(不是 Three.js 中的 Material)和ContactMaterial來讓它變的富有彈性。
材料只是一個(gè)參考。您可以給它起一個(gè)名字并將它與一個(gè)Body相關(guān)聯(lián)。然后為場景中的每種材質(zhì)創(chuàng)建一個(gè)材質(zhì)。
如果場景中有多種材質(zhì),假設(shè)一種木料材質(zhì)用于地板,一種金屬材質(zhì)用于球。然后,您應(yīng)該創(chuàng)建各種材質(zhì)并為它們命名,例如'concrete''plastic'
(假設(shè)你世界里的一切都是塑料材質(zhì)制成的。在這種情況下,您只需創(chuàng)建一種材料并將其命名為'default’即可。)
你可以給他們互相關(guān)聯(lián)到'ground''ball'中。盡管如此,如果您想對墻壁和立方體等其他對象使用相同的材質(zhì),都名為'ground'即可.
在創(chuàng)建球體和地板之前,創(chuàng)建這兩個(gè)材質(zhì):

const concreteMaterial = new CANNON.Material('concrete')
const plasticMaterial = new CANNON.Material('plastic')

現(xiàn)在我們有了Material,我們必須創(chuàng)建一個(gè)ContactMaterial。它是兩種材質(zhì)的組合,用來關(guān)聯(lián)兩種材料并模擬??碰撞發(fā)生,包含對象發(fā)生碰撞時(shí)的屬性。
前兩個(gè)參數(shù)是Materials。第三個(gè)參數(shù)是一個(gè)**{}**包含兩個(gè)重要屬性的對象:**friction**系數(shù)(摩擦系數(shù))和**restitution**系數(shù)(彈跳系數(shù))——兩者的默認(rèn)值為0.3.
創(chuàng)建后,使用以下方法addContactMaterial(...)將ContactMaterial添加到世界:

const concretePlasticContactMaterial = new CANNON.ContactMaterial(
    concreteMaterial,
    plasticMaterial,
    {
        friction: 0.1,
        restitution: 0.7
    }
)
world.addContactMaterial(concretePlasticContactMaterial)

混凝土和塑料材質(zhì)之間沒有太大的摩擦力,但是如果你讓一個(gè)橡膠球落在混凝土地板上,你會看到它會反彈的很高。
我們現(xiàn)在可以在身體上使用我們的材質(zhì)。您可以在實(shí)例化Body時(shí)或在material屬性之后直接傳遞材質(zhì)。我們做這兩件事:

const sphereBody = new CANNON.Body({
    // ...
    material: plasticMaterial
})

// ...

const floorBody = new CANNON.Body()
floorBody.material = concreteMaterial

【Three.js】第二十一章 Physics 物理,javascript,開發(fā)語言,ecmascript
在停止之前,您應(yīng)該看到球反彈了很多次。我們看不到friction動(dòng)作,因?yàn)槲覀兊那蛲耆P直地落在我們的地板上,而且球大部分時(shí)間都在空中。
擁有不同的材料并為每種組合創(chuàng)建一個(gè)接觸材料可能會令人費(fèi)解。為了簡化一切,讓我們將兩種材質(zhì)替換為默認(rèn)材質(zhì),并將其用于每個(gè)Bodies:

const defaultMaterial = new CANNON.Material('default')
const defaultContactMaterial = new CANNON.ContactMaterial(
    defaultMaterial,
    defaultMaterial,
    {
        friction: 0.1,
        restitution: 0.7
    }
)
world.addContactMaterial(defaultContactMaterial)

// ...

const sphereBody = new CANNON.Body({
    // ...
    material: defaultMaterial
})

// ...

floorBody.material = defaultMaterial

【Three.js】第二十一章 Physics 物理,javascript,開發(fā)語言,ecmascript
我們應(yīng)該得到相同的結(jié)果。
我們可以更進(jìn)一步,將我們的材質(zhì)設(shè)置為World的默認(rèn)材質(zhì)。為此,只需將defaultContactMaterial 分配給world.defaultContactMaterial屬性:

world.defaultContactMaterial = defaultContactMaterial

我們現(xiàn)在可以刪除或注釋floorBodysphereBody材料分配。

施力

有很多方法可以對Body施加力:

  • applyForce從空間中的指定點(diǎn)(不一定在Body的表面)向Body施加一個(gè)力,就像風(fēng)一直將所有東西推一點(diǎn)點(diǎn),可以是多米諾骨牌穿導(dǎo)的推力,可以是更大爆發(fā)力讓憤怒的小鳥飛向敵人的城堡。
  • applyImpulse與applyForce類似,但它不是自增導(dǎo)致速度變化的力,而是直接應(yīng)用于速度。
  • applyLocalForce與applyForce相同,但坐標(biāo)是Body的內(nèi)部中心坐標(biāo)(意味著它將是Body0, 0, 0的中心)。
  • applyLocalImpulse與applyImpulse相同,但坐標(biāo)是Body的內(nèi)部中心坐標(biāo)。

因?yàn)橛谩傲Α钡姆绞綍斐伤俣鹊淖兓?,我們還是不要用“沖量”的方式
讓我們在開始時(shí)applyLocalForce(...)對我們的sphereBody施加一個(gè)小的力推動(dòng)它:

sphereBody.applyLocalForce(new CANNON.Vec3(150, 0, 0), new CANNON.Vec3(0, 0, 0))

【Three.js】第二十一章 Physics 物理,javascript,開發(fā)語言,ecmascript
您可以看到球向右彈跳并滾動(dòng)。
現(xiàn)在讓我們使用applyForce(...)施加一些風(fēng)的感覺。因?yàn)轱L(fēng)是永久性的,所以我們應(yīng)該在更新World之前將此力應(yīng)用于每一幀。要正確施加此力,重點(diǎn)應(yīng)該是**sphereBody.position**

const tick = () =>
{
    // ...

    // Update physics
    sphereBody.applyForce(new CANNON.Vec3(- 0.5, 0, 0), sphereBody.position)

    world.step(1 / 60, deltaTime, 3)

    // ...
}

【Three.js】第二十一章 Physics 物理,javascript,開發(fā)語言,ecmascript

處理多個(gè)對象

處理一兩個(gè)對象很容易,但管理幾十個(gè)對象可能會很麻煩。我們需要稍微優(yōu)化一下讓多個(gè)對象也能同時(shí)管理。
首先,刪除或注釋sphere、 sphereShapesphereBody的相關(guān)代碼。

自動(dòng)化功能

首先,讓我們改進(jìn)我們創(chuàng)建球體的方式,該函數(shù)將同時(shí)包括 Three.js 和 Cannon.js 創(chuàng)建球體的方法。
作為此函數(shù)的參數(shù),我們向函數(shù)傳遞radiusposition兩個(gè)值,但你也可以再隨意添加其他參數(shù),例如mass、material、subdivisions等。

/**
 * Utils
 */
const createSphere = (radius, position) =>
{
}

現(xiàn)在我們可以創(chuàng)建:

Three.js網(wǎng)格:

const createSphere = (radius, position) =>
{
    // Three.js mesh
    const mesh = new THREE.Mesh(
        new THREE.SphereGeometry(radius, 20, 20),
        new THREE.MeshStandardMaterial({
            metalness: 0.3,
            roughness: 0.4,
            envMap: environmentMapTexture,
            envMapIntensity: 0.5
        })
    )
    mesh.castShadow = true
    mesh.position.copy(position)
    scene.add(mesh)
}

和 Cannon.js主體:

const createSphere = (radius, position) =>
{
    // ...

    // Cannon.js body
    const shape = new CANNON.Sphere(radius)

    const body = new CANNON.Body({
        mass: 1,
        position: new CANNON.Vec3(0, 3, 0),
        shape: shape,
        material: defaultMaterial
    })
    body.position.copy(position)
    world.addBody(body)
}

我們可以刪除之前創(chuàng)建的球體并調(diào)用createSphere(...)(在創(chuàng)建 Cannon.js 世界和 Three.js 場景之后)。不要忘記刪除tick()函數(shù)中的球體更新代碼:

createSphere(0.5, { x: 0, y: 3, z: 0 })

【Three.js】第二十一章 Physics 物理,javascript,開發(fā)語言,ecmascript
如您所見,位置不必是 Three.js Vector3或 Cannon.js Vec3 兩個(gè)標(biāo)準(zhǔn)中心點(diǎn) ,我們可以簡單地使用具有x``,yz屬性的對象(對我們來說很幸運(yùn))。
您應(yīng)該看到球體漂浮在地板上方,但不幸的是,它不再移動(dòng)了。這是完全正常的,因?yàn)槲覀儎偛抛⑨尰蛘邉h除了將 Cannon.js Body 的position屬性應(yīng)用于 Three.js Mesh 的 position 屬性的代碼。

使用對象數(shù)組

為了處理這個(gè)問題,我們將創(chuàng)建一個(gè)包含所有需要更新的對象的數(shù)組。然后我們將對象內(nèi)新創(chuàng)建的Mesh和Body添加到該數(shù)組:

const objectsToUpdate = []

const createSphere = (radius, position) =>
{
    // ...

    // Save in objects to update
    objectsToUpdate.push({
        mesh: mesh,
        body: body
    })
}

您可以這樣優(yōu)化,重寫最后一部分(JavaScript 中變量名相同時(shí)無需指定屬性):

objectsToUpdate.push({ mesh, body })

我們現(xiàn)在可以在tick()函數(shù)內(nèi)循環(huán)遍歷該數(shù)組(在我們更新世界之后)并將每個(gè)數(shù)組body.position數(shù)值復(fù)制到mesh.position屬性里:

const tick = () =>
{
    // ...

    world.step(1 / 60, deltaTime, 3)

    for(const object of objectsToUpdate)
    {
        object.mesh.position.copy(object.body.position)
    }
}

【Three.js】第二十一章 Physics 物理,javascript,開發(fā)語言,ecmascript
球體應(yīng)該再次開始下降。

添加到 Dat.GUI

現(xiàn)在我們可以向我們的 Dat.GUI 添加一個(gè)按鈕createSphere。問題是使用該gui.add(...)方法時(shí)第一個(gè)參數(shù)應(yīng)該是一個(gè)對象,第二個(gè)參數(shù)應(yīng)該是一個(gè)屬性名。不幸的是,我們的createSphere是個(gè)函數(shù),不是一個(gè)對象,而且還需要向它傳遞參數(shù)。這種情況經(jīng)常會發(fā)生。一個(gè)不錯(cuò)的解決方案是我們再創(chuàng)建一個(gè)對象,其唯一目的是將那些丟失的功能作為屬性:

const gui = new dat.GUI()
const debugObject = {}

然后在需要時(shí)向其添加函數(shù)(在createSphere創(chuàng)建函數(shù)之后):

debugObject.createSphere = () =>
{
    createSphere(0.5, { x: 0, y: 3, z: 0 })
}

最后,我們可以將這個(gè)新createSphere屬性添加到 Dat.GUI

gui.add(debugObject, 'createSphere')

【Three.js】第二十一章 Physics 物理,javascript,開發(fā)語言,ecmascript
如果您單擊新創(chuàng)建的createSphere按鈕,您應(yīng)該會看到球體相互重疊。這是由于球體在完全相同的位置彈出。讓我們添加一些隨機(jī)性即可防止球體重疊了:

debugObject.createSphere = () =>
{
    createSphere(
        Math.random() * 0.5,
        {
            x: (Math.random() - 0.5) * 3,
            y: 3,
            z: (Math.random() - 0.5) * 3
        }
    )
}

【Three.js】第二十一章 Physics 物理,javascript,開發(fā)語言,ecmascript
像下雨了一樣!
為了盡量不要燒毀你的電腦;此代碼需要優(yōu)化。

優(yōu)化

因?yàn)門hree.js Mesh的幾何體和材質(zhì)是一樣的,我們應(yīng)該把它們從createSphere函數(shù)中提取出來。問題是我們正在根據(jù)半徑radius來創(chuàng)建我們的幾何體。一個(gè)簡單的解決方案是將SphereGeometry的半徑radius固定為1然后縮放Mesh:

const sphereGeometry = new THREE.SphereGeometry(1, 20, 20)
const sphereMaterial = new THREE.MeshStandardMaterial({
    metalness: 0.3,
    roughness: 0.4,
    envMap: environmentMapTexture,
    envMapIntensity: 0.5
})
const createSphere = (radius, position) =>
{
    // Three.js mesh
    const mesh = new THREE.Mesh(sphereGeometry, sphereMaterial)
    mesh.castShadow = true
    mesh.scale.set(radius, radius, radius)
    mesh.position.copy(position)
    scene.add(mesh)

    // ...
}

這樣材質(zhì)都是相同的,你應(yīng)該得到和之前相同的結(jié)果并且大大優(yōu)化了性能。

添加立方體

現(xiàn)在我們的球體運(yùn)行良好,讓我們用立方體也進(jìn)行一次相同的實(shí)現(xiàn)過程。
要?jiǎng)?chuàng)建一個(gè)立方體,我們必須使用一個(gè)BoxGeometry和一個(gè)Box形狀。當(dāng)心; 參數(shù)不一樣。BoxGeometry需要一個(gè)width、一個(gè)height和一個(gè)depth。與此同時(shí),一個(gè)Box形狀需要一個(gè)halfExtents. 它由Vec3 表示,該 Vec3對應(yīng)于從框的中心開始并連接該框角之一的段:

// Create box
const boxGeometry = new THREE.BoxGeometry(1, 1, 1)
const boxMaterial = new THREE.MeshStandardMaterial({
    metalness: 0.3,
    roughness: 0.4,
    envMap: environmentMapTexture,
    envMapIntensity: 0.5
})
const createBox = (width, height, depth, position) =>
{
    // Three.js mesh
    const mesh = new THREE.Mesh(boxGeometry, boxMaterial)
    mesh.scale.set(width, height, depth)
    mesh.castShadow = true
    mesh.position.copy(position)https://www.yuque.com/channel1/wvnr6v/dtdmh6s06vgyxn6p/edit#kKBqS
    scene.add(mesh)

    // Cannon.js body
    const shape = new CANNON.Box(new CANNON.Vec3(width * 0.5, height * 0.5, depth * 0.5))

    const body = new CANNON.Body({
        mass: 1,
        position: new CANNON.Vec3(0, 3, 0),
        shape: shape,
        material: defaultMaterial
    })
    body.position.copy(position)
    world.addBody(body)

    // Save in objects
    objectsToUpdate.push({ mesh, body })
}

createBox(1, 1.5, 2, { x: 0, y: 3, z: 0 })

debugObject.createBox = () =>
{
    createBox(
        Math.random(),
        Math.random(),
        Math.random(),
        {
            x: (Math.random() - 0.5) * 3,
            y: 3,
            z: (Math.random() - 0.5) * 3
        }
    )
}
gui.add(debugObject, 'createBox')

【Three.js】第二十一章 Physics 物理,javascript,開發(fā)語言,ecmascript
不要忘記刪除第一個(gè)createSphere(...)調(diào)用,否則您將同時(shí)在同一位置創(chuàng)建球體和長方體,這可能會變得混亂。

【Three.js】第二十一章 Physics 物理,javascript,開發(fā)語言,ecmascript
如果你點(diǎn)擊Dat.GUI 的createBox按鈕, 您應(yīng)該會看到一個(gè)盒子掉落并突然彈跳平移向地板。它看起來不太正常。
我們忘記了一件重要的事情:我們的網(wǎng)格沒有旋轉(zhuǎn)。這里發(fā)生的事情應(yīng)該是盒子在地板上彈跳起來并倒向一邊。但我們所能看到的只是盒子跳起來并一直立著移動(dòng)了起來(很怪異),因?yàn)?Three.js網(wǎng)格不像 Cannon.js主體那樣可以進(jìn)行旋轉(zhuǎn),所以立方體就一直立著運(yùn)動(dòng)了。
我們之前沒有看到這個(gè)問題,因?yàn)槲覀兪褂玫氖乔蝮w,無論我們是否旋轉(zhuǎn)它們,它們落地后的物理表現(xiàn)看起來都一樣(其實(shí)他們都不會旋轉(zhuǎn),這不正確)。
我們可以通過將Body quaternion復(fù)制到Mesh quaternion來解決這個(gè)問題,就像我們復(fù)制position時(shí)一樣:

const tick = () =>
{
    // ...

    for(const object of objectsToUpdate)
    {
        object.mesh.position.copy(object.body.position)
        object.mesh.quaternion.copy(object.body.quaternion)
    }

    // ...
}

【Three.js】第二十一章 Physics 物理,javascript,開發(fā)語言,ecmascript
箱子現(xiàn)在應(yīng)該會在落地后倒下了!您可以根據(jù)需要?jiǎng)?chuàng)建球體和盒子。一如既往,盡量不要燒毀你的電腦顯卡。
【Three.js】第二十一章 Physics 物理,javascript,開發(fā)語言,ecmascript

性能 Performance

廣相 broadphase

在測試對象之間的碰撞時(shí),一種天真的方法是測試每個(gè)Body與其他每個(gè)Body 的對比。雖然這很容易做到,但在性能方面代價(jià)高昂。
這就是 broadphase 出現(xiàn)的地方。broadphase在測試之前對身體進(jìn)行粗略的分類。想象一下,兩堆箱子彼此遠(yuǎn)離。你為什么要用一堆的盒子和另一堆的盒子進(jìn)行測試?它們相距太遠(yuǎn),不會發(fā)生碰撞。
Cannon.js 中有 3 種 broadphase 算法可用:

  • NaiveBroadphase : 測試每一個(gè)身體對抗每一個(gè)其他身體
  • GridBroadphase : Quadrilles the world 并且僅在同一個(gè)網(wǎng)格框或鄰居的網(wǎng)格框中針對其他主體測試主體。
  • SAPBroadphase(broadphase 掃描和修剪 ):在多個(gè)步驟中測試任意軸上的主體。

broadphase 默認(rèn)的算法 是NaiveBroadphase,我建議你切換到SAPBroadphase。使用這個(gè) broadphase 可能會產(chǎn)生物體不發(fā)生碰撞的錯(cuò)誤行為,但這種情況很少見,并且它涉及到做一些事情,比如非常快速地移動(dòng)物體時(shí)導(dǎo)致不發(fā)生碰撞。
要切換到SAPBroadphase,只需在屬性中對其進(jìn)行實(shí)例化world.broadphase,并使用相同的世界作為參數(shù):

world.broadphase = new CANNON.SAPBroadphase(world)

休眠 Sleep

就算我們使用改進(jìn)的 broadphase 算法,我們所有的身體還是都會被物理測試?yán)速M(fèi)了性能。那些不再移動(dòng)的身體,我們可以使用sleep稱為睡眠的功能。
當(dāng)Body速度變得非常慢時(shí)(在您看不到它移動(dòng)的點(diǎn)),Body可能會休眠并且不會被測試,除非通過代碼對其施加足夠的力或者如果另一個(gè)Body擊中它。
要激活此功能,只需將[World](http://schteppe.github.io/cannon.js/docs/classes/World.html).allowSleep屬性設(shè)置為true :

world.allowSleep = true

您還可以使用sleepSpeedLimitsleepTimeLimit屬性控制Body入睡的范圍,但我們這節(jié)課不會更改這些。

事件

您可以在Body上收聽事件。如果你想做一些事情,比如在物體碰撞時(shí)播放聲音,或者如果你想知道子彈發(fā)射是否碰到了敵人,這會很有用。
您可以收聽Body上的事件,例如'colide','sleep''wakeup'。
當(dāng)我們的球體和盒子與任何物體發(fā)生碰撞時(shí),讓我們播放撞擊聲。首先,在原生 JavaScript 中創(chuàng)建聲音并創(chuàng)建一個(gè)播放聲音的函數(shù)。
某些瀏覽器(如 Chrome)會阻止播放聲音,除非用戶與頁面進(jìn)行了交互(例如單擊任何地方),因此如果您沒有聽到第一個(gè)聲音,請不要擔(dān)心。

/**
 * Sounds
 */
const hitSound = new Audio('/sounds/hit.mp3')

const playHitSound = () =>
{
    hitSound.play()
}

只是播放聲音有點(diǎn)牽強(qiáng),但我們稍后會為該功能添加更多內(nèi)容。
現(xiàn)在,讓我們來聽聽'collide'關(guān)于Bodies的事件。我們將只關(guān)注createBox函數(shù),并在完成后將其添加到createSphere函數(shù)中。
現(xiàn)在,監(jiān)聽碰撞事件并使用該playHitSound函數(shù)作為回調(diào):

const createBox = (width, height, depth, position) =>
{
    // ...

    body.addEventListener('collide', playHitSound)

    // ...
}

當(dāng)立方體接觸地面或立方體碰撞時(shí),您應(yīng)該會聽到撞擊聲。如果您使用的是 Chrome,請不要忘記在框落地之前點(diǎn)擊頁面,因?yàn)槿绻形窗l(fā)生用戶交互,Chrome 會拒絕播放聲音。
聲音似乎還不錯(cuò)。不幸的是,當(dāng)我們添加多個(gè)框時(shí),事情變得非常奇怪,那個(gè)聲音像是犯病了一樣一直噠噠噠噠。
第一個(gè)問題是,當(dāng)我們在調(diào)用hitSound.play()播放聲音時(shí),沒有任何反應(yīng),因?yàn)樗呀?jīng)在播放了。我們可以通過將聲音currentTime重置為屬性來解決這個(gè)0問題:

const playHitSound = () =>
{
    hitSound.currentTime = 0
    hitSound.play()
}

雖然這在物體掉落開始時(shí)比較好,但即使一個(gè)立方體輕微接觸另一個(gè)立方體,我們也會聽到太多的撞擊聲。我們需要知道影響力有多強(qiáng),如果不夠強(qiáng),我們就什么都不播放才行。
要獲得沖擊強(qiáng)度,我們首先需要獲得有關(guān)碰撞的信息。我們可以通過向'collide'回調(diào)(這是我們的playHitSound函數(shù))添加一個(gè)參數(shù)來做到這一點(diǎn):

const playHitSound = (collision) =>
{
    console.log(collision)

    // ...
}

collision變量現(xiàn)在包含大量碰撞信息??梢酝ㄟ^調(diào)用屬性getImpactVelocityAlongNormal()上的方法來找到?jīng)_擊強(qiáng)度contact

const playHitSound = (collision) =>
{
    console.log(collision.contact.getImpactVelocityAlongNormal())
    
    // ...
}

如果您查看日志,您應(yīng)該會看到一個(gè)數(shù)字。沖擊力越強(qiáng),數(shù)值越高。
我們測試impactStrength該值并僅在足夠強(qiáng)的情況下播放聲音:

const playHitSound = (collision) =>
{
    const impactStrength = collision.contact.getImpactVelocityAlongNormal()

    if(impactStrength > 1.5)
    {
        hitSound.currentTime = 0
        hitSound.play()
    }
}

為了更加真實(shí),我們可以為音量添加一些隨機(jī)性:

const playHitSound = (collision) =>
{
    const impactStrength = collision.contact.getImpactVelocityAlongNormal()

    if(impactStrength > 1.5)
    {
        hitSound.volume = Math.random()
        hitSound.currentTime = 0
        hitSound.play()
    }
}

如果我們想更加完善這個(gè)功能,我們可以有多個(gè)略有不同的擊打聲音。為了防止同時(shí)播放太多聲音,我們可以添加一個(gè)非常短的延遲,使聲音在播放一次后無法再次播放。
我們不會在本課中做這些,但請隨意嘗試。
讓我們將createBox函數(shù)中使用的代碼復(fù)制到createSphere函數(shù)中:

const createSphere = (radius, position) =>
{
    // ...

    body.addEventListener('collide', playHitSound)

    // ...
}

移除物體 Remove things

讓我們添加一個(gè)reset按鈕。
創(chuàng)建一個(gè)reset函數(shù)并將其添加到您的 Dat.GUI 中,就像我們對createBoxcreateSphere 所做的那樣:

// Reset
debugObject.reset = () =>
{
    console.log('reset')
}
gui.add(debugObject, 'reset')

現(xiàn)在,讓我們循環(huán)遍歷objectsToUpdate數(shù)組中的每個(gè)對象。然后從object.body 中刪除world和從 object.mesh 中刪除 scene。另外,不要忘記像在本機(jī) JavaScript 中那樣刪除 eventListener

debugObject.reset = () =>
{
    for(const object of objectsToUpdate)
    {
        // Remove body
        object.body.removeEventListener('collide', playHitSound)
        world.removeBody(object.body)

        // Remove mesh
        scene.remove(object.mesh)
    }
}

【Three.js】第二十一章 Physics 物理,javascript,開發(fā)語言,ecmascript
我們還需要清空objectsToUpdate數(shù)組。在 JS 中有許多清空數(shù)組的神奇方法,其中之一是用splice方法將其內(nèi)容替換為空:

debugObject.reset = () =>
{
    // ...

    objectsToUpdate.splice(0, objectsToUpdate.length)
}

就是這樣。您可以單擊reset按鈕刪除所有內(nèi)容。

使用 Cannon.js 走得更遠(yuǎn)

雖然我們介紹了基礎(chǔ)知識并且您已經(jīng)可以做很多事情,但這里有一些需要改進(jìn)的地方。

約束條件

顧名思義,約束可以在兩個(gè)主體之間啟用約束。我們不會在本課中介紹這些內(nèi)容,但這是約束列表:

  • HingeConstraint:就像門鉸鏈一樣。
  • DistanceConstraint:強(qiáng)制物體彼此保持一定距離。
  • LockConstraint:合并實(shí)體,就像它們是一件一樣。
  • PointToPointConstraint:將主體粘附到特定點(diǎn)。

類、方法、屬性和事件

有許多類,每個(gè)類都有不同的方法、屬性和事件。嘗試至少瀏覽一次所有這些以了解它們的存在。它可能會為您在未來的項(xiàng)目中節(jié)省一些時(shí)間。

例子

文檔并不完美。如果您花一些時(shí)間在演示和研究中以了解如何開發(fā),將會有所幫助。許多人可能遇到了您可能遇到的問題。不要猶豫,依靠社區(qū)。

多線程workers

運(yùn)行物理模擬需要時(shí)間。執(zhí)行這項(xiàng)工作的計(jì)算機(jī)組件是 CPU。當(dāng)你運(yùn)行 Three.js、Cannon.js、你的代碼邏輯等時(shí),一切都由你 CPU 中的同一個(gè)線程完成。如果有太多事情要做(例如物理模擬中的對象太多),該線程會很快過載,從而導(dǎo)致幀速率下降。
正確的解決方案是使用多線程。Workers 允許您將一部分代碼放在不同的線程中以分散負(fù)載。然后您可以從該代碼發(fā)送和接收數(shù)據(jù)。它可以顯著提高性能。
問題是代碼必須明顯分開防止競爭資源。您可以在頁面源代碼中找到一個(gè)很好的簡單示例。

Cannon-es

正如我們之前所說,Cannon.js 多年未更新。幸運(yùn)的是,有些人 fork 了存儲庫并開始進(jìn)行更新。多虧了他們,我們才能訪問更好且維護(hù)得更好的 Cannon.js 版本:

  • Git 存儲庫: https: //github.com/pmndrs/cannon-es
  • NPM 頁面:https://www.npmjs.com/package/cannon-es

要使用此版本而不是原始版本,請?jiān)陧?xiàng)目文件夾中打開終端(或關(guān)閉服務(wù)器),刪除之前的 cannon.js 依賴項(xiàng)npm uninstall --save cannon。
至于cannon-es,您可以安裝最新版本并npm install --save cannon-es更改您在代碼中導(dǎo)入 Cannon.js 的方式:

import * as CANNON from 'cannon-es'

一切都應(yīng)該像以前一樣工作。您可以在Git 存儲庫頁面上查看版本改動(dòng)。
最新版本應(yīng)該可以作為直接替代品,但如果出現(xiàn)錯(cuò)誤,您可以使用更具體的版本,如(0.20測試過的)通過運(yùn)行npm install --save cannon-es@0.20.

Ammo.js

我們使用 Cannon.js 是因?yàn)樵搸煲子趯?shí)施和理解。它最大的競爭對手之一是 Ammo.js。雖然在您的項(xiàng)目中更難使用和實(shí)施,但您可能會對以下功能感興趣:

  • 它是 Bullet 的一個(gè)移植版,Bullet 是一個(gè)眾所周知且運(yùn)行良好的物理引擎,用 C++ 編寫。
  • 它具有 WebAssembly (wasm) 支持。WebAssembly 是大多數(shù)最新瀏覽器都支持的低級語言。因?yàn)樗堑图墑e的,所以它具有更好的性能。
  • 它更受歡迎,您可以找到更多 Three.js 的示例。
  • 它支持更多功能。

如果您需要最佳性能或在您的項(xiàng)目中具有特定功能,您可能應(yīng)該選擇 Ammo.js 而不是 Cannon.js。

Physijs

Physijs 簡化了 Three.js 項(xiàng)目中物理的實(shí)現(xiàn)。它使用 Ammo.js 并原生支持 workers。

  • 網(wǎng)站: https: //chandlerprall.github.io/Physijs/
  • Git 存儲庫:https://github.com/chandlerprall/Physijs
  • 文檔: https: //github.com/chandlerprall/Physijs/wiki

您無需創(chuàng)建 Three.js 對象和物理對象,而是同時(shí)創(chuàng)建兩者即可:

box = new Physijs.BoxMesh(
    new THREE.CubeGeometry(5, 5, 5),
    new THREE.MeshBasicMaterial({ color: 0x888888 })
)
scene.add(box)

Physijs 會處理剩下的事情。
雖然它很吸引人,尤其是對于初學(xué)者來說,但當(dāng)您嘗試做該庫不支持的事情時(shí),事情就會變得復(fù)雜。查找錯(cuò)誤的來源也可能很麻煩,因?yàn)榉庋b過頭了。
就像 Ammo.js 一樣,花點(diǎn)時(shí)間想想用哪個(gè)物理庫是您項(xiàng)目的最佳解決方案。文章來源地址http://www.zghlxwxcb.cn/news/detail-699266.html

到了這里,關(guān)于【Three.js】第二十一章 Physics 物理的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 第二十一章 : Spring Boot 集成RabbitMQ(五)

    第二十一章 : Spring Boot 集成RabbitMQ(五) 前言 本章知識點(diǎn): 如何保證消息100%可靠性發(fā)送的技術(shù)解決方案。 一、 應(yīng)用場景 在使用消息隊(duì)列時(shí),因?yàn)樯a(chǎn)者和消費(fèi)者不直接交互,所以面臨下面幾個(gè)問題: 1)要把消息添加到隊(duì)列中,怎么保證消息成功添加? 2)如何保證消息

    2024年02月03日
    瀏覽(20)
  • UCB Data100:數(shù)據(jù)科學(xué)的原理和技巧:第二十一章到第二十六章

    UCB Data100:數(shù)據(jù)科學(xué)的原理和技巧:第二十一章到第二十六章

    原文:SQL II 譯者:飛龍 協(xié)議:CC BY-NC-SA 4.0 學(xué)習(xí)成果 介紹過濾組的能力 在 SQL 中執(zhí)行數(shù)據(jù)清理和文本操作 跨表連接數(shù)據(jù) 在本講座中,我們將繼續(xù)上次的工作,介紹一些高級的 SQL 語法。 首先,讓我們加載上一堂課的數(shù)據(jù)庫。 HAVING 通過在每個(gè)組的所有行上應(yīng)用一些條件來過

    2024年01月21日
    瀏覽(99)
  • 第二十一章行為性模式—訪問者模式

    第二十一章行為性模式—訪問者模式

    行為型模式用于描述程序在運(yùn)行時(shí)復(fù)雜的流程控制,即描述多個(gè)類或?qū)ο笾g怎樣相互協(xié)作共同完成單個(gè)對象無法單獨(dú)完成的任務(wù),它涉及算法與對象間職責(zé)的分配。行為型模式分為類行為模式和對象行為模式: 類行為模式:采用繼承機(jī)制來在類間分派行為 對象行為模式:

    2024年02月07日
    瀏覽(35)
  • 第二十一章 Prim算法與Kruskal算法(通俗證明與詳細(xì)講解)

    第二十一章 Prim算法與Kruskal算法(通俗證明與詳細(xì)講解)

    我們先解釋一下什么是最小生成樹。 這個(gè)概念是基于圖的,如果說存在一條路線串通起來了所有的點(diǎn),那么這條路線就叫做生成樹。而在這些路線中最短的那一條就叫做最小生成樹。 如上圖所示,圖中的紅色路線就是一個(gè)生成樹,假設(shè)這條紅色路線是眾多生成樹路線中最小

    2024年02月11日
    瀏覽(30)
  • Chrome 開發(fā)者工具 第二十一章(替換 Web 內(nèi)容和 HTTP 響應(yīng))

    Chrome 開發(fā)者工具 第二十一章(替換 Web 內(nèi)容和 HTTP 響應(yīng))

    Chrome 開發(fā)者工具的本地替換功能是一個(gè)強(qiáng)大的工具,它允許開發(fā)者在不修改服務(wù)器代碼的情況下模擬前端更改。這個(gè)功能特別適用于那些需要快速測試前端更改,但又不想或不能等待后端更新的情況。 本地替換的工作原理 本地替換通過在開發(fā)者工具中進(jìn)行更改,并將這些更

    2024年02月22日
    瀏覽(21)
  • 第二十一章:CCNet:Criss-Cross Attention for Semantic Segmentation ——用于語義分割的交叉注意力

    第二十一章:CCNet:Criss-Cross Attention for Semantic Segmentation ——用于語義分割的交叉注意力

    原文題目:《CCNet:Criss-Cross Attention for Semantic Segmentation?》 原文引用:Huang Z, Wang X, Huang L, et al. Ccnet: Criss-cross attention for semantic segmentation[C]//Proceedings of the IEEE/CVF international conference on computer vision. 2019: 603-612. 原文鏈接: https://openaccess.thecvf.com/content_ICCV_2019/papers/Huang_CCNet_Criss

    2024年02月16日
    瀏覽(27)
  • 【正點(diǎn)原子STM32連載】第二十一章 高級定時(shí)器輸出指定個(gè)數(shù)PWM實(shí)驗(yàn) 摘自【正點(diǎn)原子】APM32E103最小系統(tǒng)板使用指南

    1)實(shí)驗(yàn)平臺:正點(diǎn)原子APM32E103最小系統(tǒng)板 2)平臺購買地址:https://detail.tmall.com/item.htm?id=609294757420 3)全套實(shí)驗(yàn)源碼+手冊+視頻下載地址: http://www.openedv.com/docs/boards/xiaoxitongban 本章將介紹使用APM32E103高級定時(shí)器輸出指定個(gè)數(shù)的PWM。通過本章的學(xué)習(xí),讀者將學(xué)習(xí)到高級定時(shí)器重

    2024年02月21日
    瀏覽(24)
  • 【正點(diǎn)原子FPGA連載】第二十一章AXI DMA環(huán)路測試 摘自【正點(diǎn)原子】DFZU2EG_4EV MPSoC之嵌入式Vitis開發(fā)指南

    【正點(diǎn)原子FPGA連載】第二十一章AXI DMA環(huán)路測試 摘自【正點(diǎn)原子】DFZU2EG_4EV MPSoC之嵌入式Vitis開發(fā)指南

    1)實(shí)驗(yàn)平臺:正點(diǎn)原子MPSoC開發(fā)板 2)平臺購買地址:https://detail.tmall.com/item.htm?id=692450874670 3)全套實(shí)驗(yàn)源碼+手冊+視頻下載地址: http://www.openedv.com/thread-340252-1-1.html DMA(Direct Memory Access,直接存儲器訪問)是計(jì)算機(jī)科學(xué)中的一種內(nèi)存訪問技術(shù)。它允許某些計(jì)算機(jī)內(nèi)部的硬件子系

    2024年02月16日
    瀏覽(27)
  • Android SDK 上手指南||第十一章 虛擬與物理設(shè)備

    Android SDK 上手指南||第十一章 虛擬與物理設(shè)備

    在之前的文章里,大家已經(jīng)了解了Android項(xiàng)目當(dāng)中的基本元素、接觸了用戶界面的設(shè)計(jì)以及數(shù)據(jù)存儲方案。接下來,我們將一同探索如何在物理及虛擬設(shè)備上運(yùn)行自己的應(yīng)用程序并與之互動(dòng)。在系列文章的下一篇中,我們將分步講解如何讓應(yīng)用程序運(yùn)行在物理設(shè)備及模擬器當(dāng)中

    2024年02月09日
    瀏覽(17)
  • 第二十一回:布局約束類Widget

    我們在上一章回中介紹了進(jìn)度條Widget相關(guān)的內(nèi)容,,本章回中將介紹 布局約束類Widget 。閑話休提,讓我們一起Talk Flutter吧。 我們在這里說的布局約束表示可以控制其它Widget大小,F(xiàn)lutter中提供了一些Widget,它們專門用來控制其它Widget的大小,我將它們稱作約束布局類Widget. 之所

    2024年02月02日
    瀏覽(22)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包