以下介紹一種針對簡單、封閉、三角化的 3D 網格進行體積計算的快速演算法。此假設是散度定理的結果。進一步的擴展或許能推廣到其他網格,但目前不在範圍內。

我們從體積的定義開始,即對某區域內常數一的三重積分:

V = ∭ R 1 d V

令 F 為 ℝ³ 中的一個函數,其散度等於一。為方便本文討論,我們選擇:

𝐅 ( x , y , z ) = < x , 0 , 0 >

div 𝐅 = ∂F/∂x + ∂F/∂y + ∂F/∂z = 1 + 0 + 0 = 1

V = ∭ R 1 d V = ∭ R div 𝐅 ( x , y , z ) d V

根據散度定理,這等於表面積分:

V = ∬ S 𝐅 ( x , y , z ) d 𝐒

此表面積分定義在 3D 網格的表面 S 上,等於其分段三角形部分的總和。令 Ti 表示網格中第 i 個三角形的表面。則:

V = ∑ᵢ<0xE2><0x82><0x8A>₀ ∬<0xE1><0xB5><0xA2>ᵢ 𝐅 ( x , y , z ) d 𝐒

令 Tinᵢ 表示第 i 個三角形的第 n 個頂點。令 Δ₁ 等於 Tᵢ₁ 和 Tᵢ₀ 之間的向量差,Δ₂ 同樣等於 Tᵢ₂ - Tᵢ₀。每個獨立的三角形 Ti 可參數化為:

𝐫 ( u , v ) = Tᵢ₀ + u Δ₁ + v Δ₂

接著,簡單微分可得:

𝐫<0xE1><0xB5><0xA2> = Δ₁

𝐫<0xE1><0xB5><0xA3> = Δ₂

𝐫<0xE1><0xB5><0xA2> × 𝐫<0xE1><0xB5><0xA3> = Δ₁ × Δ₂

因此,表面積分可以根據此參數化重寫,並在需要時代入 𝐅 的定義:

V = ∑ᵢ<0xE2><0x82><0x8A>₀ ∬<0xE1><0xB5><0xA2>ᵢ 𝐅 ( x , y , z ) ( 𝐫<0xE1><0xB5><0xA2> × 𝐫<0xE1><0xB5><0xA3> ) d A = ∑ᵢ<0xE2><0x82><0x8A>₀ ∬<0xE1><0xB5><0xA2>ᵢ 𝐅 ( x , y , z ) ( ̇ Δᵢ₁ × Δᵢ₂ ) d A = ∑ᵢ<0xE2><0x82><0x8A>₀ ∬<0xE1><0xB5><0xA2>ᵢ < x , 0 , 0 > ( ̇ Δᵢ₁ × Δᵢ₂ ) d A

此叉積在整個三角形內是常數,且易於從頂點數據計算。由於與 𝐅 的零分量的點積,只有叉積的 X 分量需要計算;其他分量為零。因此,V 可重寫為:

V = ∑ᵢ<0xE2><0x82><0x8A>₀ ( Δᵢ₁ × Δᵢ₂ )ₓ ∬<0xE1><0xB5><0xA2>ᵢ x d A

我們現在專注於表面積分 ∬<0xE1><0xB5><0xA2>ᵢ x d A。使用參數化展開得到:

∬<0xE1><0xB5><0xA2>ᵢ x d A = ∫₀¹ ∫₀<0xE1><0xB5><0xA2> ( Tᵢ₀ₓ + u Δᵢ₁ₓ + v Δᵢ₂ₓ ) d v d u

此積分可以被直接評估,將頂點數據視為常數:

∫₀¹ ∫₀<0xE2><0x81><0xBB>¹⁻<0xE1><0xB5><0xA2> ( Tᵢ₀ₓ + u Δᵢ₁ₓ + v Δᵢ₂ₓ ) d v d u = Tᵢ₀ₓ ∫₀¹ ∫₀<0xE2><0x81><0xBB>¹⁻<0xE1><0xB5><0xA2> d v d u + Δᵢ₁ₓ ∫₀¹ ∫₀<0xE2><0x81><0xBB>¹⁻<0xE1><0xB5><0xA2> u d v d u + Δᵢ₂ₓ ) ∫₀¹ ∫₀<0xE2><0x81><0xBB>¹⁻<0xE1><0xB5><0xA2> v d v d u = Tᵢ₀ₓ ( 1/2 ) + Δᵢ₁ₓ ( 1/6 ) + Δᵢ₂ₓ ( 1/6 )

= Tᵢ₀ₓ ( 1/2 ) + ( Tᵢ₁ₓ - Tᵢ₀ₓ ) ( 1/6 ) + ( Tᵢ₂ₓ - Tᵢ₀ₓ ) ( 1/6 )

= Tᵢ₀ₓ ( 1/6 ) + Tᵢ₁ₓ ( 1/6 ) + Tᵢ₂ₓ ( 1/6 )

= 1/6 ( Tᵢ₀ₓ + Tᵢ₁ₓ + Tᵢ₂ₓ )

將其代入原始總和並提出常數因子 1/6 以避免內部循環除法,得到體積的緊湊公式如下:

V = 1/6 ∑ᵢ<0xE2><0x82><0x8A>₀ ( Δᵢ₁ × Δᵢ₂ )ₓ ( Tᵢ₀ₓ + Tᵢ₁ₓ + Tᵢ₂ₓ )

最終的演算法不包含數值積分或微分。與常見的體積計算的樸素演算法(相當於渲染網格然後對渲染結果進行採樣,這是一個昂貴的操作)相比,此演算法只有一個循環,遍歷網格中的三角形。因此,此體積計算演算法的時間複雜度為 O(n),其中 n 是三角形的數量。此外,每個三角形的計算同樣高效:考慮到叉積的自然展開,內部包含七次加法和三次乘法。循環外部只有一次乘法。因此,對於一個包含 n 個三角形的網格,該演算法需要 8n-1 次加法和 3n+1 次乘法,或 11n 次浮點運算。這非常快速。

作為一個粗略的數字,如果需要在每秒 60 幀的高性能應用程式中計算體積,且不借助 GPU,僅使用 $35 的 Raspberry Pi 的 CPU 能力,每幀大約可以測量 3000 萬個三角形。

向量微積分考試即將到來,我需要學習。而且,誰不喜歡 3D 圖形呢?

如果這個演算法是新穎的,我會(愉快地)感到驚訝。發布後的進一步研究發現了 Cha Zheng 和 Tsuhan Chen 的論文「Efficient Feature Extraction for 2D/3D Objects in Mesh Representation」,其中似乎描述了相同的演算法,儘管推導方式不同。能持續有趣就好!