def deform(self, dataBlock, geoIterator, matrix, geometryIndex): input = OpenMayaMPx.cvar.MPxGeometryFilter_input # 1. Attach a handle to input Array Attribute. dataHandleInputArray = dataBlock.outputArrayValue(input) # 2. Jump to particular element dataHandleInputArray.jumpToElement(geometryIndex) # 3. Attach a handle to specific data block dataHandleInputElement = dataHandleInputArray.outputValue() # 4. Reach to the child - inputGeom inputGeom = OpenMayaMPx.cvar.MPxGeometryFilter_inputGeom dataHandleInputGeom = dataHandleInputElement.child(inputGeom) inMesh = dataHandleInputGeom.asMesh() #Envelope envelope = OpenMayaMPx.cvar.MPxGeometryFilter_envelope dataHandleEnvelope = dataBlock.inputValue(envelope) envelopeValue = dataHandleEnvelope.asFloat() # Amplitude dataHandleAmplitude = dataBlock.inputValue(Ripple.mObj_Amplitude) amplitudeValue = dataHandleAmplitude.asFloat() # Displace dataHandleDisplace = dataBlock.inputValue(Ripple.mObj_Displace) displaceValue = dataHandleDisplace.asFloat() # Matrix dataHandleMatrix = dataBlock.inputValue(Ripple.mObj_Matrix) matrixValue = dataHandleMatrix.asMatrix() # Read the translation from Matrix mTransMatrix = OpenMaya.MTransformationMatrix(matrixValue) translationValue = mTransMatrix.getTranslation(OpenMaya.MSpace.kObject) mFloatVectorArray_normal = OpenMaya.MFloatVectorArray() mFnMesh = OpenMaya.MFnMesh(inMesh) mFnMesh.getVertexNormals(False, mFloatVectorArray_normal, OpenMaya.MSpace.kObject) mPointArray_meshVert = OpenMaya.MPointArray() while (not geoIterator.isDone()): pointPosition = geoIterator.position() weight = self.weightValue(dataBlock, geometryIndex, geoIterator.index()) pointPosition.x = pointPosition.x + math.sin( geoIterator.index() + displaceValue + translationValue[0] ) * amplitudeValue * mFloatVectorArray_normal[ geoIterator.index()].x * weight * envelopeValue pointPosition.y = pointPosition.y + math.sin( geoIterator.index() + displaceValue + translationValue[0] ) * amplitudeValue * mFloatVectorArray_normal[ geoIterator.index()].y * weight * envelopeValue pointPosition.z = pointPosition.z + math.sin( geoIterator.index() + displaceValue + translationValue[0] ) * amplitudeValue * mFloatVectorArray_normal[ geoIterator.index()].z * weight * envelopeValue mPointArray_meshVert.append(pointPosition) #geoIterator.setPosition(pointPosition) geoIterator.next() geoIterator.setAllPositions(mPointArray_meshVert)
def deform(self, pDataBlock, pGeometryIterator, pLocalToWorldMatrix, pGeometryIndex): envelopeAttribute = kEnvelope envelopeValue = pDataBlock.inputValue( envelopeAttribute ).asFloat() AmplitudeValue = pDataBlock.inputValue(RippleNode.mObjAmplitude).asFloat() DisplaceValue = pDataBlock.inputValue(RippleNode.mObjDisplace).asFloat() inputGeometryObject = self.getDeformerInputGeometry(pDataBlock, pGeometryIndex) mFloatVectorArrayNormal = OpenMaya.MFloatVectorArray() mFnMesh = OpenMaya.MFnMesh(inputGeometryObject) mFnMesh.getVertexNormals(False,mFloatVectorArrayNormal,OpenMaya.MSpace.kObject) while (not pGeometryIterator.isDone()): pointsPosition = pGeometryIterator.position() weight = self.weightValue(pDataBlock, pGeometryIndex, pGeometryIterator.index()) pointsPosition.x = pointsPosition.x + math.sin(pGeometryIterator.index()+DisplaceValue)*AmplitudeValue *mFloatVectorArrayNormal[pGeometryIterator.index()].x *envelopeValue *weight pointsPosition.Y = pointsPosition.y + math.sin(pGeometryIterator.index()+DisplaceValue)*AmplitudeValue *mFloatVectorArrayNormal[pGeometryIterator.index()].y *envelopeValue * weight pointsPosition.z = pointsPosition.z + math.sin(pGeometryIterator.index()+DisplaceValue)*AmplitudeValue *mFloatVectorArrayNormal[pGeometryIterator.index()].z *envelopeValue * weight pGeometryIterator.setPosition(pointsPosition) pGeometryIterator.next()
def getNormals(mesh, worldSpace=False): ''' Return all vertex normals for the specified mesh @param mesh: Mesh to get vertex normals for @type mesh: str @param worldSpace: Return the normals in world or object space @type worldSpace: bool ''' # Check mesh if not isMesh(mesh): raise Exception('Object ' + mesh + ' is not a polygon mesh!') # Get MFnMesh meshFn = getMeshFn(mesh) # Determine sample space if worldSpace: sampleSpace = OpenMaya.MSpace.kWorld else: sampleSpace = OpenMaya.MSpace.kObject # Get Normals normalArray = OpenMaya.MFloatVectorArray() meshFn.getVertexNormals(False, normalArray, sampleSpace) # Return result return normalArray
class model: fnMesh = om.MFnMesh() numVtx = 0 numPoly = 0 mPointArr = om.MPointArray() mCountArr = om.MIntArray() verticesInFaces = [] facesInVertices = [] normals = om.MFloatVectorArray() nearestDists = om.MDoubleArray() weights = om.MFloatArray() circleNames = [] checkLevels = om.MIntArray() continueIndex = om.MIntArray() def clear(cls): cls.fnMesh = om.MFnMesh() cls.numVtx = 0 cls.numPoly = 0 cls.mPointArr = om.MPointArray() cls.mCountArr = om.MIntArray() cls.verticesInFaces = [] cls.facesInVertices = [] cls.normals = om.MFloatVectorArray() cls.nearestDists = om.MDoubleArray() cls.weights = om.MFloatArray() cls.circleNames = [] cls.checkLevels = om.MIntArray() cls.continueIndex = om.MIntArray() clear = classmethod(clear)
def deform(self, dataBlock, geoIterator, matrix, geometryIndex): input = omp.cvar.MPxGeometryFilter_input dataHandleInputArray = dataBlock.inputArrayValue(input) dataHandleInputArray.jumpToElement(geometryIndex) dataHandleInputElement = dataHandleInputArray.inputValue() inputGeom = omp.cvar.MPxGeometryFilter_inputGeom dataHandleInputGeom = dataHandleInputElement.child(inputGeom) inMesh = dataHandleInputGeom.asMesh() envelope = omp.cvar.MPxGeometryFilter_envelope dataHandleEnvelope = dataBlock.inputValue(envelope) envelopeValue = dataHandleEnvelope.asFloat() dataHandleAmplitude = dataBlock.inputValue(rippleNode.mObj_Amplitude) amplitudeValue = dataHandleAmplitude.asFloat() dataHandleDisplace = dataBlock.inputValue(rippleNode.mObj_Displace) displaceValue = dataHandleDisplace.asFloat() mFloatVectorArray_normal = om.MFloatVectorArray() mFnMesh = om.MFnMesh(inMesh) mFnMesh.getVertexNormals(False, mFloatVectorArray_normal, om.MSpace.kObject) while(not geoIterator.isDone()): pointPosition = geoIterator.position() pointPosition.x = pointPosition.x + math.sin(geoIterator.index() + displaceValue) * amplitudeValue * mFloatVectorArray_normal[geoIterator.index()].x * envelopeValue pointPosition.y = pointPosition.y + math.sin(geoIterator.index() + displaceValue) * amplitudeValue * mFloatVectorArray_normal[geoIterator.index()].y * envelopeValue pointPosition.z = pointPosition.z + math.sin(geoIterator.index() + displaceValue) * amplitudeValue * mFloatVectorArray_normal[geoIterator.index()].z * envelopeValue geoIterator.setPosition(pointPosition) geoIterator.next()
def deform(self, pDataBlock, pGeometryIterator, pLocalToWorldMatrix, pGeometryIndex): ''' Deform each vertex using the geometry iterator. ''' # The envelope determines the overall weight of the deformer on the mesh. # The envelope is obtained via the OpenMayaMPx.cvar.MPxDeformerNode_envelope variable. # This variable and others like it are generated by SWIG to expose variables or constants declared in C++ header files. envelopeAttribute = OpenMayaMPx.cvar.MPxDeformerNode_envelope envelopeValue = pDataBlock.inputValue(envelopeAttribute).asFloat() # Get the value of the mesh inflation node attribute. meshInflationHandle = pDataBlock.inputValue( MyDeformerNode.meshInflationAttribute) meshInflation = meshInflationHandle.asDouble() # Get the value of the bounding box scale node attribute. boundingBoxScaleHandle = pDataBlock.inputValue( MyDeformerNode.boundingBoxScaleAttribute) boundingBoxScale = boundingBoxScaleHandle.asDouble() # Get the input mesh from the datablock using our getDeformerInputGeometry() helper function. inputGeometryObject = self.getDeformerInputGeometry( pDataBlock, pGeometryIndex) # Compute the bounding box using the input the mesh. boundingBox = self.getBoundingBox(inputGeometryObject, boundingBoxScale) # Obtain the list of normals for each vertex in the mesh. normals = OpenMaya.MFloatVectorArray() meshFn = OpenMaya.MFnMesh(inputGeometryObject) meshFn.getVertexNormals(True, normals, OpenMaya.MSpace.kTransform) # Iterate over the vertices to move them. global vertexIncrement while not pGeometryIterator.isDone(): # Obtain the vertex normal of the geometry. This normal is the vertex's averaged normal value if that # vertex is shared among several polygons. vertexIndex = pGeometryIterator.index() normal = OpenMaya.MVector( normals[vertexIndex] ) # Cast the MFloatVector into a simple vector. # Increment the point along the vertex normal. point = pGeometryIterator.position() newPoint = point + (normal * vertexIncrement * meshInflation * envelopeValue) # Clamp the new point within the bounding box. self.clampPointInBoundingBox(newPoint, boundingBox) # Set the position of the current vertex to the new point. pGeometryIterator.setPosition(newPoint) # Jump to the next vertex. pGeometryIterator.next()
def deform(self, dataBlock, geoIter, mtx, multiIndex): """This method performs the deformation algorithm. The geometry iterator passed to this method is in local space and not world space. To convert points to world space use the matrix that is suppied. * dataBlock [MDataBlock] is the node's datablock. * geoIter [MItGeometry] is an iterator for the current geometry being deformed. * mtx [MMatrix] is the geometry's world space transformation matrix. * multiIndex [int] is the index corresponding to the requested output geometry. """ # pylint: disable=unused-argument envelope = dataBlock.inputValue( ompx.cvar.MPxGeometryFilter_envelope).asFloat() amplitude = dataBlock.inputValue(TestDeformer.inAmplitude).asFloat() displace = dataBlock.inputValue(TestDeformer.inDisplace).asFloat() inputArrayHandle = dataBlock.outputArrayValue( ompx.cvar.MPxGeometryFilter_input) inputArrayHandle.jumpToElement(multiIndex) inputElement = inputArrayHandle.outputValue() inMesh = inputElement.child( ompx.cvar.MPxGeometryFilter_inputGeom).asMesh() outMeshArrayHandle = dataBlock.outputArrayValue( ompx.cvar.MPxGeometryFilter_outputGeom) outMesh = outMeshArrayHandle.inputValue().asMesh() mMatrix = dataBlock.inputValue(TestDeformer.inMatrix).asMatrix() vTrans = om1.MVector(mMatrix(3, 0), mMatrix(3, 1), mMatrix(3, 2)) meshFn = om1.MFnMesh(inMesh) normalsArray = om1.MFloatVectorArray() meshFn.getVertexNormals(False, normalsArray, om1.MSpace.kObject) posArray = om1.MPointArray() colorsArray = om1.MColorArray() vertexArray = om1.MIntArray() while not geoIter.isDone(): index = geoIter.index() vertexArray.append(index) pntPos = geoIter.position() weight = self.weightValue(dataBlock, multiIndex, index) colorsArray.append(om1.MColor(1, 0, 0, 1)) if weight != 0: pntPos.x = pntPos.x + math.sin( index + displace - vTrans[0] ) * amplitude * normalsArray[index].x * weight * envelope pntPos.y = pntPos.y + math.sin( index + displace - vTrans[0] ) * amplitude * normalsArray[index].y * weight * envelope pntPos.z = pntPos.z + math.sin( index + displace - vTrans[0] ) * amplitude * normalsArray[index].z * weight * envelope posArray.append(pntPos) geoIter.next() meshFn.setObject(outMesh) meshFn.setVertexColors(colorsArray, vertexArray) geoIter.setAllPositions(posArray)
def __init__(self): self.vertAry = OpenMaya.MFloatPointArray() self.normAry = OpenMaya.MFloatVectorArray() self.uAry = OpenMaya.MFloatArray() self.vAry = OpenMaya.MFloatArray() self.vertIndex = OpenMaya.MIntArray() self.normIndex = OpenMaya.MIntArray() self.uvIndex = OpenMaya.MIntArray() self.matIndex = 0
def deform(self, dataBlock, geoIterator, matrix, grometryIndex): """ Args: dataBlock: the node's datablock. MDataBlock geoIterator: an iterator for the current geometry being deformed. MItGeometry matrix: the geometry's world space transformation matrix. MMatrix grometryIndex: the index corresponding to the requested output geometry. Unsigned Int """ # print 'hi i am inputAttr %s:' % inputAttr # print 'hi i am inputGeom %s:' % inputGeom # print 'hi i am outputGeom %s:' % outputGeom # 1. attach a handle to input Array Attribute # EXPLANATION: MDataBlock: provides storage for the data being received by or sent by the node. dataHandleInputArray = dataBlock.outputArrayValue(inputAttr) # 2. Jump to particular element and get the desired output by geometryIndex dataHandleInputArray.jumpToElement(grometryIndex) # 3. attach a handle to specific data Block dataHandleInputElement = dataHandleInputArray.outputValue() # 4. reach the child - inputGeom dataHandleInputGeom = dataHandleInputElement.child(inputGeom) inMesh = dataHandleInputGeom.asMesh() # Envelope dataHandleEnvelope = dataBlock.inputValue(envelope) # get envelope Value inserted by the user envelopeValue = dataHandleEnvelope.asFloat() # Amplitude, editable value dataHandleAmplitude = dataBlock.inputValue(self.mObj_Amplitude) amplitudeValue = dataHandleAmplitude.asFloat() # Displace, editable value dataHandleDisplace = dataBlock.inputValue(self.mObj_Displace) displaceValue = dataHandleDisplace.asFloat() mFloatVectorArray_normal = OpenMaya.MFloatVectorArray() mFnMesh = OpenMaya.MFnMesh(inMesh) mFnMesh.getVertexNormals(False, mFloatVectorArray_normal, OpenMaya.MSpace.kObject) mPointArray_meshVert = OpenMaya.MPointArray() while not geoIterator.isDone(): pointPosition = geoIterator.position() pointPosition.x = pointPosition.x + math.sin(geoIterator.index() + displaceValue) * amplitudeValue * mFloatVectorArray_normal[geoIterator.index()].x * envelopeValue pointPosition.y = pointPosition.y + math.sin(geoIterator.index() + displaceValue) * amplitudeValue * mFloatVectorArray_normal[geoIterator.index()].y * envelopeValue pointPosition.z = pointPosition.z + math.sin(geoIterator.index() + displaceValue) * amplitudeValue * mFloatVectorArray_normal[geoIterator.index()].z * envelopeValue mPointArray_meshVert.append(pointPosition) geoIterator.next() geoIterator.setAllPositions(mPointArray_meshVert)
def sampleShadingNetworkAtPoints(nodeAttr, points): numSamples = len(points) pointArray = points pointArray = OpenMaya.MFloatPointArray() pointArray.setLength(numSamples) refPoints = OpenMaya.MFloatPointArray() refPoints.setLength(numSamples) for i, point in enumerate(points): location = OpenMaya.MFloatPoint(point[0], point[1], point[2]) pointArray.set(location, i) refPoints.set(location, i) # but we don't need these useShadowMap = False reuseMaps = False cameraMatrix = OpenMaya.MFloatMatrix() uCoords = None vCoords = None normals = None tangentUs = None tangentVs = None filterSizes = None # and the return arguments are empty.... resultColors = OpenMaya.MFloatVectorArray() resultTransparencies = OpenMaya.MFloatVectorArray() # sample the node network OpenMayaRender.MRenderUtil.sampleShadingNetwork( nodeAttr, numSamples, useShadowMap, reuseMaps, cameraMatrix, pointArray, uCoords, vCoords, normals, refPoints, tangentUs, tangentVs, filterSizes, resultColors, resultTransparencies) # return formatted sampled colours return resultColors
def deform(self, data, geoIterator, matrix, geometryIndex): # get push value # data is a class? pushHandle = data.inputValue(self.push) push = pushHandle.asFloat() # get envelope value envelopeHandle = data.inputValue(envelopeAttr) envelope = envelopeHandle.asFloat() # get the input geometry mesh = self.getInputMesh(data, geometryIndex) # crete an empty array (list) of floats vectors to store our normals normals = om.MFloatVectorArray() # the make de meshFn to interact with the mesh meshFn = om.MFnMesh(mesh) # use this to get and store the normals froms the mesh onto the normals array 'normals' # remember pay attention to the pluralization of the normals meshFn.getVertexNormals( # if True, the normals are angleWeighted which is what we want True, # we tell were store normals, in this case normals above normals, # finally tell the space, in this case object space om.MSpace.kTransform) # now we can iterate throught the geometry vertices and do our deformation while not geoIterator.isDone(): # geo iterator is ... # current point index index = geoIterator.index() # look normal from our array normal = om.MVector(normals[index]) # index may be int # get the positions of the point position = geoIterator.position() # calculate the offset # multiply vector by magnitude offset = (normal * push * envelope) # push is the input value // # we then query the painted weitght for this area weight = self.weightValue(data, geometryIndex, index) # from MPxDeformerNode class offset = (offset * weight) # Finally we can set the position geoIterator.setPosition(position + offset) # go to the next item geoIterator.next()
def deform(self, data_block, geo_iter, world_matrix, multi_index): envelope = data_block.inputValue(self.envelope).asFloat() if envelope == 0: return max_distance = data_block.inputValue( AttractorDeformerNode.max_distance).asFloat() if max_distance == 0: return target_position = data_block.inputValue( AttractorDeformerNode.target_position).asFloatVector() target_position = om.MPoint(target_position) * world_matrix.inverse() target_position = om.MFloatVector(target_position) input_handle = data_block.outputArrayValue(self.input) input_handle.jumpToElement(multi_index) input_element_handle = input_handle.outputValue() input_geom = input_element_handle.child(self.inputGeom).asMesh() mesh_fn = om.MFnMesh(input_geom) normals = om.MFloatVectorArray() mesh_fn.getVertexNormals(False, normals) geo_iter.reset() while not geo_iter.isDone(): pt_local = geo_iter.position() target_vector = target_position - om.MFloatVector(pt_local) distance = target_vector.length() if distance <= max_distance: normal = normals[geo_iter.index()] angle = normal.angle(target_vector) if angle <= AttractorDeformerNode.MAX_ANGLE: offset = target_vector * ( (max_distance - distance) / max_distance) geo_iter.setPosition(pt_local + om.MVector(offset)) geo_iter.next()
def deform(self, data, geoIterator, matrix, geometryIndex): # Get the push value pushHandle = data.inputValue(self.push) push = pushHandle.asFloat() # get the envelope value envelopeHandle = data.inputValue(envelopeAttr) envelope = envelopeHandle.asFloat() # Get the input geometry mesh = self.getInputMesh(data, geometryIndex) # Create an empty array(list) of Float Vectors to store our normals in normals = om.MFloatVectorArray() # Then make the meshFn to interact with the mesh meshFn = om.MFnMesh(mesh) # And we use this to get and store the normals from the mesh onto the normals array we created above # Remember to pay attention to the pluralization of normals meshFn.getVertexNormals( True, # If True, the normals are angleWeighted which is what we want normals, # We tell it what to store the data in, in this case our array above, om.MSpace. kTransform # Finally we tell it what space we want the normals in, in this case the local object space ) # Now we can iterate through the geometry vertices and do our deformation while not geoIterator.isDone(): # Get the index of our current point index = geoIterator.index() # Look up the normals for this point from our array normal = om.MVector(normals[index]) # Get the position of the point position = geoIterator.position() # Then calculate the offset # we do this by multiplying the magnitude of the normal vector by the intensity of the push and envelope offset = (normal * push * envelope) # We then query the painted weight for this area weight = self.weightValue(data, geometryIndex, index) offset = (offset * weight) # Finally we can set the position geoIterator.setPosition(position + offset) # And always remember to go on to the next item in the list geoIterator.next()
def deform(self, data, geom_it, local_to_world_mat, geom_idx): envelope_attr = OpenMayaMPx.cvar.MPxDeformerNode_envelope envelope = data.inputValue(envelope_attr).asFloat() inflation_handle = data.inputValue(PushDeformerNode.inflation_attr) inflation = inflation_handle.asDouble() input_geom_obj = self.get_input_geom(data, geom_idx) normals = OpenMaya.MFloatVectorArray() mesh = OpenMaya.MFnMesh(input_geom_obj) mesh.getVertexNormals(True, normals, OpenMaya.MSpace.kTransform) while not geom_it.isDone(): idx = geom_it.index() nrm = OpenMaya.MVector(normals[idx]) pos = geom_it.position() new_pos = pos + (nrm * inflation * envelope) geom_it.setPosition(new_pos) geom_it.next()
def __init__(self): super(polyModifierCmd, self).__init__() # polymesh self._fDagPathInitialized = False self._fDagPath = om.MDagPath() self._fDuplicateDagPath = om.MDagPath() # modifier node type self._fModifierNodeTypeInitialized = False self._fModifierNodeNameInitialized = False self._fModifierNodeType = om.MTypeId() self._fModifierNodeName = "" # node state self._fHasHistory = False self._fHasTweaks = False self._fHasRecordHistory = False # cached tweak data self._fTweakIndexArray = om.MIntArray() self._fTweakVectorArray = om.MFloatVectorArray() # cached mesh data self._fMeshData = om.MObject() # dg and dag modifier self._fDGModifier = om.MDGModifier() self._fDagModifier = om.MDagModifier() # manual shape management self._manual_redo_queue = [] numDataFn = om.MFnNumericData() numDataFn.create(om.MFnNumericData.k3Float) numDataFn.setData3Float(0.0, 0.0, 0.0) self.__class__.NULL_VECTOR = numDataFn.object()
def getTangent(self, faceID, targetFnMesh): """ Return a tangent vector of a face. Args: faceID (int) mVector (OpenMaya.MVector) Returns: OpenMaya.MVector : tangent vector """ tangentArray = OpenMaya.MFloatVectorArray() targetFnMesh.getFaceVertexTangents(faceID, tangentArray, self.SPACE) numOfVtx = tangentArray.length() x = sum([tangentArray[i].x for i in range(numOfVtx)]) / numOfVtx y = sum([tangentArray[i].y for i in range(numOfVtx)]) / numOfVtx z = sum([tangentArray[i].z for i in range(numOfVtx)]) / numOfVtx tangentVector = OpenMaya.MVector() tangentVector.x = x tangentVector.y = y tangentVector.z = z tangentVector.normalize() return tangentVector
def __init__(self): super(polyModifierCmd, self).__init__() # polymesh self._fDagPathInitialized = False self._fDagPath = om.MDagPath() self._fDuplicateDagPath = om.MDagPath() # modifier node type self._fModifierNodeTypeInitialized = False self._fModifierNodeNameInitialized = False self._fModifierNodeType = om.MTypeId() self._fModifierNodeName = "" # node state self._fHasHistory = False self._fHasTweaks = False self._fHasRecordHistory = False # cached tweak data self._fTweakIndexArray = om.MIntArray() self._fTweakVectorArray = om.MFloatVectorArray() # cached mesh data self._fMeshData = om.MObject() # dg and dag modifier self._fDGModifier = om.MDGModifier() self._fDagModifier = om.MDagModifier() # manual shape management self._manual_redo_queue = []
def averageNormal( *args ): for dagPath, vtxList in selectedVertices(): fnMesh = OpenMaya.MFnMesh( dagPath ) points = OpenMaya.MPointArray() normals = OpenMaya.MFloatVectorArray() fnMesh.getPoints( points ) fnMesh.getVertexNormals( True, normals ) itMeshVtx = OpenMaya.MItMeshVertex( dagPath ) resultPoints = [] for i in range( vtxList.length() ): pPrevIndex = getIntPtr() itMeshVtx.setIndex( vtxList[i], pPrevIndex ) conVertices = OpenMaya.MIntArray(); itMeshVtx.getConnectedVertices(conVertices) bb = OpenMaya.MBoundingBox() for j in range( conVertices.length() ): bb.expand( points[conVertices[j]] ) center = bb.center() centerVector = points[ vtxList[i] ] - center normal = normals[ vtxList[i] ] normal.normalize() projVector = normal * ( normal * OpenMaya.MFloatVector(centerVector) ) resultPoint = -OpenMaya.MVector(projVector)/3.0 + OpenMaya.MVector( points[ vtxList[i] ] ) resultPoints.append( resultPoint ) meshName = fnMesh.partialPathName() for i in range( vtxList.length() ): cmds.move( resultPoints[i].x, resultPoints[i].y, resultPoints[i].z, meshName + ".vtx[%d]" % vtxList[i], os=1 )
def getGeometry(self, iSet): # get all object verts meshPoints = OpenMaya.MPointArray() self.fShape.getPoints(meshPoints) # get all object normals meshNormals = OpenMaya.MFloatVectorArray() self.fShape.getNormals(meshNormals) # get all object UVs, if any if self.hasUVs: try: meshUArray = OpenMaya.MFloatArray() meshVArray = OpenMaya.MFloatArray() self.fShape.getUVs(meshUArray, meshVArray, self.UVSets[self.currentUVSet]) except: OpenMaya.MGlobal.displayError( "Error with UV mapping on object: %s" % self.fShape.name()) raise # set up some scripting junk numTrianglesPx = OpenMaya.MScriptUtil() numTrianglesPx.createFromInt(0) numTrianglesPtr = numTrianglesPx.asIntPtr() uvIdxPx = OpenMaya.MScriptUtil() uvIdxPx.createFromInt(0) uvIdxPtr = uvIdxPx.asIntPtr() # set up mesh face iterator itMeshPolys = OpenMaya.MItMeshPolygon(self.dagPath, self.fPolygonComponents[iSet]) if not itMeshPolys.hasValidTriangulation(): OpenMaya.MGlobal.displayWarning( "Shape %s has invalid triangulation, skipping" % self.fShape.name()) return # storage for obj-relative vert indices in a face polygonVertices = OpenMaya.MIntArray() # storage for the face vert points vertPoints = OpenMaya.MPointArray() # storage for the face vert indices vertIndices = OpenMaya.MIntArray() # set syntax for trianglemesh/loopsubdiv or portalshape if self.type == 'geom': # detect Material or AreaLight materialNode = self.findSurfaceShader(self.instanceNum, iSet) if materialNode.typeName() == "pbrtAreaLightMaterial": self.addToOutput(self.getAreaLight(materialNode)) else: self.addToOutput(self.getNamedMaterial(materialNode)) #self.shadingGroup = self.findShadingGroup(self.instanceNum, iSet) #self.addToOutput( self.findSurfaceShader( shadingGroup = self.shadingGroup ) ) # detect trianglemesh/loopsubdiv subPlug1 = self.fShape.findPlug('useMaxSubdivisions') useLoopSubdiv = subPlug1.asBool() if useLoopSubdiv: self.mode = 'loopsubdiv' subPlug2 = self.fShape.findPlug('maxSubd') nlevels = subPlug2.asInt() self.addToOutput('\tShape "loopsubdiv"') self.addToOutput('\t\t"integer nlevels" [%i]' % nlevels) # find displacement, if any #self.addToOutput( self.findDisplacementShader( self.shadingGroup ) ) else: self.mode = 'trianglemesh' self.addToOutput('\tShape "trianglemesh"') def compileWithUVs(): totalVertIndices = 0 # each face while not itMeshPolys.isDone(): # get number of triangles in face itMeshPolys.numTriangles(numTrianglesPtr) numTriangles = OpenMaya.MScriptUtil(numTrianglesPtr).asInt() itMeshPolys.getVertices(polygonVertices) # each triangle in each face for currentTriangle in range(0, numTriangles): # get the triangle points and indices itMeshPolys.getTriangle(currentTriangle, vertPoints, vertIndices, OpenMaya.MSpace.kObject) # get a list of local indices localIndex = self.GetLocalIndex(polygonVertices, vertIndices) # each vert in this triangle for i, vertIndex in enumerate(vertIndices): # get indices to points/normals/uvs vertNormalIndex = itMeshPolys.normalIndex( localIndex[i]) try: itMeshPolys.getUVIndex( localIndex[i], uvIdxPtr, self.UVSets[self.currentUVSet]) vertUVIndex = OpenMaya.MScriptUtil( uvIdxPtr).asInt() except: OpenMaya.MGlobal.displayWarning( 'Invalid UV data on object %s (UV set "%s"), restarting object export without UVs' % (self.dagPath.fullPathName(), self.UVSets[self.currentUVSet])) self.resetLists() itMeshPolys.reset() compileWithoutUVs() self.hasUVs = False return # if we've seen this combo before, testVal = (vertIndex, vertNormalIndex, vertUVIndex) #try: if testVal in self.vertNormUVList: self.vertIndexList.append( self.vertNormUVList[testVal]) #except KeyError: else: # add it to the lists self.vertPointList.append(meshPoints[vertIndex]) self.vertNormList.append( meshNormals[vertNormalIndex]) self.vertUVList.append((meshUArray[vertUVIndex], meshVArray[vertUVIndex])) # and keep track of what we've seen self.vertNormUVList[testVal] = totalVertIndices # and use the most recent idx value self.vertIndexList.append(totalVertIndices) totalVertIndices += 1 itMeshPolys.next() def compileWithoutUVs(): totalVertIndices = 0 # each face while not itMeshPolys.isDone(): # get number of triangles in face itMeshPolys.numTriangles(numTrianglesPtr) numTriangles = OpenMaya.MScriptUtil(numTrianglesPtr).asInt() itMeshPolys.getVertices(polygonVertices) # each triangle in each face for currentTriangle in range(0, numTriangles): # get the triangle points and indices itMeshPolys.getTriangle(currentTriangle, vertPoints, vertIndices, OpenMaya.MSpace.kObject) # get a list of local indices localIndex = self.GetLocalIndex(polygonVertices, vertIndices) # each vert in this triangle for i, vertIndex in enumerate(vertIndices): # get indices to points/normals/uvs vertNormalIndex = itMeshPolys.normalIndex( localIndex[i]) # if we've seen this combo yet, testVal = (vertIndex, vertNormalIndex) #try: if testVal in self.vertNormUVList: self.vertIndexList.append( self.vertNormUVList[testVal]) #except KeyError: else: # add it to the lists self.vertPointList.append(meshPoints[vertIndex]) self.vertNormList.append( meshNormals[vertNormalIndex]) # and keep track of what we've seen self.vertNormUVList[testVal] = totalVertIndices # and use the most recent idx value self.vertIndexList.append(totalVertIndices) totalVertIndices += 1 itMeshPolys.next() startTime = time.clock() if itMeshPolys.hasUVs(): compileWithUVs() else: compileWithoutUVs() procTime = time.clock() procDuration = procTime - startTime # mesh iteration done, do output. self.addToOutput('\t"integer indices" [') self.addToOutput('\t\t' + ' '.join(map(str, self.vertIndexList))) self.addToOutput('\t]') self.fileHandle.flush() self.addToOutput('\t"point P" [') for vP in self.vertPointList: self.addToOutput('\t\t%f %f %f' % (vP.x, vP.y, vP.z)) self.addToOutput('\t]') self.fileHandle.flush() # add UVs for trianglemesh and loopsubdiv, but not for portals and only if the shape has uvs if self.type == 'geom' and itMeshPolys.hasUVs() and len( self.vertUVList) > 0: self.addToOutput('\t"float uv" [') for uv in self.vertUVList: self.addToOutput('\t\t%f %f' % uv) self.addToOutput('\t]') self.fileHandle.flush() # Add normals to trianglemesh if self.mode == 'trianglemesh': self.addToOutput('\t"normal N" [') for vN in self.vertNormList: self.addToOutput('\t\t%f %f %f' % (vN.x, vN.y, vN.z)) self.addToOutput('\t]') outTime = time.clock() writeDuration = outTime - procTime if self.doBenchmark: vLen = len(self.vertNormUVList) pSpeed = vLen / procDuration wSpeed = vLen / writeDuration print "%i verts processed in %f seconds: %f verts/sec" % ( vLen, procDuration, pSpeed) print " -> written in %f seconds: %f verts/sec" % (writeDuration, wSpeed) sf = open("e:\meshopt_stats.csv", "a") sf.write(('%i,%f,%f' % (vLen, pSpeed, wSpeed)) + os.linesep) sf.close()
def exportPly(self, mObject, mFnDagNode, dagPath, exportOptions): verbose = False triangulate = False if exportOptions: if 'verbose' in exportOptions and exportOptions[ 'verbose'] == 'true': verbose = True if 'triangulate' in exportOptions and exportOptions[ 'triangulate'] == 'true': triangulate = True dagNode = OpenMaya.MDagPath() mFnDagNode.getPath(dagNode) dagNode.extendToShape() meshNode = OpenMaya.MFnMesh(dagNode) dagPath = dagNode.fullPathName() if verbose: print("exportPly : %s" % dagPath) # Space to evaluate normals, point positions space = OpenMaya.MSpace.kWorld if exportOptions: if 'space' in exportOptions and exportOptions['space'] == 'object': if verbose: print("\tSpace : %s" % "object space") space = OpenMaya.MSpace.kObject else: if verbose: print("\tSpace : %s" % "world space") ''' polygonSets = OpenMaya.MObjectArray() polygonComponents = OpenMaya.MObjectArray() isInstanced = dagNode.isInstanced() print( "\tInstanced : %s" % isInstanced ) if dagNode.isInstanced(): instanceNum = dagNode.instanceNumber() print( "\tInstance Number : %s" % instanceNum ) meshNode.getConnectedSetsAndMembers(instanceNum, polygonSets, polygonComponents, True) print( "\tPolygon Sets : %s" % polygonSets.length() ) print( "\tPolygon Components : %s" % polygonComponents.length() ) ''' # Get Vertices numVertices = meshNode.numVertices() if verbose: print("\tVerts : %d" % numVertices) points = OpenMaya.MPointArray() meshNode.getPoints(points, space) numPoints = points.length() if verbose: print("\tPoints : %d" % numPoints) # Get UVs us = OpenMaya.MFloatArray() vs = OpenMaya.MFloatArray() meshNode.getUVs(us, vs) numUVs = us.length() if verbose: print("\tUVs : %d" % numUVs) # Get Normals normals = OpenMaya.MFloatVectorArray() meshNode.getNormals(normals, space) numNormals = normals.length() if verbose: print("\tNorms : %d" % numNormals) # Faces numFaces = meshNode.numPolygons() if verbose: print("\tFaces : %d" % numFaces) # Vertex Colors numColors = meshNode.numColors() vertexColors = None faceVertexColors = None if numColors > 0: vertexColors = OpenMaya.MColorArray() meshNode.getVertexColors(vertexColors) numVertexColors = vertexColors.length() if verbose: print("\tVertex Colors : %d" % numVertexColors) #for i in range(numVertexColors): # print( "Color %d : %3.3f, %3.3f, %3.3f" % ( # i, vertexColors[i].r, vertexColors[i].g, vertexColors[i].b)) faceVertexColors = OpenMaya.MColorArray() meshNode.getFaceVertexColors(faceVertexColors) numFaceVertexColors = faceVertexColors.length() if verbose: print("\tFace Vert Colors : %d" % numFaceVertexColors) #for i in range(numFaceVertexColors): # print( "Color %d : %3.3f, %3.3f, %3.3f" % ( # i, faceVertexColors[i].r, faceVertexColors[i].g, faceVertexColors[i].b)) # Per-Face data itMeshPoly = OpenMaya.MItMeshPolygon(mObject) # Check for triangulation hasValidTriangulation = itMeshPoly.hasValidTriangulation() if verbose: print("\tHas Triangulation : %s" % hasValidTriangulation) if hasValidTriangulation: triangleCount = OpenMaya.MIntArray() triangleIndices = OpenMaya.MIntArray() meshNode.getTriangles(triangleCount, triangleIndices) else: if triangulate: OpenMaya.MGlobal.displayWarning( "Shape %s has invalid triangulation, skipping" % dagPath) return None if verbose: t0 = timeit.default_timer() if triangulate and hasValidTriangulation: plyData = self.exportTriangulatedMesh(mObject, dagPath, meshNode, points, us, vs, normals, faceVertexColors, triangleCount, triangleIndices, exportOptions, verbose) else: plyData = self.exportMesh(mObject, dagPath, meshNode, points, us, vs, normals, faceVertexColors, exportOptions, verbose) if verbose: t1 = timeit.default_timer() elapsed = (t1 - t0) print("export elapsed : %s" % elapsed) return plyData
def deform(self, dataBlock, geoIterator, matrix, geometryIndex): # 0. Grab the input Attribute come with the deformer node # input = openmayampx.cvar.MPxDeformerNode_input input = openmayampx.cvar.MPxGeometryFilter_input # 1. Attach a handle to input Array Attribute # Whenever using MDatablock.inputValue, it will check the Dependency Node plugs are clean or dirty. # If the plugs are dirty, it will starting evaluating the whole linked Dependency Graph. # The complete Dependency Graph will be evaluated, it will return the clean values. # Then it will start compute() i.e deform() method. # To prevent the re-computation of the mesh, we need to replace the inputArrayValue with outputArrayValue. dataHandleInputArray = dataBlock.outputArrayValue(input) # 2. Jump to particular element in array dataHandleInputArray.jumpToElement(geometryIndex) # 3. Attach a handle to specific data block # To prevent the re-computation of the mesh, we need to replace the inputValue with outputValue. dataHandleInputElement = dataHandleInputArray.outputValue() # 4. Reach to the child - inputGeom # inputGeom = openmayampx.cvar.MPxDeformerNode_inputGeom inputGeom = openmayampx.cvar.MPxGeometryFilter_inputGeom dataHandleInputGeom = dataHandleInputElement.child(inputGeom) inMesh = dataHandleInputGeom.asMesh() # Envelope # envelope = openmayampx.cvar.MPxDeformerNode_envelope envelope = openmayampx.cvar.MPxGeometryFilter_envelope dataHandleEnvolope = dataBlock.inputValue(envelope) envelopeValue = dataHandleEnvolope.asFloat() # Amplitude dataHandleAmplitude = dataBlock.inputValue(Ripple.mObj_Amplitude) amplitudeValue = dataHandleAmplitude.asFloat() # Displace dataHandleDisplace = dataBlock.inputValue(Ripple.mObj_Displace) disPlaceValue = dataHandleDisplace.asFloat() mFloatVectorArray_normal = openmaya.MFloatVectorArray() mFnMesh = openmaya.MFnMesh(inMesh) mFnMesh.getVertexNormals(False, mFloatVectorArray_normal, openmaya.MSpace.kObject) # store the vertex positions of the mesh. mPointArray_meshVert = openmaya.MPointArray() while (not geoIterator.isDone()): pointPosition = geoIterator.position() pointPosition.x = pointPosition.x + math.sin(geoIterator.index( ) + disPlaceValue) * amplitudeValue * mFloatVectorArray_normal[ geoIterator.index()].x * envelopeValue pointPosition.y = pointPosition.y + math.sin(geoIterator.index( ) + disPlaceValue) * amplitudeValue * mFloatVectorArray_normal[ geoIterator.index()].y * envelopeValue pointPosition.z = pointPosition.z + math.sin(geoIterator.index( ) + disPlaceValue) * amplitudeValue * mFloatVectorArray_normal[ geoIterator.index()].z * envelopeValue #geoIterator.setPosition(pointPosition) mPointArray_meshVert.append(pointPosition) geoIterator.next() # Set all the Position at once. geoIterator.setAllPositions(mPointArray_meshVert)
# Only click on load to load plugin. Click again to unload. You'll need to # load and unload the plugin to see code changes # put this file in C:\Program Files\Autodesk\Maya<year>\bin\plug-ins import sys import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx import maya.OpenMayaRender as OpenMayaRender import fileExportHeader as header import array import maya.cmds as cmds # Unique Lists uniqueVertAry = OpenMaya.MFloatPointArray() uniqueNormAry = OpenMaya.MFloatVectorArray() uniqueUAry = OpenMaya.MFloatArray() uniqueVAry = OpenMaya.MFloatArray() uniqueMaterialPathAry = list() faceGrpList = list() #cmds.confirmDialog( title='Confirm', message='Are you sure?', button=['Yes','No'], defaultButton='Yes', cancelButton='No', dismissString='No' ) kPluginCmdName = "myExport" class CFaceGrp: # define as self so that these arrays are unique instances def __init__(self): self.vertAry = OpenMaya.MFloatPointArray() self.normAry = OpenMaya.MFloatVectorArray() self.uAry = OpenMaya.MFloatArray()
def compute(self, plug, data): if plug == self.outColor or plug.parent() == self.outColor: thisNode = self.thisMObject() fnThisNode = om.MFnDependencyNode(thisNode) uData = data.inputValue(self.inUCoord) uValue = uData.asFloat() uArray = om.MFloatArray(1) uArray.set(uValue, 0) timeData = data.inputValue(self.time) timeValue = timeData.asFloat() vData = data.inputValue(self.inVCoord) vValue = vData.asFloat() vArray = om.MFloatArray(1) vArray.set(vValue, 0) shadowsData = data.inputValue(self.useShadowMaps) shadowsValue = shadowsData.asBool() reShadowsData = data.inputValue(self.reUseShadowMaps) reShadowsValue = reShadowsData.asBool() filterSizeData = data.inputValue(self.filterSize) filterSizeValue = filterSizeData.asFloat() filterSizeArray = om.MFloatArray(1) filterSizeArray.set(filterSizeValue, 0) inPointData = data.inputValue(self.inPoint) inPointValue = inPointData.asFloatVector() inPointArray = om.MFloatPointArray(1) inPointArray.set(0, inPointValue.x, inPointValue.y, inPointValue.z, 1) useRefPointData = data.inputValue(self.useRefPoint) useRefPointValue = useRefPointData.asBool() refPointArray = om.MFloatPointArray(1) if useRefPointValue: refPointData = data.inputValue(self.refPoint) refPointValue = refPointData.asFloatVector() refPointArray.set(0, refPointValue.x, refPointValue.y, refPointValue.z, 1) else: refPointArray.set(0, inPointValue.x, inPointValue.y, inPointValue.z, 1) normalData = data.inputValue(self.normal) normalValue = normalData.asFloatVector() normalArray = om.MFloatVectorArray(1) normalArray.set(normalValue, 0) tangentUData = data.inputValue(self.tangentU) tangentUValue = tangentUData.asFloatVector() tangentUArray = om.MFloatVectorArray(1) tangentUArray.set(tangentUValue, 0) tangentVData = data.inputValue(self.tangentV) tangentVValue = tangentVData.asFloatVector() tangentVArray = om.MFloatVectorArray(1) tangentVArray.set(tangentVValue, 0) useSGData = data.inputValue(self.useSG) useSGValue = useSGData.asBool() plugArray = om.MPlugArray() inColorPlugName = "" inSGPlugName = "" sampleSource = "" isSGNode = False sgPlug = om.MPlug(thisNode, self.inSG) hasConnections = sgPlug.connectedTo(plugArray, 1, 0) if hasConnections: inSGPlugName = plugArray[0].name() inSGPlugNameSplit = inSGPlugName.split(".") sourceNode = om.MObject() sourceNode = plugArray[0].node() isSGNode = sourceNode.hasFn(om.MFn.kShadingEngine) inSGPlugName = inSGPlugNameSplit[0] else: inSGPlugName = "" colorPlug = om.MPlug(thisNode, self.inColor) hasConnections = colorPlug.connectedTo(plugArray, 1, 0) if hasConnections: inColorData = data.inputValue(self.inColor) inColorPlugName = plugArray[0].name() if useSGValue: if isSGNode: sampleSource = inSGPlugName elif inSGPlugName == "": print( "\"inSG\" has no connections. Please connect the \"message\" attribute of a shadingGroup to \"inSG\"" ) #return om.MStatus.kUnknownParameter else: print( inSGPlugName + " is not a shading group. Only the \"message\" attribute of a shadingGroup should be connected to \"inSG\"" ) #return om.MStatus.kUnknownParameter else: if not inColorPlugName == "": sampleSource = inColorPlugName else: print("\"inColor\" has no connections") #return om.MStatus.kUnknownParameter cameraMatData = data.inputValue(self.eyeToWorld) cameraMat = om.MFloatMatrix() cameraMat = cameraMatData.asFloatMatrix() resColors = om.MFloatVectorArray(1) resTransparencies = om.MFloatVectorArray(1) renderUtil = omRender.MRenderUtil renderUtil.sampleShadingNetwork( sampleSource, 1, shadowsValue, reShadowsValue, cameraMat, inPointArray, uArray, vArray, normalArray, refPointArray, tangentUArray, tangentVArray, filterSizeArray, resColors, resTransparencies) outColorRAttr = fnThisNode.attribute("outColorR") outColorRPlug = om.MPlug(thisNode, outColorRAttr) outColorRHandle = data.outputValue(outColorRPlug) outColorRHandle.setFloat(resColors[0].x) outColorRHandle.setClean() outColorGAttr = fnThisNode.attribute("outColorG") outColorGPlug = om.MPlug(thisNode, outColorGAttr) outColorGHandle = data.outputValue(outColorGPlug) outColorGHandle.setFloat(resColors[0].y) outColorGHandle.setClean() outColorBAttr = fnThisNode.attribute("outColorB") outColorBPlug = om.MPlug(thisNode, outColorBAttr) outColorBHandle = data.outputValue(outColorBPlug) outColorBHandle.setFloat(resColors[0].z) outColorBHandle.setClean() data.setClean(plug) #return om.MStatus.kSuccess else: print("something Failed")
def doIt(self, args): """ Print string to the console. """ try: argData = om.MArgDatabase( self.syntax(), args) # if this fails, it will raise its own exception... except: print "failed..." pass # ...so we can just pass here else: print "converting..." # get the active selection selection = om.MSelectionList() om.MGlobal.getActiveSelectionList(selection) iterSel = om.MItSelectionList(selection, om.MFn.kMesh) if argData.isFlagSet(MP_WriteMeshCmd.kVoxelSizeFlag): self.__voxelSize = argData.flagArgumentDouble( MP_WriteMeshCmd.kVoxelSizeFlag, 0) if argData.isFlagSet(MP_WriteMeshCmd.kFileNameFlag): self.__fileName = argData.flagArgumentString( MP_WriteMeshCmd.kFileNameFlag, 0) # go through selection while not iterSel.isDone(): # get dagPath dagPath = om.MDagPath() iterSel.getDagPath(dagPath) # create empty point array inMeshMPointArray = om.MPointArray() # create empy normal array inMeshMNormalArray = om.MFloatVectorArray() # create function set and get points and normals in world space currentInMeshMFnMesh = om.MFnMesh(dagPath) currentInMeshMFnMesh.getPoints(inMeshMPointArray, om.MSpace.kWorld) currentInMeshMFnMesh.getNormals(inMeshMNormalArray, om.MSpace.kWorld) #get the number of faces for the selection numFaces = currentInMeshMFnMesh.numPolygons() normalList = [] faceList = [] #get normals for i in range(0, numFaces): normal = om.MVector() currentInMeshMFnMesh.getPolygonNormal( i, normal, om.MFn.kMesh) normal = normal.normal() normalList.append( [str(normal[0]), str(normal[1]), str(normal[2])]) #get faces for i in range(0, numFaces): vertexL = om.MIntArray() currentInMeshMFnMesh.getPolygonVertices(i, vertexL) vertices = [] for n in range(vertexL.length()): vertices.append(str(vertexL[n] + 1)) faceList.append(vertices) # put each point to a list pointList = [] for i in range(inMeshMPointArray.length()): pointList.append([ str(inMeshMPointArray[i][0]), str(inMeshMPointArray[i][1]), str(inMeshMPointArray[i][2]) ]) # return the vertices, normals and faces omesh_cube = vdbout.VDBOutputMesh() meshspec = mepo.MeshSpec() meshspec.voxelSize = self.__voxelSize omesh_cube.loadMesh(mepo.getPythonList(pointList), mepo.getPythonList(normalList), mepo.getPythonList(faceList), meshspec) omesh_cube.writeMesh(str(self.__fileName)) print("Wrote mesh %s" % self.__fileName) return [pointList, normalList, faceList]
def _getMeshData(self): maya.cmds.select(self.maya_node) selList = OpenMaya.MSelectionList() OpenMaya.MGlobal.getActiveSelectionList(selList) meshPath = OpenMaya.MDagPath() selList.getDagPath(0, meshPath) meshIt = OpenMaya.MItMeshPolygon(meshPath) meshFn = OpenMaya.MFnMesh(meshPath) dagFn = OpenMaya.MFnDagNode(meshPath) boundingBox = dagFn.boundingBox() do_color = False if meshFn.numColorSets(): do_color = True indices = [] positions = [None] * meshFn.numVertices() normals = [None] * meshFn.numVertices() colors = [None] * meshFn.numVertices() uvs = [None] * meshFn.numVertices() ids = OpenMaya.MIntArray() points = OpenMaya.MPointArray() if do_color: vertexColorList = OpenMaya.MColorArray() meshFn.getFaceVertexColors(vertexColorList) normal = OpenMaya.MVector() face_verts = OpenMaya.MIntArray() polyNormals = OpenMaya.MFloatVectorArray() meshFn.getNormals(polyNormals) uv_util = OpenMaya.MScriptUtil() uv_util.createFromList([0, 0], 2) uv_ptr = uv_util.asFloat2Ptr() while not meshIt.isDone(): meshIt.getTriangles(points, ids) meshIt.getVertices(face_verts) face_vertices = list(face_verts) for point, vertex_index in zip(points, ids): indices.append(vertex_index) pos = (point.x, point.y, point.z) face_vert_id = face_vertices.index(vertex_index) norm_id = meshIt.normalIndex(face_vert_id) norm = polyNormals[norm_id] norm = (norm.x, norm.y, norm.z) meshIt.getUV(face_vert_id, uv_ptr, meshFn.currentUVSetName()) u = uv_util.getFloat2ArrayItem(uv_ptr, 0, 0) v = uv_util.getFloat2ArrayItem(uv_ptr, 0, 1) # flip V for openGL # This fails if the the UV is exactly on the border (e.g. (0.5,1)) # but we really don't know what udim it's in for that case. if ExportSettings.vflip: v = int(v) + (1 - (v % 1)) uv = (u, v) if not positions[vertex_index]: positions[vertex_index] = pos normals[vertex_index] = norm uvs[vertex_index] = uv elif not (positions[vertex_index] == pos and normals[vertex_index] == norm and uvs[vertex_index] == uv): positions.append(pos) normals.append(norm) uvs.append(uv) indices[-1] = len(positions) - 1 if do_color: color = vertexColorList[vertex_index] colors[vertex_index] = (color.r, color.g, color.b) meshIt.next() if not len(Buffer.instances): primary_buffer = Buffer('primary_buffer') else: primary_buffer = Buffer.instances[0] if len(positions) >= 0xffff: idx_component_type = ComponentTypes.UINT else: idx_component_type = ComponentTypes.USHORT self.indices_accessor = Accessor(indices, "SCALAR", idx_component_type, 34963, primary_buffer, name=self.name + '_idx') self.indices_accessor.min_ = [0] self.indices_accessor.max_ = [len(positions) - 1] self.position_accessor = Accessor(positions, "VEC3", ComponentTypes.FLOAT, 34962, primary_buffer, name=self.name + '_pos') self.position_accessor.max_ = list(boundingBox.max())[:3] self.position_accessor.min_ = list(boundingBox.min())[:3] self.normal_accessor = Accessor(normals, "VEC3", ComponentTypes.FLOAT, 34962, primary_buffer, name=self.name + '_norm') self.texcoord0_accessor = Accessor(uvs, "VEC2", ComponentTypes.FLOAT, 34962, primary_buffer, name=self.name + '_uv')
def sampleColorAtParticle(textureNode, particleShapeNode): # get the particle object as an MObject selectionList = om.MSelectionList() selectionList.add(particleShapeNode) particleObject = om.MObject() selectionList.getDependNode(0, particleObject) # create a MFnParticle to get to the data particleDataFn = omFX.MFnParticleSystem(particleObject) # get the positionPP data posPPArray = om.MVectorArray() particleDataFn.getPerParticleAttribute("position", posPPArray) # these are the arguments required to sample a 3d texture: shadingNodeName = textureNode numSamples = posPPArray.length() pointArray = om.MFloatPointArray() pointArray.setLength(numSamples) refPoints = om.MFloatPointArray() refPoints.setLength(numSamples) for i in range(posPPArray.length()): particlePosVector = om.MVector() particlePosVector = posPPArray[i] location = om.MFloatPoint( particlePosVector[0], particlePosVector[1], particlePosVector[2]) pointArray.set(location, i) refPoints.set(location, i) # but we don't need these useShadowMap = False reuseMaps = False cameraMatrix = om.MFloatMatrix() uCoords = None vCoords = None normals = None tangentUs = None tangentVs = None filterSizes = None # and the return arguments are empty.... resultColors = om.MFloatVectorArray() resultTransparencies = om.MFloatVectorArray() # this is the command wot samples omr.MRenderUtil.sampleShadingNetwork(shadingNodeName, numSamples, useShadowMap, reuseMaps, cameraMatrix, pointArray, uCoords, vCoords, normals, refPoints, tangentUs, tangentVs, filterSizes, resultColors, resultTransparencies) # use the sampled colours to set rgbPP resultPPColors = om.MVectorArray() resultPPColors.clear() for i in range(resultColors.length()): floatVector = om.MFloatVector(resultColors[i]) vector = om.MVector(floatVector) resultPPColors.append(vector) particleDataFn.setPerParticleAttribute("rgbPP", resultPPColors)
def ExportMesh(filepath, meshShapedagPath): meshFn = OpenMaya.MFnMesh(meshShapedagPath) meshIntersector = OpenMaya.MMeshIntersector() meshIntersector.create(meshShapedagPath.node()) faceIdList = [] baryCoordList = [] points = OpenMaya.MPointArray() meshFn.getPoints(points, OpenMaya.MSpace.kWorld) normals = OpenMaya.MFloatVectorArray() meshFn.getVertexNormals(False, normals, OpenMaya.MSpace.kWorld) triangleCounts = OpenMaya.MIntArray() triangleVertexIndices = OpenMaya.MIntArray( ) # the size of this array is three times of the number of total triangles meshFn.getTriangles(triangleCounts, triangleVertexIndices) #------------------------- # Get skin cluster object #------------------------- skinClusterName = '' mesh_shape_name = meshFn.name() skinClusters = cmds.listHistory(mesh_shape_name) skinClusters = cmds.ls(skinClusters, type="skinCluster") if skinClusters: skinClusterName = skinClusters[0] else: cmds.warning('No skin cluster found on ' + mesh_shape_name) return #print skinClusterName # get the MFnSkinCluster using skinClusterName selList = OpenMaya.MSelectionList() selList.add(skinClusterName) skinClusterNode = OpenMaya.MObject() selList.getDependNode(0, skinClusterNode) skinFn = OpenMayaAnim.MFnSkinCluster(skinClusterNode) dagPaths = MDagPathArray() skinFn.influenceObjects(dagPaths) # influence object is a joint influenceObjectsNames = [] # get joint names for i in range(dagPaths.length()): influenceName = dagPaths[i].partialPathName() influenceObjectsNames.append( influenceName) # Need to remove namespace? skinMeshes = cmds.skinCluster(skinClusterName, query=1, geometry=1) geoIter = OpenMaya.MItGeometry(meshShapedagPath) infCount = OpenMaya.MScriptUtil() infCountPtr = infCount.asUintPtr() numVertices = geoIter.count() weightArray = [ 0 ] * TRESSFX_MAX_INFLUENTIAL_BONE_COUNT * numVertices # joint weight array for all vertices. Each vertex will have TRESSFX_MAX_INFLUENTIAL_BONE_COUNT weights. # It is initialized with zero for empty weight in case there are less weights than TRESSFX_MAX_INFLUENTIAL_BONE_COUNT . jointIndexArray = [ -1 ] * TRESSFX_MAX_INFLUENTIAL_BONE_COUNT * numVertices # joint index array for all vertices. It is initialized with -1 for an empty element in case # there are less weights than TRESSFX_MAX_INFLUENTIAL_BONE_COUNT . # collect bone weights for all vertices in the mesh index = 0 progressBar = ProgressBar('Collect data', numVertices) while geoIter.isDone() == False: weights = OpenMaya.MDoubleArray() skinFn.getWeights(meshShapedagPath, geoIter.currentItem(), weights, infCountPtr) weightJointIndexPairs = [] for i in range(len(weights)): pair = WeightJointIndexPair() pair.weight = weights[i] pair.joint_index = i weightJointIndexPairs.append(pair) weightJointIndexPairs.sort() a = 0 for j in range( min(len(weightJointIndexPairs), TRESSFX_MAX_INFLUENTIAL_BONE_COUNT)): weightArray[index * TRESSFX_MAX_INFLUENTIAL_BONE_COUNT + a] = weightJointIndexPairs[j].weight jointIndexArray[index * TRESSFX_MAX_INFLUENTIAL_BONE_COUNT + a] = weightJointIndexPairs[j].joint_index a += 1 index += 1 progressBar.Increment() geoIter.next() progressBar.Kill() #---------------------------------------------------------- # We collected all necessary data. Now save them in file. #---------------------------------------------------------- totalProgress = points.length() + triangleVertexIndices.length() / 3 + len( influenceObjectsNames) progressBar = ProgressBar('Export collision mesh', totalProgress) f = open(filepath, "w") f.write("# TressFX collision mesh exported by TressFX Exporter in Maya\n") # Write all bone (joint) names f.write("numOfBones %g\n" % (len(influenceObjectsNames))) f.write("# bone index, bone name\n") for i in range(len(influenceObjectsNames)): f.write("%d %s\n" % (i, influenceObjectsNames[i])) progressBar.Increment() # write vertex positions and skinning data f.write("numOfVertices %g\n" % (points.length())) f.write( "# vertex index, vertex position x, y, z, normal x, y, z, joint index 0, joint index 1, joint index 2, joint index 3, weight 0, weight 1, weight 2, weight 3\n" ) for vertexIndex in xrange(points.length()): point = points[vertexIndex] normal = normals[vertexIndex] weightJointIndexPairs = GetSortedWeightsFromOneVertex( TRESSFX_MAX_INFLUENTIAL_BONE_COUNT, vertexIndex, jointIndexArray, weightArray) f.write( "%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g\n" % (vertexIndex, point.x, point.y, point.z, normal.x, normal.y, normal.z, weightJointIndexPairs[0].joint_index, weightJointIndexPairs[1].joint_index, weightJointIndexPairs[2].joint_index, weightJointIndexPairs[3].joint_index, weightJointIndexPairs[0].weight, weightJointIndexPairs[1].weight, weightJointIndexPairs[2].weight, weightJointIndexPairs[3].weight)) progressBar.Increment() # write triangle face indices f.write("numOfTriangles %g\n" % (triangleVertexIndices.length() / 3)) f.write( "# triangle index, vertex index 0, vertex index 1, vertex index 2\n") for i in range(triangleVertexIndices.length() / 3): f.write("%g %d %d %d\n" % (i, triangleVertexIndices[i * 3 + 0], triangleVertexIndices[i * 3 + 1], triangleVertexIndices[i * 3 + 2])) progressBar.Increment() f.close() progressBar.Kill() return
def deform(self, dataBlock, geoIterator, local2WorldMatrix, geomIndex): inputAttr = ompx.cvar.MPxGeometryFilter_input # Envelope envelope = ompx.cvar.MPxGeometryFilter_envelope dataHandleEnvolope = dataBlock.inputValue(envelope) envelopeValue = dataHandleEnvolope.asFloat() # damping dataHandleDamping = dataBlock.inputValue(JiggleDeformerNode.dampingVal) dampMagnitude = dataHandleDamping.asFloat() # stiffness dataHandleStiff = dataBlock.inputValue(JiggleDeformerNode.stiffVal) stiffMagnitude = dataHandleStiff.asFloat() # time dataHandleTime = dataBlock.inputValue(JiggleDeformerNode.time) currentTime = dataHandleTime.asTime() # scale dataHandleScale = dataBlock.inputValue(JiggleDeformerNode.scale) scale = dataHandleScale.asFloat() # max velocity dataHandleVelocity = dataBlock.inputValue( JiggleDeformerNode.maxVelocity) maxVelocity = dataHandleVelocity.asFloat() * scale # direction bias dataHandleDirection = dataBlock.inputValue( JiggleDeformerNode.directionBias) directionBias = dataHandleDirection.asFloat() # normal strength dataHandleNormalStrength = dataBlock.inputValue( JiggleDeformerNode.normalStrength) normalStrength = dataHandleNormalStrength.asFloat() # start frame dataHandleStartFrame = dataBlock.inputValue( JiggleDeformerNode.startFrame) startFrame = dataHandleStartFrame.asInt() # points' positions in local space points = om.MPointArray() geoIterator.allPositions(points) # INITIALIZE ATTRIBUTES if geomIndex not in self.initialFlagDict.keys(): self.initialFlagDict[geomIndex] = False if geomIndex not in self.dirtyMapDict.keys(): self.dirtyMapDict[geomIndex] = False if geomIndex not in self.preTimeDict.keys(): self.preTimeDict[geomIndex] = om.MTime() if geomIndex not in self.curPosDict.keys(): self.curPosDict[geomIndex] = om.MPointArray() if geomIndex not in self.prePosDict.keys(): self.prePosDict[geomIndex] = om.MPointArray() if geomIndex not in self.membershipDict.keys(): self.membershipDict[geomIndex] = om.MIntArray() # Get normalsDict normals = om.MFloatVectorArray() if directionBias != 0.0 or normalStrength < 1.0: inputMesh = self.getInputMesh(dataBlock, geomIndex, inputAttr) MFnMesh = om.MFnMesh(inputMesh) MFnMesh.getVertexNormals(0, normals) # test initialize flag for the first time if not self.initialFlagDict[geomIndex]: self.preTimeDict[geomIndex] = currentTime self.curPosDict[geomIndex].setLength(geoIterator.count()) self.prePosDict[geomIndex].setLength(geoIterator.count()) for i in range(points.length()): self.curPosDict[geomIndex].set(points[i] * local2WorldMatrix, i) self.prePosDict[geomIndex].set(self.curPosDict[geomIndex][i], i) self.initialFlagDict[geomIndex] = True self.dirtyMapDict[geomIndex] = True # for stable simulation, check the time difference whether it is 1 frame or not # If the current time smaller than the startFrame, jiggling effect will not be performed timeDiff = currentTime.value() - self.preTimeDict[geomIndex].value() if timeDiff > 1.0 or timeDiff < 0.0 or currentTime.value( ) <= startFrame: self.initialFlagDict[geomIndex] = False self.preTimeDict[geomIndex] = om.MTime(currentTime) return # perGeometry hGeo = dataBlock.inputArrayValue(JiggleDeformerNode.perGeo) # jump to each geometry self.jump2Element(hGeo, geomIndex) hGeo.jumpToElement(geomIndex) hPerGeo = hGeo.inputValue() # get the different map handle in component attribute hJiggleMap = om.MArrayDataHandle( hPerGeo.child(JiggleDeformerNode.jiggleMap)) hStiffMap = om.MArrayDataHandle( hPerGeo.child(JiggleDeformerNode.stiffMap)) hDampMap = om.MArrayDataHandle( hPerGeo.child(JiggleDeformerNode.dampMap)) matrix = hPerGeo.child(JiggleDeformerNode.worldMatrix).asMatrix() if geomIndex not in self.weightMapDict.keys(): self.weightMapDict[geomIndex] = om.MFloatArray() # self.weightMapDict[geomIndex].setLength(geoIterator.count()) if geomIndex not in self.jiggleMapDict.keys(): self.jiggleMapDict[geomIndex] = om.MFloatArray() # self.jiggleMapDict[geomIndex].setLength(geoIterator.count()) if geomIndex not in self.stiffMapDict.keys(): self.stiffMapDict[geomIndex] = om.MFloatArray() # self.stiffMapDict[geomIndex].setLength(geoIterator.count()) if geomIndex not in self.dampMapDict.keys(): self.dampMapDict[geomIndex] = om.MFloatArray() # self.dampMapDict[geomIndex].setLength(geoIterator.count()) if self.dirtyMapDict[geomIndex] or geoIterator.count( ) != self.membershipDict[geomIndex].length(): self.weightMapDict[geomIndex].setLength(geoIterator.count()) self.jiggleMapDict[geomIndex].setLength(geoIterator.count()) self.stiffMapDict[geomIndex].setLength(geoIterator.count()) self.dampMapDict[geomIndex].setLength(geoIterator.count()) self.membershipDict[geomIndex].setLength(geoIterator.count()) # loop through the geoIterator.count() (i.e. mesh geometry) for getting the jiggleMap Value. ii = 0 geoIterator.reset() while not geoIterator.isDone(): index = geoIterator.index() # JIGGLE MAP self.jump2Element(hJiggleMap, index) hJiggleMap.jumpToElement(index) self.jiggleMapDict[geomIndex].set( hJiggleMap.inputValue().asFloat(), ii) # STIFF MAP self.jump2Element(hStiffMap, index) hStiffMap.jumpToElement(index) self.stiffMapDict[geomIndex].set( hStiffMap.inputValue().asFloat(), ii) # DAMP MAP self.jump2Element(hDampMap, index) hDampMap.jumpToElement(index) self.dampMapDict[geomIndex].set( hDampMap.inputValue().asFloat(), ii) # WEIGHT MAP self.weightMapDict[geomIndex].set( self.weightValue(dataBlock, geomIndex, geoIterator.index()), ii) # MEMBERSHIP self.membershipDict[geomIndex].set(geoIterator.index(), ii) ii += 1 geoIterator.next() self.dirtyMapDict[geomIndex] = False ####################### # CALCULATE POSITIONS # ####################### i = 0 geoIterator.reset() while not geoIterator.isDone(): goal = points[i] * local2WorldMatrix damping = dampMagnitude * self.dampMapDict[geomIndex][i] stiff = stiffMagnitude * self.stiffMapDict[geomIndex][i] # velocity velocity = (self.curPosDict[geomIndex][i] - self.prePosDict[geomIndex][i]) * (1.0 - damping) newPos = self.curPosDict[geomIndex][i] + velocity goalForce = (goal - newPos) * stiff newPos = newPos + goalForce # clamp to the MAX velocity displacement = newPos - goal if displacement.length() > maxVelocity: displacement = displacement.normal() * maxVelocity newPos = goal + displacement # normal strength if normalStrength < 1.0: normalDot = displacement * om.MVector( normals[self.membershipDict[geomIndex][i]]) newPos -= om.MVector( normals[self.membershipDict[geomIndex][i]]) * normalDot * ( 1.0 - normalStrength) # direction bias membership = self.membershipDict[geomIndex][i] # displacement = om.MFloatVector(displacement) if directionBias > 0.0: normalDot = displacement.normal() * om.MVector( normals[membership]) if normalDot < 0.0: RESULT = displacement * ( (displacement * om.MVector(normals[membership])) * directionBias) newPos = newPos + RESULT elif directionBias < 0.0: normalDot = displacement.normal() * om.MVector( normals[membership]) if normalDot > 0.0: RESULT = displacement * ( (displacement * om.MVector(normals[membership])) * directionBias) newPos = newPos + RESULT # store for next time computing self.prePosDict[geomIndex].set(self.curPosDict[geomIndex][i], i) self.curPosDict[geomIndex].set(newPos, i) # multi with weight map and envelope newPosLoc = newPos * local2WorldMatrix.inverse() jiggle = self.jiggleMapDict[geomIndex][i] weight = self.weightMapDict[geomIndex][i] points.set( (points[i] + (newPosLoc - points[i]) * weight * envelopeValue * jiggle), i) self.preTimeDict[geomIndex] = om.MTime(currentTime) i = i + 1 geoIterator.next() # set positions geoIterator.setAllPositions(points)
def deform(self, block, geoIterator, matrix, geometryIndex): # Configure mesh and get all inputs attributes kInput = omp.cvar.MPxGeometryFilter_input inputArray_dh = block.outputArrayValue(kInput) inputArray_dh.jumpToElement(geometryIndex) inputElement_dh = inputArray_dh.outputValue() kInputGeom = omp.cvar.MPxGeometryFilter_inputGeom inputGeom_dh = inputElement_dh.child(kInputGeom) inMesh = inputGeom_dh.asMesh() kEnvelope = omp.cvar.MPxGeometryFilter_envelope dataHandleEnvelope = block.inputValue(kEnvelope) envelope_value = dataHandleEnvelope.asFloat() # Getting custom inputs attributes data handles try: inputMatrix_dh = block.inputValue(noiseDeformer.inputMatrix) except ImportError: sys.stderr.write("Failed to get MDataHandle") # Getting values of custom inputs attributes through data handles inputMatrix_value = inputMatrix_dh.asMatrix() # Getting translation of input transform matrix mTransMatrix = om.MTransformationMatrix(inputMatrix_value) inputMatrixTranslation_value = mTransMatrix.getTranslation( om.MSpace.kObject) # Get mesh normals mFloatVectorArray_normal = om.MFloatVectorArray() mFnMesh = om.MFnMesh(inMesh) mFnMesh.getVertexNormals(False, mFloatVectorArray_normal, om.MSpace.kObject) # Temporal array to save all vertices modified mPointArray_meshVertex = om.MPointArray() # Iterate around all vertices while (not geoIterator.isDone()): pointPosition = geoIterator.position() # Get the painted weights of the mesh weight = self.weightValue(block, geometryIndex, geoIterator.index()) # Create a new vertex position pointPosition.x = pointPosition.x + ( inputMatrixTranslation_value[0] * mFloatVectorArray_normal[geoIterator.index()].x * envelope_value * weight) pointPosition.y = pointPosition.y + ( inputMatrixTranslation_value[1] * mFloatVectorArray_normal[geoIterator.index()].y * envelope_value * weight) pointPosition.z = pointPosition.z + ( inputMatrixTranslation_value[2] * mFloatVectorArray_normal[geoIterator.index()].z * envelope_value * weight) # Save the new position in the temporal array mPointArray_meshVertex.append(pointPosition) geoIterator.next() # When the iterator finish, we replace its vertices values with the # temporal array geoIterator.setAllPositions(mPointArray_meshVertex)
def deform(self, block, iter, mat, multiIndex): # ################################### # get attributes # ################################### # envelope envelope = block.inputValue( OpenMayaMPx.cvar.MPxDeformerNode_envelope).asFloat() if (envelope == 0.0): return # ================================== # aOrigMesh oOrig = block.inputValue(self.aOrigMesh).asMesh() if oOrig.isNull(): return fnOrig = om.MFnMesh(oOrig) # ================================== # input[multiIndex].inputGeometry hInput = block.outputArrayValue(self.input) hInput.jumpToElement(multiIndex) hInputGeom = hInput.outputValue().child(self.inputGeom) oInputGeom = hInputGeom.asMesh() fnCurrent = om.MFnMesh(oInputGeom) # ================================== # aDisplayColors displayColors = block.inputValue(self.aDisplayColors).asBool() if (displayColors): colorBase = block.inputValue(self.aColorBase).asFloatVector() colorStretch = block.inputValue(self.aColorStretch).asFloatVector() colorSquash = block.inputValue(self.aColorSquash).asFloatVector() # ================================== # aMeasureTypeHeat measureTypeHeat = block.inputValue(self.aMeasureTypeHeat).asShort() # aMultiplyHeat aSquashMultiplyHeat aStretchMultiplyHeat multHeat = block.inputValue(self.aMultiplyHeat).asFloat() squashMultHeat = block.inputValue(self.aSquashMultiplyHeat).asFloat() stretchMultHeat = block.inputValue(self.aStretchMultiplyHeat).asFloat() if (multHeat == 0.0 or squashMultHeat == 0.0 and stretchMultHeat == 0.0): return # aMaxHeat aSquashMaxHeat aStretchMaxHeat maxHeat = block.inputValue(self.aMaxHeat).asBool() squashMaxHeat = block.inputValue(self.aSquashMaxHeat).asFloat() * -1 stretchMaxHeat = block.inputValue(self.aStretchMaxHeat).asFloat() if (squashMaxHeat == 0.0 and stretchMaxHeat == 0.0): return # aGrowHeat aSquashGrowHeat aStretchGrowHeat growHeat = block.inputValue(self.aGrowHeat).asInt() squashGrowHeat = block.inputValue(self.aSquashGrowHeat).asInt() stretchGrowHeat = block.inputValue(self.aStretchGrowHeat).asInt() # aIterationsSmoothHeat iterationsSmoothHeat = block.inputValue( self.aIterationsSmoothHeat).asInt() # aStrengthSmoothHeat strengthSmoothHeat = block.inputValue( self.aStrengthSmoothHeat).asFloat() # ================================== # aDeformationType deformationType = block.inputValue(self.aDeformationType).asShort() if (deformationType == 0): return # aIterationsSmoothDeformation iterationsSmoothDeformation = block.inputValue( self.aIterationsSmoothDeformation).asInt() # aStrengthSmoothDeformation strengthSmoothDeformation = block.inputValue( self.aStrengthSmoothDeformation).asFloat() # aTangentSpace tangentSpace = False if (deformationType == 2): tangentSpace = block.inputValue(self.aTangentSpace).asShort() # ================================== # aStretchMesh aSquashMesh if (deformationType == 2): # aStretchMesh oStretch = block.inputValue(self.aStretchMesh).asMesh() if oStretch.isNull(): return fnStretch = om.MFnMesh(oStretch) stretchPoints = om.MPointArray() fnStretch.getPoints(stretchPoints) # aSquashMesh oSquash = block.inputValue(self.aSquashMesh).asMesh() if oSquash.isNull(): return fnSquash = om.MFnMesh(oSquash) squashPoints = om.MPointArray() fnSquash.getPoints(squashPoints) # orig points origPoints = om.MPointArray() fnOrig.getPoints(origPoints) # ################################### # Gather information TODO: STORE in node (refresh button) # ################################### d_util = om.MScriptUtil() doublePtr = d_util.asDoublePtr() # orig edge lengths itEdgeOrig = om.MItMeshEdge(oOrig) edgeLengthsOrig = [] lengthSum = 0.0 while not itEdgeOrig.isDone(): itEdgeOrig.getLength(doublePtr) eachLength = d_util.getDouble(doublePtr) lengthSum += eachLength edgeLengthsOrig.append(eachLength) itEdgeOrig.next() edgeLengthAvrg = lengthSum / itEdgeOrig.count() # orig face area itPolyOrig = om.MItMeshPolygon(oOrig) polyAreasOrig = [] while not itPolyOrig.isDone(): itPolyOrig.getArea(doublePtr) eachArea = d_util.getDouble(doublePtr) polyAreasOrig.append(eachArea) itPolyOrig.next() # connected edges and vertices (and faces) connectedEdges = [] connectedPoints = [] connectedFaces = [] itPointCurrent = om.MItMeshVertex(oOrig) iaConnectedObjects = om.MIntArray() while not itPointCurrent.isDone(): # edges itPointCurrent.getConnectedEdges(iaConnectedObjects) connectedEdges.append(list(iaConnectedObjects)) # vertices itPointCurrent.getConnectedVertices(iaConnectedObjects) connectedPoints.append(list(iaConnectedObjects)) # faces itPointCurrent.getConnectedFaces(iaConnectedObjects) connectedFaces.append(list(iaConnectedObjects)) # finish itPointCurrent.next() # ################################### # Gather information per call # ################################### d_util = om.MScriptUtil() doublePtr = d_util.asDoublePtr() # current polygon area if (measureTypeHeat == 0): itPolyCurrent = om.MItMeshPolygon(oInputGeom) polyAreasCurrent = [] while not itPolyCurrent.isDone(): itPolyCurrent.getArea(doublePtr) eachArea = d_util.getDouble(doublePtr) polyAreasCurrent.append(eachArea) itPolyCurrent.next() # current edge length elif (measureTypeHeat == 1): edgeLengthsCurrent = [] itEdgeCurrent = om.MItMeshEdge(oInputGeom) while not itEdgeCurrent.isDone(): itEdgeCurrent.getLength(doublePtr) edgeLengthsCurrent.append(d_util.getDouble(doublePtr)) itEdgeCurrent.next() # current normals if (deformationType == 1): currentNormals = om.MFloatVectorArray() fnCurrent.getVertexNormals(False, currentNormals, om.MSpace.kObject) # find relevant points paPoints = om.MPointArray() ptIndices = [] ptWeights = [] while not iter.isDone(): iterIndex = iter.index() pt = iter.position() # get painted weight wPt = self.weightValue(block, multiIndex, iterIndex) if (wPt == 0.0): iter.next() continue # only store points with weights paPoints.append(pt) ptIndices.append(iterIndex) ptWeights.append(wPt) iter.next() iter.reset() # ################################### # Heat Calculation # ################################### # input: relevant points, default lengths, current lengths, edgeLengthAvrg # output: arHeat # # eachHeat =-1.0 // origLength*0 // squashed # eachHeat = 0.0 // origLength*1 // default # eachHeat = 1.0 // origLength*2 // stretched arHeat = [] for x, eachId in enumerate(ptIndices): # measure difference between orig and current currentMeasure = 0.0 origMeasure = 0.0 # faces if (measureTypeHeat == 0): for eachFace in connectedFaces[eachId]: currentMeasure += polyAreasCurrent[eachFace] origMeasure += polyAreasOrig[eachFace] eachHeat = ((currentMeasure - origMeasure) / origMeasure) # edges elif (measureTypeHeat == 1): for eachEdge in connectedEdges[eachId]: currentMeasure += edgeLengthsCurrent[eachEdge] origMeasure += edgeLengthsOrig[eachEdge] # to have similar behavior as face area multiply eachHeat = ((currentMeasure - origMeasure) / origMeasure) * 2 # # stretch and squash specific modification if (eachHeat < 0.0): eachHeat *= squashMultHeat * multHeat if (eachHeat < squashMaxHeat and maxHeat): eachHeat = squashMaxHeat elif (eachHeat > 0.0): eachHeat *= stretchMultHeat * multHeat if (eachHeat > stretchMaxHeat and maxHeat): eachHeat = stretchMaxHeat # store arHeat.append(eachHeat) # ################################### # Heat Grow # ################################### squashGrowHeat += growHeat stretchGrowHeat += growHeat if (squashGrowHeat or stretchGrowHeat): # find iteration count growIterations = squashGrowHeat if (stretchGrowHeat > growIterations): growIterations = stretchGrowHeat for y in range(growIterations): arHeatNew = list(arHeat) # loop through effected points for x, eachId in enumerate(ptIndices): strongestSquash = arHeatNew[x] strongestStretch = arHeatNew[x] # loop over neighbors for eachNeighborId in connectedPoints[eachId]: if (eachNeighborId in ptIndices): eachNeighborHeat = arHeat[ptIndices.index( eachNeighborId)] if (eachNeighborHeat < strongestSquash): strongestSquash = eachNeighborHeat if (eachNeighborHeat > strongestStretch): strongestStretch = eachNeighborHeat # set proper value if (squashGrowHeat > y and stretchGrowHeat > y): newValue = 0.0 if (strongestSquash < 0.0): newValue = strongestSquash if (strongestStretch > 0.0): newValue += strongestStretch if (newValue): arHeatNew[x] = newValue elif (squashGrowHeat > y and strongestSquash < 0.0): if (arHeatNew[x] > 0.0): arHeatNew[x] += strongestSquash else: arHeatNew[x] = strongestSquash elif (stretchGrowHeat > y and strongestStretch > 0.0): if (arHeatNew[x] < 0.0): arHeatNew[x] += strongestStretch else: arHeatNew[x] = strongestStretch arHeat = arHeatNew # # ################################### # Heat Smooth # ################################### # input: arHeat # output: arHeat for y in range(iterationsSmoothHeat): arHeatNew = list(arHeat) for x, eachId in enumerate(ptIndices): neighborIds = connectedPoints[eachId] neighborAvrg = 0.0 validNeighbor = False for eachNeighborId in neighborIds: if (eachNeighborId in ptIndices): validNeighbor = True neighborAvrg += arHeat[ptIndices.index(eachNeighborId)] if (validNeighbor): neighborAvrg /= len(neighborIds) arHeatNew[x] = arHeatNew[x] * ( 1.0 - strengthSmoothHeat) + neighborAvrg * strengthSmoothHeat arHeat = arHeatNew # ################################### # Heat Display # ################################### # input: arHeat # result: vertexColors if (displayColors): colorList = om.MColorArray() indexList = om.MIntArray() for x, eachId in enumerate(ptIndices): # colorBase colorStretch colorSquash eachColor = om.MFloatVector(colorBase) if (arHeat[x] > 0.0): eachColor += (colorStretch - eachColor) * (arHeat[x]) elif (arHeat[x] < 0.0): eachColor += (colorSquash - eachColor) * (arHeat[x] * -1) colorList.append( om.MColor(eachColor.x, eachColor.y, eachColor.z, 1.0)) indexList.append(eachId) #fnCurrent.setVertexColor( om.MColor(eachColor.x, eachColor.y, eachColor.z), eachId )# (setting all at once is faster) fnCurrent.setVertexColors(colorList, indexList) # ################################### # Deformation Calculation # ################################### # input: heatArray # output: motionVectorArray arVectors = [] for x, eachId in enumerate(ptIndices): eachHeat = arHeat[x] vecMove = om.MVector() # skip calculation for 0.0 heat if (eachHeat == 0.0): arVectors.append(vecMove) continue # ################################### # Normal # ################################### if (deformationType == 1): # normal deformation vecMove += om.MVector( currentNormals[eachId]) * (eachHeat * -1) * edgeLengthAvrg # ################################### # BlendShape # ################################### if (deformationType == 2): if (eachHeat < 0.0): targetPt = squashPoints[eachId] vecMove += (targetPt - origPoints[eachId]) * (eachHeat * -1) elif (eachHeat > 0.0): targetPt = stretchPoints[eachId] vecMove += (targetPt - origPoints[eachId]) * (eachHeat) # tangent spaces if (tangentSpace): matTangentOrig = getTangentSpace(tangentSpace, fnOrig, eachId, connectedFaces[eachId]) matTangentCurrent = getTangentSpace( tangentSpace, fnCurrent, eachId, connectedFaces[eachId]) vecMove *= matTangentOrig.inverse() * matTangentCurrent # # save vector arVectors.append(vecMove) # ################################### # Deformation Smooth # ################################### # input: motionVectorArray # result: motionVectorArray for x in range(iterationsSmoothDeformation): arVectorsNew = list(arVectors) for x, eachId in enumerate(ptIndices): neighborIds = connectedPoints[eachId] neighborAvrg = om.MVector() validNeighbor = False for eachNeighborId in neighborIds: if (eachNeighborId in ptIndices): validNeighbor = True neighborAvrg += arVectors[ptIndices.index( eachNeighborId)] if (validNeighbor): neighborAvrg /= len(neighborIds) arVectorsNew[x] = arVectorsNew[x] * ( 1.0 - strengthSmoothDeformation ) + neighborAvrg * strengthSmoothDeformation arVectors = arVectorsNew # ################################### # Deformation # ################################### # input: motionVectorArray, weights # result: deformed mesh counter = 0 while not iter.isDone(): if (iter.index() in ptIndices): iter.setPosition(paPoints[counter] + arVectors[counter] * ptWeights[counter] * envelope) counter += 1 iter.next()