如何计算3D质心?

8 投票
4 回答
9165 浏览
提问于 2025-04-16 10:45

有没有所谓的3D质心呢?我想说的是,我这两天一直在这个网站和网上阅读关于质心的内容,所以我对这个话题的现有帖子非常了解,包括维基百科上的内容。

接下来,我来解释一下我想做的事情。基本上,我想选择一些边或者顶点,但不是面。然后,我想把一个物体放在3D质心的位置。

我告诉你我不想要的:

  • 顶点的平均值,因为这样会在细节较多的方向拉得太远。
  • 包围盒的中心,因为我已经有其他方法可以处理这种情况。

我对质心的建议持开放态度,但我不明白这怎么能工作,因为单靠顶点或边并不能定义任何质量,尤其是当我只选择了一个边环的时候。

为了好玩,我会给你展示一些我用PyMEL写的代码,参考了@Emile的代码,但我觉得它并没有按预期工作:

from pymel.core import ls, spaceLocator
from pymel.core.datatypes import Vector
from pymel.core.nodetypes import NurbsCurve

def get_centroid(node):
    if not isinstance(node, NurbsCurve):
        raise TypeError("Requires NurbsCurve.")
    centroid = Vector(0, 0, 0)
    signed_area = 0.0
    cvs = node.getCVs(space='world')
    v0 = cvs[len(cvs) - 1]
    for i, cv in enumerate(cvs[:-1]):
        v1 = cv
        a = v0.x * v1.y - v1.x * v0.y
        signed_area += a
        centroid += sum([v0, v1]) * a
        v0 = v1
    signed_area *= 0.5
    centroid /= 6 * signed_area
    return centroid

texas = ls(selection=True)[0]
centroid = get_centroid(texas)
print(centroid)
spaceLocator(position=centroid)

4 个回答

2

我觉得这个问题很有意思。质心听起来不错,但接下来就要问,每个顶点的质量该怎么算呢?

为什么不考虑每条边的平均长度呢?这些边都和这个顶点有关。这样做可以很好地解决网格比较密集的地方的问题。

3

不仅仅是三维的中心点,还有n维的中心点,计算它的公式可以在你引用的维基百科文章的“通过积分公式”部分找到。

也许你在设置这个积分时遇到了困难?你还没有定义你的形状。

[编辑] 我会根据你的评论来补充这个回答。既然你用边和顶点来描述你的形状,我就假设它是一个多面体。你可以把多面体分成几个金字塔,找到这些金字塔的中心点,然后你形状的中心点就是这些中心点的中心点(这个最后的计算是用ja72的公式来做的)。

我假设你的形状是凸的(没有空心部分——如果不是这样,那就把它分成几个凸的部分)。你可以通过选择一个内部的点并画出边到各个顶点来把它分成金字塔(也就是三角化)。然后你形状的每个面就是一个金字塔的底面。金字塔的中心点有公式可以计算(你可以查一下,距离底面中心点到内部点的距离是1/4)。然后,正如所说的,你形状的中心点就是这些中心点的中心点——ja72的有限计算,而不是积分——在其他回答中有提到。

这和Hugh Bothwell的回答是一样的算法,不过我认为1/4是正确的,而不是1/3。也许你可以在某个地方找到相关的代码,试着用这个描述中的搜索词去找找。

8

理论上,当你把一个物体分成多个小块,每个小块都有一个位置 pos 和一个体积值 volume 时,计算中心点的公式是 centroid = SUM(pos*volume)/SUM(volume)

这个公式正是用来找出一个复合物体的重心的计算方法。

撰写回答