跳到主内容
@wquguru
精选70Hacker News Best(web_list)技巧与观点

用散度定理极速计算三维网格体积的算法

用散度定理极速计算体积

原文
发到 X

(No, there won’t be jokes.)

(不,不会有笑话。)

The following presents a fast algorithm for volume computation of a simple, closed, triangulated 3D mesh. This assumption is a consequence of the divergence theorem. Further extensions may generalise to other meshes as well, although that is presently out of scope.

以下内容介绍了一种用于计算简单、封闭、三角化三维网格体积的快速算法。这一假设是散度定理的结果。进一步的扩展可能也适用于其他网格,尽管目前这不在讨论范围内。

We begin with the definition of volume as the triple integral over a region of the constant one:

我们首先将体积定义为区域上常数一的三重积分:

V=∭R1dVV = \iiint_R 1 \mathrm{d}V

V=∭R1dVV = \iiint_R 1 \mathrm{d}V

Let 𝐅\mathbf{F} be a function in ℝ3\mathbb{R}^3 such that its divergence is equal to one. For the purposes of this paper, we choose:

设 𝐅\mathbf{F} 为 ℝ3\mathbb{R}^3 中的一个函数,其散度等于一。出于本文的目的,我们选择:

𝐅(x,y,z)=<x,0,0>\mathbf{F}(x, y, z) = <x, 0, 0>

𝐅(x,y,z)=<x,0,0>\mathbf{F}(x, y, z) = <x, 0, 0>

It can easily be verified that

可以轻松验证:

div𝐅=∂F∂x+∂F∂y+∂F∂z=1+0+0=1\mathrm{div} \mathbf{F} = \frac{\partial F}{\partial x} + \frac{\partial F}{\partial y} + \frac{\partial F}{\partial z} = 1 + 0 + 0 = 1

div𝐅=∂F∂x+∂F∂y+∂F∂z=1+0+0=1\mathrm{div} \mathbf{F} = \frac{\partial F}{\partial x} + \frac{\partial F}{\partial y} + \frac{\partial F}{\partial z} = 1 + 0 + 0 = 1

Therefore,

因此,

V=∭R1dV=∭Rdiv𝐅(x,y,z)dVV = \iiint_R 1 dV = \iiint_R \mathrm{div} \mathbf{F}(x, y, z) \mathrm{d}V

V=∭R1dV=∭Rdiv𝐅(x,y,z)dVV = \iiint_R 1 dV = \iiint_R \mathrm{div} \mathbf{F}(x, y, z) \mathrm{d}V

By the Divergence Theorem, this is equal to the surface integral:

根据散度定理,这等于曲面积分:

V=∬S𝐅(x,y,z)d𝐒V = \iint_S \mathbf{F}(x, y, z) \mathrm{d}\mathbf{S}

V=∬S𝐅(x,y,z)d𝐒V = \iint_S \mathbf{F}(x, y, z) \mathrm{d}\mathbf{S}

This surface integral, defined over the surface S of the 3D mesh, is equal to the sum of its piecewise triangle parts. Let TiT_i denote the surface of the ii’th triangle in the mesh. Then,

这个定义在三维网格表面 S 上的曲面积分,等于其逐片三角形部分之和。设 TiT_i 表示网格中第 ii 个三角形的表面。那么,

V=∑i=0∬Ti𝐅(x,y,z)d𝐒V = \sum_{i = 0} \iint_{T_i} \mathbf{F}(x, y, z) \mathrm{d}\mathbf{S}

V=∑i=0∬Ti𝐅(x,y,z)d𝐒V = \sum_{i = 0} \iint_{T_i} \mathbf{F}(x, y, z) \mathrm{d}\mathbf{S}

Let TinT_{in} represent the nn’th vertex of the ii’th triangle. Let Δ1\Delta_1 equal the vector difference between Ti1T_{i1} and Ti0T_{i0}, and Δ2\Delta_2 likewise equal to Ti2−Ti0T_{i2} - T{i0}. Each individual triangle TiT_i may thus be parametrised as:

