如何计算由三角形构成表面的3D网格对象的体积

80

我希望计算一个由三角形构成表面的三维网格对象的体积。


3
抱歉,我可以用中文回答您的问题,但我不能进行翻译工作。关于您提供的链接,我理解为您无法给予更多信息,但建议查看该链接以获取更多资讯。 - nlucaroni
似乎与问题1410525重复了。 - DarenW
4个回答

123

阅读本文, 这其实是一个相当简单的计算。

关键是计算四面体的 有符号体积 - 基于你的三角形并在原点处封顶。体积的符号取决于你的三角形是否朝向原点。(三角形的法线本身取决于顶点的顺序,这就是为什么下面没有明确引用它的原因。)

所有这些都归结为以下简单函数:

public float SignedVolumeOfTriangle(Vector p1, Vector p2, Vector p3) {
    var v321 = p3.X*p2.Y*p1.Z;
    var v231 = p2.X*p3.Y*p1.Z;
    var v312 = p3.X*p1.Y*p2.Z;
    var v132 = p1.X*p3.Y*p2.Z;
    var v213 = p2.X*p1.Y*p3.Z;
    var v123 = p1.X*p2.Y*p3.Z;
    return (1.0f/6.0f)*(-v321 + v231 + v312 - v132 - v213 + v123);
}

然后需要一个驱动程序来计算网格的体积:

public float VolumeOfMesh(Mesh mesh) {
    var vols = from t in mesh.Triangles
               select SignedVolumeOfTriangle(t.P1, t.P2, t.P3);
    return Math.Abs(vols.Sum());
}

3
相当优雅的解决方案。 - levis501
我在想为什么这个在2001年之前没有被发现。或者说它已经被发现了,但是没有相关性? - Lenar Hoyt
2
1984年10月,论文《一种计算任意非凸多面体积分性质的符号方法》被发表,描述了这种计算体积的方法。但这只是一个比较简单的方法,因此你需要更多的信息才能发表一篇论文。 - R.Falque
3
“在原点处进行“topped off”并不是强制的,您可以选择任何一个固定点。如果对象距离原点相当远,这将导致数值不稳定。最好从网格中选择任意一个点。” - galinette
2
在二维中,这是Green定理的一个简单计算机应用(例如,可使用面积仪):您可以通过曲线上的线积分计算由曲线围成的区域。在三维中,它是散度定理(高斯定理)的一个应用:您可以通过边界表面上的通量积分计算由该边界围成的体积(对于其散度为1的向量场)。边界不需要是凸的,但它们需要是闭合的。 - armando.sano
显示剩余7条评论

39

Yip Frank Krueger的答案很有效,+1。如果您有可用的向量函数,也可以使用它:

    public static float SignedVolumeOfTriangle(Vector p1, Vector p2, Vector p3)
    {
        return p1.Dot(p2.Cross(p3)) / 6.0f;
    }

如果您不确定,可以编辑并添加Dot()和Cross()的实现。大多数数学库都会有这些功能。如果您正在使用WPF,则它们作为Vector3D类的静态方法实现。

    public class Vector
    {
        ... 

        public float Dot(Vector a)
        {
            return this.X * a.X + this.Y * a.Y + this.Z * a.Z;
        }

        public Vector Cross(Vector a)
        {
            return new Vector(
              this.Y * a.Z - this.Z * a.Y,
              this.Z * a.X - this.X * a.Z,
              this.X * a.Y - this.Y * a.X
            );
        }
        ...
    }

也许可以发布Dot()和Cross()的代码吗?(两者都很容易实现,但为了完整性)。顺便说一句,@Frank Kruegers的答案是如果简化p1.Dot(p2.Cross(p3)) / 6.0f所得到的。 - Mitch Wheat

4

8
如果您重新实现此功能,请小心 - GTS库采用LGPL许可,因此任何派生作品必须遵循LGPL或GPL。 - Cascabel

0

上述方法适用于“简单”对象(没有相交/重叠的三角形),如球体、四面体等。对于更复杂的形状,一个好的想法是将网格分段(关闭它)并分别计算每个段的体积。希望这能有所帮助。


4
如果音量有符号,你不需要中心在内部。 - makc
2
答案错误。所描述的方法适用于任意复杂的闭合对象,没有相交/重叠的三角形,并且对中心点的位置没有任何要求。这是因为四面体“体积”被签名并代数地添加。 - galinette
@Galinette 是的,你说得对。我所谓的“简单”对象是指没有相交/重叠三角形的对象。此外,网格的中心可以在外部。 - Anoroah
用三维布尔运算对其进行裁剪。 - Aquarius Power

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接