scripted/pyPointOnMeshInfo.py

scripted/pyPointOnMeshInfo.py
1 #
2 # ==========================================================================
3 # Copyright 2015 Autodesk, Inc. All rights reserved.
4 #
5 # Use of this software is subject to the terms of the Autodesk
6 # license agreement provided at the time of installation or download,
7 # or which otherwise accompanies this software in either electronic
8 # or hard copy form.
9 # ==========================================================================
10 #
11 
12 import sys
13 import maya.api.OpenMaya as om
14 
15 def maya_useNewAPI():
16  """
17  The presence of this function tells Maya that the plugin produces, and
18  expects to be passed, objects created using the Maya Python API 2.0.
19  """
20  pass
21 
22 # FUNCTION THAT FINDS THE POINT AND NORMAL OF A POLY AT A SPECIFIED FACE UV COORD ABOUT A SPECIFIED FACE:
23 def getPointAndNormal(meshDagPath, faceIndex, relative, parameterU, parameterV, point, normal, theMesh):
24  polyObj = meshDagPath
25  if not theMesh.isNull():
26  polyObj = theMesh
27  # CREATE FACE ITERATOR, AND SET ITS INDEX TO THAT OF THE SPECIFIED FACE:
28  faceIter = om.MItMeshPolygon(polyObj)
29  faceIter.setIndex(faceIndex)
30 
31  # WHEN "RELATIVE" MODE IS SPECIFIED, CALCULATE THE *ABSOLUTE* UV'S FROM THE SPECIFIED FACE AND "RELATIVE" UV'S:
32  # OTHERWISE, JUST TAKE THE ABSOLUTE UV'S TO BE THE ONES SPECIFIED:
33  u = parameterU
34  v = parameterV
35  if relative:
36  uvs = faceIter.getUVs()
37  uArray = uvs[0]
38  vArray = uvs[1]
39  minU=999999
40  minV=999999
41  maxU=0
42  maxV=0
43  for i in range(len(uArray)):
44  if uArray[i] < minU:
45  minU = uArray[i]
46  if vArray[i] < minV:
47  minV = vArray[i]
48  if uArray[i] > maxU:
49  maxU = uArray[i]
50  if vArray[i] > maxV:
51  maxV = vArray[i]
52 
53  u = minU + parameterU * (maxU - minU)
54  v = minV + parameterV * (maxV - minV)
55 
56  # FIND THE WORLDSPACE COORDINATE AT THE SPECIFIED UV:
57  UV = [u, v]
58  try:
59  newPoint = faceIter.getPointAtUV(UV, om.MSpace.kWorld)
60  point.x = newPoint.x
61  point.y = newPoint.y
62  point.z = newPoint.z
63  point.w = newPoint.w
64  except:
65  pass
66 
67  # FIND THE NORMAL AT THE SPECIFIED UV:
68  meshFn = om.MFnMesh(meshDagPath)
69  if not theMesh.isNull():
70  meshFn.setObject(theMesh)
71  newNormal = meshFn.getClosestNormal(point, om.MSpace.kWorld)
72  normal.x = newNormal[0].x
73  normal.y = newNormal[0].y
74  normal.z = newNormal[0].z
75 
76 #
77 # MAIN CLASS DECLARATION FOR THE MEL COMMAND:
78 #
79 class pointOnMeshCommand(om.MPxCommand):
80  nodeCreated = False
81  positionSpecified = False
82  normalSpecified = False
83  faceIndexSpecified = False
84  relativeSpecified = False
85  parameterUSpecified = False
86  parameterVSpecified = False
87  meshNodeName = ""
88  pointOnMeshInfoName = ""
89  faceIndex = -1
90  relative = False
91  parameterU = 0.0
92  parameterV = 0.0
93 
94  def __init__(self):
95  om.MPxCommand.__init__(self)
96 
97  # METHOD FOR CREATING AN INSTANCE OF THIS COMMAND:
98  @staticmethod
99  def cmdCreator():
100  return pointOnMeshCommand()
101 
102  # MAKE THIS COMMAND UNDOABLE:
103  def isUndoable(self):
104  return True
105 
106  # FIRST INVOKED WHEN COMMAND IS CALLED, PARSING THE COMMAND ARGUMENTS, INITIALIZING DEFAULT PARAMETERS, THEN CALLING redoIt():
107  def doIt(self, args):
108  # PARSE THE COMMAND'S ARGUMENTS:
109  for i in range(len(args)):
110  if ("-name" == args.asString(i)) or ("-na" == args.asString(i)):
111  i = i+1
112  self.pointOnMeshInfoName = args.asString(i)
113 
114  elif ("-position" == args.asString(i)) or ("-p" == args.asString(i)):
115  self.positionSpecified = True
116 
117  elif ("-normal" == args.asString(i)) or ("-nr" == args.asString(i)):
118  self.normalSpecified = True
119 
120  elif ("-faceIndex" == args.asString(i)) or ("-f" == args.asString(i)):
121  self.faceIndexSpecified = True
122  i = i+1
123  temp = args.asInt(i)
124  if temp < 0:
125  raise ValueError("Invalid faceIndex!")
126  faceIndex = temp
127 
128  elif ("-relative" == args.asString(i)) or ("-r" ==args.asString(i)):
129  self.relativeSpecified = True
130  i = i+1
131  self.relative = args.asBool(i)
132 
133  elif ("-parameterU" == args.asString(i)) or ("-u" == args.asString(i)):
134  self.parameterUSpecified = True
135  i = i+1
136  temp = args.asDouble(i)
137  if temp < 0 or temp > 1:
138  raise ValueError("Invalid parameterU!")
139  self.parameterU = temp
140 
141  elif ("-parameterV" == args.asString(i)) or ("-v" == args.asString(i)):
142  self.parameterVSpecified = True
143  i = i+1
144  temp = args.asDouble(i)
145  if temp < 0 or temp > 1:
146  raise ValueError("Invalid parameterV!")
147  self.parameterV = temp
148 
149  elif i == (len(args)-1):
150  self.meshNodeName = args.asString(i)
151 
152  else:
153  raise ValueError("Invalid flag:" + args.asString(i))
154 
155  # MAKE SURE UNSPECIFIED INPUT PARAMETER FLAGS GET DEFAULT VALUES:
156  if not self.faceIndexSpecified:
157  self.faceIndex = 0
158  if not self.relativeSpecified:
159  self.relative = True
160  if not self.parameterUSpecified:
161  parameterU = 0.5
162  if not self.parameterVSpecified:
163  self.parameterV = 0.5
164 
165  # DO THE WORK:
166  self.redoIt()
167 
168  # DOES MOST OF THE WORK IN COMPUTING THE POSITION, NORMAL, OR CREATING A "pointOnMeshInfo" NODE:
169  def redoIt(self):
170  # WHEN NO MESH IS SPECIFIED IN THE COMMAND, GET THE FIRST SELECTED MESH FROM THE SELECTION LIST:
171  sList = om.MSelectionList()
172  if self.meshNodeName == "":
173  sList = om.MGlobal.getActiveSelectionList()
174  if sList.length() == 0:
175  raise ValueError("No mesh or mesh transform specified!")
176 
177  # OTHERWISE, USE THE NODE NAME SPECIFIED IN THE LAST ARGUMENT OF THE COMMAND:
178  else:
179  sList.add(self.meshNodeName)
180 
181  # RETRIEVE THE FIRST ITEM FROM THE SELECTION LIST:
182  meshDagPath = sList.getDagPath(0)
183 
184  # CREATE AND CONNECT A "pointOnMeshInfo" NODE, OR GET THE POINT AND NORMAL ACCORDING TO
185  # WHETHER THE "-position/-p" AND/OR "-normal/-nr" FLAGS WERE SPECIFIED, AND WHETHER THE MESH
186  # "SHAPE" OR ITS "TRANSFORM" WAS SPECIFIED/SELECTED:
187  point = om.MPoint()
188  normal = om.MVector()
189  # WHEN THE SPECIFIED NODE IS THE MESH "SHAPE":
190  if meshDagPath.node().hasFn(om.MFn.kMesh):
191  # WHEN NEITHER "-position/-p" NOR "-normal/-nr" ARE SPECIFIED, CREATE AND CONNECT A "pointOnMeshInfo" NODE AND RETURN ITS NODE NAME:
192  if not self.positionSpecified and not self.normalSpecified:
193  # CREATE THE NODE:
194  self.nodeCreated = True
195  depNodeFn = om.MFnDependencyNode()
196 
197  if self.pointOnMeshInfoName == "":
198  depNodeFn.create("pointOnMeshInfo")
199  else:
200  depNodeFn.create("pointOnMeshInfo", self.pointOnMeshInfoName)
201  self.pointOnMeshInfoName = depNodeFn.name()
202 
203  # SET THE ".faceIndex" ATTRIBUTE, IF SPECIFIED IN THE COMMAND:
204  if self.faceIndexSpecified:
205  faceIndexPlug = depNodeFn.findPlug("faceIndex", True)
206  faceIndexPlug.setValue(self.faceIndex)
207 
208  # SET THE ".relative" ATTRIBUTE, IF SPECIFIED IN THE COMMAND:
209  if self.relativeSpecified:
210  relativePlug = depNodeFn.findPlug("relative", True)
211  relativePlug.setValue(self.relative)
212 
213  # SET THE ".parameterU" ATTRIBUTE, IF SPECIFIED IN THE COMMAND:
214  if self.parameterUSpecified:
215  parameterUPlug = depNodeFn.findPlug("parameterU", True)
216  parameterUPlug.setValue(self.parameterU)
217 
218  # SET THE ".parameterV" ATTRIBUTE, IF SPECIFIED IN THE COMMAND:
219  if self.parameterVSpecified:
220  parameterVPlug = depNodeFn.findPlug("parameterV", True)
221  parameterVPlug.setValue(self.parameterV)
222 
223  # CONNECT THE NODES:
224  inMeshPlug = depNodeFn.findPlug("inMesh", True)
225  depNodeFn.setObject(meshDagPath.node())
226  worldMeshPlug = depNodeFn.findPlug("worldMesh", True)
227  worldMeshPlug = worldMeshPlug.elementByLogicalIndex(0) # ASSUME THE *FIRST* INSTANCE OF THE MESH IS REQUESTED FOR MESH SHAPES.
228 
229  dgModifier = om.MDGModifier()
230  dgModifier.connect(worldMeshPlug, inMeshPlug)
231  dgModifier.doIt()
232 
233  # SET COMMAND RESULT AND RETURN:
234  om.MPxCommand.setResult(self.pointOnMeshInfoName)
235 
236  # OTHERWISE, COMPUTE THE POINT-POSITION AND NORMAL, USING THE *FIRST* INSTANCE'S TRANSFORM:
237  else:
238  getPointAndNormal(meshDagPath, self.faceIndex, self.relative, self.parameterU, self.parameterV, point, normal)
239 
240  # WHEN THE SPECIFIED NODE IS A "TRANSFORM" OF A MESH SHAPE:
241  elif meshDagPath.node().hasFn(om.MFn.kTransform) and meshDagPath.hasFn(om.MFn.kMesh):
242  # WHEN NEITHER "-position/-p" NOR "-normal/-nr" ARE SPECIFIED, CREATE AND CONNECT A "pointOnMeshInfo" NODE AND RETURN ITS NODE NAME:
243  if not self.positionSpecified and not self.normalSpecified:
244  # CREATE THE NODE:
245  self.nodeCreated = True
246  meshDagPath.extendToShape()
247  depNodeFn = om.MFnDependencyNode()
248 
249  if self.pointOnMeshInfoName == "":
250  depNodeFn.create("pointOnMeshInfo")
251  else:
252  depNodeFn.create("pointOnMeshInfo", self.pointOnMeshInfoName)
253  self.pointOnMeshInfoName = depNodeFn.name()
254 
255  # SET THE ".faceIndex" ATTRIBUTE, IF SPECIFIED IN THE COMMAND:
256  if self.faceIndexSpecified:
257  faceIndexPlug = depNodeFn.findPlug("faceIndex", True)
258  faceIndexPlug.setValue(self.faceIndex)
259 
260  # SET THE ".relative" ATTRIBUTE, IF SPECIFIED IN THE COMMAND:
261  if self.relativeSpecified:
262  relativePlug = depNodeFn.findPlug("relative", True)
263  relativePlug.setValue(self.relative)
264 
265  # SET THE ".parameterU" ATTRIBUTE, IF SPECIFIED IN THE COMMAND:
266  if self.parameterUSpecified:
267  parameterUPlug = depNodeFn.findPlug("parameterU", True)
268  parameterUPlug.setValue(self.parameterU)
269 
270  # SET THE ".parameterV" ATTRIBUTE, IF SPECIFIED IN THE COMMAND:
271  if self.parameterVSpecified:
272  parameterVPlug = depNodeFn.findPlug("parameterV", True)
273  parameterVPlug.setValue(self.parameterV)
274 
275  # CONNECT THE NODES:
276  inMeshPlug = depNodeFn.findPlug("inMesh", True)
277  depNodeFn.setObject(meshDagPath.node())
278  worldMeshPlug = depNodeFn.findPlug("worldMesh", True)
279  worldMeshPlug = worldMeshPlug.elementByLogicalIndex(meshDagPath.instanceNumber())
280 
281  dgModifier = om.MDGModifier()
282  dgModifier.connect(worldMeshPlug, inMeshPlug)
283  dgModifier.doIt()
284 
285  # SET COMMAND RESULT AND RETURN:
286  om.MPxCommand.setResult(self.pointOnMeshInfoName)
287 
288  # OTHERWISE, COMPUTE THE POINT-POSITION AND NORMAL:
289  else:
290  getPointAndNormal(meshDagPath, self.faceIndex, self.relative, self.parameterU, self.parameterV, point, normal)
291 
292  # INVALID INPUT WHEN SPECIFIED/SELECTED NODE IS NOT A MESH NOR TRANSFORM:
293  else:
294  raise ValueError("Invalid type! Only a mesh or its transform can be specified!")
295 
296  # SET THE RETURN VALUES OF THE COMMAND'S RESULT TO BE AN ARRAY OF FLOATS OUTPUTTING THE POSITION AND/OR NORMAL:
297  result = om.MDoubleArray()
298  if self.positionSpecified:
299  result.append(point.x)
300  result.append(point.y)
301  result.append(point.z)
302  if self.normalSpecified:
303  result.append(normal.x)
304  result.append(normal.y)
305  result.append(normal.z)
306 
307  om.MPxCommand.setResult(result)
308 
309  # CALLED WHEN USER UNDOES THE COMMAND:
310  def undoIt(self):
311  # MERELY DELETE THE "pointOnMeshInfo" NODE THAT WAS CREATED, IF ONE WAS CREATED:
312  if self.nodeCreated:
313  deleteCmd = "delete " + self.pointOnMeshInfoName
314  om.MGlobal.executeCommand(deleteCmd)
315 
316 #
317 # MAIN CLASS DECLARATION FOR THE CUSTOM NODE:
318 #
319 class pointOnMeshInfoNode(om.MPxNode):
320  id = om.MTypeId(0x00105480)
321  aInMesh = None
322  aFaceIndex = None
323  aRelative = None
324  aParameterU = None
325  aParameterV = None
326  aPosition = None
327  aPositionX = None
328  aPositionY = None
329  aPositionZ = None
330  aNormal = None
331  aNormalX = None
332  aNormalY = None
333  aNormalZ = None
334 
335  aNurbsCurve = None
336 
337  def __init__(self):
338  om.MPxNode.__init__(self)
339 
340  # FOR CREATING AN INSTANCE OF THIS NODE:
341  @staticmethod
342  def cmdCreator():
343  return pointOnMeshInfoNode()
344 
345  # INITIALIZES THE NODE BY CREATING ITS ATTRIBUTES:
346  @staticmethod
347  def initialize():
348  # CREATE AND ADD ".inMesh" ATTRIBUTE:
349  inMeshAttrFn = om.MFnTypedAttribute()
350  pointOnMeshInfoNode.aInMesh = inMeshAttrFn.create("inMesh", "im", om.MFnData.kMesh)
351  inMeshAttrFn.storable = True
352  inMeshAttrFn.keyable = False
353  inMeshAttrFn.readable = True
354  inMeshAttrFn.writable = True
355  inMeshAttrFn.cached = False
356  om.MPxNode.addAttribute(pointOnMeshInfoNode.aInMesh)
357 
358  # CREATE AND ADD ".faceIndex" ATTRIBUTE:
359  faceIndexAttrFn = om.MFnNumericAttribute()
360  pointOnMeshInfoNode.aFaceIndex = faceIndexAttrFn.create("faceIndex", "f", om.MFnNumericData.kLong, 0)
361  faceIndexAttrFn.storable = True
362  faceIndexAttrFn.keyable = True
363  faceIndexAttrFn.readable = True
364  faceIndexAttrFn.writable = True
365  faceIndexAttrFn.setMin(0)
366  om.MPxNode.addAttribute(pointOnMeshInfoNode.aFaceIndex)
367 
368  # CREATE AND ADD ".relative" ATTRIBUTE:
369  relativeAttrFn = om.MFnNumericAttribute()
370  pointOnMeshInfoNode.aRelative = relativeAttrFn.create("relative", "r", om.MFnNumericData.kBoolean, 1)
371  relativeAttrFn.storable = True
372  relativeAttrFn.keyable = True
373  relativeAttrFn.readable = True
374  relativeAttrFn.writable = True
375  om.MPxNode.addAttribute(pointOnMeshInfoNode.aRelative)
376 
377  # CREATE AND ADD ".parameterU" ATTRIBUTE:
378  parameterUAttrFn = om.MFnNumericAttribute()
379  pointOnMeshInfoNode.aParameterU = parameterUAttrFn.create("parameterU", "u", om.MFnNumericData.kDouble, 0.5)
380  parameterUAttrFn.storable = True
381  parameterUAttrFn.keyable = True
382  parameterUAttrFn.readable = True
383  parameterUAttrFn.writable = True
384  om.MPxNode.addAttribute(pointOnMeshInfoNode.aParameterU)
385 
386  # CREATE AND ADD ".parameterV" ATTRIBUTE:
387  parameterVAttrFn = om.MFnNumericAttribute()
388  pointOnMeshInfoNode.aParameterV = parameterVAttrFn.create("parameterV", "v", om.MFnNumericData.kDouble, 0.5)
389  parameterVAttrFn.storable = True
390  parameterVAttrFn.keyable = True
391  parameterVAttrFn.readable = True
392  parameterVAttrFn.writable = True
393  om.MPxNode.addAttribute(pointOnMeshInfoNode.aParameterV)
394 
395  # CREATE AND ADD ".positionX" ATTRIBUTE:
396  pointXAttrFn = om.MFnNumericAttribute()
397  pointOnMeshInfoNode.aPositionX = pointXAttrFn.create("positionX", "px", om.MFnNumericData.kDouble, 0.0)
398  pointXAttrFn.storable = False
399  pointXAttrFn.keyable = False
400  pointXAttrFn.readable = True
401  pointXAttrFn.writable = False
402  om.MPxNode.addAttribute(pointOnMeshInfoNode.aPositionX)
403 
404  # CREATE AND ADD ".positionY" ATTRIBUTE:
405  pointYAttrFn = om.MFnNumericAttribute()
406  pointOnMeshInfoNode.aPositionY = pointYAttrFn.create("positionY", "py", om.MFnNumericData.kDouble, 0.0)
407  pointYAttrFn.storable = False
408  pointYAttrFn.keyable = False
409  pointYAttrFn.readable = True
410  pointYAttrFn.writable = False
411  om.MPxNode.addAttribute(pointOnMeshInfoNode.aPositionY)
412 
413  # CREATE AND ADD ".positionZ" ATTRIBUTE:
414  pointZAttrFn = om.MFnNumericAttribute()
415  pointOnMeshInfoNode.aPositionZ = pointZAttrFn.create("positionZ", "pz", om.MFnNumericData.kDouble, 0.0)
416  pointZAttrFn.storable = False
417  pointZAttrFn.keyable = False
418  pointZAttrFn.readable = True
419  pointZAttrFn.writable = False
420  om.MPxNode.addAttribute(pointOnMeshInfoNode.aPositionZ)
421 
422  # CREATE AND ADD ".position" ATTRIBUTE:
423  pointAttrFn = om.MFnNumericAttribute()
424  pointOnMeshInfoNode.aPosition = pointAttrFn.create("position", "p", pointOnMeshInfoNode.aPositionX, pointOnMeshInfoNode.aPositionY, pointOnMeshInfoNode.aPositionZ)
425  pointAttrFn.storable = False
426  pointAttrFn.keyable = False
427  pointAttrFn.readable = True
428  pointAttrFn.writable = False
429  om.MPxNode.addAttribute(pointOnMeshInfoNode.aPosition)
430 
431  # CREATE AND ADD ".normalX" ATTRIBUTE:
432  normalXAttrFn = om.MFnNumericAttribute()
433  pointOnMeshInfoNode.aNormalX = normalXAttrFn.create("normalX", "nx", om.MFnNumericData.kDouble, 0.0)
434  normalXAttrFn.storable = False
435  normalXAttrFn.keyable = False
436  normalXAttrFn.readable = True
437  normalXAttrFn.writable = False
438  om.MPxNode.addAttribute(pointOnMeshInfoNode.aNormalX)
439 
440  # CREATE AND ADD ".normalY" ATTRIBUTE:
441  normalYAttrFn = om.MFnNumericAttribute()
442  pointOnMeshInfoNode.aNormalY = normalYAttrFn.create("normalY", "ny", om.MFnNumericData.kDouble, 0.0)
443  normalYAttrFn.storable = False
444  normalYAttrFn.keyable = False
445  normalYAttrFn.readable = True
446  normalYAttrFn.writable = False
447  om.MPxNode.addAttribute(pointOnMeshInfoNode.aNormalY)
448 
449  # CREATE AND ADD ".normalZ" ATTRIBUTE:
450  normalZAttrFn = om.MFnNumericAttribute()
451  pointOnMeshInfoNode.aNormalZ = normalZAttrFn.create("normalZ", "nz", om.MFnNumericData.kDouble, 0.0)
452  normalZAttrFn.storable = False
453  normalZAttrFn.keyable = False
454  normalZAttrFn.readable = True
455  normalZAttrFn.writable = False
456  om.MPxNode.addAttribute(pointOnMeshInfoNode.aNormalZ)
457 
458  # CREATE AND ADD ".normal" ATTRIBUTE:
459  normalAttrFn = om.MFnNumericAttribute()
460  pointOnMeshInfoNode.aNormal = normalAttrFn.create("normal", "n", pointOnMeshInfoNode.aNormalX, pointOnMeshInfoNode.aNormalY, pointOnMeshInfoNode.aNormalZ)
461  normalAttrFn.storable = False
462  normalAttrFn.keyable = False
463  normalAttrFn.readable = True
464  normalAttrFn.writable = False
465  om.MPxNode.addAttribute(pointOnMeshInfoNode.aNormal)
466 
467  # DEPENDENCY RELATIONS FOR ".inMesh":
468  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aInMesh, pointOnMeshInfoNode.aPosition)
469  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aInMesh, pointOnMeshInfoNode.aPositionX)
470  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aInMesh, pointOnMeshInfoNode.aPositionY)
471  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aInMesh, pointOnMeshInfoNode.aPositionZ)
472  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aInMesh, pointOnMeshInfoNode.aNormal)
473  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aInMesh, pointOnMeshInfoNode.aNormalX)
474  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aInMesh, pointOnMeshInfoNode.aNormalY)
475  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aInMesh, pointOnMeshInfoNode.aNormalZ)
476 
477  # DEPENDENCY RELATIONS FOR ".faceIndex":
478  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aFaceIndex, pointOnMeshInfoNode.aPosition)
479  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aFaceIndex, pointOnMeshInfoNode.aPositionX)
480  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aFaceIndex, pointOnMeshInfoNode.aPositionY)
481  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aFaceIndex, pointOnMeshInfoNode.aPositionZ)
482  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aFaceIndex, pointOnMeshInfoNode.aNormal)
483  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aFaceIndex, pointOnMeshInfoNode.aNormalX)
484  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aFaceIndex, pointOnMeshInfoNode.aNormalY)
485  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aFaceIndex, pointOnMeshInfoNode.aNormalZ)
486 
487  # DEPENDENCY RELATIONS FOR ".relative":
488  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aRelative, pointOnMeshInfoNode.aPosition)
489  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aRelative, pointOnMeshInfoNode.aPositionX)
490  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aRelative, pointOnMeshInfoNode.aPositionY)
491  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aRelative, pointOnMeshInfoNode.aPositionZ)
492  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aRelative, pointOnMeshInfoNode.aNormal)
493  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aRelative, pointOnMeshInfoNode.aNormalX)
494  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aRelative, pointOnMeshInfoNode.aNormalY)
495  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aRelative, pointOnMeshInfoNode.aNormalZ)
496 
497  # DEPENDENCY RELATIONS FOR ".parameterU":
498  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aParameterU, pointOnMeshInfoNode.aPosition)
499  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aParameterU, pointOnMeshInfoNode.aPositionX)
500  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aParameterU, pointOnMeshInfoNode.aPositionY)
501  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aParameterU, pointOnMeshInfoNode.aPositionZ)
502  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aParameterU, pointOnMeshInfoNode.aNormal)
503  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aParameterU, pointOnMeshInfoNode.aNormalX)
504  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aParameterU, pointOnMeshInfoNode.aNormalY)
505  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aParameterU, pointOnMeshInfoNode.aNormalZ)
506 
507  # DEPENDENCY RELATIONS FOR ".parameterV":
508  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aParameterV, pointOnMeshInfoNode.aPosition)
509  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aParameterV, pointOnMeshInfoNode.aPositionX)
510  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aParameterV, pointOnMeshInfoNode.aPositionY)
511  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aParameterV, pointOnMeshInfoNode.aPositionZ)
512  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aParameterV, pointOnMeshInfoNode.aNormal)
513  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aParameterV, pointOnMeshInfoNode.aNormalX)
514  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aParameterV, pointOnMeshInfoNode.aNormalY)
515  om.MPxNode.attributeAffects(pointOnMeshInfoNode.aParameterV, pointOnMeshInfoNode.aNormalZ)
516 
517  # COMPUTE METHOD'S DEFINITION:
518  def compute(self, plug, data):
519  assert(isinstance(data.context(), om.MDGContext))
520  assert(data.setContext(data.context()) == data)
521 
522  # DO THE COMPUTE ONLY FOR THE *OUTPUT* PLUGS THAT ARE DIRTIED:
523  if plug == pointOnMeshInfoNode.aPosition or plug == pointOnMeshInfoNode.aPositionX or plug == pointOnMeshInfoNode.aPositionY or plug == pointOnMeshInfoNode.aPositionZ or plug == pointOnMeshInfoNode.aNormal or plug == pointOnMeshInfoNode.aNormalX or plug == pointOnMeshInfoNode.aNormalY or plug == pointOnMeshInfoNode.aNormalZ:
524  # READ IN ".inMesh" DATA:
525  inMeshDataHandle = data.inputValue(pointOnMeshInfoNode.aInMesh)
526  inMesh = inMeshDataHandle.asMesh()
527 
528  # READ IN ".faceIndex" DATA:
529  faceIndexDataHandle = data.inputValue(pointOnMeshInfoNode.aFaceIndex)
530  faceIndex = faceIndexDataHandle.asInt()
531 
532  # READ IN ".relative" DATA:
533  relativeDataHandle = data.inputValue(pointOnMeshInfoNode.aRelative)
534  relative = relativeDataHandle.asBool()
535 
536  # READ IN ".parameterU" DATA:
537  parameterUDataHandle = data.inputValue(pointOnMeshInfoNode.aParameterU)
538  parameterU = parameterUDataHandle.asDouble()
539 
540  # READ IN ".parameterV" DATA:
541  parameterVDataHandle = data.inputValue(pointOnMeshInfoNode.aParameterV)
542  parameterV = parameterVDataHandle.asDouble()
543 
544  # GET THE POINT AND NORMAL:
545  point = om.MPoint()
546  normal = om.MVector()
547  dummyDagPath = om.MDagPath()
548  getPointAndNormal(dummyDagPath, faceIndex, relative, parameterU, parameterV, point, normal, inMesh)
549 
550  # WRITE OUT ".position" DATA:
551  pointDataHandle = data.outputValue(pointOnMeshInfoNode.aPosition)
552  pointDataHandle.set3Double(point.x, point.y, point.z)
553  data.setClean(plug)
554 
555  # WRITE OUT ".normal" DATA:
556  normalDataHandle = data.outputValue(pointOnMeshInfoNode.aNormal)
557  normalDataHandle.set3Double(normal.x, normal.y, normal.z)
558  data.setClean(plug)
559  else:
560  return None # let Maya handle this attribute
561 
562 
563 # INITIALIZES THE PLUGIN BY REGISTERING THE COMMAND AND NODE:
564 #
565 def initializePlugin(obj):
566  plugin = om.MFnPlugin(obj)
567  try:
568  plugin.registerCommand("pointOnMesh", pointOnMeshCommand.cmdCreator)
569  except:
570  sys.stderr.write("Failed to register command\n")
571  raise
572 
573  try:
574  plugin.registerNode("pointOnMeshInfo", pointOnMeshInfoNode.id, pointOnMeshInfoNode.cmdCreator, pointOnMeshInfoNode.initialize)
575  except:
576  sys.stderr.write("Failed to register node\n")
577  raise
578 
579 #
580 # UNINITIALIZES THE PLUGIN BY DEREGISTERING THE COMMAND AND NODE:
581 #
582 def uninitializePlugin(obj):
583  plugin = om.MFnPlugin(obj)
584  try:
585  plugin.deregisterCommand("pointOnMesh")
586  except:
587  sys.stderr.write("Failed to deregister command\n")
588  raise
589 
590  try:
591  plugin.deregisterNode(pointOnMeshInfoNode.id)
592  except:
593  sys.stderr.write("Failed to deregister node\n")
594  raise
595