如何在 Maya 中获得平均面法线?

How to get face normals average in Maya?

我通常编写 Unity3D 相关的东西,我对 Maya 还是很陌生 python API。

我要做的是获取当前选定的面法线平均值:

到目前为止,我实现的是根据移动操纵器定位的立方体实例。

import maya.cmds as cmds
import re #regular expression

# get current position of the move manipulator
pos = cmds.manipMoveContext('Move', q=True, p=True)

# get the current selection
selection = cmds.ls(sl=True)

# trying to get the face normal angles of the current selection
polyInfo = cmds.polyInfo(selection, fn=True)
polyInfoArray = re.findall(r"[\w.-]+", polyInfo[0]) # convert the string to array with regular expression
polyInfoX = float(polyInfoArray[2])
polyInfoY = float(polyInfoArray[3])
polyInfoZ = float(polyInfoArray[4])

print str(polyInfoX) + ', ' + str(polyInfoY) + ', ' + str(polyInfoZ)

target = cmds.polyCube()

cmds.move(pos[0], pos[1], pos[2], target)

现在我只需要将立方体旋转到选区的面平均法线

请问有什么想法吗?

Maya有什么方法可以给我这些角度吗?我尝试使用带有面法线的 polyInfo 进行旋转,但我想我遗漏了一些东西...

编辑:

最终解决方案(感谢@theodox)

import maya.cmds as cmds

# get current position of the move manipulator
pos = cmds.manipMoveContext('Move', query=True, position=True) 

# get the current selection
selection = cmds.ls(selection=True)

target = cmds.polyCube()

cmds.move(pos[0], pos[1], pos[2], target)

constr = cmds.normalConstraint(selection, target, aimVector = (0,0,1), worldUpType= 0)
cmds.delete(constr)

不解决问题中的问题,你也可以达到你想要的效果。 normalConstraint 节点会将对象定向到最近的可用面法线。如果你只是想要面部对齐,你可以定位你的对象,然后创建并立即删除一个 normalConstraint。最小版本为:

 constr = cmds.normalConstraint('reference_object', 
                                'object_to_align', 
                                 aimVector = (0,0,1),
                                 worldUpType= 0)
 cmds.delete(constr)

其中目标向量是将与表面对齐的局部轴。 (关于如何进行对齐有很多选项,您应该查看 normalConstraint 命令中的文档以获取更多信息)。

要真正获得面的法线,您可以使用 polyNormalPerVertex 命令来获得面的顶点面法线(它们将以数字形式返回,因此您不需要对其进行正则表达式。您需要对它们进行平均:

def face_normal(face):
    vtxface = cmds.polyListComponentConversion(face, tvf = True)
    xes = cmds.polyNormalPerVertex(vtxface, q=True, x =True)
    yes = cmds.polyNormalPerVertex(vtxface, q=True, y =True)
    zes = cmds.polyNormalPerVertex(vtxface, q=True, z =True)
    divisor = 1.0 / len(xes)
    return sum(xes)* divisor, sum(yes)  * divisor, sum(zes) * divisor

然而那些在本地space。将它们转换为世界 space 的唯一方法是将它们转换为矢量(使用 Pymel 或 Maya api),然后将它们与对象矩阵相乘(也使用 API) .一旦你有了一个世界 space 向量,你就可以使用该向量作为 'aim vector'、世界向上和它们的交叉向量作为你想要对齐的对象的新矩阵来构造一个新矩阵。 .

...所有这些都不是 超级 难,但是如果您还不了解 API 的话,需要做很多工作。这就是为什么我会先尝试 normalConstraint 技巧。