设 TinT_{in} 表示第 ii 个三角形的第 nn 个顶点。设 Δ1\Delta_1 等于 Ti1T_{i1} 与 Ti0T_{i0} 之间的向量差,Δ2\Delta_2 同样等于 Ti2−Ti0T_{i2} - T{i0}。因此,每个单独的三角形 TiT_i 可以参数化为:

𝐫(u,v)=Ti0+uΔ1+vΔ2\mathbf{r}(u, v) = T_{i0} + u\Delta_1 + v\Delta_2

𝐫(u,v)=Ti0+uΔ1+vΔ2\mathbf{r}(u, v) = T_{i0} + u\Delta_1 + v\Delta_2

Then, simple differentiation yields:

然后,简单的微分得到:

𝐫u=Δ1\mathbf{r}_u = \Delta_1 𝐫v=Δ2\mathbf{r}_v = \Delta_2

𝐫u=Δ1\mathbf{r}_u = \Delta_1 𝐫v=Δ2\mathbf{r}_v = \Delta_2

Therefore,

因此,

𝐫u×𝐫v=Δ1×Δ2\mathbf{r}_u \times \mathbf{r}_v = \Delta_1 \times \Delta_2

𝐫u×𝐫v=Δ1×Δ2\mathbf{r}_u \times \mathbf{r}_v = \Delta_1 \times \Delta_2

Thus, the surface integral can be rewritten in terms of this parametrisation, substituting in the definition of 𝐅\mathbf{F} as needed:

因此,曲面积分可以用这个参数化重写,并根据需要代入 𝐅\mathbf{F} 的定义:

V=∑i=0∬Ti𝐅(x,y,z)(𝐫u×𝐫v)dAV = \sum_{i = 0} \iint_{T_i} \mathbf{F}(x, y, z) (\mathbf{r}_u \times \mathbf{r}_v) dA =∑i=0∬Ti𝐅(x,y,z)(̇Δi1×Δi2)dA= \sum_{i = 0} \iint_{T_i} \mathbf{F}(x, y, z) \dot (\Delta_{i1} \times \Delta_{i2}) dA =∑i=0∬Ti<x,0,0>(̇Δi1×Δi2)dA= \sum_{i = 0} \iint_{T_i} <x, 0, 0> \dot (\Delta_{i1} \times \Delta_{i2}) dA

V=∑i=0∬Ti𝐅(x,y,z)(𝐫u×𝐫v)dAV = \sum_{i = 0} \iint_{T_i} \mathbf{F}(x, y, z) (\mathbf{r}_u \times \mathbf{r}_v) dA =∑i=0∬Ti𝐅(x,y,z)(̇Δi1×Δi2)dA= \sum_{i = 0} \iint_{T_i} \mathbf{F}(x, y, z) \dot (\Delta_{i1} \times \Delta_{i2}) dA =∑i=0∬Ti<x,0,0>(̇Δi1×Δi2)dA= \sum_{i = 0} \iint_{T_i} <x, 0, 0> \dot (\Delta_{i1} \times \Delta_{i2}) dA

This cross product is constant throughout the triangle and easy to calculate from the vertex data. Only the X component of the cross product should be calculated; the others are equal to zero due to the dot product with the zero components of 𝐅\mathbf{F}. VV can be thus be rewritten as:

这个叉积在整个三角形中是常数,并且易于从顶点数据计算。只需计算叉积的 X 分量;由于与 𝐅\mathbf{F} 的零分量点积,其他分量等于零。因此,VV 可以重写为:

V=∑i=0(Δi1×Δi2)x∬TixdAV = \sum_{i = 0} (\Delta_{i1} \times \Delta_{i2})_x \iint_{T_i} x dA

