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  @staticmethod
222  def draw(context, data):
223  return
224 
225  def __init__(self, obj):
226  omr.MPxDrawOverride.__init__(self, obj, footPrintDrawOverride.draw)
227 
228  ## We want to perform custom bounding box drawing
229  ## so return True so that the internal rendering code
230  ## will not draw it for us.
231  self.mCustomBoxDraw = True
232  self.mCurrentBoundingBox = om.MBoundingBox()
233 
234  def supportedDrawAPIs(self):
235  ## this plugin supports both GL and DX
236  return omr.MRenderer.kOpenGL | omr.MRenderer.kDirectX11 | omr.MRenderer.kOpenGLCoreProfile
237 
238  def isBounded(self, objPath, cameraPath):
239  return True
240 
241  def boundingBox(self, objPath, cameraPath):
242  corner1 = om.MPoint( -0.17, 0.0, -0.7 )
243  corner2 = om.MPoint( 0.17, 0.0, 0.3 )
244 
245  multiplier = self.getMultiplier(objPath)
246  corner1 *= multiplier
247  corner2 *= multiplier
248 
249  self.mCurrentBoundingBox.clear()
250  self.mCurrentBoundingBox.expand( corner1 )
251  self.mCurrentBoundingBox.expand( corner2 )
252 
253  return self.mCurrentBoundingBox
254 
255  def disableInternalBoundingBoxDraw(self):
256  return self.mCustomBoxDraw
257 
258  def prepareForDraw(self, objPath, cameraPath, frameContext, oldData):
259  ## Retrieve data cache (create if does not exist)
260  data = oldData
261  if not isinstance(data, footPrintData):
262  data = footPrintData()
263 
264  ## compute data and cache it
265  global soleCount, sole
266  global heelCount, heel
267 
268  fMultiplier = self.getMultiplier(objPath)
269 
270  data.fSoleLineList.clear()
271  for i in range(soleCount):
272  data.fSoleLineList.append( om.MPoint(sole[i][0] * fMultiplier, sole[i][1] * fMultiplier, sole[i][2] * fMultiplier) )
273 
274  data.fHeelLineList.clear()
275  for i in range(heelCount):
276  data.fHeelLineList.append( om.MPoint(heel[i][0] * fMultiplier, heel[i][1] * fMultiplier, heel[i][2] * fMultiplier) )
277 
278  data.fSoleTriangleList.clear()
279  for i in range(1,soleCount-1):
280  data.fSoleTriangleList.append( om.MPoint(sole[0][0] * fMultiplier, sole[0][1] * fMultiplier, sole[0][2] * fMultiplier) )
281  data.fSoleTriangleList.append( om.MPoint(sole[i][0] * fMultiplier, sole[i][1] * fMultiplier, sole[i][2] * fMultiplier) )
282  data.fSoleTriangleList.append( om.MPoint(sole[i+1][0] * fMultiplier, sole[i+1][1] * fMultiplier, sole[i+1][2] * fMultiplier) )
283 
284  data.fHeelTriangleList.clear()
285  for i in range(1,heelCount-1):
286  data.fHeelTriangleList.append( om.MPoint(heel[0][0] * fMultiplier, heel[0][1] * fMultiplier, heel[0][2] * fMultiplier) )
287  data.fHeelTriangleList.append( om.MPoint(heel[i][0] * fMultiplier, heel[i][1] * fMultiplier, heel[i][2] * fMultiplier) )
288  data.fHeelTriangleList.append( om.MPoint(heel[i+1][0] * fMultiplier, heel[i+1][1] * fMultiplier, heel[i+1][2] * fMultiplier) )
289 
290  data.fColor = omr.MGeometryUtilities.wireframeColor(objPath)
291 
292  return data
293 
294  def hasUIDrawables(self):
295  return True
296 
297  def addUIDrawables(self, objPath, drawManager, frameContext, data):
298  locatordata = data
299  if not isinstance(locatordata, footPrintData):
300  return
301 
302  drawManager.beginDrawable()
303 
304  ##Draw the foot print solid/wireframe
305  drawManager.setColor( locatordata.fColor )
306  drawManager.setDepthPriority(5)
307 
308  if (frameContext.getDisplayStyle() & omr.MFrameContext.kGouraudShaded):
309  drawManager.mesh(omr.MGeometry.kTriangles, locatordata.fSoleTriangleList)
310  drawManager.mesh(omr.MGeometry.kTriangles, locatordata.fHeelTriangleList)
311 
312  drawManager.mesh(omr.MUIDrawManager.kClosedLine, locatordata.fSoleLineList)
313  drawManager.mesh(omr.MUIDrawManager.kClosedLine, locatordata.fHeelLineList)
314 
315  ## Draw a text "Foot"
316  pos = om.MPoint( 0.0, 0.0, 0.0 ) ## Position of the text
317  textColor = om.MColor( (0.1, 0.8, 0.8, 1.0) ) ## Text color
318 
319  drawManager.setColor( textColor )
320  drawManager.setFontSize( omr.MUIDrawManager.kSmallFontSize )
321  drawManager.text(pos, "Footprint", omr.MUIDrawManager.kCenter )
322 
323  drawManager.endDrawable()
324 
325  def getMultiplier(self, objPath):
326  ## Retrieve value of the size attribute from the node
327  footprintNode = objPath.node()
328  plug = om.MPlug(footprintNode, footPrint.size)
329  if not plug.isNull:
330  sizeVal = plug.asMDistance()
331  return sizeVal.asCentimeters()
332 
333  return 1.0
334 
335 def initializePlugin(obj):
336  plugin = om.MFnPlugin(obj, "Autodesk", "3.0", "Any")
337 
338  try:
339  plugin.registerNode("footPrint", footPrint.id, footPrint.creator, footPrint.initialize, om.MPxNode.kLocatorNode, footPrint.drawDbClassification)
340  except:
341  sys.stderr.write("Failed to register node\n")
342  raise
343 
344  try:
345  omr.MDrawRegistry.registerDrawOverrideCreator(footPrint.drawDbClassification, footPrint.drawRegistrantId, footPrintDrawOverride.creator)
346  except:
347  sys.stderr.write("Failed to register override\n")
348  raise
349 
350 def uninitializePlugin(obj):
351  plugin = om.MFnPlugin(obj)
352 
353  try:
354  plugin.deregisterNode(footPrint.id)
355  except:
356  sys.stderr.write("Failed to deregister node\n")
357  pass
358 
359  try:
360  omr.MDrawRegistry.deregisterDrawOverrideCreator(footPrint.drawDbClassification, footPrint.drawRegistrantId)
361  except:
362  sys.stderr.write("Failed to deregister override\n")
363  pass
364