【问题标题】:How to find matching vertices in multiple maya meshes如何在多个 Maya 网格中找到匹配的顶点
【发布时间】:2015-04-17 21:28:32
【问题描述】:

我正在尝试将一个网格上的顶点位置与另一个网格进行比较,并生成一个配对顶点列表,(最终目的是将颈部几何上的顶点与身体几何的顶部顶点配对。)

我“配对”它们的方式是比较两个网格中所有顶点之间的距离,然后通过在单独的列表中对它们进行排序来匹配最接近的顶点,(neck_geo_verts[0] 与 body_geo_verts[ 0].)

我想使用 OpenMaya,因为我听说它比 cmds.xform 快得多。

这是我目前获取顶点的代码,尽管它使用的是 cmds 而不是 Maya API。我很难从 Maya 文档中找到我需要的东西。

# The user selects an edge on both the bottom of the neck and top of the body, then this code gets all the vertices in an edge border on both of those geos and populates two lists with the vertices

import maya.cmds as mc
import maya.api.OpenMaya as om
import re

mc.unloadPlugin('testingPlugin.py')
mc.loadPlugin('testingPlugin.py')

def main():
    geoOneVerts = []
    geoTwoVerts = []

    edges = cmds.ls(selection=True, sn=True)

    geoOneEdgeNum = re.search(r"\[([0-9_]+)\]", edges[0])
    geoTwoEdgeNum = re.search(r"\[([0-9_]+)\]", edges[1])

    cmds.polySelect(add=True, edgeBorder=int(geoOneEdgeNum.group(1)))
    geoOneEdgeBorder = cmds.ls(selection=True, sn=True)
    geoOneEdgeVerts = cmds.polyInfo(edgeToVertex=True)

    for vertex in geoOneEdgeVerts:
        vertexPairNums = re.search(r":\s*([0-9_]+)\s*([0-9_]+)", vertex)
        geoOneVerts.append(vertexPairNums.group(1))
        geoOneVerts.append(vertexPairNums.group(2))

    cmds.polySelect(replace=True, edgeBorder=int(geoTwoEdgeNum.group(1)))
    geoTwoEdgeBorder = cmds.ls(selection=True, sn=True)
    geoTwoEdgeVerts = cmds.polyInfo(edgeToVertex=True)

    for vertex in geoTwoEdgeVerts:
        vertexPairNums = re.search(r":\s*([0-9_]+)\s*([0-9_]+)", vertex)
        geoTwoVerts.append(vertexPairNums.group(1))
        geoTwoVerts.append(vertexPairNums.group(2))

    geoOneVerts = list(set(geoOneVerts))
    geoTwoVerts = list(set(geoTwoVerts))

    # How do I use OpenMaya to compare the distance from the verts in both lists?

main()

编辑:此代码为我提供了两个列表,其中填充了两个网格上顶点的 DAG 名称。我不确定如何获取这些顶点的位置来比较两个列表中顶点之间的距离,我也不确定我是否应该使用maya.cmds 而不是maya.api.OpenMaya 考虑到我的顶点数量'将开始手术。

EDIT2:感谢 Theodox 和数百次搜索的帮助。我最终制作了一个使用边界顶点工作的版本,并且假设两个网格上的成对顶点将位于相同的全局空间中。出于性能原因,我都选择使用 Maya API 并完全放弃了 Maya 命令。

Vesion1(使用边界顶点):

import maya.OpenMaya as om

def main():
    geo1Verts = om.MFloatPointArray()
    geo2Verts = om.MFloatPointArray()

    selectionList = om.MSelectionList()
    om.MGlobal.getActiveSelectionList(selectionList)

    geo1SeamVerts = getSeamVertsOn(selectionList, 1)
    geo2SeamVerts = getSeamVertsOn(selectionList, 2)

    pairedVertsDict = pairSeamVerts(geo1SeamVerts, geo2SeamVerts)

