<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>
"); //-->

博客專(zhuān)欄

EEPW首頁(yè) > 博客 > 3D 碰撞檢測

3D 碰撞檢測

發(fā)布人:ygtu 時(shí)間:2023-08-30 來(lái)源:工程師 發(fā)布文章
推薦:使用NSDT場(chǎng)景編輯器快速搭建3D應用場(chǎng)景
軸對齊邊界框

與 2D 碰撞檢測一樣,軸對齊邊界框 (AABB) 是確定兩個(gè)游戲實(shí)體是否重疊的最快算法。這包括將游戲實(shí)體包裝在一個(gè)非旋轉(因此軸對齊)的框中,并檢查這些框在 3D 坐標空間中的位置以查看它們是否重疊。

兩個(gè)漂浮在空間中的 3-D 非方形物體,被虛擬矩形框包圍。

由于性能原因,存在軸對齊約束。兩個(gè)非旋轉框之間的重疊區域可以?xún)H通過(guò)邏輯比較來(lái)檢查,而旋轉框需要額外的三角運算,這些操作的計算速度較慢。如果您有將要旋轉的實(shí)體,則可以修改邊界框的尺寸,使其仍環(huán)繞對象,或者選擇使用其他邊界幾何類(lèi)型,例如球體(對旋轉不變)。下面的動(dòng)畫(huà) GIF 顯示了 AABB 的圖形示例,該示例調整其大小以適應旋轉實(shí)體。盒子不斷改變尺寸,以緊密貼合其中包含的實(shí)體。

顯示虛擬矩形框的動(dòng)畫(huà)旋轉節點(diǎn)隨著(zhù)其中的節點(diǎn)旋轉而收縮和增長(cháng)。盒子不旋轉。

注意:查看 使用 THREE.js 進(jìn)行邊界體積碰撞檢測 一文,了解此技術(shù)的實(shí)際實(shí)現。

點(diǎn) vs. AABB

檢查一個(gè)點(diǎn)是否在 AABB 內非常簡(jiǎn)單——我們只需要檢查點(diǎn)的坐標是否在 AABB 內;分別考慮每個(gè)軸。如果我們假設 P x、P y 和 Pz 是點(diǎn)的坐標,B minX–B maxX、B minY–B maxY 和 B minZB maxZ 是 AABB 每個(gè)軸的范圍,我們可以使用以下公式計算兩者之間是否發(fā)生了碰撞:

或者在 JavaScript 中:

.JS復制到剪貼板

function isPointInsideAABB(point, box) {
  return (
    point.x >= box.minX &&
    point.x <= box.maxX &&
    point.y >= box.minY &&
    point.y <= box.maxY &&
    point.z >= box.minZ &&
    point.z <= box.maxZ
  );
}
AABB vs. AABB

檢查一個(gè) AABB 是否與另一個(gè) AABB 相交類(lèi)似于點(diǎn)測試。我們只需要使用框的邊界對每個(gè)軸進(jìn)行一次測試。下圖顯示了我們將在 X 軸上執行的測試 — 基本上,范圍 A minX–A maxX 和 B minX–B maxX 是否重疊?

Hand drawing of two rectangles showing the upper right corner of A overlapping the bottom left corner of B, as A's largest x coordinate is greater than B's smallest x coordinate.

從數學(xué)上講,這看起來(lái)像這樣:

在 JavaScript 中,我們會(huì )使用這個(gè):

.JS復制到剪貼板

function intersect(a, b) {
  return (
    a.minX <= b.maxX &&
    a.maxX >= b.minX &&
    a.minY <= b.maxY &&
    a.maxY >= b.minY &&
    a.minZ <= b.maxZ &&
    a.maxZ >= b.minZ
  );
}
邊界球體

使用邊界球體來(lái)檢測碰撞比 AABB 稍微復雜一些,但測試起來(lái)仍然相當快。球體的主要優(yōu)點(diǎn)是它們對旋轉是不變的,因此如果包裹的實(shí)體旋轉,邊界球體仍將相同。它們的主要缺點(diǎn)是,除非它們要包裝的實(shí)體實(shí)際上是球形的,否則包裝通常不是很好的擬合(即用邊界球體包裹一個(gè)人會(huì )導致很多誤報,而 AABB 會(huì )是更好的匹配)。

點(diǎn)與球體

要檢查球體是否包含點(diǎn),我們需要計算點(diǎn)和球心之間的距離。如果此距離小于或等于球體的半徑,則該點(diǎn)位于球體內部。

