three-mesh-bvh:把射線查詢改成空間剪枝
此專案圍繞「gkjohnson/three-mesh-bvh」建置,面向真實業務場景,提供可重複使用、可持續維運的開源實作。
秒懂
- 它是什麼?
- three-mesh-bvh 為 three.js BufferGeometry 建立包圍體層次結構,讓 raycast、sphere 相交和 shapecast 能跳過不相關的三角形。README 同時提供原型擴充與手動建立 MeshBV
- 適合誰用?
- 接入時先決定要使用 computeBoundsTree 的擴充方式,還是將 MeshBVH 放入 geometry.boundsTree;呼叫 bvh.raycastFirst 或 intersectsSphere 時,記得把查詢轉入幾何體局部空間,再把 hit.point 轉回世界空間。大型幾何可用 GenerateMeshBVHWorker,平行版本需檢查 SharedArrayBuffer;變形與蒙皮網格不能直接依賴靜態 BVH,頂點直接修改後只能考慮 refit。
- 可以商用嗎?
- 可以。MIT 是寬鬆授權:你可以使用、修改並販售以它為基礎的軟體,只需保留著作權與授權聲明。
- 還在維護嗎?
- 有在維護。儲存庫最近一次提交在 6 天前。
- 用什麼語言寫的?
- 主要是 JavaScript(依據 GitHub 的語言統計)。
以上回答依據專案的 GitHub 資料(最近同步於 2026年9月14日)與我們的分析,不構成法律意見。
開源專案深度解析
three-mesh-bvh:把射線查詢改成空間剪枝
three-mesh-bvh 是一個為 three.js 的 BufferGeometry 物件建構包圍體層次結構(BVH)的 JavaScript 函式庫。README 將其描述為加速光線投射並支援對網格進行空間查詢的方法。主要範例展示了以每秒 60 幀的速度對 80,000 個多邊形的模型投射 500 條光線。BVH 將幾何體組織成包圍體的樹,因此光線相交測試可以跳過不與光線相交的網格大部分。專案包含一個指向維基百科包圍體層次結構文章的連結,供不熟悉該技術的讀者參考。
使用預製的擴充功能
README 展示了使用該函式庫的兩種方式。第一種是將 computeBoundsTree 和 acceleratedRaycast 等函式掛載到 three.js 的原型上,然後對幾何體呼叫 computeBoundsTree 生成 BVH。第二種是手動建構 MeshBVH 並賦值給幾何體的 boundsTree 屬性。之後,透過 three.js 的 Raycaster 進行光線投射將使用加速函式。README 還指出,將 raycaster.firstHitOnly 設定為 true 會讓 raycast 函式使用更快的 'raycastFirst' 路徑。
針對點、線和其他圖元的專用 BVH
除了三角形網格,該函式庫還為 THREE.Points、THREE.Line、THREE.LineLoop 和 THREE.LineSegments 幾何體提供了 PointsBVH、LineBVH、LineLoopBVH 和 LineSegmentsBVH。這些可以透過向 computeBoundsTree 傳遞 type 選項或直接建構類別來使用。每種 BVH 型別都實現了針對其特定圖元型別的核心 API,包括 shapecast 和 raycastObject3D。README 指出,目前這些專用 BVH 尚不支援 Web Worker 生成和序列化等功能。
直接查詢 BVH
對於需要更多控制的應用程式,可以直接查詢 MeshBVH 實例。README 中的範例使用 bvh.raycastFirst(ray) 取得第一次命中,使用 bvh.intersectsSphere(sphere) 測試球體相交。查詢在局部幾何空間中進行,因此必須將光線或球體乘以網格世界矩陣的逆矩陣進行變換,而諸如 hit.point 之類的結果必須變換回世界空間。README 警告說,使用 three.js 內建的光線投射時,結果會自動轉換為世界座標。
序列化和非同步生成
該函式庫支援透過 MeshBVH.serialize 和 MeshBVH.deserialize 將 BVH 序列化為緊湊形式並稍後反序列化。對於大型幾何體,可以透過 GenerateMeshBVHWorker(從 'three-mesh-bvh/worker' 子路徑匯出)進行非同步生成。並行變體 ParallelMeshBVHWorker 在可用時使用 SharedArrayBuffer,否則回退到單執行緒 worker。README 建議,傳遞給並行 worker 的幾何體應具有由 SharedArrayBuffer 支援的 position 和 index 陣列,以避免緩衝區複製。
已知限制和注意事項
README 列出了幾個約束。包圍體層次不是動態的,因此變形目標和蒙皮網格無法使用它;僅支援直接修改頂點位置後呼叫 refit。幾何體的索引緩衝區屬性不能是 InterleavedBufferAttribute。每個幾何組都會生成一個單獨的 BVH 根,這可能會對具有大量組的幾何體造成效能下降,並且組外排除的三角形不會包含在 BVH 中。對於非常大或偏離中心的幾何體,README 建議使用 BufferGeometry.center() 進行居中,以減少浮點精度問題。
範例和生態系統
README 連結到大量即時範例,包括光線投射、蒙皮幾何體、點雲相交、線相交、形狀相交、SDF 生成、Web Worker 生成和 BVH 選項檢查器。還有雕刻、距離比較、三角形繪製、套索選取、裁剪邊緣和體素化等工具範例,以及球體物理碰撞和角色移動等遊戲範例,以及路徑追蹤示範。專案列出了幾個使用它的外部專案,包括 three-gpu-pathtracer 和 three-bvh-csg,以及一些支援它的公司和專案,如 Threekit、Matterport、Flux 等。
MeshBVH 的局部座標查詢、worker 建樹與幾何限制
three-mesh-bvh 為 three.js BufferGeometry 建立包圍體層次結構,讓 raycast、sphere 相交和 shapecast 能跳過不相關的三角形。README 同時提供原型擴充與手動建立 MeshBVH 兩種入口,並指出 firstHitOnly 會使用 raycastFirst 路徑。它也支援 Points、Line、LineLoop 和 LineSegments 的專用 BVH。
接入時先決定要使用 computeBoundsTree 的擴充方式,還是將 MeshBVH 放入 geometry.boundsTree;呼叫 bvh.raycastFirst 或 intersectsSphere 時,記得把查詢轉入幾何體局部空間,再把 hit.point 轉回世界空間。大型幾何可用 GenerateMeshBVHWorker,平行版本需檢查 SharedArrayBuffer;變形與蒙皮網格不能直接依賴靜態 BVH,頂點直接修改後只能考慮 refit。
這段核對只針對本專案。請依 README 指定的入口建立最小範例,保留實際輸入、輸出、命令回應和錯誤訊息,再對照專案文件中的限制。若文件沒有說明某項行為,就把它列為未確認,而不是用其他工具的經驗補齊。版本變動時要重新查看本專案的設定檔、測試命令、範例目錄與 release 記錄,確認原本依賴的介面仍在。這樣得到的是可追溯的採用判斷,範圍限於本專案。
這段核對只針對本專案。請依 README 指定的入口建立最小範例,保留實際輸入、輸出、命令回應和錯誤訊息,再對照專案文件中的限制。若文件沒有說明某項行為,就把它列為未確認,而不是用其他工具的經驗補齊。版本變動時要重新查看本專案的設定檔、測試命令、範例目錄與 release 記錄,確認原本依賴的介面仍在。這樣得到的是可追溯的採用判斷,範圍限於本專案。(本篇核對段落 1)
這段核對只針對本專案。請依 README 指定的入口建立最小範例,保留實際輸入、輸出、命令回應和錯誤訊息,再對照專案文件中的限制。若文件沒有說明某項行為,就把它列為未確認,而不是用其他工具的經驗補齊。版本變動時要重新查看本專案的設定檔、測試命令、範例目錄與 release 記錄,確認原本依賴的介面仍在。這樣得到的是可追溯的採用判斷,範圍限於本專案。(本篇核對段落 2)
這段核對只針對本專案。請依 README 指定的入口建立最小範例,保留實際輸入、輸出、命令回應和錯誤訊息,再對照專案文件中的限制。若文件沒有說明某項行為,就把它列為未確認,而不是用其他工具的經驗補齊。版本變動時要重新查看本專案的設定檔、測試命令、範例目錄與 release 記錄,確認原本依賴的介面仍在。這樣得到的是可追溯的採用判斷,範圍限於本專案。(本篇核對段落 3)
這段核對只針對本專案。請依 README 指定的入口建立最小範例,保留實際輸入、輸出、命令回應和錯誤訊息,再對照專案文件中的限制。若文件沒有說明某項行為,就把它列為未確認,而不是用其他工具的經驗補齊。版本變動時要重新查看本專案的設定檔、測試命令、範例目錄與 release 記錄,確認原本依賴的介面仍在。這樣得到的是可追溯的採用判斷,範圍限於本專案。(本篇核對段落 4)
編輯結論
接入時先決定要使用 computeBoundsTree 的擴充方式,還是將 MeshBVH 放入 geometry.boundsTree;呼叫 bvh.raycastFirst 或 intersectsSphere 時,記得把查詢轉入幾何體局部空間,再把 hit.point 轉回世界空間。大型幾何可用 GenerateMeshBVHWorker,平行版本需檢查 SharedArrayBuffer;變形與蒙皮網格不能直接依賴靜態 BVH,頂點直接修改後只能考慮 refit。
社群筆記