scripted/pyFootPrintNode.py

scripted/pyFootPrintNode.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 license
6 # agreement provided at the time of installation or download, or which
7 # otherwise accompanies this software in either electronic or hard copy form.
8 # ===========================================================================
9 #+
10 
11 ########################################################################
12 # DESCRIPTION:
13 #
14 # Produces the dependency graph node "footPrint".
15 #
16 # This example demonstrates how to create a user-defined locator. A locator
17 # is a DAG object that is drawn in 3D views, but does not render.
18 # This example plug-in defines a new locator node that draws a foot print.
19 # The foot print can be selected and moved using the regular manipulators.
20 #
21 # To use, load the plug-in and execute:
22 #
23 # maya.cmds.createNode('footPrint')
24 #
25 ########################################################################
26 
27 import sys
28 import maya.api.OpenMaya as om
29 import maya.api.OpenMayaUI as omui
30 import maya.api.OpenMayaAnim as oma
31 import maya.api.OpenMayaRender as omr
32 
33 def maya_useNewAPI():
34  """
35  The presence of this function tells Maya that the plugin produces, and
36  expects to be passed, objects created using the Maya Python API 2.0.
37  """
38  pass
39 
40 def matrixAsArray(matrix):
41  array = []
42  for i in range(16):
43  array.append(matrix[i])
44  return array
45 
46 ## Foot Data
47 ##
48 sole = [ [ 0.00, 0.0, -0.70 ],
49  [ 0.04, 0.0, -0.69 ],
50  [ 0.09, 0.0, -0.65 ],
51  [ 0.13, 0.0, -0.61 ],
52  [ 0.16, 0.0, -0.54 ],
53  [ 0.17, 0.0, -0.46 ],
54  [ 0.17, 0.0, -0.35 ],
55  [ 0.16, 0.0, -0.25 ],
56  [ 0.15, 0.0, -0.14 ],
57  [ 0.13, 0.0, 0.00 ],
58  [ 0.00, 0.0, 0.00 ],
59  [ -0.13, 0.0, 0.00 ],
60  [ -0.15, 0.0, -0.14 ],
61  [ -0.16, 0.0, -0.25 ],
62  [ -0.17, 0.0, -0.35 ],
63  [ -0.17, 0.0, -0.46 ],
64  [ -0.16, 0.0, -0.54 ],
65  [ -0.13, 0.0, -0.61 ],
66  [ -0.09, 0.0, -0.65 ],
67  [ -0.04, 0.0, -0.69 ],
68  [ -0.00, 0.0, -0.70 ] ]
69 heel = [ [ 0.00, 0.0, 0.06 ],
70  [ 0.13, 0.0, 0.06 ],
71  [ 0.14, 0.0, 0.15 ],
72  [ 0.14, 0.0, 0.21 ],
73  [ 0.13, 0.0, 0.25 ],
74  [ 0.11, 0.0, 0.28 ],
75  [ 0.09, 0.0, 0.29 ],
76  [ 0.04, 0.0, 0.30 ],
77  [ 0.00, 0.0, 0.30 ],
78  [ -0.04, 0.0, 0.30 ],
79  [ -0.09, 0.0, 0.29 ],
80  [ -0.11, 0.0, 0.28 ],
81  [ -0.13, 0.0, 0.25 ],
82  [ -0.14, 0.0, 0.21 ],
83  [ -0.14, 0.0, 0.15 ],
84  [ -0.13, 0.0, 0.06 ],
85  [ -0.00, 0.0, 0.06 ] ]
86 soleCount = 21
87 heelCount = 17
88 
89 
90 #############################################################################
91 ##
92 ## Node implementation with standard viewport draw
93 ##
94 #############################################################################
95 class footPrint(omui.MPxLocatorNode):
96  id = om.MTypeId( 0x80007 )
97  drawDbClassification = "drawdb/geometry/footPrint"
98  drawRegistrantId = "FootprintNodePlugin"
99 
100  size = None ## The size of the foot
101 
102  @staticmethod
103  def creator():
104  return footPrint()
105 
106  @staticmethod
107  def initialize():
108  unitFn = om.MFnUnitAttribute()
109 
110  footPrint.size = unitFn.create( "size", "sz", om.MFnUnitAttribute.kDistance )
111  unitFn.default = om.MDistance(1.0)
112 
113  om.MPxNode.addAttribute( footPrint.size )
114 
115  def __init__(self):
116  omui.MPxLocatorNode.__init__(self)
117 
118  def compute(self, plug, data):
119  return None
120 
121  def draw(self, view, path, style, status):
122  ## Get the size
123  ##
124  thisNode = self.thisMObject()
125  plug = om.MPlug( thisNode, footPrint.size )
126  sizeVal = plug.asMDistance()
127  multiplier = sizeVal.asCentimeters()
128 
129  global sole, soleCount
130  global heel, heelCount
131 
132  view.beginGL()
133 
134  ## drawing in VP1 views will be done using V1 Python APIs:
135  import maya.OpenMayaRender as v1omr
136  glRenderer = v1omr.MHardwareRenderer.theRenderer()
137  glFT = glRenderer.glFunctionTable()
138 
139  if ( style == omui.M3dView.kFlatShaded ) or ( style == omui.M3dView.kGouraudShaded ):
140  ## Push the color settings
141  ##
142  glFT.glPushAttrib( v1omr.MGL_CURRENT_BIT )
143 
144  # Show both faces
145  glFT.glDisable( v1omr.MGL_CULL_FACE )
146 
147  if status == omui.M3dView.kActive:
148  view.setDrawColor( 13, omui.M3dView.kActiveColors )
149  else:
150  view.setDrawColor( 13, omui.M3dView.kDormantColors )
151 
152  glFT.glBegin( v1omr.MGL_TRIANGLE_FAN )
153  for i in range(soleCount-1):
154  glFT.glVertex3f( sole[i][0] * multiplier, sole[i][1] * multiplier, sole[i][2] * multiplier )
155  glFT.glEnd()
156 
157  glFT.glBegin( v1omr.MGL_TRIANGLE_FAN )
158  for i in range(heelCount-1):
159  glFT.glVertex3f( heel[i][0] * multiplier, heel[i][1] * multiplier, heel[i][2] * multiplier )
160  glFT.glEnd()
161 
162  glFT.glPopAttrib()
163 
164  ## Draw the outline of the foot
165  ##
166  glFT.glBegin( v1omr.MGL_LINES )
167  for i in range(soleCount-1):
168  glFT.glVertex3f( sole[i][0] * multiplier, sole[i][1] * multiplier, sole[i][2] * multiplier )
169  glFT.glVertex3f( sole[i+1][0] * multiplier, sole[i+1][1] * multiplier, sole[i+1][2] * multiplier )
170 
171  for i in range(heelCount-1):
172  glFT.glVertex3f( heel[i][0] * multiplier, heel[i][1] * multiplier, heel[i][2] * multiplier )
173  glFT.glVertex3f( heel[i+1][0] * multiplier, heel[i+1][1] * multiplier, heel[i+1][2] * multiplier )
174  glFT.glEnd()
175 
176  view.endGL()
177 
178  ## Draw the name of the footPrint
179  view.setDrawColor( om.MColor( (0.1, 0.8, 0.8, 1.0) ) )
180  view.drawText( "Footprint", om.MPoint( 0.0, 0.0, 0.0 ), omui.M3dView.kCenter )
181 
182  def isBounded(self):
183  return True
184 
185  def boundingBox(self):
186  ## Get the size
187  ##
188  thisNode = self.thisMObject()
189  plug = om.MPlug( thisNode, footPrint.size )
190  sizeVal = plug.asMDistance()
191  multiplier = sizeVal.asCentimeters()
192 
193  corner1 = om.MPoint( -0.17, 0.0, -0.7 )
194  corner2 = om.MPoint( 0.17, 0.0, 0.3 )
195 
196  corner1 *= multiplier
197  corner2 *= multiplier
198 
199  return om.MBoundingBox( corner1, corner2 )
200 
201 #############################################################################
202 ##
203 ## Viewport 2.0 override implementation
204 ##
205 #############################################################################
206 class footPrintData(om.MUserData):
207  def __init__(self):
208  om.MUserData.__init__(self, False) ## don't delete after draw
209 
210  self.fColor = om.MColor()
211  self.fLineList = om.MPointArray()
212  self.fTriangleList = om.MPointArray()
213 
214 class footPrintDrawOverride(omr.MPxDrawOverride):
215  @staticmethod
216  def creator(obj):
217  return footPrintDrawOverride(obj)
218 
219  ## By setting isAlwaysDirty to false in MPxDrawOverride constructor, the
220  ## draw override will be updated (via prepareForDraw()) only when the node
221  ## is marked dirty via DG evaluation or dirty propagation. Additional
222  ## callback is also added to explicitly mark the node as being dirty (via
223  ## MRenderer::setGeometryDrawDirty()) for certain circumstances.
224  def __init__(self, obj):
225  omr.MPxDrawOverride.__init__(self, obj, None, False)
226 
227  ## We want to perform custom bounding box drawing
228  ## so return True so that the internal rendering code
229  ## will not draw it for us.
230  self.mCustomBoxDraw = True
231  self.mCurrentBoundingBox = om.MBoundingBox()
232 
233  def supportedDrawAPIs(self):
234  ## this plugin supports both GL and DX
235  return omr.MRenderer.kOpenGL | omr.MRenderer.kDirectX11 | omr.MRenderer.kOpenGLCoreProfile
236 
237  def isBounded(self, objPath, cameraPath):
238  return True
239 
240  def boundingBox(self, objPath, cameraPath):
241  corner1 = om.MPoint( -0.17, 0.0, -0.7 )
242  corner2 = om.MPoint( 0.17, 0.0, 0.3 )
243 
244  multiplier = self.getMultiplier(objPath)
245  corner1 *= multiplier
246  corner2 *= multiplier
247 
248  self.mCurrentBoundingBox.clear()
249  self.mCurrentBoundingBox.expand( corner1 )
250  self.mCurrentBoundingBox.expand( corner2 )
251 
252  return self.mCurrentBoundingBox
253 
254  def disableInternalBoundingBoxDraw(self):
255  return self.mCustomBoxDraw
256 
257  def prepareForDraw(self, objPath, cameraPath, frameContext, oldData):
258  ## Retrieve data cache (create if does not exist)
259  data = oldData
260  if not isinstance(data, footPrintData):
261  data = footPrintData()
262 
263  ## compute data and cache it
264  global soleCount, sole
265  global heelCount, heel
266 
267  fMultiplier = self.getMultiplier(objPath)
268 
269  data.fLineList.clear()
270 
271  for i in range(soleCount-1):
272  data.fLineList.append( om.MPoint(sole[i][0] * fMultiplier, sole[i][1] * fMultiplier, sole[i][2] * fMultiplier) )
273  data.fLineList.append( om.MPoint(sole[i+1][0] * fMultiplier, sole[i+1][1] * fMultiplier, sole[i+1][2] * fMultiplier) )
274 
275  for i in range(heelCount-1):
276  data.fLineList.append( om.MPoint(heel[i][0] * fMultiplier, heel[i][1] * fMultiplier, heel[i][2] * fMultiplier) )
277  data.fLineList.append( om.MPoint(heel[i+1][0] * fMultiplier, heel[i+1][1] * fMultiplier, heel[i+1][2] * fMultiplier) )
278 
279  data.fTriangleList.clear()
280 
281  for i in range(1,soleCount-1):
282  data.fTriangleList.append( om.MPoint(sole[0][0] * fMultiplier, sole[0][1] * fMultiplier, sole[0][2] * fMultiplier) )
283  data.fTriangleList.append( om.MPoint(sole[i][0] * fMultiplier, sole[i][1] * fMultiplier, sole[i][2] * fMultiplier) )
284  data.fTriangleList.append( om.MPoint(sole[i+1][0] * fMultiplier, sole[i+1][1] * fMultiplier, sole[i+1][2] * fMultiplier) )
285 
286  for i in range(1,heelCount-1):
287  data.fTriangleList.append( om.MPoint(heel[0][0] * fMultiplier, heel[0][1] * fMultiplier, heel[0][2] * fMultiplier) )
288  data.fTriangleList.append( om.MPoint(heel[i][0] * fMultiplier, heel[i][1] * fMultiplier, heel[i][2] * fMultiplier) )
289  data.fTriangleList.append( om.MPoint(heel[i+1][0] * fMultiplier, heel[i+1][1] * fMultiplier, heel[i+1][2] * fMultiplier) )
290 
291  data.fColor = omr.MGeometryUtilities.wireframeColor(objPath)
292 
293  return data
294 
295  def hasUIDrawables(self):
296  return True
297 
298  def addUIDrawables(self, objPath, drawManager, frameContext, data):
299  locatordata = data
300  if not isinstance(locatordata, footPrintData):
301  return
302 
303  drawManager.beginDrawable()
304 
305  ##Draw the foot print solid/wireframe
306  drawManager.setColor( locatordata.fColor )
307  drawManager.setDepthPriority(5)
308 
309  if (frameContext.getDisplayStyle() & omr.MFrameContext.kGouraudShaded):
310  drawManager.mesh(omr.MGeometry.kTriangles, locatordata.fTriangleList)
311 
312  drawManager.mesh(omr.MUIDrawManager.kLines, locatordata.fLineList)
313 
314  ## Draw a text "Foot"
315  pos = om.MPoint( 0.0, 0.0, 0.0 ) ## Position of the text
316  textColor = om.MColor( (0.1, 0.8, 0.8, 1.0) ) ## Text color
317 
318  drawManager.setColor( textColor )
319  drawManager.setFontSize( omr.MUIDrawManager.kSmallFontSize )
320  drawManager.text(pos, "Footprint", omr.MUIDrawManager.kCenter )
321 
322  drawManager.endDrawable()
323 
324  def getMultiplier(self, objPath):
325  ## Retrieve value of the size attribute from the node
326  footprintNode = objPath.node()
327  plug = om.MPlug(footprintNode, footPrint.size)
328  if not plug.isNull:
329  sizeVal = plug.asMDistance()
330  return sizeVal.asCentimeters()
331 
332  return 1.0
333 
334 def initializePlugin(obj):
335  plugin = om.MFnPlugin(obj, "Autodesk", "3.0", "Any")
336 
337  try:
338  plugin.registerNode("footPrint", footPrint.id, footPrint.creator, footPrint.initialize, om.MPxNode.kLocatorNode, footPrint.drawDbClassification)
339  except:
340  sys.stderr.write("Failed to register node\n")
341  raise
342 
343  try:
344  omr.MDrawRegistry.registerDrawOverrideCreator(footPrint.drawDbClassification, footPrint.drawRegistrantId, footPrintDrawOverride.creator)
345  except:
346  sys.stderr.write("Failed to register override\n")
347  raise
348 
349 def uninitializePlugin(obj):
350  plugin = om.MFnPlugin(obj)
351 
352  try:
353  plugin.deregisterNode(footPrint.id)
354  except:
355  sys.stderr.write("Failed to deregister node\n")
356  pass
357 
358  try:
359  omr.MDrawRegistry.deregisterDrawOverrideCreator(footPrint.drawDbClassification, footPrint.drawRegistrantId)
360  except:
361  sys.stderr.write("Failed to deregister override\n")
362  pass
363