手繪笛卡爾坐標系中球體和點(diǎn)的 2D 投影。該點(diǎn)在圓圈的右下角。距離由一條虛線(xiàn)表示,標記為 D,從圓的中心到點(diǎn)。較淺的線(xiàn)顯示從圓心到圓邊界的半徑,標記為 R。

考慮到兩點(diǎn) A 和 B 之間的歐幾里得距離為

我們的點(diǎn)與球體碰撞檢測公式將如下所示:

或者在 JavaScript 中:

.JS復制到剪貼板

function isPointInsideSphere(point, sphere) {
  // we are using multiplications because is faster than calling Math.pow
  const distance = Math.sqrt(
    (point.x - sphere.x) * (point.x - sphere.x) +
      (point.y - sphere.y) * (point.y - sphere.y) +
      (point.z - sphere.z) * (point.z - sphere.z),
  );
  return distance < sphere.radius;
}

注意:上面的代碼具有平方根,計算起來(lái)可能很昂貴。避免這種情況的簡(jiǎn)單優(yōu)化包括將平方距離與平方半徑進(jìn)行比較,因此優(yōu)化方程將涉及 。distanceSqr < sphere.radius * sphere.radius

球體與球體

球體與球體測試類(lèi)似于點(diǎn)與球體測試。我們在這里需要測試的是球體中心之間的距離小于或等于它們的半徑之和。

兩個(gè)部分重疊的圓的手繪。每個(gè)圓(不同大?。┒加幸粭l從其中心到邊界的光半徑線(xiàn),標記為 R。距離用一條虛線(xiàn)表示,標記為 D,連接兩個(gè)圓的中心點(diǎn)。

在數學(xué)上,這看起來(lái)像:

或者在 JavaScript 中:

.JS復制到剪貼板

function intersect(sphere, other) {
  // we are using multiplications because it's faster than calling Math.pow
  const distance = Math.sqrt(
    (sphere.x - other.x) * (sphere.x - other.x) +
      (sphere.y - other.y) * (sphere.y - other.y) +
      (sphere.z - other.z) * (sphere.z - other.z),
  );
  return distance < sphere.radius + other.radius;
}
球體 vs. AABB

測試球體和AABB是否碰撞稍微復雜一些,但仍然簡(jiǎn)單快捷。一種合乎邏輯的方法是檢查 AABB 的每個(gè)頂點(diǎn),對每個(gè)頂點(diǎn)進(jìn)行點(diǎn)與球面測試。然而,這是矯枉過(guò)正的——測試所有頂點(diǎn)是不必要的,因為我們只需計算 AABB 的最近點(diǎn)(不一定是頂點(diǎn))和球體中心之間的距離,看看它是否小于或等于球體的半徑。我們可以通過(guò)將球體的中心鉗制到 AABB 的極限來(lái)獲得此值。

手繪一個(gè)正方形,部分重疊在圓的頂部。半徑由標記為 R 的淺線(xiàn)表示。距離線(xiàn)從圓的中心到正方形的最近點(diǎn)。

在 JavaScript 中,我們會(huì )像這樣做這個(gè)測試:

.JS復制到剪貼板

function intersect(sphere, box) {
  // get box closest point to sphere center by clamping
  const x = Math.max(box.minX, Math.min(sphere.x, box.maxX));
  const y = Math.max(box.minY, Math.min(sphere.y, box.maxY));
  const z = Math.max(box.minZ, Math.min(sphere.z, box.maxZ));

  // this is the same as isPointInsideSphere
  const distance = Math.sqrt(
    (x - sphere.x) * (x - sphere.x) +
      (y - sphere.y) * (y - sphere.y) +
      (z - sphere.z) * (z - sphere.z),
  );

  return distance < sphere.radius;
}
使用物理引擎

3D物理引擎提供碰撞檢測算法,其中大多數也基于邊界體積。物理引擎的工作方式是創(chuàng )建一個(gè)物理身體,通常附加到它的視覺(jué)表示上。該主體具有速度、位置、旋轉、扭矩等屬性,以及物理形狀。此形狀是碰撞檢測計算中考慮的形狀。

原文鏈接:3D 碰撞檢測 (mvrlink.com)


*博客內容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀(guān)點(diǎn),如有侵權請聯(lián)系工作人員刪除。



關(guān)鍵詞: 3dsmax 3D建模

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>