V=∑i=0(Δi1×Δi2)x∬TixdAV = \sum_{i = 0} (\Delta_{i1} \times \Delta_{i2})_x \iint_{T_i} x dA

We now focus on the surface integral ∬TixdA\iint_{T_i} x dA. Expanding with the parametrisation yields:

现在我们关注表面积分 ∬TixdA\iint_{T_i} x dA。用参数化展开得到:

∬TixdA=∫01∫0uxdvdu=∫01∫0u(Ti0x+uΔi1x+vΔi2x)dvdu\iint_{T_i} x dA = \int_{0}^{1} \int_{0}^{u} x dv du = \int_{0}^{1} \int_{0}^{u} (T_{i0x} + u \Delta_{i1x} + v \Delta_{i2x}) dv du

∬TixdA=∫01∫0uxdvdu=∫01∫0u(Ti0x+uΔi1x+vΔi2x)dvdu\iint_{T_i} x dA = \int_{0}^{1} \int_{0}^{u} x dv du = \int_{0}^{1} \int_{0}^{u} (T_{i0x} + u \Delta_{i1x} + v \Delta_{i2x}) dv du

This integral can be directly evaluated, treating vertex data as constants:

这个积分可以直接求值,将顶点数据视为常数:

∫01∫01−u(Ti0x+uΔi1x+vΔi2x)dvdu\int_{0}^{1} \int_{0}^{1-u} (T_{i0x} + u \Delta_{i1x} + v \Delta_{i2x}) dv du =Ti0x∫01∫01−udvdu+Δi1x∫01∫01−uudvdu+Δi2x)∫01∫01−uvdvdu= T_{i0x} \int_{0}^{1} \int_{0}^{1-u} dv du + \Delta_{i1x} \int_{0}^{1} \int_{0}^{1-u} u dv du + \Delta_{i2x}) \int_{0}^{1} \int_{0}^{1-u} v dv du =Ti0x(12)+Δi1x(16)+Δi2x(16)= T_{i0x} (\frac{1}{2}) + \Delta_{i1x} (\frac{1}{6}) + \Delta_{i2x} (\frac{1}{6}) =Ti0x(12)+(Ti1x−Ti0x)(16)+(Ti2x−Ti0x)(16)= T_{i0x} (\frac{1}{2}) + (T_{i1x} - T_{i0x})(\frac{1}{6}) + (T_{i2x} - T_{i0x})(\frac{1}{6}) =Ti0x(16)+(Ti1x)(16)+(Ti2x)(16)= T_{i0x} (\frac{1}{6}) + (T_{i1x})(\frac{1}{6}) + (T_{i2x})(\frac{1}{6}) =16(Ti0x+Ti1x+Ti2x)= \frac{1}{6}(T_{i0x} + T_{i1x} + T_{i2x})

∫01∫01−u(Ti0x+uΔi1x+vΔi2x)dvdu\int_{0}^{1} \int_{0}^{1-u} (T_{i0x} + u \Delta_{i1x} + v \Delta_{i2x}) dv du =Ti0x∫01∫01−udvdu+Δi1x∫01∫01−uudvdu+Δi2x)∫01∫01−uvdvdu= T_{i0x} \int_{0}^{1} \int_{0}^{1-u} dv du + \Delta_{i1x} \int_{0}^{1} \int_{0}^{1-u} u dv du + \Delta_{i2x}) \int_{0}^{1} \int_{0}^{1-u} v dv du =Ti0x(12)+Δi1x(16)+Δi2x(16)= T_{i0x} (\frac{1}{2}) + \Delta_{i1x} (\frac{1}{6}) + \Delta_{i2x} (\frac{1}{6}) =Ti0x(12)+(Ti1x−Ti0x)(16)+(Ti2x−Ti0x)(16)= T_{i0x} (\frac{1}{2}) + (T_{i1x} - T_{i0x})(\frac{1}{6}) + (T_{i2x} - T_{i0x})(\frac{1}{6}) =Ti0x(16)+(Ti1x)(16)+(Ti2x)(16)= T_{i0x} (\frac{1}{6}) + (T_{i1x})(\frac{1}{6}) + (T_{i2x})(\frac{1}{6}) =16(Ti0x+Ti1x+Ti2x)= \frac{1}{6}(T_{i0x} + T_{i1x} + T_{i2x})

