Как найти соседей по лицу в Maya?

У меня проблема, когда мне нужно выбрать лица, которые находятся рядом с одним предварительно выбранным лицом.

Это можно сделать легко, но проблема в том, что когда я получаю лицо соседа, мне нужно знать, в каком направлении он смотрит.

Итак, теперь я могу выбрать грани, которые связаны с ребром, но я не могу получить грань, которая, например, находится слева или справа от первой выбранной грани. Я пробовал несколько подходов, но не могу найти решения.

Я пробовал:

  1. pickWalk - cmds.pickWalk()- проблема в том, что его поведение невозможно предсказать, поскольку он проходит по сетке с точки зрения камеры.

  2. polyInfo - cmds.polyInfo() - это очень полезная функция и наиболее близкая к ответу. В этом подходе я пытаюсь выделить края грани, а затем с помощью edgeToFace() посмотреть, какие из них являются соседями. Это хорошо работает, но не решает мою проблему. Чтобы уточнить, когда polyInfo возвращает грани с общими краями, он не возвращает их таким образом, чтобы я всегда мог знать, что edgesList[0] (например) - это край, указывающий влево или вправо. Следовательно, если я использую это на разных гранях, полученное лицо может быть обращено в разных направлениях в каждом случае.

  3. Трудный путь с множеством преобразований из вершины в ребро, затем в грань и т. д. Но опять же, это та же проблема, когда я не знаю, какое ребро является верхним или левым.

  4. conectedFaces()method, который я вызываю для выбранного лица, и он возвращает лица, которые связаны с первым лицом, но все равно это та же проблема, я не знаю, какое лицо смотрит в какую сторону.

Для ясности, я не использую заранее выбранный список лиц и не проверяю их, но мне нужно знать лица, не зная и не храня где-нибудь их имена. Кто-нибудь знает способ, который работает с выделением лиц?

Чтобы прояснить свой вопрос, я сделал изображение, чтобы прояснить его:

пример

Как видно из примера, если есть выделенное лицо, мне нужно выбрать любую из заостренных граней, но это должно быть именно то лицо, которое я хочу выбрать. Другие методы выбирают все соседние грани, но мне нужен метод, в котором я могу сказать «выберите право» и выберет правильное из первого выбранного лица.


person Dimitar    schedule 04.11.2016    source источник
comment
Так не нравится выращивать отбор? Что определяет их направление? Их позиция?   -  person Green Cell    schedule 05.11.2016
comment
Я обновил вопрос примером изображения для моей проблемы, чтобы вопрос можно было лучше понять.   -  person Dimitar    schedule 05.11.2016
comment
Что вам нужно подумать, так это то, какие критерии вы используете, чтобы определить, что находится слева / справа / вверх / вниз. Если ваша сетка не имеет 4 ребра и выровнена по общей оси, вам необходимо предоставить определение того, что такое верх. В этой проблеме отсутствует это ключевое требование, чтобы дать полезный ответ.   -  person scottiedoo    schedule 05.11.2016
comment
да, у каждого лица должно быть 4 края. Я хочу, чтобы он работал хотя бы таким образом. Положение объекта в другой руке может быть любым. . поэтому он должен быть объектно-ориентированным. чтобы уточнить более подробно: если я поверну объект, а затем верхняя грань, которую я получаю, будет обращена вниз, это нормально. точка состоит в том, чтобы каким-то образом пройти через грани, но это движение не должно быть случайным. Термины, которые я использую, такие как вверх, вниз ... предназначены для объяснения, какое лицо с выбранной точки зрения мне нужно получить, а не в мировых координатах.   -  person Dimitar    schedule 06.11.2016
comment
Что ж, вы можете получить все смежные грани от той, от которой вы двигаетесь, а затем получить их центральное положение. Затем, скажем, вы движетесь вверх, вы можете выбрать тот, у которого наивысшая позиция по оси Y. Это также будет означать, что это не обязательно должен быть четырехугольник, поскольку он всегда сравнивается с тем, что находится рядом. Может ли это быть решением?   -  person Green Cell    schedule 06.11.2016


Ответы (3)


Это одно из решений, которое будет достаточно согласованным при условии, что верх / низ / лево / право выровнены с преобразованием меша (локальное пространство), хотя также может быть мировым пространством.

Первое, что я сделал бы, это построил систему относительных координат грани для каждой грани сетки, используя среднее положение вершины грани, нормаль грани и ось Y мирового пространства преобразования сетки. Это требует небольшой векторной математики, поэтому я воспользуюсь API, чтобы упростить задачу. Эта первая часть создаст систему координат для каждого лица, которую мы будем хранить в списках для будущих запросов. Увидеть ниже.

from maya import OpenMaya, cmds

meshTransform = 'polySphere'
meshShape = cmds.listRelatives(meshTransform, c=True)[0]

meshMatrix = cmds.xform(meshTransform, q=True, ws=True, matrix=True)
primaryUp = OpenMaya.MVector(*meshMatrix[4:7])
# have a secondary up vector for faces that are facing the same way as the original up
secondaryUp = OpenMaya.MVector(*meshMatrix[8:11])

sel = OpenMaya.MSelectionList()
sel.add(meshShape)

meshObj = OpenMaya.MObject()
sel.getDependNode(0, meshObj)

