我正在试图找出一种计算世界空间点是否在任意网格内部的方法。
如果它不是立方体或球体,我不太确定如何计算它。
任何帮助都会很棒!
答案 0 :(得分:12)
可以使用简单的光线追踪技巧来测试您是在形状内部还是外部。事实证明,2D,3D对象或甚至更高维度的对象具有整洁的属性。也就是说,如果您在形状内部的任何方向上拍摄任意光线,并且只有当您触及形状和奇数次的边界时。无需知道正常方向或任何东西。只知道你有多少个十字路口。这很容易在2D中可视化,因为3D也只是许多2D切片同样适用于3D。
图1:从任意方向的点射出光线会产生奇数次的命中,如果在内部,即使在外部,所以O_1在内部而O_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))
在您的具体情况下,这可能是矫枉过正。我假设你做了某种拒绝抽样。也可以用棱镜构建物体并用重心坐标随机化。这具有永不浪费结果的优点。但跟踪代码通常更容易使用。
答案 1 :(得分:1)
如果您尝试为任何网格解决此问题,您将遇到麻烦,因为并非每个任意网格都已关闭。如果您的网格可以假定为闭合且格式良好,那么您可能必须执行类似3D填充填充算法的操作,以确定是否存在可以从您正在测试的点外部看到对象外部的点的路径。 / p>
如果您愿意采用更宽松的方法来给出一个近似的答案,并假设法线都是向外均匀指出的话,那么这个页面上的代码示例(用MEL编写)可能会转换为蟒。
答案 2 :(得分:0)
马克是正确的,没有保证测试适用于开放网格。此外,任意网格测试将变得缓慢且昂贵,因此首先尝试廉价测试(边界球和/或边界框)。如果您的网格上有任何开放边缘,您也可以告诉用户“对不起,没有骰子” - 这可以保证“内部”概念没有解决方案
如果你想要一个比边界测试更好但不像体素测试那样昂贵的近似答案,你可以使用qHull或类似的东西来为你的网格生成凸包并测试凸面啮合。这不会处理内部扭曲的网格的严重凹陷,但会捕获比边界测试更优雅的奇形状对象。
如果您确实需要速度或具有复杂对象,您可能想要对对象进行体素化并测试体素数据。对于脚本来说,这通常过于繁重(例如,请参阅this)并且实现起来并非易事。
所有这一切,这里是使用内置nParticle的非常hacky 近似的体素:
如果你有nParticles(maya 2011 +),你可以尝试用粒子填充你的对象( nParticles> createNParticles>填充对象)。然后,您可以将您的点与粒子集中每个粒子的位置进行距离测试。如果到任何粒子的距离小于或等于粒子的半径,则“内部”在1/2粒子半径范围内。你会注意到有些形状不能用nparticles填充 - 无论如何你都无法测试'insideness'。