69

我想计算具有由三角形组成的表面的 3D 网格对象的体积。

4

4 回答 4

108

阅读这篇论文,实际上是一个非常简单的计算。

诀窍是计算四面体的有符号体积- 基于您的三角形并在原点处达到顶峰。体积的符号来自你的三角形是否指向原点的方向。(三角形的法线本身取决于顶点的顺序,这就是为什么您没有看到下面明确引用它的原因。)

这一切都归结为以下简单功能:

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());
}
于 2009-10-14T19:47:39.513 回答
31

Yip Frank Kruegers 的回答对此效果很好 +1。如果您有可用的矢量函数,您也可以使用它:

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

编辑..添加了impl。如果您不确定,请使用 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
            );
        }
        ...
    }
于 2012-12-18T06:43:59.700 回答
4

GNU Triangulated Surface Library 可以为您做到这一点。请记住,曲面必须是封闭的。对于很多 3D 模型来说,情况并非如此。

如果你想自己实现它,你可以先看看他们的代码。

于 2009-09-10T15:56:52.513 回答
0

上面的方法对于像球体四面体等“简单”对象(没有相交/重叠的三角形)是正确的。对于更复杂的形状,一个好主意是分割网格(关闭它)并分别计算每个部分的体积。希望这可以帮助。

于 2015-04-24T13:59:00.087 回答