Reputation: 438
I generally program Unity3D related stuff, I'm still pretty new to Maya's python API.
What I'm trying to do is to get the currently selected face normals average:
What I achieved until now is an instance of a cube positioned according to the Move Manipulator.
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)
Now what I only need is to rotate the cube to the face average normals of the selection
Please, any thoughts about this?
Maya does have any method to give me those angles? I tried to rotate using polyInfo with face normals, but I think I'm missing something...
EDIT:
The final solution (thanks to @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)
Upvotes: 2
Views: 6099
Reputation: 12218
You can achieve what you want without solving the issue in the question. The normalConstraint
node will orient an object towards the closest available face normal. If you just want the face alignment, you can position your object and then create and immediately delete a normalConstraint. A minimal version would be:
constr = cmds.normalConstraint('reference_object',
'object_to_align',
aimVector = (0,0,1),
worldUpType= 0)
cmds.delete(constr)
where the aim vector is the local axis that will be aligned to the surface. (There are a lot of options for how to do the alignment, you should check the docs in the normalConstraint command for more).
To actually get the face normal, you can use the polyNormalPerVertex
command to get the vertex-face normals for a face (they'll come back as numbers so you don't need to regex it. You will need to average them:
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
However those are in local space. The only way to convert them to world space is to turn them into a vector (using Pymel or the Maya api) and then multiply them against the object matrix (also using the API). Once you have a world space vector you can construct a new matrix using that vector as the 'aim vector', the world up, and the cross vector of those as a new matrix for the object you want to align..
... all of which is not super hard but it's a lot of work if you don't know the API well yet. Which is why I'd try the normalConstraint trick first.
Upvotes: 3