def getSeamVertsOn(objectList, objectNumber):
    count = 0 
    indexPointDict = {}
    selectedObject = om.MObject()

    iter = om.MItSelectionList(objectList, om.MFn.kGeometric)
    while not iter.isDone():
        count += 1

        connectedVerts = om.MIntArray()

        if (count != objectNumber):
            iter.next()
        else:
            iter.getDependNode(selectedObject)
            vertexIter = om.MItMeshVertex(selectedObject)

            while not vertexIter.isDone():
                if (vertexIter.onBoundary()):
                    vertex = om.MPoint()
                    vertex = vertexIter.position()
                    indexPointDict[int(vertexIter.index())] = vertex

                vertexIter.next()

            return indexPointDict

def pairSeamVerts (dictSeamVerts1, dictSeamVerts2):
    pairedVerts = {}

    if (len(dictSeamVerts1) >= len(dictSeamVerts2)):
        for vert1 in dictSeamVerts1:
            distance = 0
            closestDistance = 1000000
            vertPair = 0

            for vert2 in dictSeamVerts2:
                distance = dictSeamVerts1[vert1].distanceTo(dictSeamVerts2[vert2])

                if (distance < closestDistance):
                    closestDistance = distance
                    vertPair = vert2

            pairedVerts[vert1] = vertPair

        return (pairedVerts)

    else:
        for vert1 in dictSeamVerts2:
            distance = 0
            closestDistance = 1000000
            vertPair = 0

            for vert2 in dictSeamVerts1:
                distance = dictSeamVerts2[vert1].distanceTo(dictSeamVerts1[vert2])

                if (distance < closestDistance):
                    closestDistance = distance
                    vertPair = vert2

            pairedVerts[vert1] = vertPair

        return (pairedVerts)

main()

Version2(假设成对的顶点共享一个全局空间):

import maya.OpenMaya as om

def main():   
    selectionList = om.MSelectionList()
    om.MGlobal.getActiveSelectionList(selectionList)

    meshOneVerts = getVertPositions(selectionList, 1)
    meshTwoVerts = getVertPositions(selectionList, 2)

    meshOneHashedPoints = hashPoints(meshOneVerts)
    meshTwoHashedPoints = hashPoints(meshTwoVerts)

    matchingVertList = set(meshOneHashedPoints).intersection(meshTwoHashedPoints)

    pairedVertList = getPairIndices(meshOneHashedPoints, meshTwoHashedPoints, matchingVertList)

def getVertPositions(objectList, objectNumber):
    count = 0
    pointList = []

    iter = om.MItSelectionList(objectList, om.MFn.kGeometric)
    while not iter.isDone():
        count = count + 1
        if (count != objectNumber):
            iter.next()

        dagPath = om.MDagPath()
        iter.getDagPath(dagPath)
        mesh = om.MFnMesh(dagPath)

        meshPoints = om.MPointArray()
        mesh.getPoints(meshPoints, om.MSpace.kWorld)

        for point in range(meshPoints.length()):
            pointList.append([meshPoints[point][0], meshPoints[point][1], meshPoints[point][2]])
        return pointList

def hashPoints(pointList):
    _clamp = lambda p: hash(int(p * 10000) / 10000.00)

    hashedPointList = []

    for point in pointList:
        hashedPointList.append(hash(tuple(map(_clamp, point))))

    return (hashedPointList)

def getPairIndices(hashListOne, hashListTwo, matchingHashList):
    pairedVertIndices = []
    vertOneIndexList = []
    vertTwoIndexList = []

    for hash in matchingHashList:
        vertListOne = []
        vertListTwo = []

        for hashOne in range(len(hashListOne)):
            if (hashListOne[hashOne] == hash):
                vertListOne.append(hashOne)

        for hashTwo in range(len(hashListTwo)):
            if (hashListTwo[hashTwo] == hash):
                vertListTwo.append(hashTwo)

        pairedVertIndices.append([vertListOne, vertListTwo])

    return pairedVertIndices