Substituting into the original sum and pulling out a constant factor of 16\frac{1}{6} to avoid the inner loop division, this yields the following compact formula for the volume:

将其代入原始求和并提取常数因子 16\frac{1}{6} 以避免内循环除法,得到以下紧凑的体积公式:

V=16∑i=0(Δi1×Δi2)x(Ti0x+Ti1x+Ti2x)V = \frac{1}{6} \sum_{i = 0} (\Delta_{i1} \times \Delta_{i2})_x (T_{i0x} + T_{i1x} + T_{i2x})

V=16∑i=0(Δi1×Δi2)x(Ti0x+Ti1x+Ti2x)V = \frac{1}{6} \sum_{i = 0} (\Delta_{i1} \times \Delta_{i2})_x (T_{i0x} + T_{i1x} + T_{i2x})

Performance analysis

性能分析

The final algorithm contains no numerical integration nor differentiation. In contrast to common naive algorithms for volume, which are equivalent to rendering the mesh and then sampling the render, an expensive operation, there is only a single loop in this algorithm, over the triangles. Thus, this algorithm for volume computation is O(n) to the number of the triangles. Furthermore, the per-triangle calculation is similarly efficient: given the natural expansion of the cross product, the inner part contains seven additions and three multiplications. On the outside of the loop is only a single multiplication. Thus, for a mesh of nn triangles, the algorithm requires 8n−18n - 1 additions and 3n+13n + 1 multiplications, or 11n11n floating point operations. This is very fast.

最终算法不包含数值积分或微分。与常见的朴素体积算法(相当于渲染网格然后采样渲染结果,这是昂贵的操作)相比,该算法仅有一个循环,遍历三角形。因此,该体积计算算法的时间复杂度为O(n),其中n为三角形数量。此外,每个三角形的计算同样高效:利用叉积的自然展开,内部部分包含七次加法和三次乘法。循环外部仅有一次乘法。因此,对于包含n个三角形的网格,该算法需要8n−1次加法和3n+1次乘法,即11n次浮点运算。这非常快速。

For a ballpark number, if volume needs to be calculated every frame in a high-performance 60 frames per second application, without the aid of a GPU, only using the CPU capabilities of a $35 Raspberry Pi, around 30 million triangles could be measured every frame.

粗略估算,如果在高性能的每秒60帧应用中每帧都需要计算体积,且不使用GPU,仅依靠价值35美元的树莓派的CPU能力,每帧可测量约三千万个三角形。

Motivation

动机

The vector calculus exam is soon, and I need to study. Plus, who doesn’t love 3D graphics?!

向量微积分考试临近,我需要学习。而且,谁不喜欢3D图形呢?!

I would be (pleasantly) surprised if the algorithm is novel. Further research after posting reveals the paper Efficient Feature Extraction for 2D/3D Objects in Mesh Representation by Cha Zheng and Tsuhan Chen, which appears to describe the same algorithm, although the derivation is different. It was fun while it lasted!

如果该算法是新颖的,我会(愉快地)感到惊讶。发布后的进一步研究发现论文《网格表示中2D/3D对象的有效特征提取》(作者:Cha Zheng和Tsuhan Chen),该论文似乎描述了相同的算法,尽管推导方式不同。这很有趣,虽然短暂!

Retourner à l’accueil

返回首页

更进一步:量化金融体系

看懂新闻只是起点——沿量化金融路径,把它变成能交付的工程能力

进入量化体系 →

相似阅读

另一事件,读法相近