148 import maya.api.OpenMaya
as om
149 import maya.api.OpenMayaUI
as omui
150 import maya.api.OpenMayaRender
as omr
153 class GeometryOverrideHighPerformance_shape(om.MPxSurfaceShape):
154 id = om.MTypeId(0x80040)
156 fsInputMeshBoundingBoxMin =
None
157 fsInputMeshBoundingBoxMax =
None
159 fsSizeChangedSinceVP2Update =
None
160 fsInputMeshChanged =
None
161 fsInputMeshGeoChanged =
None
162 fsMaterialChanged =
None
175 return GeometryOverrideHighPerformance_shape()
178 def instancingChangedCallback(childPath, parentPath, clientData):
179 om.MGlobal.displayWarning(
"GeometryOverrideHighPerformance does't support instancing !")
183 unitFn = om.MFnUnitAttribute()
190 GeometryOverrideHighPerformance_shape.fsSize = unitFn.create(
"size",
"sz", om.MFnUnitAttribute.kDistance)
191 unitFn.default = om.MDistance(1.0)
192 unitFn.keyable =
True
193 om.MPxNode.addAttribute(GeometryOverrideHighPerformance_shape.fsSize)
199 typedFn = om.MFnTypedAttribute()
200 GeometryOverrideHighPerformance_shape.fsInputMesh = typedFn.create(
"inMesh",
"i", om.MFnData.kMesh, om.MObject.kNullObj)
201 om.MPxNode.addAttribute(GeometryOverrideHighPerformance_shape.fsInputMesh)
207 numericAttributeFn = om.MFnNumericAttribute()
208 GeometryOverrideHighPerformance_shape.fsInputMeshBoundingBoxMin = numericAttributeFn.create(
"inputBoundMin",
"inbn", om.MFnNumericData.k3Double, 0)
209 numericAttributeFn.array =
False
210 numericAttributeFn.usesArrayDataBuilder =
False
211 numericAttributeFn.hidden =
False
212 numericAttributeFn.keyable =
True
213 om.MPxNode.addAttribute(GeometryOverrideHighPerformance_shape.fsInputMeshBoundingBoxMin)
215 GeometryOverrideHighPerformance_shape.fsInputMeshBoundingBoxMax = numericAttributeFn.create(
"inputBoundMax",
"inbm", om.MFnNumericData.k3Double, 0)
216 numericAttributeFn.array =
False
217 numericAttributeFn.usesArrayDataBuilder =
False
218 numericAttributeFn.hidden =
False
219 numericAttributeFn.keyable =
True
220 om.MPxNode.addAttribute(GeometryOverrideHighPerformance_shape.fsInputMeshBoundingBoxMax)
222 om.MPxNode.attributeAffects(GeometryOverrideHighPerformance_shape.fsInputMeshBoundingBoxMin, om.MPxSurfaceShape.nodeBoundingBoxMin)
223 om.MPxNode.attributeAffects(GeometryOverrideHighPerformance_shape.fsInputMeshBoundingBoxMax, om.MPxSurfaceShape.nodeBoundingBoxMax)
224 om.MPxNode.attributeAffects(GeometryOverrideHighPerformance_shape.fsSize, om.MPxSurfaceShape.nodeBoundingBoxMin)
225 om.MPxNode.attributeAffects(GeometryOverrideHighPerformance_shape.fsSize, om.MPxSurfaceShape.nodeBoundingBoxMax)
247 attrFn = om.MFnNumericAttribute()
248 GeometryOverrideHighPerformance_shape.fsSizeChangedSinceVP2Update = attrFn.create(
"sizeChangedSinceVP2Update",
"sd", om.MFnNumericData.kBoolean,
True)
249 attrFn.storable =
False
251 attrFn.connectable =
False
252 om.MPxNode.addAttribute(GeometryOverrideHighPerformance_shape.fsSizeChangedSinceVP2Update)
254 attrFn = om.MFnNumericAttribute()
255 GeometryOverrideHighPerformance_shape.fsInputMeshChanged = attrFn.create(
"inputMeshChangedSinceVP2Update",
"imd", om.MFnNumericData.kBoolean,
True)
256 attrFn.storable =
False
258 attrFn.connectable =
False
259 om.MPxNode.addAttribute(GeometryOverrideHighPerformance_shape.fsInputMeshChanged)
261 attrFn = om.MFnNumericAttribute()
262 GeometryOverrideHighPerformance_shape.fsInputMeshGeoChanged = attrFn.create(
"inputMeshGeoChangedSinceVP2Update",
"img", om.MFnNumericData.kBoolean,
True)
263 attrFn.storable =
False
265 attrFn.connectable =
False
266 om.MPxNode.addAttribute(GeometryOverrideHighPerformance_shape.fsInputMeshGeoChanged)
268 attrFn = om.MFnNumericAttribute()
269 GeometryOverrideHighPerformance_shape.fsMaterialChanged = attrFn.create(
"materialChangedSinceVP2Update",
"mcd", om.MFnNumericData.kBoolean,
True)
270 attrFn.storable =
False
272 attrFn.connectable =
False
273 om.MPxNode.addAttribute(GeometryOverrideHighPerformance_shape.fsMaterialChanged)
275 GeometryOverrideHighPerformance_shape.createSphere(1, 50, 50)
278 om.MPxSurfaceShape.__init__(self)
280 self.fUseInputMesh =
False
282 self.mInstanceAddedCallbackId =
None
285 om.MMessage.removeCallback(self.mInstanceAddedCallbackId)
287 def postConstructor(self):
289 When instances of this node are created internally, the MObject
290 associated with the instance is not created until after the constructor
291 of this class is called. This means that no member functions of
292 MPxSurfaceShape can be called in the constructor. The postConstructor
293 solves this problem. Maya will call this function after the internal
294 object has been created. As a general rule do all of your initialization
295 in the postConstructor.
297 Note : For more information, see MPxSurfaceShape.postConstructor()
301 self.isRenderable =
True
306 path = om.MDagPath.getAPathTo(self.thisMObject())
307 self.mInstanceAddedCallbackId = om.MDagMessage.addInstanceAddedDagPathCallback(path, GeometryOverrideHighPerformance_shape.instancingChangedCallback)
309 def getShapeSelectionMask(self):
311 This method is overriden to support interactive object selection in
314 Returns The selection mask of the shaper.
316 Note : For more information, see MPxSurfaceShape::getShapeSelectionMask()
319 selType = om.MSelectionMask.kSelectMeshes
320 return om.MSelectionMask( selType )
325 def boundingBox(self):
327 Returns the bounding box for this object.
328 It is a good idea not to recompute here as this function is called
331 Note : This function is only called if MPxSurfaceShape.isBounded()
332 return true. For more information, see MPxSurfaceShape.boundingBox()
334 thisNode = self.thisMObject()
339 plug = om.MPlug( thisNode, GeometryOverrideHighPerformance_shape.fsSize )
340 sizeVal = plug.asMDistance()
341 multiplier = sizeVal.asCentimeters()
347 if self.fUseInputMesh:
348 block = self.forceCache()
349 boundingBoxMin = block.inputValue(GeometryOverrideHighPerformance_shape.fsInputMeshBoundingBoxMin).asDouble3()
350 boundingBoxMax = block.inputValue(GeometryOverrideHighPerformance_shape.fsInputMeshBoundingBoxMax).asDouble3()
351 return om.MBoundingBox(om.MPoint(boundingBoxMin) * multiplier, om.MPoint(boundingBoxMax) * multiplier)
356 return om.MBoundingBox(GeometryOverrideHighPerformance_shape.fsBoundingBox.min * multiplier, GeometryOverrideHighPerformance_shape.fsBoundingBox.max * multiplier)
358 def connectionMade(self, plug, otherPlug, asSrc):
360 This method gets called when connections are made to attributes
363 Note : For more information, see MPxNode.connectionMade()
369 otherPlug.node().hasFn(om.MFn.kShadingEngine)
and
370 (plug.attribute() == om.MPxSurfaceShape.instObjGroups
or
371 plug.attribute() == om.MPxSurfaceShape.objectGroups)):
373 self.setMaterialChangedSinceVP2Update(
True)
378 otherPlug.node().hasFn(om.MFn.kMesh)
and
379 plug.attribute() == GeometryOverrideHighPerformance_shape.fsInputMesh):
381 self.fUseInputMesh =
True
382 self.setInputMeshChangedSinceVP2Update(
True)
384 thisNode = self.thisMObject()
385 boundingBoxMinPlug = om.MPlug(thisNode, GeometryOverrideHighPerformance_shape.fsInputMeshBoundingBoxMin)
386 boundingBoxMaxPlug = om.MPlug(thisNode, GeometryOverrideHighPerformance_shape.fsInputMeshBoundingBoxMax)
388 inputMeshBoundingBoxMinPlug = om.MPlug(otherPlug.node(), om.MPxSurfaceShape.nodeBoundingBoxMin)
389 inputMeshBoundingBoxMaxPlug = om.MPlug(otherPlug.node(), om.MPxSurfaceShape.nodeBoundingBoxMax)
391 modifier = om.MDGModifier()
392 modifier.connect(inputMeshBoundingBoxMinPlug, boundingBoxMinPlug)
393 modifier.connect(inputMeshBoundingBoxMaxPlug, boundingBoxMaxPlug)
396 return om.MPxNode.connectionMade(self, plug, otherPlug, asSrc)
398 def connectionBroken(self, plug, otherPlug, asSrc):
400 This method gets called when connections are broken with attributes
403 Note : For more information, see MPxNode.connectionBroken()
409 otherPlug.node().hasFn(om.MFn.kShadingEngine)
and
410 (plug.attribute() == om.MPxSurfaceShape.instObjGroups
or
411 plug.attribute() == om.MPxSurfaceShape.objectGroups)):
413 self.fMaterialChanged =
True
418 otherPlug.node().hasFn(om.MFn.kMesh)
and
419 plug.attribute() == GeometryOverrideHighPerformance_shape.fsInputMesh):
421 self.fUseInputMesh =
False
422 self.setInputMeshChangedSinceVP2Update(
True)
424 thisNode = self.thisMObject()
425 boundingBoxMinPlug = om.MPlug(thisNode, GeometryOverrideHighPerformance_shape.fsInputMeshBoundingBoxMin)
426 boundingBoxMaxPlug = om.MPlug(thisNode, GeometryOverrideHighPerformance_shape.fsInputMeshBoundingBoxMax)
428 inputMeshBoundingBoxMinPlug = om.MPlug(otherPlug.node(), om.MPxSurfaceShape.nodeBoundingBoxMin)
429 inputMeshBoundingBoxMaxPlug = om.MPlug(otherPlug.node(), om.MPxSurfaceShape.nodeBoundingBoxMax)
431 modifier = om.MDGModifier()
432 modifier.disconnect(inputMeshBoundingBoxMinPlug, boundingBoxMinPlug)
433 modifier.disconnect(inputMeshBoundingBoxMaxPlug, boundingBoxMaxPlug)
436 return om.MPxNode.connectionBroken(self, plug, otherPlug, asSrc)
438 def setDependentsDirty(self, plug, plugArray):
440 This method can be overridden in user defined nodes to specify
441 which plugs should be set dirty based upon an input plug
443 Note : For more information, see MPxNode.setDependentsDirty()
445 if (plug.attribute() == GeometryOverrideHighPerformance_shape.fsSize):
447 self.setSizeChangedSinceVP2Update(
True)
449 elif(plug.attribute() == GeometryOverrideHighPerformance_shape.fsInputMesh):
450 self.setInputMeshGeoChangedSinceVP2Update(
True)
452 def postEvaluation(self, context, evaluationNode, evalType):
454 After the evaluation graph execution, each node gets a chance to
455 restore / update its internal states.For example, resetting
458 This code has to be thread safe, non - blocking and work only on
459 data owned by the node.
461 This call will most likely happen from a worker thread.
463 Note : For more information, see MPxNode.postEvaluation()
465 if evaluationNode.dirtyPlugExists(GeometryOverrideHighPerformance_shape.fsSize):
467 self.setSizeChangedSinceVP2Update(
True)
469 if evaluationNode.dirtyPlugExists(GeometryOverrideHighPerformance_shape.fsInputMesh):
471 self.setInputMeshGeoChangedSinceVP2Update(
True)
474 def getPositions(self):
475 return GeometryOverrideHighPerformance_shape.fsPositions
477 def getNormals(self):
478 return GeometryOverrideHighPerformance_shape.fsNormals
480 def getTangents(self):
481 return GeometryOverrideHighPerformance_shape.fsTangents
483 def getBiTangents(self):
484 return GeometryOverrideHighPerformance_shape.fsBiTangents
486 def getTextureCoords(self):
487 return GeometryOverrideHighPerformance_shape.fsTexCoords
489 def getIndices(self):
490 return GeometryOverrideHighPerformance_shape.fsIndices
492 def setSizeChangedSinceVP2Update(self, value):
500 dataBlock = self.forceCache()
501 dataHandle = dataBlock.outputValue(GeometryOverrideHighPerformance_shape.fsSizeChangedSinceVP2Update)
502 dataHandle.setBool(value)
504 def evalSizeChangedSinceVP2Update(self):
505 dataBlock = self.forceCache()
506 dataHandle = dataBlock.outputValue(GeometryOverrideHighPerformance_shape.fsSizeChangedSinceVP2Update)
507 return dataHandle.asBool()
509 def evalInputMeshChangedSinceVP2Update(self):
510 dataBlock = self.forceCache()
511 dataHandle = dataBlock.outputValue(GeometryOverrideHighPerformance_shape.fsInputMeshChanged)
512 return dataHandle.asBool()
514 def setInputMeshChangedSinceVP2Update(self, value):
515 dataBlock = self.forceCache()
516 dataHandle = dataBlock.outputValue(GeometryOverrideHighPerformance_shape.fsInputMeshChanged)
517 dataHandle.setBool(value)
519 def evalInputMeshGeoChangedSinceVP2Update(self):
520 dataBlock = self.forceCache()
521 dataHandle = dataBlock.outputValue(GeometryOverrideHighPerformance_shape.fsInputMeshGeoChanged)
522 return dataHandle.asBool()
524 def setInputMeshGeoChangedSinceVP2Update(self, value):
525 dataBlock = self.forceCache()
526 dataHandle = dataBlock.outputValue(GeometryOverrideHighPerformance_shape.fsInputMeshGeoChanged)
527 dataHandle.setBool(value)
529 def evalMaterialChangedSinceVP2Update(self):
530 dataBlock = self.forceCache()
531 dataHandle = dataBlock.outputValue(GeometryOverrideHighPerformance_shape.fsMaterialChanged)
532 return dataHandle.asBool()
534 def setMaterialChangedSinceVP2Update(self, value):
535 dataBlock = self.forceCache()
536 dataHandle = dataBlock.outputValue(GeometryOverrideHighPerformance_shape.fsMaterialChanged)
537 dataHandle.setBool(value)
540 def createSphere(radius, sliceCount, stackCount):
543 GeometryOverrideHighPerformance_shape.fsPositions.append([0.0, radius, 0.0] )
544 GeometryOverrideHighPerformance_shape.fsNormals.append([0.0, 1.0, 0.0])
545 GeometryOverrideHighPerformance_shape.fsTangents.append([1.0, 0.0, 0.0])
546 GeometryOverrideHighPerformance_shape.fsBiTangents.append([0.0, 0.0, -1.0])
547 GeometryOverrideHighPerformance_shape.fsTexCoords.append([0.0, 0.0])
550 phiStep = math.pi / stackCount
551 thetaStep = 2.0 * math.pi / sliceCount
555 for i
in xrange(1, stackCount):
559 for j
in xrange(0, sliceCount+1):
560 theta = j * thetaStep
563 positionX = radius * math.sin(phi) * math.cos(theta)
564 positionY = radius * math.cos(phi)
565 positionZ = radius * math.sin(phi) * math.sin(theta)
566 GeometryOverrideHighPerformance_shape.fsPositions.append([positionX, positionY, positionZ])
568 normal = om.MFloatVector(positionX , positionY , positionZ)
570 GeometryOverrideHighPerformance_shape.fsNormals.append([normal.x, normal.y, normal.z])
573 tangent = om.MFloatVector( -radius * math.sin(phi) * math.sin(theta),
575 radius * math.sin(phi) * math.cos(theta) )
577 GeometryOverrideHighPerformance_shape.fsTangents.append([tangent.x, tangent.y, tangent.z])
579 biTangents = normal ^ tangent
580 GeometryOverrideHighPerformance_shape.fsBiTangents.append(biTangents)
582 GeometryOverrideHighPerformance_shape.fsTexCoords.append([ theta / math.pi, phi / math.pi])
585 GeometryOverrideHighPerformance_shape.fsPositions.append([0.0, -radius, 0.0])
586 GeometryOverrideHighPerformance_shape.fsNormals.append([0.0, -1.0, 0.0])
587 GeometryOverrideHighPerformance_shape.fsTangents.append([1.0, 0.0, 0.0])
588 GeometryOverrideHighPerformance_shape.fsBiTangents.append([0.0, 0.0, -1.0])
589 GeometryOverrideHighPerformance_shape.fsTexCoords.append([0.0, 1.0])
596 for i
in xrange(1,sliceCount+1):
597 GeometryOverrideHighPerformance_shape.fsIndices.append(0)
598 GeometryOverrideHighPerformance_shape.fsIndices.append(i + 1)
599 GeometryOverrideHighPerformance_shape.fsIndices.append(i)
604 ringVertexCount = sliceCount + 1
605 for i
in xrange(sliceCount - 2):
606 for j
in xrange(sliceCount):
607 GeometryOverrideHighPerformance_shape.fsIndices.append(baseIndex + i*ringVertexCount + j)
608 GeometryOverrideHighPerformance_shape.fsIndices.append(baseIndex + i*ringVertexCount + j + 1)
609 GeometryOverrideHighPerformance_shape.fsIndices.append(baseIndex + (i + 1)*ringVertexCount + j)
611 GeometryOverrideHighPerformance_shape.fsIndices.append(baseIndex + (i + 1)*ringVertexCount + j)
612 GeometryOverrideHighPerformance_shape.fsIndices.append(baseIndex + i*ringVertexCount + j + 1)
613 GeometryOverrideHighPerformance_shape.fsIndices.append(baseIndex + (i + 1)*ringVertexCount + j + 1)
616 southPoleIndex = len(GeometryOverrideHighPerformance_shape.fsPositions) - 1
619 baseIndex = southPoleIndex - ringVertexCount;
621 for i
in xrange(sliceCount):
622 GeometryOverrideHighPerformance_shape.fsIndices.append(southPoleIndex)
623 GeometryOverrideHighPerformance_shape.fsIndices.append(baseIndex + i)
624 GeometryOverrideHighPerformance_shape.fsIndices.append(baseIndex + i + 1)
630 corner1Point = om.MPoint(-radius, -radius, -radius)
631 corner2Point = om.MPoint(radius, radius, radius)
632 GeometryOverrideHighPerformance_shape.fsBoundingBox = om.MBoundingBox(corner1Point, corner2Point)
641 class PerformanceExampleGeometryOverride(omr.MPxGeometryOverride):
642 sActiveWireframeRenderItemName =
"PerformanceExampleGeometryOverride_ActiveWireframe"
643 sDormantWireframeRenderItemName=
"PerformanceExampleGeometryOverride_DormantWireframe"
644 sCustomShadedItemName =
"PerformanceExampleGeometryOverride_shaded"
648 return PerformanceExampleGeometryOverride(obj)
650 def __init__(self, obj):
651 omr.MPxGeometryOverride.__init__(self, obj)
653 node = om.MFnDependencyNode(obj)
654 self.fMesh = node.userNode()
656 self.fSurfaceNode = obj
657 self.fInputMeshPath =
None
659 self.fDisplayStatus =
None
660 self.fWireframeDisplayColor =
None
662 self.fSizeMultiplier = 1.0
667 def supportedDrawAPIs(self):
669 This function return draw API that is supported by this plugin.
671 Note : Dependency graph evaluation is not allowed in this function.
672 Note : For more information, see MPxGeometryOverride.supportedDrawAPIs()
676 return omr.MRenderer.kOpenGL | omr.MRenderer.kDirectX11 | omr.MRenderer.kOpenGLCoreProfile
680 Perform any work required to translate the geometry data that needs to get
681 information from the dependency graph.This should be the only place that
682 dependency graph evaluation occurs.Any data retrieved should be cached for
685 Note : For more information, see MPxGeometryOverride.updateDG()
691 if self.fMesh
and self.fMesh.evalInputMeshChangedSinceVP2Update():
693 plug = om.MPlug(self.fSurfaceNode, GeometryOverrideHighPerformance_shape.fsInputMesh)
695 self.fInputMeshPath =
None
697 connections = plug.connectedTo(
True,
False)
699 for i
in xrange(len(connections)):
700 node = connections[i].node()
702 if node.hasFn(om.MFn.kMesh):
703 self.fInputMeshPath = om.MDagPath.getAPathTo(node)
708 if self.fMesh
and self.fMesh.evalSizeChangedSinceVP2Update():
709 plug = om.MPlug(self.fSurfaceNode, GeometryOverrideHighPerformance_shape.fsSize)
712 sizeVal = plug.asMDistance()
713 self.fSizeMultiplier = sizeVal.asCentimeters()
715 def isStreamDirty(self, desc):
717 This method is called for each geometry stream on the assocated DAG object
718 whenever the object changes.This method is passed a vertex buffer
719 descriptor representing one stream on the object to be updated.This
720 method should return false if it is safe to reuse the existing buffer rather
721 than filling a new buffer with data. Note that returning false from
722 isStreamDirty may NOT prevent populateGeometry from requiring that a stream
725 Note : Dependency graph evaluation is not allowed in this function.
726 Note : For more information, see MPxGeometryOverride.isStreamDirty()
728 if self.fInputMeshPath:
729 if self.fMesh
and self.fMesh.evalInputMeshChangedSinceVP2Update():
736 elif self.fMesh
and \
737 (self.fMesh.evalInputMeshGeoChangedSinceVP2Update()
or self.fMesh.evalSizeChangedSinceVP2Update()):
747 if(self.fMesh
and self.fMesh.evalInputMeshChangedSinceVP2Update()):
755 elif desc.semantic == omr.MGeometry.kPosition:
758 return self.fMesh
and self.fMesh.evalSizeChangedSinceVP2Update()
768 def isIndexingDirty(self, item):
770 This method is called for each render item on the assocated DAG object
771 whenever the object changes.This method is passed a render item.This
772 method should return true if the indexing for the render item has changed
773 since the last frame.Note that returning false from isIndexingDirty may
774 NOT prevent populate geometry from requiring that an index buffer is
777 Note : Dependency graph evaluation is not allowed in this function.
778 Note : For more information, see MPxGeometryOverride.isIndexingDirty()
782 return self.fMesh
and self.fMesh.evalInputMeshChangedSinceVP2Update()
784 def requiresGeometryUpdate(self):
786 This method is called once during each draw-preparation phase. If this
787 method returns true then the associated DAG object will have a chance
788 to update its render geometry this frame. (By calling populateGeometry())
790 This code has to be thread safe, non - blocking and work only on
791 data owned by the associated DAG object.
793 Note : Dependency graph evaluation is not allowed in this function.
794 Note: For more information, see MPxGeometryOverride.requiresGeometryUpdate()
802 return self.fMesh
and \
803 (self.fMesh.evalInputMeshChangedSinceVP2Update()
or \
804 self.fMesh.evalInputMeshGeoChangedSinceVP2Update()
or \
805 self.fMesh.evalSizeChangedSinceVP2Update() )
807 def requiresUpdateRenderItems(self, path):
809 If this method returns false for an MDagPath instance
810 of the associated DAG object then updateRenderItems() will not be called
811 for that MDagPath draw-preparation phase. If requiresUpdateRenderItems()
812 returns false for all MDagPaths then updateRenderItems() will not be
813 called at all for the draw-preparation phase.
815 Note : Dependency graph evaluation is not allowed in this function.
816 Note : For more information, see MPxGeometryOverride.requiresUpdateRenderItems()
819 if self.fMesh
and self.fMesh.evalMaterialChangedSinceVP2Update():
820 self.fMesh.setMaterialChangedSinceVP2Update(
False);
823 currentDisplayStatus = omr.MGeometryUtilities.displayStatus(path)
829 if (currentDisplayStatus == self.fDisplayStatus):
834 def supportsEvaluationManagerParallelUpdate(self):
836 If this method returns true then the MPxGeometryOverride will be considered
837 for Evaluation Manager Parallel Update.
839 Note : Dependency graph evaluation is not allowed in this function.
840 Note : For more information, see MPxGeometryOverride.supportsEvaluationManagerParallelUpdate()
845 def supportsVP2CustomCaching(self):
847 This method is called at any time during evaluation to determine if VP2
848 Custom Caching is supported.
850 Note : Dependency graph evaluation is not allowed in this function.
851 Note : For more information, see MPxGeometryOverride::supportsVP2CustomCaching()
857 def updateRenderItems(self, path, renderItems):
859 This method is called for each instance of the associated DAG object whenever
860 the object changes and receive the path to the instance and the current list
861 of render items associated with that instance. Implementations of this method
862 may add, remove or modify items in the list. As an alternative this method
863 can enable or disable items that must be used or not based on some properties.
865 A render item represents a single renderable entity and contain many properties
866 to let the Viewport 2.0 to know how to render the entity. By example, A render
867 item contain a name, a type, the geometry primitive, the geometry buffer and a
870 In this example, this functions will create 3 render items to render the object's
871 geometry. The first render item will be use to display the oject with a single color
872 only when the Viewport 2.0 is in shaded or textured mode. The second render item
873 will be use to display the object in wireframe with a single color only when the
874 Viewport 2.0 is in wireframe mode. The last render item will be use to render the
875 object with a single color in wireframe only when the object is selected independing
876 of the Viewport 2.0 display mode. Both wireframe render item will be enable or disable
877 depending of the object selection state.
879 Note : Dependency graph evaluation is not allowed in this function.
880 Note : For more information, see MPxGeometryOverride.updateRenderItems()
883 if not path.isValid():
886 shaderManager = omr.MRenderer.getShaderManager()
887 if not shaderManager:
895 standardShadedItemIndex = renderItems.indexOf(
"StandardShadedItem");
897 renderItemIndex = renderItems.indexOf(self.sCustomShadedItemName)
905 if standardShadedItemIndex < 0
and renderItemIndex < 0:
909 shadedRenderItem = omr.MRenderItem.create(self.sCustomShadedItemName,
910 omr.MRenderItem.MaterialSceneItem,
911 omr.MGeometry.kTriangles)
914 shadedRenderItem.setDrawMode(omr.MGeometry.kShaded)
920 shadedRenderItem.setDepthPriority(omr.MRenderItem.sDormantFilledDepthPriority)
923 shadedRenderItem.enable(
True)
929 shader = shaderManager.getFragmentShader(
"mayaLambertSurface",
"outSurfaceFinal",
True)
932 blueColor = [ 0.0, 0.0, 1.0, 1.0 ]
933 shader.setParameter(
"color", blueColor)
937 shadedRenderItem.setShader(shader)
940 shaderManager.releaseShader(shader)
944 renderItems.append(shadedRenderItem)
954 if standardShadedItemIndex >= 0
and renderItemIndex >= 0:
955 renderItem = renderItems[renderItemIndex]
957 renderItem.enable(
False)
959 renderItem = renderItems[standardShadedItemIndex]
961 renderItem.enable(
True)
968 if standardShadedItemIndex < 0
and renderItemIndex >= 0:
969 renderItem = renderItems[renderItemIndex]
971 renderItem.enable(
True)
976 self.fWireframeDisplayColor = omr.MGeometryUtilities.wireframeColor(path)
977 self.fDisplayStatus = omr.MGeometryUtilities.displayStatus(path)
980 isWireFrameRenderItemEnabled = self.fDisplayStatus == omr.MGeometryUtilities.kLead
or \
981 self.fDisplayStatus == omr.MGeometryUtilities.kActive
983 self.updateWireframeItems(PerformanceExampleGeometryOverride.sActiveWireframeRenderItemName, \
984 omr.MGeometry.kAll, \
985 omr.MRenderItem.sSelectionDepthPriority, \
986 self.fWireframeDisplayColor, \
987 isWireFrameRenderItemEnabled, \
992 isWireFrameRenderItemEnabled = self.fDisplayStatus == omr.MGeometryUtilities.kDormant
994 self.updateWireframeItems(PerformanceExampleGeometryOverride.sDormantWireframeRenderItemName,
995 omr.MGeometry.kWireframe,
996 omr.MRenderItem.sDormantWireDepthPriority,
997 self.fWireframeDisplayColor,
998 isWireFrameRenderItemEnabled,
1003 def populateGeometry(self, requirements, renderItems, data):
1005 Fill in data and index streams based on the requirements passed in.
1006 Associate indexing with the render items passed in.
1008 Note : Dependency graph evaluation is not allowed in this function.
1009 Note : For more information, see MPxGeometryOverride.populateGeometry()
1014 if self.fInputMeshPath
and self.fInputMeshPath.isValid():
1015 self.populateInputMeshGeometry(requirements, renderItems, data)
1017 self.populateDefaultMeshGeometry(requirements, renderItems, data)
1022 self.fMesh.setSizeChangedSinceVP2Update(
False)
1023 self.fMesh.setInputMeshChangedSinceVP2Update(
False)
1024 self.fMesh.setInputMeshGeoChangedSinceVP2Update(
False)
1027 def populateInputMeshGeometry(self, requirements, renderItems, data):
1029 This function is used to populate the geometry data from the
1030 input mesh. It used the MGeometryExtractor to extract
1037 options = omr.MGeometryExtractor.kPolyGeom_NotSharing
1038 extractor = omr.MGeometryExtractor(requirements, self.fInputMeshPath, options)
1039 if (extractor
is None):
1042 vertexBufferDescriptorList = requirements.vertexRequirements()
1043 for i
in xrange(len(vertexBufferDescriptorList)):
1044 desc = vertexBufferDescriptorList[i]
1046 vertexBuffer = data.createVertexBuffer(desc)
1048 vertexCount = extractor.vertexCount()
1050 bufferAdress = vertexBuffer.acquire(vertexCount,
True)
1053 extractor.populateVertexBuffer(bufferAdress, vertexCount, desc)
1057 if desc.semantic == omr.MGeometry.kPosition:
1059 bufferData = ( (ctypes.c_float * 3) * vertexCount ).from_address(bufferAdress)
1061 for i
in xrange(vertexCount):
1062 bufferData[i][0] *= self.fSizeMultiplier
1063 bufferData[i][1] *= self.fSizeMultiplier
1064 bufferData[i][2] *= self.fSizeMultiplier
1067 vertexBuffer.commit(bufferAdress)
1073 for i
in xrange(len(renderItems)):
1074 item = renderItems[i]
1078 indexBuffer = data.createIndexBuffer(omr.MGeometry.kUnsignedInt32)
1082 if item.primitive() == omr.MGeometry.kTriangles:
1083 triangleDesc = omr.MIndexBufferDescriptor(omr.MIndexBufferDescriptor.kTriangle,
"", omr.MGeometry.kTriangles, 3)
1085 numTriangles = extractor.primitiveCount(triangleDesc)
1087 indices = indexBuffer.acquire(3 * numTriangles,
True)
1091 extractor.populateIndexBuffer(indices, numTriangles, triangleDesc)
1094 indexBuffer.commit(indices)
1096 elif item.primitive() == omr.MGeometry.kLines:
1097 edgeDesc = omr.MIndexBufferDescriptor(omr.MIndexBufferDescriptor.kEdgeLine,
"", omr.MGeometry.kLines, 2)
1099 numEdges = extractor.primitiveCount(edgeDesc)
1101 indices = indexBuffer.acquire(2 * numEdges,
True)
1105 extractor.populateIndexBuffer(indices, numEdges, edgeDesc)
1108 indexBuffer.commit(indices)
1111 item.associateWithIndexBuffer(indexBuffer)
1113 def populateDefaultMeshGeometry(self, requirements, renderItems, data):
1115 This function is used to populate the geometry data from the
1116 default mesh (Hardcoded mesh) in case there is no input mesh
1117 attached to the node.
1119 vertexBufferDescriptorList = requirements.vertexRequirements()
1120 for i
in xrange(len(vertexBufferDescriptorList)):
1122 desc = vertexBufferDescriptorList[i]
1124 if desc.semantic == omr.MGeometry.kPosition:
1128 positionBuffer = data.createVertexBuffer(desc)
1131 position = self.fMesh.getPositions()
1133 bufferAdress = positionBuffer.acquire(len(position),
True)
1136 bufferData = ((ctypes.c_float * 3)*len(position)).from_address(bufferAdress)
1138 for i
in xrange(len(position)):
1139 bufferData[i][0] = position[i][0] * self.fSizeMultiplier
1140 bufferData[i][1] = position[i][1] * self.fSizeMultiplier
1141 bufferData[i][2] = position[i][2] * self.fSizeMultiplier
1144 positionBuffer.commit(bufferAdress)
1147 elif desc.semantic == omr.MGeometry.kNormal:
1151 normalsBuffer = data.createVertexBuffer(desc)
1154 normals = self.fMesh.getNormals()
1156 bufferAdress = normalsBuffer.acquire(len(normals),
True)
1159 bufferData = ((ctypes.c_float * 3)*len(normals)).from_address(bufferAdress)
1161 for i
in xrange(len(normals)):
1162 bufferData[i][0] = normals[i][0]
1163 bufferData[i][1] = normals[i][1]
1164 bufferData[i][2] = normals[i][2]
1167 normalsBuffer.commit(bufferAdress)
1169 elif desc.semantic == omr.MGeometry.kTangent:
1173 buffer = data.createVertexBuffer(desc)
1176 tangents = self.fMesh.getTangents()
1178 bufferAdress = buffer.acquire(len(tangents),
True)
1181 bufferData = ((ctypes.c_float * 3)*len(tangents)).from_address(bufferAdress)
1183 for i
in xrange(len(tangents)):
1184 bufferData[i][0] = tangents[i][0]
1185 bufferData[i][1] = tangents[i][1]
1186 bufferData[i][2] = tangents[i][2]
1189 buffer.commit(bufferAdress)
1191 elif desc.semantic == omr.MGeometry.kBitangent:
1195 buffer = data.createVertexBuffer(desc)
1198 biTangents = self.fMesh.getBiTangents()
1200 bufferAdress = buffer.acquire(len(biTangents),
True)
1203 bufferData = ((ctypes.c_float * 3)*len(biTangents)).from_address(bufferAdress)
1205 for i
in xrange(len(biTangents)):
1206 bufferData[i][0] = biTangents[i][0]
1207 bufferData[i][1] = biTangents[i][1]
1208 bufferData[i][2] = biTangents[i][2]
1211 buffer.commit(bufferAdress)
1213 elif desc.semantic == omr.MGeometry.kTexture:
1217 buffer = data.createVertexBuffer(desc)
1220 textureCoords = self.fMesh.getTextureCoords()
1222 bufferAdress = buffer.acquire(len(textureCoords),
True)
1225 bufferData = ((ctypes.c_float * 2)*len(textureCoords)).from_address(bufferAdress)
1227 for i
in xrange(len(textureCoords)):
1228 bufferData[i][0] = textureCoords[i][0]
1229 bufferData[i][1] = textureCoords[i][1]
1232 buffer.commit(bufferAdress)
1240 for i
in xrange(len(renderItems)):
1241 item = renderItems[i]
1245 if item.primitive() == omr.MGeometry.kTriangles:
1249 indexBuffer = data.createIndexBuffer(omr.MGeometry.kUnsignedInt32)
1251 indices = self.fMesh.getIndices()
1252 bufferAdress = indexBuffer.acquire(len(indices),
True)
1255 bufferData = (ctypes.c_uint * len(indices)).from_address(bufferAdress)
1257 for i
in xrange(len(indices)):
1258 bufferData[i] = indices[i]
1261 indexBuffer.commit(bufferAdress)
1264 item.associateWithIndexBuffer(indexBuffer)
1267 elif item.primitive() == omr.MGeometry.kLines:
1271 indexBuffer = data.createIndexBuffer(omr.MGeometry.kUnsignedInt32)
1273 indices = self.fMesh.getIndices()
1274 bufferAdress = indexBuffer.acquire(len(indices),
True)
1277 bufferData = (ctypes.c_uint * len(indices)).from_address(bufferAdress)
1279 for i
in xrange(len(indices)):
1280 bufferData[i] = indices[i]
1283 indexBuffer.commit(bufferAdress)
1286 item.associateWithIndexBuffer(indexBuffer)
1298 def updateWireframeItems(self, renderItemName, drawMode, depthPriority, color, isEnabled, renderItemList, shaderManager):
1300 ## Update the wireframe render item named 'renderItemName' or create it
1301 ## if it doesn't exists.
1303 ## Note : Arguments drawMode and depthPriority are only used for creation of
1312 renderItemIndex = renderItemList.indexOf(renderItemName)
1313 if renderItemIndex < 0:
1318 renderItem = omr.MRenderItem.create(renderItemName, \
1319 omr.MRenderItem.DecorationItem, \
1320 omr.MGeometry.kLines)
1324 renderItem.setDrawMode(drawMode)
1327 renderItem.setDepthPriority(depthPriority)
1333 shader = shaderManager.getStockShader(omr.MShaderManager.k3dSolidShader)
1337 renderItem.setShader(shader)
1340 shaderManager.releaseShader(shader)
1344 renderItemList.append(renderItem)
1346 renderItem = renderItemList[renderItemIndex]
1350 shader = renderItem.getShader()
1353 shader.setParameter(
"solidColor", color)
1355 renderItem.enable(isEnabled)
1363 class GeometryOverrideHighPerformance_shapeUI(omui.MPxSurfaceShapeUI):
1367 return GeometryOverrideHighPerformance_shapeUI()
1370 omui.MPxSurfaceShapeUI.__init__(self)
1382 def maya_useNewAPI():
1384 The presence of this function tells Maya that the plugin produces, and
1385 expects to be passed, objects created using the Maya Python API 2.0.
1390 sDrawDbClassification =
"drawdb/geometry/performanceExample_py"
1391 sDrawRegistrantId =
"performanceExamplePlugin_py"
1394 def initializePlugin(obj):
1395 plugin = om.MFnPlugin(obj,
"Autodesk",
"1.0",
"Any")
1397 global sDrawDbClassification, sDrawRegistrantId
1400 plugin.registerShape(
"geometryOverrideHighPerformance_shape_py", \
1401 GeometryOverrideHighPerformance_shape.id, \
1402 GeometryOverrideHighPerformance_shape.creator, \
1403 GeometryOverrideHighPerformance_shape.initialize, \
1404 GeometryOverrideHighPerformance_shapeUI.creator, \
1405 sDrawDbClassification)
1407 sys.stderr.write(
"Failed to register geometryOverrideHighPerformance_shape_py\n")
1412 omr.MDrawRegistry.registerGeometryOverrideCreator(sDrawDbClassification, \
1413 sDrawRegistrantId, \
1414 PerformanceExampleGeometryOverride.creator)
1416 sys.stderr.write(
"Failed to register override\n")
1420 def uninitializePlugin(obj):
1421 plugin = om.MFnPlugin(obj)
1423 global sUseSubSceneOverride, sDrawDbClassification, sDrawRegistrantId
1427 omr.MDrawRegistry.deregisterGeometryOverrideCreator(sDrawDbClassification, sDrawRegistrantId)
1429 sys.stderr.write(
"Failed to deregister override\n")
1434 plugin.deregisterNode(GeometryOverrideHighPerformance_shape.id)
1436 sys.stderr.write(
"Failed to deregister node\n")