OpenMaya api 2.0 中 MFnNurbsSurface.closestPoint 的问题

Trouble with MFnNurbsSurface.closestPoint in OpenMaya api 2.0

我最近了解到 python OpenMaya api v2.0,所以我一直在检查我的代码并尝试更新它以使用 2.0 版本。在大多数情况下,它对我来说比旧版本的 OpenMaya 更有意义...

我在尝试使用 OpenMaya.MFnNurbsSurface.closestPoint 方法时 运行 遇到了麻烦。我似乎无法弄清楚如何实际使用 kwargs 作为方法。 Maya 的文档是这样说的:

closestPoint(testPoint, uStart=None, vStart=None,
    ignoreTrimBoundaries=False, tolerance=kPointTolerance,
    space=kObject) -> (MPoint, float, float)

所以对我来说,这看起来像是我应该能够使用的 kwargs...但是我几乎每次尝试使用它们时都会遇到错误 - 当它没有错误时,我真的不理解为什么它没有(下面的例子)。如果我不输入 kwargs,它 'works' 但不会给我正确的结果,因为我实际上确实需要更改其中一些 kwargs。

下面是执行此操作的新旧方法的一些代码(新的正是我目前所拥有的...):

import maya.OpenMaya as oldOM
import maya.api.OpenMaya as om

def getClosestPointOnSurfaceOLD(surf, position):
    selList = oldOM.MSelectionList()
    selList.add(surf)
    mDagPath = oldOM.MDagPath()
    selList.getDagPath(0, mDagPath)
    surfFn = oldOM.MFnNurbsSurface(mDagPath)

    u_util = oldOM.MScriptUtil()
    u_util.createFromDouble(0)
    u_param = u_util.asDoublePtr()

    v_util = oldOM.MScriptUtil()
    v_util.createFromDouble(0)
    v_param = v_util.asDoublePtr()

    p = surfFn.closestPoint(oldOM.MPoint(*position), u_param, v_param, False, 1.0, oldOM.MSpace.kWorld)

    return [(p[0], p[1], p[2]), (oldOM.MScriptUtil.getDouble(u_param), oldOM.MScriptUtil.getDouble(v_param))]

def getClosestPointOnSurfaceNEW(surf, position):
    selList = om.MSelectionList()
    selList.add(surf)
    surfFn = om.MFnNurbsSurface(selList.getDagPath(0))

    p, u, v = surfFn.closestPoint(om.MPoint(*position), ignoreTrimBoundaries=False, tolerance=1.0, space=om.MSpace.kWorld)

    return [(p[0], p[1], p[2]), (u, v)]

我已经通过创建一个 nurbsPlane(使用默认设置)然后将它在 y 方向向上移动 0.5 个单位并将两个函数的输出与这些行进行比较来测试它:

getClosestPointOnSurfaceOLD('nurbsPlane1', (0.0, 1.0, 0.0))
getClosestPointOnSurfaceNEW('nurbsPlane1', (0.0, 1.0, 0.0))

# Result: [(-2.7755575615628914e-17, 0.5, 2.7755575615628914e-17), (0.5, 0.5)] # <-- old function result
# Error: TypeError: file <maya console> line 28: integer argument expected, got float # <-- new function result

我在我的函数中尝试用 'closestPoint' 行做的其他事情:

surfFn.closestPoint(om.MPoint(*position), ignoreTrimBoundaries=False)
# Result: [(-2.7755575615628914e-17, -1.5407439555097887e-33, 2.7755575615628914e-17), (0.5, 0.5)] #

surfFn.closestPoint(om.MPoint(*position), False)
# Result: [(-1.1102230246251565e-16, -6.162975822039155e-33, 1.1102230246251565e-16), (0.5, 0.5)] #

surfFn.closestPoint(om.MPoint(*position), tolerance=1.0)
# Error: TypeError: file <maya console> line 28: integer argument expected, got float #

surfFn.closestPoint(om.MPoint(*position), tolerance=1)
# Error: RuntimeError: file <maya console> line 28: More keyword list entries (6) than format specifiers (5) #

surfFn.closestPoint(om.MPoint(*position), 1.0)
# Result: [(-1.1102230246251565e-16, -6.162975822039155e-33, 1.1102230246251565e-16), (0.5, 0.5)] #

surfFn.closestPoint(om.MPoint(*position), space=om.MSpace.kWorld)
# Error: RuntimeError: file <maya console> line 28: More keyword list entries (6) than format specifiers (5) #