meshPolyIt = OpenMaya.MItMeshPolygon(meshObj)
faceNeighbors = []
faceCoordinates = []

while not meshPolyIt.isDone():

    normal = OpenMaya.MVector()
    meshPolyIt.getNormal(normal)

    # use the seconary up if the normal is facing the same direction as the object Y
    up = primaryUp if (1 - abs(primaryUp * normal)) > 0.001 else secondaryUp

    center = meshPolyIt.center()

    faceArray = OpenMaya.MIntArray()
    meshPolyIt.getConnectedFaces(faceArray)

    meshPolyIt.next()

    faceNeighbors.append([faceArray[i] for i in range(faceArray.length())])

    xAxis = up ^ normal
    yAxis = normal ^ xAxis

    matrixList = [xAxis.x, xAxis.y, xAxis.z, 0,
                  yAxis.x, yAxis.y, yAxis.z, 0,
                  normal.x, normal.y, normal.z, 0,
                  center.x, center.y, center.z, 1]

    faceMatrix = OpenMaya.MMatrix()
    OpenMaya.MScriptUtil.createMatrixFromList(matrixList, faceMatrix)

    faceCoordinates.append(faceMatrix)

Эти функции будут искать и возвращать, какое лицо находится рядом с лицом, заданным в определенном направлении (X и Y) относительно лица. Здесь используется скалярное произведение, чтобы увидеть, какое лицо больше в этом конкретном направлении. Это должно работать с любым количеством граней, но вернет только одно лицо, которое находится в большей части этого направления.

def getUpFace(faceIndex):
    return getDirectionalFace(faceIndex, OpenMaya.MVector(0,1,0))

def getDownFace(faceIndex):
    return getDirectionalFace(faceIndex, OpenMaya.MVector(0,-1,0))

def getRightFace(faceIndex):
    return getDirectionalFace(faceIndex, OpenMaya.MVector(1,0,0))

def getLeftFace(faceIndex):
    return getDirectionalFace(faceIndex, OpenMaya.MVector(-1,0,0))

def getDirectionalFace(faceIndex, axis):
    faceMatrix = faceCoordinates[faceIndex]

    closestDotProd = -1.0
    nextFace = -1

    for n in faceNeighbors[faceIndex]:
        nMatrix = faceCoordinates[n] * faceMatrix.inverse()
        nVector = OpenMaya.MVector(nMatrix(3,0), nMatrix(3,1), nMatrix(3,2))

        dp = nVector * axis

        if dp > closestDotProd:
            closestDotProd = dp
            nextFace = n

    return nextFace

Вы бы назвали это так:

getUpFace(123) 

Число является индексом лица, и вы хотите получить лицо, которое находится "вверх" от него.

Попробуйте и посмотрите, удовлетворит ли он ваши потребности.

person scottiedoo    schedule 06.11.2016
comment
Я тестировал его, и он работает, но это одна проблема. Если у меня есть лица с одинаковыми координатами Y (пример плоской поверхности), он не работает. Это хорошая идея, но именно поэтому я не использовал координаты раньше, потому что я не могу предсказать, как объект будет расположен в пространстве или грани будут обращены к какой-либо оси, поэтому я могу их проверить. - person Dimitar; 07.11.2016
comment
чтобы уточнить больше. если я сделаю куб и начну подниматься от грани, это работает хорошо. когда я доберусь до края, я точно получу грань, которая находится с другой стороны куба, как я хочу получить. Но затем, когда я вызываю getUpFace на это возвращенное лицо не продолжает следовать по пути, но дает другое лицо (левое или правое). Это не было указано в вопросе, так как я этого не ожидал, но все же это решение работает на 100% для поиска одного лица. - person Dimitar; 07.11.2016
comment
Да, это не сработает, если грани обращены прямо вверх, вы можете поймать этот случай при построении системы координат и установить новый вектор вверх вместо Y. Таким образом, можно обрабатывать эти угловые случаи. Вы могли бы просто получить скалярное произведение вектора нормали и вектора вверх, и, если он имеет очень небольшой допуск на -1 и 1, установите для него что-то еще, что, по вашему мнению, имеет смысл, например Z. Я обновлю свой ответ, включив это. - person scottiedoo; 07.11.2016

polyListComponentConversion

import pprint
init_face = cmds.ls(sl=True)

#get edges
edges = cmds.polyListComponentConversion(init_face, ff=True, te=True)
#get neighbour faces
faces = cmds.polyListComponentConversion(edges, fe=True, tf=True, bo=True)
# show neighbour faces
cmds.select(faces)
# print face normal of each neighbour face
pprint.pprint(cmds.ployInfo(faces,fn=True))
person Ari Gold    schedule 07.11.2016

Самый простой способ сделать это - использовать connectedFaces () Pymel на MeshFace:

http://download.autodesk.com/us/maya/2011help/pymel/generated/classes/pymel.core.general/pymel.core.general.MeshFace.html

import pymel.core as pm

sel = pm.ls(sl=True)[0]
pm.select(sel.connectedFaces())
person gibbonofdoom    schedule 10.11.2016
comment
как вы можете видеть в вопросе, который я уже пробовал с connectedFaces (), он заявил, что это не решает проблему. - person Dimitar; 14.11.2016