import maya.cmds as cmdsimport maya.OpenMaya as OM
# gets the blendShape node MObject
bsNodeName = 'blendShape1'bsNodeObj = OM.MObject()sel = OM.MSelectionList()sel.add(bsNodeName, 0)sel.getDependNode(0, bsNodeObj)
# gets the plug for the inputTargetItem[] compound attribute and ...
dgFn = OM.MFnDependencyNode(bsNodeObj)plug = dgFn.findPlug('inputTarget').elementByPhysicalIndex(0).child(0).elementByPhysicalIndex(0).child(0).elementByPhysicalIndex(0)
# if connected, retrieves the input target object and queries his points
if plug.child(0).isConnected(): inputGeomTarget = plug.child(0).asMObject() targetPoints = OM.MPointArray() fnMesh = OM.MFnMesh(inputGeomTarget) fnMesh.getPoints(targetPoints)
# if not connected, retrieves the deltas and the affected component list
else: inputPointsTarget = plug.child(1).asMObject() inputComponentsTarget = plug.child(2).asMObject() # to read the offset data, I had to use a MFnPointArrayData fnPoints = OM.MFnPointArrayData(inputPointsTarget) targetPoints = OM.MPointArray() fnPoints.copyTo(targetPoints) # read the component list data was the trickiest part, since I had to use MFnSingleIndexedComponent to extract (finally), an MIntArray # with the indices of the affected vertices componentList = OM.MFnComponentListData(inputComponentsTarget)[0] fnIndex = OM.MFnSingleIndexedComponent(componentList) targetIndices = OM.MIntArray() fnIndex.getElements(targetIndices)
if targetIndices.length() == targetPoints.length(): for i in range(targetPoints.length()): print "vertex %d has offset " %targetIndices[i], targetPoints[i].x,targetPoints[i].y, targetPoints[i].z
(and possibly faster)
Unless the shapes are also being manipulated during playback, I would be surprised if this were true, considering that the input would be deemed not-dirty regardless of anything being plugged into it.
Still, having access to these deltas allows you to work with a wider range of data and opens up to new possibilities!
On the contrary, I would say.
By removing the shapes to begin with you limit yourself greatly. Does a blendshape node even cache enough of the mesh to fully re-produce it? I’d imagine it only bothers to store pointpositions, but I could be mistaken.
We are now working on a rig with several tens of targets, each one of which has something like one million polygons… Deleting the shapes freed up about 700mb!
That’s a good reason, I’ve done the same in similar situations. What I found less destructive however was to reference the shapes - they can be for example Maya scenefiles, plain obj or alembic - that make the scenes even lighter as the blendShape node wouldn’t need to keep track of deltas either.
Out of curiosity, are you really rebuilding tens of shapes at millions of polygons each using Python?
index_list = OM.MIntArray() # indices to be writtendeltas_list = OM.MPointArray() # deltas to be written (maya wants points instead of vectors) ¯\_(ツ)_/¯
####################################################################################
### values for index_list and deltas_list are assigned outside this code snippet ###
####################################################################################
# initializes function sets, needed to create the MObjects and set their data
dg_component_fn = OM.MFnComponentListData()dg_component_data = dg_component_fn.create()singleComponent_fn = OM.MFnSingleIndexedComponent()singleComponent_data = singleComponent_fn.create(OM.MFn.kMeshVertComponent)singleComponent_fn.addElements(index_list)
# write the index data in the inputComponentsTarget plugif not singleComponent_data.isNull(): dg_component_fn.add(singleComponent_data) inputComponentsTarget_plug.setMObject(dg_component_data)
print dg_component_fn.length() # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< this line prints 1 (in my test index_list and deltas_list had 11476 elements each)
# writes the delta data in the inputPointsTarget plugdg_pointArray_fn = OM.MFnPointArrayData()dg_pointArray_data = dg_pointArray_fn.create(deltas_list)if not dg_pointArray_data.isNull(): inputPointsTarget_plug.setMObject(dg_pointArray_data)
print dg_pointArray_fn.length() # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< this line prints 11476 (correct!)
inputPointsTarget_data = inputPointsTarget_plug.asMDataHandle().data()inputComponentsTarget_data = inputComponentsTarget_plug.asMDataHandle().data()
# to read the deltas, use a MFnPointArrayDatatargetPoints = OM.MPointArray()fnPoints = OM.MFnPointArrayData(inputPointsTarget_data)
fnPoints.copyTo(targetPoints)
# use MFnSingleIndexedComponent to extract an MIntArray with the indices
dg_component_fn = OM.MFnComponentListData(inputComponentsTarget_data)[0] # <<<<<<<<<<<< why does this need to be only the first element?if dg_component_fn.isNull():
continuesingleComponent_fn = OM.MFnSingleIndexedComponent(dg_component_fn)targetIndices = OM.MIntArray()singleComponent_fn.getElements(targetIndices)
print "indices: ", targetIndices.length(), "points: ", targetPoints.length() # <<<<<<<<<<<< prints "indices: 1 points: 11476"
OM.MFnComponentListData(inputComponentsTarget_data)
OM.MFnComponentListData(inputComponentsTarget_data)[0]
OM.MFnComponentListData(inputComponentsTarget_data)[1]
OM.MFnComponentListData(inputComponentsTarget_data)[2]