【发布时间】:2013-08-08 20:35:18
【问题描述】:
我正在尝试找出一种计算世界空间点是否在任意网格内的方法。
如果它不是立方体或球体,我不太确定如何计算它。
任何帮助都会很棒!
【问题讨论】:
我正在尝试找出一种计算世界空间点是否在任意网格内的方法。
如果它不是立方体或球体,我不太确定如何计算它。
任何帮助都会很棒!
【问题讨论】:
您可以使用简单的光线追踪技巧来测试您是在形状内部还是外部。事实证明,2D、3D 对象甚至可能更高维度的对象都具有整洁的属性。也就是说,如果你在任何方向上射出任意光线,那么当且仅当你击中你的形状边界并且达到奇数次时,你就在形状内。无需知道法线方向或任何东西。只知道你有多少个十字路口。这很容易在 2D 中可视化,并且由于 3D 只是许多 2D 切片,因此同样适用于 3D。
图1:从一个点向任意方向射出一条射线,如果在里面,在外面产生偶数,所以O1在里面,而O1 O2 不是。作为一种特殊情况,扫视命中需要测试曲线,因为它们会使 2 个命中在一个地方重合 (O3)。
图 2: 网格表面具有更好的边界条件,因为只有顶点命中在掠过 但是大多数跟踪引擎会忽略掠过命中,因为完全垂直的命中 (O4) 将是有问题,因此他们在本次测试中表现正确。 Maya 追踪器也不例外。
请注意,这种方法不需要关闭表面,它仍然有效,它只是关闭了光线方向上的间隙,打开的表面可能会报告奇怪的结果。但在某些情况下可以接受。
诚然,光线追踪在没有加速例程的情况下是相当繁重的操作,但是一旦加速到位,它就会变得相当快。 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))
在您的具体情况下,这可能是矫枉过正。我假设你在做某种拒绝抽样。也可以用棱镜构建身体并使用重心坐标随机化。这具有从不浪费结果的优点。但是跟踪代码更容易使用。
【讨论】:
如果您尝试为任何网格解决此问题,您将遇到麻烦,因为并非每个任意网格都是封闭的。如果您的网格可以假定为闭合且格式良好,那么您可能需要执行 3D 填充算法之类的操作,以确定是否有一条路径可以通向可以从您正在测试的点看到对象外部的点。
如果您愿意采用更宽松的方法来为您提供近似答案,并假设法线都一致地指向外部,则此页面上有一个用 MEL 编写的代码示例,您可以将其转换为蟒蛇。
【讨论】:
标记是正确的,没有保证测试适用于开放网格。此外,任意网格测试会既慢又昂贵,因此请先尝试便宜的测试(边界球和/或边界框)。如果你的网格上有任何开放的边缘,你也可以告诉用户“对不起,没有骰子”——这保证了“内部”的概念没有解决方案
如果您想要一个比边界测试更好但又不像体素测试那样昂贵的近似答案,您可以使用qHull 或类似的东西为您的网格生成凸包并针对凸网格进行测试。这不会处理由内向外扭曲的网格的严重凹陷,但会比边界测试更优雅地捕捉形状奇特的物体。
如果您真的需要速度或拥有复杂的对象,您可能希望对对象进行体素化并测试体素数据。这对于编写脚本来说通常过于数学化(例如,参见this),而且实现起来也并非易事。
说了这么多,这里是使用内置 nParticles 的非常hacky近似体素:
如果您有 nParticles (maya 2011 +),您可以尝试用粒子填充您的对象 (nParticles > createNParticles > Fill Object)。然后,您可以根据粒子集中每个粒子的位置对您的点进行距离测试。如果到任何粒子的距离小于或等于粒子的半径,则您处于“内部”到粒子半径精度的 1/2 以内。您会注意到,某些形状不能由 nparticle 填充 - 这些形状是您无论如何都无法测试“内在性”的形状。
【讨论】: