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.fSoleLineList = om.MPointArray()
212  self.fSoleTriangleList = om.MPointArray()
213  self.fHeelLineList = om.MPointArray()
214  self.fHeelTriangleList = om.MPointArray()
215 
216 class footPrintDrawOverride(omr.MPxDrawOverride):
217  @staticmethod
218  def creator(obj):
219  return footPrintDrawOverride(obj)
220 
221  ## By setting isAlwaysDirty to false in MPxDrawOverride constructor, the
222  ## draw override will be updated (via prepareForDraw()) only when the node
223  ## is marked dirty via DG evaluation or dirty propagation. Additional
224  ## callback is also added to explicitly mark the node as being dirty (via
225  ## MRenderer::setGeometryDrawDirty()) for certain circumstances.
226  def __init__(self, obj):
227  omr.MPxDrawOverride.__init__(self, obj, None, False)
228 
229  ## We want to perform custom bounding box drawing
230  ## so return True so that the internal rendering code
231  ## will not draw it for us.
232  self.mCustomBoxDraw = True
233  self.mCurrentBoundingBox = om.MBoundingBox()
234 
235  def supportedDrawAPIs(self):
236  ## this plugin supports both GL and DX
237  return omr.MRenderer.kOpenGL | omr.MRenderer.kDirectX11 | omr.MRenderer.kOpenGLCoreProfile
238 
239  def isBounded(self, objPath, cameraPath):
240  return True
241 
242  def boundingBox(self, objPath, cameraPath):
243  corner1 = om.MPoint( -0.17, 0.0, -0.7 )
244  corner2 = om.MPoint( 0.17, 0.0, 0.3 )
245 
246  multiplier = self.getMultiplier(objPath)
247  corner1 *= multiplier
248  corner2 *= multiplier
249 
250  self.mCurrentBoundingBox.clear()
251  self.mCurrentBoundingBox.expand( corner1 )
252  self.mCurrentBoundingBox.expand( corner2 )
253 
254  return self.mCurrentBoundingBox
255 
256  def disableInternalBoundingBoxDraw(self):
257  return self.mCustomBoxDraw
258 
259  def prepareForDraw(self, objPath, cameraPath, frameContext, oldData):
260  ## Retrieve data cache (create if does not exist)
261  data = oldData
262  if not isinstance(data, footPrintData):
263  data = footPrintData()
264 
265  ## compute data and cache it
266  global soleCount, sole
267  global heelCount, heel
268 
269  fMultiplier = self.getMultiplier(objPath)
270 
271  data.fSoleLineList.clear()
272  for i in range(soleCount):
273  data.fSoleLineList.append( om.MPoint(sole[i][0] * fMultiplier, sole[i][1] * fMultiplier, sole[i][2] * fMultiplier) )
274 
275  data.fHeelLineList.clear()
276  for i in range(heelCount):
277  data.fHeelLineList.append( om.MPoint(heel[i][0] * fMultiplier, heel[i][1] * fMultiplier, heel[i][2] * fMultiplier) )
278 
279  data.fSoleTriangleList.clear()
280  for i in range(1,soleCount-1):
281  data.fSoleTriangleList.append( om.MPoint(sole[0][0] * fMultiplier, sole[0][1] * fMultiplier, sole[0][2] * fMultiplier) )
282  data.fSoleTriangleList.append( om.MPoint(sole[i][0] * fMultiplier, sole[i][1] * fMultiplier, sole[i][2] * fMultiplier) )
283  data.fSoleTriangleList.append( om.MPoint(sole[i+1][0] * fMultiplier, sole[i+1][1] * fMultiplier, sole[i+1][2] * fMultiplier) )
284 
285  data.fHeelTriangleList.clear()
286  for i in range(1,heelCount-1):
287  data.fHeelTriangleList.append( om.MPoint(heel[0][0] * fMultiplier, heel[0][1] * fMultiplier, heel[0][2] * fMultiplier) )
288  data.fHeelTriangleList.append( om.MPoint(heel[i][0] * fMultiplier, heel[i][1] * fMultiplier, heel[i][2] * fMultiplier) )
289  data.fHeelTriangleList.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.fSoleTriangleList)
311  drawManager.mesh(omr.MGeometry.kTriangles, locatordata.fHeelTriangleList)
312 
313  drawManager.mesh(omr.MUIDrawManager.kClosedLine, locatordata.fSoleLineList)
314  drawManager.mesh(omr.MUIDrawManager.kClosedLine, locatordata.fHeelLineList)
315 
316  ## Draw a text "Foot"
317  pos = om.MPoint( 0.0, 0.0, 0.0 ) ## Position of the text
318  textColor = om.MColor( (0.1, 0.8, 0.8, 1.0) ) ## Text color
319 
320  drawManager.setColor( textColor )
321  drawManager.setFontSize( omr.MUIDrawManager.kSmallFontSize )
322  drawManager.text(pos, "Footprint", omr.MUIDrawManager.kCenter )
323 
324  drawManager.endDrawable()
325 
326  def getMultiplier(self, objPath):
327  ## Retrieve value of the size attribute from the node
328  footprintNode = objPath.node()
329  plug = om.MPlug(footprintNode, footPrint.size)
330  if not plug.isNull:
331  sizeVal = plug.asMDistance()
332  return sizeVal.asCentimeters()
333 
334  return 1.0
335 
336 def initializePlugin(obj):
337  plugin = om.MFnPlugin(obj, "Autodesk", "3.0", "Any")
338 
339  try:
340  plugin.registerNode("footPrint", footPrint.id, footPrint.creator, footPrint.initialize, om.MPxNode.kLocatorNode, footPrint.drawDbClassification)
341  except:
342  sys.stderr.write("Failed to register node\n")
343  raise
344 
345  try:
346  omr.MDrawRegistry.registerDrawOverrideCreator(footPrint.drawDbClassification, footPrint.drawRegistrantId, footPrintDrawOverride.creator)
347  except:
348  sys.stderr.write("Failed to register override\n")
349  raise
350 
351 def uninitializePlugin(obj):
352  plugin = om.MFnPlugin(obj)
353 
354  try:
355  plugin.deregisterNode(footPrint.id)
356  except:
357  sys.stderr.write("Failed to deregister node\n")
358  pass
359 
360  try:
361  omr.MDrawRegistry.deregisterDrawOverrideCreator(footPrint.drawDbClassification, footPrint.drawRegistrantId)
362  except:
363  sys.stderr.write("Failed to deregister override\n")
364  pass
365