main()

【问题讨论】:

  • 您能否更具体地说明您在任务的哪一部分遇到问题?
  • 你有两个顶点的位置,你只是想得到它们之间的距离吗?或者你在问如何找到一个顶点的位置?
  • 清除它 - 我有两个带有顶点编号的列表,(即 [u'7810', u'5292'... 等)我展示了我目前使用 Maya 的位置.cmds 但我不确定如何从我所拥有的中获取顶点位置,我也不确定使用 maya.cmds 是考虑到我正在操作的顶点数量的最佳选择。
  • Maya cmds 应该可以正常运行,直到您感觉到非常明显的性能下降。 cmds.ls() 是否感觉慢到你想提高它的效率?

标签: python api 3d maya vertices


【解决方案1】:

对于距离比较方法,API 明显更快,但在这种情况下,我认为真正的杀手可能是算法。将每个顶点与其他顶点进行比较需要大量的数学运算。

可能最简单的做法是想出一种方法来散列顶点:将每个 xyz 点转换为一个值,可以在不计算距离的情况下与其他点进行比较:两个具有相同散列的顶点必然是在同一个位置。您可以调整哈希算法以稍微量化顶点位置以同时解决浮点错误。

这是一种散列点的方法(低至 4 位有效数字,您可以通过更改 _clamp 中的常量来调整):

def point_hash(point):
    '''
    hash a tuple, probably a cmds vertex pos
    '''
    _clamp = lambda p: hash(int(p * 10000) / 10000.00)
    return hash(tuple(map(_clamp, point)))

只要两组顶点都在同一个空间(可能是世界空间)中进行散列,相同的散列将意味着匹配的顶点。您所要做的就是遍历每个网格,创建一个字典,将顶点散列键控到顶点索引。这是在 cmds 中执行此操作的一种方法:

def vert_dict(obj):
    '''
    returns a dictionary of hash: index pairs representing the hashed verts of <obj>
    '''
    results = dict()
    verts = cmds.xform(obj + ".vtx[*]", q=True, t=True, ws=True)
    total = len(verts)/ 3
    for v in range(total):
        idx = v * 3
        hsh = point_hash (verts[idx: idx + 3])
        results[hsh] = v
    return results         

您可以通过将两个字典中的键相交来找到相交的顶点(两个网格中都存在的顶点)。然后通过在两个字典中查找将两个网格中的匹配顶点转换回顶点索引。

除非网格真的很重,否则这应该在没有 API 的情况下是可行的,因为所有工作都在没有 API 模拟的哈希函数中。

唯一可能的问题是确保顶点在同一个空间中。如果由于某种原因无法将顶点置于同一空间中,则必须使用基于距离的策略。

【讨论】:

  • 或者构建一个更适合距离搜索的 bsp/octree/rangetree
  • 我最终在我的第二个版本中使用了哈希,这对我有很大帮助,我用我的工具的工作版本更新了我的问题。
  • RE "您可以调整哈希算法以稍微量化顶点位置以同时解决浮点错误。' - 这不可靠:散列(又名“桶”)的限制是两个点可以非常接近,但落入不同的桶中。因此,如果您的点不相同,那么对于给定的点,ALSO查看 NEXT 桶(哈希值 + 1)和 PREVIOUS 桶(哈希值 - 1)中的点。如果找到多个点,请进行距离检查以确定哪个点最近。要避免 SQRT,请比较“距离平方” :“dx * dx + dy * dy + dz * dz”
  • 对此没有真正确定性的答案,因为所有数字都是浮点数 - 您将始终与容差进行比较,并且只有在网格完全相同的情况下才能获得精确匹配并且转换更改没有产生任何浮点错误。哈希 + 距离检查会更准确 - 但也会更慢。正确的解决方案实际上取决于网格的密度,
猜你喜欢
  • 2016-12-23
  • 1970-01-01
  • 2019-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多