scripted/pyFootPrintNode_GeometryOverride.py

scripted/pyFootPrintNode_GeometryOverride.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 # This plug-in demonstrates how to draw a simple mesh like foot Print in an efficient way.
15 #
16 # This efficient way is supported in Viewport 2.0.
17 #
18 # For comparison, you can also reference a devkit sample named footPrintNode. (See: pyFootPrintNode.py)
19 # In that sample, we draw the footPrint using the MUIDrawManager primitives in footPrintDrawOverride::addUIDrawables()
20 #
21 # For comparison, you can also reference another devkit sample named rawfootPrintNode.
22 # In that sample, we draw the footPrint with OpenGL\DX in method rawFootPrintDrawOverride::draw().
23 #
24 # Note that the method:
25 # footPrint.draw()
26 # is only called in legacy default viewport to draw the foot print.
27 # while the methods:
28 # footPrintGeometryOverride.updateDG()
29 # footPrintGeometryOverride.updateRenderItems()
30 # footPrintGeometryOverride.populateGeometry()
31 # are only called in Viewport 2.0 to prepare and draw the foot print.
32 #
33 # Example usage is to load the plug-in and create the node using
34 # the createNode command:
35 #
36 # import maya.cmds as cmds
37 # cmds.loadPlugin('footPrintNode_GeometryOverride')
38 # cmds.createNode('footPrint_GeometryOverride')
39 #
40 #########################################################################
41 import sys
42 import ctypes
43 import maya.api.OpenMaya as om
44 import maya.api.OpenMayaUI as omui
45 import maya.api.OpenMayaAnim as oma
46 import maya.api.OpenMayaRender as omr
47 
48 def maya_useNewAPI():
49  """
50  The presence of this function tells Maya that the plugin produces, and
51  expects to be passed, objects created using the Maya Python API 2.0.
52  """
53  pass
54 
55 def matrixAsArray(matrix):
56  array = []
57  for i in xrange(16):
58  array.append(matrix[i])
59  return array
60 
61 ## Foot Data
62 ##
63 sole = [ [ 0.00, 0.0, -0.70 ],
64  [ 0.04, 0.0, -0.69 ],
65  [ 0.09, 0.0, -0.65 ],
66  [ 0.13, 0.0, -0.61 ],
67  [ 0.16, 0.0, -0.54 ],
68  [ 0.17, 0.0, -0.46 ],
69  [ 0.17, 0.0, -0.35 ],
70  [ 0.16, 0.0, -0.25 ],
71  [ 0.15, 0.0, -0.14 ],
72  [ 0.13, 0.0, 0.00 ],
73  [ 0.00, 0.0, 0.00 ],
74  [ -0.13, 0.0, 0.00 ],
75  [ -0.15, 0.0, -0.14 ],
76  [ -0.16, 0.0, -0.25 ],
77  [ -0.17, 0.0, -0.35 ],
78  [ -0.17, 0.0, -0.46 ],
79  [ -0.16, 0.0, -0.54 ],
80  [ -0.13, 0.0, -0.61 ],
81  [ -0.09, 0.0, -0.65 ],
82  [ -0.04, 0.0, -0.69 ],
83  [ -0.00, 0.0, -0.70 ] ]
84 heel = [ [ 0.00, 0.0, 0.06 ],
85  [ 0.13, 0.0, 0.06 ],
86  [ 0.14, 0.0, 0.15 ],
87  [ 0.14, 0.0, 0.21 ],
88  [ 0.13, 0.0, 0.25 ],
89  [ 0.11, 0.0, 0.28 ],
90  [ 0.09, 0.0, 0.29 ],
91  [ 0.04, 0.0, 0.30 ],
92  [ 0.00, 0.0, 0.30 ],
93  [ -0.04, 0.0, 0.30 ],
94  [ -0.09, 0.0, 0.29 ],
95  [ -0.11, 0.0, 0.28 ],
96  [ -0.13, 0.0, 0.25 ],
97  [ -0.14, 0.0, 0.21 ],
98  [ -0.14, 0.0, 0.15 ],
99  [ -0.13, 0.0, 0.06 ],
100  [ -0.00, 0.0, 0.06 ] ]
101 soleCount = 21
102 heelCount = 17
103 
104 
105 #############################################################################
106 ##
107 ## Node implementation with standard viewport draw
108 ##
109 #############################################################################
110 class footPrint(omui.MPxLocatorNode):
111  id = om.MTypeId( 0x00080033 )
112  drawDbClassification = "drawdb/geometry/footPrint_GeometryOverride"
113  drawRegistrantId = "FootprintNode_GeometryOverridePlugin"
114 
115  size = None ## The size of the foot
116 
117  @staticmethod
118  def creator():
119  return footPrint()
120 
121  @staticmethod
122  def initialize():
123  unitFn = om.MFnUnitAttribute()
124 
125  footPrint.size = unitFn.create( "size", "sz", om.MFnUnitAttribute.kDistance )
126  unitFn.default = om.MDistance(1.0)
127 
128  om.MPxNode.addAttribute( footPrint.size )
129 
130  def __init__(self):
131  omui.MPxLocatorNode.__init__(self)
132 
133  def compute(self, plug, data):
134  return None
135 
136  def draw(self, view, path, style, status):
137  ## Get the size
138  ##
139  thisNode = self.thisMObject()
140  plug = om.MPlug( thisNode, footPrint.size )
141  sizeVal = plug.asMDistance()
142  multiplier = sizeVal.asCentimeters()
143 
144  global sole, soleCount
145  global heel, heelCount
146 
147  view.beginGL()
148 
149  ## drawing in VP1 views will be done using V1 Python APIs:
150  import maya.OpenMayaRender as v1omr
151  glRenderer = v1omr.MHardwareRenderer.theRenderer()
152  glFT = glRenderer.glFunctionTable()
153 
154  if ( style == omui.M3dView.kFlatShaded ) or ( style == omui.M3dView.kGouraudShaded ):
155  ## Push the color settings
156  ##
157  glFT.glPushAttrib( v1omr.MGL_CURRENT_BIT )
158 
159  # Show both faces
160  glFT.glDisable( v1omr.MGL_CULL_FACE )
161 
162  if status == omui.M3dView.kActive:
163  view.setDrawColor( 13, omui.M3dView.kActiveColors )
164  else:
165  view.setDrawColor( 13, omui.M3dView.kDormantColors )
166 
167  glFT.glBegin( v1omr.MGL_TRIANGLE_FAN )
168  for i in xrange(soleCount-1):
169  glFT.glVertex3f( sole[i][0] * multiplier, sole[i][1] * multiplier, sole[i][2] * multiplier )
170  glFT.glEnd()
171 
172  glFT.glBegin( v1omr.MGL_TRIANGLE_FAN )
173  for i in xrange(heelCount-1):
174  glFT.glVertex3f( heel[i][0] * multiplier, heel[i][1] * multiplier, heel[i][2] * multiplier )
175  glFT.glEnd()
176 
177  glFT.glPopAttrib()
178 
179  ## Draw the outline of the foot
180  ##
181  glFT.glBegin( v1omr.MGL_LINES )
182  for i in xrange(soleCount-1):
183  glFT.glVertex3f( sole[i][0] * multiplier, sole[i][1] * multiplier, sole[i][2] * multiplier )
184  glFT.glVertex3f( sole[i+1][0] * multiplier, sole[i+1][1] * multiplier, sole[i+1][2] * multiplier )
185 
186  for i in xrange(heelCount-1):
187  glFT.glVertex3f( heel[i][0] * multiplier, heel[i][1] * multiplier, heel[i][2] * multiplier )
188  glFT.glVertex3f( heel[i+1][0] * multiplier, heel[i+1][1] * multiplier, heel[i+1][2] * multiplier )
189  glFT.glEnd()
190 
191  view.endGL()
192 
193  def isBounded(self):
194  return True
195 
196  def boundingBox(self):
197  ## Get the size
198  ##
199  thisNode = self.thisMObject()
200  plug = om.MPlug( thisNode, footPrint.size )
201  sizeVal = plug.asMDistance()
202  multiplier = sizeVal.asCentimeters()
203 
204  corner1 = om.MPoint( -0.17, 0.0, -0.7 )
205  corner2 = om.MPoint( 0.17, 0.0, 0.3 )
206 
207  corner1 *= multiplier
208  corner2 *= multiplier
209 
210  return om.MBoundingBox( corner1, corner2 )
211 
212 #############################################################################
213 ##
214 ## Viewport 2.0 override implementation
215 ##
216 #############################################################################
217 
218 class footPrintGeometryOverride(omr.MPxGeometryOverride):
219  colorParameterName_ = "solidColor"
220  wireframeHeelItemName_ = "heelLocatorWires"
221  wireframeSoleItemName_ = "soleLocatorWires"
222  shadedHeelItemName_ = "heelLocatorTriangles"
223  shadedSoleItemName_ = "soleLocatorTriangles"
224 
225  @staticmethod
226  def creator(obj):
227  return footPrintGeometryOverride(obj)
228 
229  def __init__(self, obj):
230  omr.MPxGeometryOverride.__init__(self, obj)
231  self. mSolidUIShader = None
232  self.mLocatorNode = obj
233  self.mMultiplier = 0.0
234  self.mMultiplierChanged = True
235 
236  shaderMgr = omr.MRenderer.getShaderManager()
237  if shaderMgr:
238  self.mSolidUIShader = shaderMgr.getStockShader(omr.MShaderManager.k3dSolidShader)
239 
240  def __del__(self):
241  if self.mSolidUIShader:
242  shaderMgr = omr.MRenderer.getShaderManager()
243  if shaderMgr:
244  shaderMgr.releaseShader(self.mSolidUIShader)
245 
246  def supportedDrawAPIs(self):
247  # this plugin supports all modes
248  return omr.MRenderer.kOpenGL | omr.MRenderer.kOpenGLCoreProfile | omr.MRenderer.kDirectX11
249 
250  def hasUIDrawables(self):
251  return False
252 
253  def updateDG(self):
254  plug = om.MPlug(self.mLocatorNode, footPrint.size)
255  newScale = 1.0
256  if not plug.isNull:
257  sizeVal = plug.asMDistance()
258  newScale = sizeVal.asCentimeters()
259 
260  if newScale != self.mMultiplier:
261  self.mMultiplier = newScale
262  self.mMultiplierChanged = True
263 
264  def cleanUp(self):
265  pass
266 
267  def isIndexingDirty(self, item):
268  return False
269 
270  def isStreamDirty(self, desc):
271  return self.mMultiplierChanged
272 
273  def updateRenderItems(self, dagPath, renderList ):
274 
275  fullItemList = (
276  # Wireframe sole and heel:
277  ( (footPrintGeometryOverride.wireframeHeelItemName_,
278  footPrintGeometryOverride.wireframeSoleItemName_),
279  omr.MGeometry.kLineStrip,
280  omr.MGeometry.kWireframe),
281 
282  # Shaded sole and heel
283  ( (footPrintGeometryOverride.shadedHeelItemName_,
284  footPrintGeometryOverride.shadedSoleItemName_),
285  omr.MGeometry.kTriangleStrip,
286  omr.MGeometry.kShaded)
287  )
288 
289  for itemNameList, geometryType, drawMode in fullItemList:
290  for itemName in itemNameList:
291  renderItem = None
292  index = renderList.indexOf(itemName)
293  if index < 0:
294  renderItem = omr.MRenderItem.create(
295  itemName,
296  omr.MRenderItem.DecorationItem,
297  geometryType)
298  renderItem.setDrawMode(drawMode)
299  renderItem.setDepthPriority(5)
300 
301  renderList.append(renderItem)
302  else:
303  renderItem = renderList[index]
304 
305  if renderItem:
306  if self.mSolidUIShader:
307  self.mSolidUIShader.setParameter(footPrintGeometryOverride.colorParameterName_, omr.MGeometryUtilities.wireframeColor(dagPath))
308  renderItem.setShader(self.mSolidUIShader)
309  renderItem.enable(True)
310 
311  def populateGeometry(self, requirements, renderItems, data):
312  vertexBufferDescriptorList = requirements.vertexRequirements()
313 
314  for vertexBufferDescriptor in vertexBufferDescriptorList:
315  if vertexBufferDescriptor.semantic == omr.MGeometry.kPosition:
316  verticesCount = soleCount+heelCount
317  verticesBuffer = data.createVertexBuffer(vertexBufferDescriptor)
318  verticesPositionDataAddress = verticesBuffer.acquire(verticesCount, True)
319  verticesPositionData = ((ctypes.c_float * 3)*verticesCount).from_address(verticesPositionDataAddress)
320 
321  verticesPointerOffset = 0
322 
323  # We concatenate the heel and sole positions into a single vertex buffer.
324  # The index buffers will decide which positions will be selected for each render items.
325  for vtxList in (heel, sole):
326  for vtx in vtxList:
327  verticesPositionData[verticesPointerOffset][0] = vtx[0] * self.mMultiplier
328  verticesPositionData[verticesPointerOffset][1] = vtx[1] * self.mMultiplier
329  verticesPositionData[verticesPointerOffset][2] = vtx[2] * self.mMultiplier
330  verticesPointerOffset += 1
331 
332  verticesBuffer.commit(verticesPositionDataAddress)
333 
334  break
335 
336  for item in renderItems:
337  if not item:
338  continue
339 
340  # Start position in the index buffer (start of heel or sole positions):
341  startIndex = 0
342  endIndex = 0
343  # Number of index to generate (for line strip, or triangle list)
344  numIndex = 0
345  isWireFrame = True
346 
347  if item.name() == footPrintGeometryOverride.wireframeHeelItemName_:
348  numIndex = heelCount
349  elif item.name() == footPrintGeometryOverride.wireframeSoleItemName_:
350  startIndex = heelCount
351  numIndex = soleCount
352  elif item.name() == footPrintGeometryOverride.shadedHeelItemName_:
353  numIndex = heelCount - 2
354  startIndex = 1
355  endIndex = heelCount - 2
356  isWireFrame = False
357  elif item.name() == footPrintGeometryOverride.shadedSoleItemName_:
358  startIndex = heelCount
359  endIndex = heelCount + soleCount - 2
360  numIndex = soleCount - 2
361  isWireFrame = False
362 
363  if numIndex:
364  indexBuffer = data.createIndexBuffer(omr.MGeometry.kUnsignedInt32)
365  indicesAddress = indexBuffer.acquire(numIndex, True)
366  indices = (ctypes.c_uint * numIndex).from_address(indicesAddress)
367 
368  i = 0
369  while i < numIndex:
370  if isWireFrame:
371  # Line strip starts at first position and iterates thru all vertices:
372  indices[i] = startIndex + i
373  i += 1
374  else:
375  # Triangle strip
376  indices[i] = startIndex + i/2
377  if i+1 < numIndex:
378  indices[i+1] = endIndex - i/2
379  i += 2
380 
381  indexBuffer.commit(indicesAddress)
382  item.associateWithIndexBuffer(indexBuffer)
383 
384  mMultiplierChanged = False
385 
386 def initializePlugin(obj):
387  plugin = om.MFnPlugin(obj, "Autodesk", "3.0", "Any")
388 
389  try:
390  plugin.registerNode("footPrint_GeometryOverride", footPrint.id, footPrint.creator, footPrint.initialize, om.MPxNode.kLocatorNode, footPrint.drawDbClassification)
391  except:
392  sys.stderr.write("Failed to register node\n")
393  raise
394 
395  try:
396  omr.MDrawRegistry.registerGeometryOverrideCreator(footPrint.drawDbClassification, footPrint.drawRegistrantId, footPrintGeometryOverride.creator)
397  except:
398  sys.stderr.write("Failed to register override\n")
399  raise
400 
401 def uninitializePlugin(obj):
402  plugin = om.MFnPlugin(obj)
403 
404  try:
405  plugin.deregisterNode(footPrint.id)
406  except:
407  sys.stderr.write("Failed to deregister node\n")
408  pass
409 
410  try:
411  omr.MDrawRegistry.deregisterGeometryOverrideCreator(footPrint.drawDbClassification, footPrint.drawRegistrantId)
412  except:
413  sys.stderr.write("Failed to deregister override\n")
414  pass
415