4

我试图找出一种计算世界空间点是否在任意网格内的方法。

如果它不是立方体或球体,我不太确定如何计算它的数学。

任何帮助都会很棒!

4

3 回答 3

15

可以使用一种简单的光线追踪技巧来测试您是在形状内部还是外部。事实证明,2D、3D 对象甚至可能更高维度的对象都具有整洁的属性。也就是说,如果你在任何方向上发射任意光线,你就在形状内,当且仅当你击中形状的边界和奇数次。无需知道法线方向或任何东西。只知道你有多少个十字路口。这很容易在 2D 中可视化,并且由于 3D 只是许多 2D 切片,因此同样适用于 3D。

在此处输入图像描述

图 1:从一个点向任意方向发射光线会产生奇数个命中,如果在内部,即使在外部,所以 O 1在内部,O 2不在。作为一种特殊情况,需要测试扫视命中的曲线,因为它们使 2 个命中在一个地方重合 (O 3 )。

在此处输入图像描述

图 2:网格表面具有更好的边界条件,因为只有顶点命中在掠过 但是大多数跟踪引擎会忽略掠过命中,因为完全垂直的命中 (O 4 ) 会出现问题,因此它们的行为对于本测试而言是正确的。玛雅示踪剂也不例外。

请注意,这种方法不需要关闭表面,它仍然有效,它只是关闭了光线方向的间隙,打开的表面可能会报告奇怪的结果。但在某些情况下可以接受。

诚然,光线追踪在没有加速程序的情况下是相当繁重的操作,但是一旦加速到位,它就会变得非常快。Maya API 为此提供了一种方法。请注意,首先构建加速器,然后每次后续调用都便宜得多。这是一个没有加速的快速编写的脚手架,有关如何加速的更多信息,请参阅MFnMesh的文档:

import maya.cmds as cmd
import maya.OpenMaya as om 

def test_if_inside_mesh(point=(0.0, 0.0, 0.0), dir=(0.0, 0.0, 1.0)):
    sel = om.MSelectionList()
    dag = om.MDagPath()

    #replace torus with arbitrary shape name
    sel.add("pTorusShape1")
    sel.getDagPath(0,dag)

    mesh = om.MFnMesh(dag)

    point = om.MFloatPoint(*point)
    dir = om.MFloatVector(*dir)
    farray = om.MFloatPointArray()

    mesh.allIntersections(
            point, dir,
            None, None,
            False, om.MSpace.kWorld,
            10000, False,
            None, # replace none with a mesh look up accelerator if needed
            False,
            farray,
            None, None,
            None, None,
            None
        ) 
    return farray.length()%2 == 1   

#test
cmd.polyTorus()
print test_if_inside_mesh()
print test_if_inside_mesh((1,0,0))

在您的具体情况下,这可能是矫枉过正。我假设你在做某种拒绝抽样。也可以用棱镜构建主体并使用重心坐标随机化。这具有从不浪费结果的优点。但是跟踪代码通常更容易使用。

于 2013-08-11T18:50:41.560 回答
2

如果你试图为任何网格解决这个问题,你会遇到麻烦,因为不是每个任意网格都是封闭的。如果可以假设您的网格是闭合的且格式良好,那么您可能需要执行 3D 填充算法之类的操作,以确定是否有一条路径可以通向可以从您正在测试的点看到对象外部的点。

如果您愿意采取更宽松的方法来给您一个大致的答案,并假设法线都一致地指向外部,那么此页面上有一个用 MEL 编写的代码示例,您可以将其转换为 Python。

http://forums.cgsociety.org/archive/index.php/t-747732.html

于 2013-08-08T21:04:45.337 回答
1

马克是正确的,没有保证测试适用于开放网格。此外,任意网格测试将变得缓慢且昂贵,因此请先尝试廉价测试(边界球体和/或边界框)。如果你的网格上有任何开放的边缘,你也可以告诉用户“对不起,没有骰子”——这保证了“内部”的概念没有解决方案

如果您想要一个比边界测试更好但又不像体素测试那样昂贵的近似答案,您可以使用qHull或类似的东西为您的网格生成凸包并针对凸网格进行测试。这不会处理由内向外扭曲的网格的严重凹陷,但会比边界测试更优雅地捕捉形状奇特的物体。

如果您真的需要速度或有复杂的对象,您可能想要体素化对象并测试体素数据。这对于编写脚本来说通常过于数学化(例如,参见this)并且实现起来并非易事。

综上所述,这是一个使用内置 nParticles 的体素近似值:

如果您有 nParticles (maya 2011 +),您可以尝试用粒子填充您的对象 ( nParticles > createNParticles > Fill Object )。然后,您可以根据粒子集中每个粒子的位置对您的点进行距离测试。如果到任何粒子的距离小于或等于粒子的半径,则您处于“内部”到 1/2 粒子半径精度以内。您会注意到某些形状不能被 nparticles 填充 - 这些形状是您无论如何都无法测试“内在性”的形状。

于 2013-08-08T21:50:26.493 回答