surfFn.closestPoint(om.MPoint(*position), om.MSpace.kWorld)
# Result: [(-1.1102230246251565e-16, -6.162975822039155e-33, 1.1102230246251565e-16), (0.5, 0.5)] #

surfFn.closestPoint(om.MPoint(*position))
# Result: [(-2.7755575615628914e-17, -1.5407439555097887e-33, 2.7755575615628914e-17), (0.5, 0.5)] #

surfFn.closestPoint(om.MPoint(*position), False, 1.0, om.MSpace.kWorld)
# Result: [(-2.7755575615628914e-17, 3.851859888774472e-33, -6.938893903907228e-17), (0.5, 0.5000000000000001)] #

surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), uStart=0.0, vStart=0.0, ignoreTrimBoundaries=False, tolerance=1.0, space=om.MSpace.kWorld)
# Error: TypeError: file <maya console> line 28: integer argument expected, got float #

surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 0.0, 0.0, False, 1.0, om.MSpace.kWorld)
# Error: TypeError: file <maya console> line 28: integer argument expected, got float #

输出中的一些差异对我来说很奇怪,错误似乎没有意义(比如调整 'tolerance' arg 值时的差异)...另外,事实证明0.5 的 uv 值是正确的只是巧合 - 如果我移动 and/or 旋转平面,旧函数 returns 不同的 uv 值而新函数总是 returns 0.5 因为它正在评估来自平面对象 space 的测试点而不是使用世界 space.

我还查看了相应的旧 OpenMaya 命令的文档,其中有两个条目 - 如果您要提供一些起始 uv 值,其中一个条目有一个 'paramAsStart' 布尔值 arg。认为 2.0 文档可能错过了这一点,我也尝试将其添加到我的 api 2.0 尝试中......它也没有用(给我一个错误,我传递了太多的参数)。

至少,我需要弄清楚如何让它评估来自世界的测试点space;然而,当我继续使用 OpenMaya api 2.0 时,我确定我会再次 运行 遇到这种类型的事情(kwargs 似乎不起作用......) - 任何帮助如何实际使用这些 kwargs 表示赞赏!

编辑:

更多测试 - 在 theodox 的回答之后,我猜测文档中的 arg 顺序可能不正确......所以,我决定测试排列。假设 uStartvStart 将始终彼此相邻,给出 "kwargs" 的 24 个排列,但我决定也尝试 None、0.0 和 0 作为它们的值(72测试!)。 ALL 出错了。

这是我的测试线:

surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), None, None, False, 1.0, om.MSpace.kWorld)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), None, None, False, om.MSpace.kWorld, 1.0)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), None, None, 1.0, False, om.MSpace.kWorld)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), None, None, 1.0, om.MSpace.kWorld, False)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), None, None, om.MSpace.kWorld, False, 1.0)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), None, None, om.MSpace.kWorld, 1.0, False)

surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), False, None, None, 1.0, om.MSpace.kWorld)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), False, None, None, om.MSpace.kWorld, 1.0)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), False, 1.0, None, None, om.MSpace.kWorld)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), False, 1.0, om.MSpace.kWorld, None, None)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), False, om.MSpace.kWorld, None, None, 1.0)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), False, om.MSpace.kWorld, 1.0, None, None)

surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 1.0, None, None, False, om.MSpace.kWorld)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 1.0, None, None, om.MSpace.kWorld, False)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 1.0, False, None, None, om.MSpace.kWorld)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 1.0, False, om.MSpace.kWorld, None, None)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 1.0, om.MSpace.kWorld, None, None, False)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 1.0, om.MSpace.kWorld, False, None, None)

surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), om.MSpace.kWorld, None, None, False, 1.0)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), om.MSpace.kWorld, None, None, 1.0, False)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), om.MSpace.kWorld, False, None, None, 1.0)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), om.MSpace.kWorld, False, 1.0, None, None)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), om.MSpace.kWorld, 1.0, None, None, False)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), om.MSpace.kWorld, 1.0, False, None, None)



surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 0.0, 0.0, False, 1.0, om.MSpace.kWorld)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 0.0, 0.0, False, om.MSpace.kWorld, 1.0)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 0.0, 0.0, 1.0, False, om.MSpace.kWorld)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 0.0, 0.0, 1.0, om.MSpace.kWorld, False)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 0.0, 0.0, om.MSpace.kWorld, False, 1.0)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 0.0, 0.0, om.MSpace.kWorld, 1.0, False)

surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), False, 0.0, 0.0, 1.0, om.MSpace.kWorld)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), False, 0.0, 0.0, om.MSpace.kWorld, 1.0)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), False, 1.0, 0.0, 0.0, om.MSpace.kWorld)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), False, 1.0, om.MSpace.kWorld, 0.0, 0.0)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), False, om.MSpace.kWorld, 0.0, 0.0, 1.0)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), False, om.MSpace.kWorld, 1.0, 0.0, 0.0)

surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 1.0, 0.0, 0.0, False, om.MSpace.kWorld)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 1.0, 0.0, 0.0, om.MSpace.kWorld, False)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 1.0, False, 0.0, 0.0, om.MSpace.kWorld)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 1.0, False, om.MSpace.kWorld, 0.0, 0.0)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 1.0, om.MSpace.kWorld, 0.0, 0.0, False)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 1.0, om.MSpace.kWorld, False, 0.0, 0.0)

surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), om.MSpace.kWorld, 0.0, 0.0, False, 1.0)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), om.MSpace.kWorld, 0.0, 0.0, 1.0, False)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), om.MSpace.kWorld, False, 0.0, 0.0, 1.0)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), om.MSpace.kWorld, False, 1.0, 0.0, 0.0)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), om.MSpace.kWorld, 1.0, 0.0, 0.0, False)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), om.MSpace.kWorld, 1.0, False, 0.0, 0.0)



surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 0, 0, False, 1.0, om.MSpace.kWorld)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 0, 0, False, om.MSpace.kWorld, 1.0)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 0, 0, 1.0, False, om.MSpace.kWorld)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 0, 0, 1.0, om.MSpace.kWorld, False)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 0, 0, om.MSpace.kWorld, False, 1.0)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 0, 0, om.MSpace.kWorld, 1.0, False)

surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), False, 0, 0, 1.0, om.MSpace.kWorld)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), False, 0, 0, om.MSpace.kWorld, 1.0)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), False, 1.0, 0, 0, om.MSpace.kWorld)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), False, 1.0, om.MSpace.kWorld, 0, 0)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), False, om.MSpace.kWorld, 0, 0, 1.0)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), False, om.MSpace.kWorld, 1.0, 0, 0)

surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 1.0, 0, 0, False, om.MSpace.kWorld)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 1.0, 0, 0, om.MSpace.kWorld, False)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 1.0, False, 0, 0, om.MSpace.kWorld)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 1.0, False, om.MSpace.kWorld, 0, 0)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 1.0, om.MSpace.kWorld, 0, 0, False)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), 1.0, om.MSpace.kWorld, False, 0, 0)

surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), om.MSpace.kWorld, 0, 0, False, 1.0)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), om.MSpace.kWorld, 0, 0, 1.0, False)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), om.MSpace.kWorld, False, 0, 0, 1.0)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), om.MSpace.kWorld, False, 1.0, 0, 0)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), om.MSpace.kWorld, 1.0, 0, 0, False)
surfFn.closestPoint(om.MPoint(0.0, 1.0, 0.0), om.MSpace.kWorld, 1.0, False, 0, 0)

这些是可能会出现的常见错误:

# Error: RuntimeError: file <maya console> line 1: More keyword list entries (6) than format specifiers (5) #
# Error: TypeError: file <maya console> line 1: integer argument expected, got float #
# Error: TypeError: file <maya console> line 1: an integer is required #
# Error: TypeError: file <maya console> line 1: a float is required #

如果有人有兴趣,我可以post line/errors...

所以,我猜这是一个 Maya 错误 - 呸...

我认为这是文档生成方式的一个怪癖。 C++ 版本以 Python 程序员看起来像 kwargs 的方式编写默认参数。但它不是真正的 kwargs,它是默认参数。您必须将它们视为只是命名的位置参数并按顺序提供它们。

这对我有用:

def getClosestPointOnSurfaceNEW(surf, position):
    selList = om.MSelectionList()
    selList.add(surf)
    surfFn = om.MFnNurbsSurface(selList.getDagPath(0))

    p, u, v = surfFn.closestPoint(om.MPoint(*position))

    return [(p[0], p[1], p[2]), (u, v)]

也是

    p, u, v = surfFn.closestPoint(om.MPoint(*position), 0, 0 )

通常,如果您想提供更多参数,通常只需按顺序提供:

p, u, v = surfFn.closestPoint(om.MPoint(*position), 0,0, False, 0.01, om.MSpace.kWorld)

但是我无法验证它是否有效,因为它会使我的(测试版)Maya 崩溃;不确定 2017 年或 2018 年的生产状态。

我也在 Autodesk Maya 论坛中发布了这个...结果发现有一个已知的错误。

这里有 link 给 maya forum thread 如果有人好奇