def compute(self, plug, dataBlock): if plug == arrayTest.output1WgtAttr: #calculations here #get inputs dataHandleInput = dataBlock.inputValue(arrayTest.input1VecAttr) inVal = dataHandleInput.asFloat() #get ouput array arrayDataHandle = OpenMaya.MArrayDataHandle( dataBlock.outputArrayValue(arrayTest.output1WgtAttr)) myBuilder = OpenMaya.MArrayDataBuilder(arrayTest.output1WgtAttr, 0) for i in range(arrayDataHandle.elementCount()): #arrayDataHandle.next() output = inVal / (i + 1) #output = inVal + outValue myElementHandle = OpenMaya.MDataHandle(myBuilder.addElement(i)) myElementHandle.setFloat(output) arrayDataHandle.set(myBuilder) arrayDataHandle.setAllClean() dataBlock.setClean(plug) else: return OpenMaya.kUnknownParameter
def compute(self, plug, block): this_node = self.thisMObject() # get input handles input_matrix_handle = block.inputValue(self.input_matrix) mat = input_matrix_handle.asMatrix() # get output plug output_elements_plug = om.MPlug(this_node, self.output_elements) output_elements_handle = output_elements_plug.constructHandle(block) array_handle = om.MArrayDataHandle(output_elements_handle) array_builder = array_handle.builder() index = 0 for i in range(4): for j in range(4): data_handle = array_builder.addElement(index) data_handle.setFloat(mat(i, j)) index += 1 # refresh connection array_handle.set(array_builder) output_elements_plug.setMDataHandle(output_elements_handle) output_elements_plug.destructHandle(output_elements_handle) block.setClean(plug)
def nodeAttrToFloatArray(DataBlock, NodeAttr): dataHandle = DataBlock.inputValue(NodeAttr) arrayDataHandle = om.MArrayDataHandle(dataHandle) outFloatArray = [] for i in range(0, arrayDataHandle.elementCount()): if not (i == 0): arrayDataHandle.next() dataHandle = arrayDataHandle.inputValue() outFloatArray.append(dataHandle.asFloat()) return outFloatArray
def nodeAttrToMStrings(DataBlock, NodeAttr): dataHandle = DataBlock.inputValue(NodeAttr) arrayDataHandle = om.MArrayDataHandle(dataHandle) outMString = [] for i in range(0, arrayDataHandle.elementCount()): if not (i == 0): arrayDataHandle.next() dataHandle = arrayDataHandle.inputValue() outMString.append(dataHandle.asString()) return outMString
def compute(self, plug, dataBlock): """Compute the arithmetic mean of all the items in input array.""" if (plug == AR_AverageArrayDoublesNode.outputAttr): # get the incoming data arrayDataHandle = om.MArrayDataHandle( dataBlock.inputValue(AR_AverageArrayDoublesNode.inputAttr)) # compute output output = 0.0 try: output = (arrayDataHandle.inputValue()).asDouble() except: pass for i in range(arrayDataHandle.elementCount() - 1): arrayDataHandle.next() output += (arrayDataHandle.inputValue()).asDouble() try: output /= arrayDataHandle.elementCount() except: pass """ # an alternative approach using an MPlug; less efficient because MPlug is slower arrayPlug = om.MPlug(self.thisMObject(), AR_AverageArrayDoublesNode.inputAttr) output = 0.0 for i in range(arrayPlug.numElements()): elementPlug = om.MPlug(arrayPlug[i]).asDouble() # index operator works with physical indices output += elementPlug.asDouble() try: output /= arrayPlug.numElements() except: pass """ # set the outgoing plug dataHandle = om.MDataHandle( dataBlock.outputValue(AR_AverageArrayDoublesNode.outputAttr)) dataHandle.setDouble(output) dataBlock.setClean(plug) else: return om.kUnknownParameter
def rebuild_solver(self, data): """recalcule le solver a l'aide de matrixMM aucun input ou output dans ce code""" # NOTE 获取 N 和 M 的长度数量 self.N = data.inputValue(self.NDimension).asInt() self.M = data.inputValue(self.MDimension).asInt() # NOTE 获取 pose 的数量 poses_H = data.inputArrayValue(self.poses) pose_ids = OpenMaya.MIntArray() OpenMaya.MPlug(self.thisMObject(), self.poses).getExistingArrayAttributeIndices( pose_ids ) self.poseUsed_ids = [] # = pose_ids utilisées # trouve les infos necessaires pour creer le system self.nKeys = [] # liste (dim poses_num) de liste ( dim N ) mValues = [] # liste (dim poses_num) de liste ( dim M ) self.weights = [] # liste (dim poses_num) de floats self.only_one_mValue = [] # NOTE 获取 self.nKeys mValues for i in pose_ids: poses_H.jumpToElement(i) pose_H = poses_H.inputValue() state = pose_H.child(self.state).asBool() # wgt = pose_H.child( self.weight ).asFloat() # if not (state and wgt>self.epsilon) : # continue if not state: continue nKey_H = OpenMaya.MArrayDataHandle(pose_H.child(self.nKey)) nKey = [] mValue_H = OpenMaya.MArrayDataHandle(pose_H.child(self.mValue)) mValue = [] for n in xrange(self.N): # try au cas ou y'aurai rien de branché ... try: nKey_H.jumpToElement(n) key = nKey_H.inputValue().asFloat() nKey.append(key) except: nKey.append(0.0) # ignore les clé deja presentes if nKey in self.nKeys: OpenMaya.MGlobal.displayWarning( "key[%s] %s can not be used more than once" % (i, nKey) ) continue for m in xrange(self.M): try: mValue_H.jumpToElement(m) value = mValue_H.inputValue().asFloat() mValue.append(value) except: mValue.append(0.0) self.nKeys.append(nKey) mValues.append(mValue) # self.weights.append( wgt ) self.poseUsed_ids.append(i) # poseUsed_num = len(self.poseUsed_ids) if poseUsed_num == 0: OpenMaya.MGlobal.displayError("RbfSolver failed : No Key") return False elif poseUsed_num == 1: # no interpolation self.only_one_mValue = mValues[0] return True # pour la suite necessite de connaitre les fonctions utilisées : # Distance fonction ? # RBF fonction ? normalize = data.inputValue(self.normalize).asBool() distance_id = data.inputValue(self.distanceMode).asInt() self.distance_fonction = self.distance_fonctions[distance_id] rbf_id = data.inputValue(self.rbfMode).asInt() self.rbf_fonction = self.rbf_fonctions[rbf_id] # matrixMM pour resoudre les system AX = Y # factorize la et solve la pour chaque m # store les X(m) dans self.mX distanceMax = 0.0 mat = MatrixNN() mat.setDimension(poseUsed_num) # ** pour les poses doublon # remove les [ligne-colonne] contenant .0 en dehor de la diagonale for i in xrange(poseUsed_num): for j in xrange(poseUsed_num): if i == j: # ici la distance d'une pose sur elle meme mat.rc[i][j] = 0.0 else: # distance de chaque pose a chaque pose # NOTE 默认使用 欧几里得度量 作为距离计算 # NOTE https://baike.baidu.com/item/%E6%AC%A7%E5%87%A0%E9%87%8C%E5%BE%97%E5%BA%A6%E9%87%8F/1274107 distance = self.distance_fonction( self.N, self.nKeys[i], self.nKeys[j] ) # stock la distance maximale entre 2 poses # ceci servira à la normalisation du system if distance > distanceMax: distanceMax = distance mat.rc[i][j] = distance # utilise le scale pour smoother plus ou moins # si on veut le system normalisé, il faut disiviser le scale par la distanceMax fScale = data.inputValue(self.scale).asFloat() # NOTE fscale 不为零 if fScale < self.epsilon: fScale = self.epsilon if normalize: self.fScale = fScale / distanceMax else: self.fScale = fScale # RBF chaque element for i in xrange(poseUsed_num): for j in xrange(poseUsed_num): # euclidienne ou angulaire ? ou autre... mat.rc[i][j] = self.rbf_fonction(mat.rc[i][j] * self.fScale) # factorizeLU et sauve les ids des lignes permutées # NOTE 矩阵 LU 分解 # NOTE https://baike.baidu.com/item/lu%E5%88%86%E8%A7%A3/764245 LU, Pids = mat.factorize_LU() # pour chaque m de chaque pose # solv_LU et store les X(m) dans self.mX # mX = m * nVector self.mX = [] for m in xrange(self.M): Y = [mValues[i][m] for i in xrange(poseUsed_num)] X = mat.solve_LU(LU, Pids, Y) # nVector des coeff self.mX.append(X) # *** setClean indique que le system est solved solved_H = data.outputValue(self.solved) solved_H.setClean() OpenMaya.MGlobal.displayInfo( "RbfSolver recomputed using poses : %s" % self.poseUsed_ids ) return True
def compute(self, plug, data): # Begin constructing data points and samples from the user inputs. # The user has specified the number of 'sites' so we need to loop through # the dataBlock to see what's actually there an construct some lists. dataPoints = list() pyFValues = list() # the function values are our samples allInputs_mDataArrayHandle = data.inputArrayValue( RbfBlender.allInputs_compound ) # numInputs = allInputs_mDataArrayHandle.elementCount() numInputs = data.inputValue( RbfBlender.numInputGroups ).asInt() sampleDimensions = data.inputValue( RbfBlender.sampleDimensions ).asInt() # get the deleted indices. this is because we can't differentiate between "optimized" # array indices and deleted indices. deletedIndices_mArrayDataHandle = data.inputArrayValue(RbfBlender.deletedIndices) deletedIndices = list() numDeletedIndices = deletedIndices_mArrayDataHandle.elementCount() for i in xrange( numDeletedIndices ): deletedIndices_mArrayDataHandle.jumpToArrayElement(i) di_i_mDataHandle = deletedIndices_mArrayDataHandle.inputValue() deletedIndices.append( di_i_mDataHandle.asInt() ) for i in xrange( numInputs + numDeletedIndices ): if not i in deletedIndices: # jumpToArrayElement handles the sparse array. # for exmaple, create three inputs, and delete the entry at index 1. #i 0, array element index 0 #i 1, array element index 2 # Just like with the individual attrs, if entire compounds with arrays have zero as their values, # maya will "optimize" by ignoring that whole compound. This is harder to detect than with regular values # because the elements still show up in the node editor. Can be checked though with mc.getAttr(<theCompoundAttr>, mi=True) # the question becomes: how do you differentiate between an index that has been optimized, with one that # has been deleted by the user? you can't just flatly assume zero, like I do with the others because then you might get # multiple "zero compounds" which will break the rbf math. # The only way I can think of, is by storing an array of which indices have been deleted by the user. elementOptimized = 0 thisDataPoint = [0.0, 0.0, 0.0] thisSampleSite = list() for l in xrange(sampleDimensions): thisSampleSite.append(0.0) try: # test for optimized allInputs_mDataArrayHandle.jumpToElement(i) except: elementOptimized = 1 if not elementOptimized: # So now this is the compound! how do I get the children... ??? you just pass in the object type # internally. it must be searching the children of the compound for a "type" currentCompound_i_mDataHandle = allInputs_mDataArrayHandle.inputValue() dataPoint_mDataHandle = currentCompound_i_mDataHandle.child(RbfBlender.dataPoint_array) sample_mDataHandle = currentCompound_i_mDataHandle.child(RbfBlender.sample_array) # convert the dataHandle to an daraArrayHandle... you'd think it would know its own type when being # returned eh. nah. dataPoint_mArrayDataHandle = om.MArrayDataHandle(dataPoint_mDataHandle) sample_mArrayDataHandle = om.MArrayDataHandle(sample_mDataHandle) for j in xrange( 3 ): # we know this is always 3 for this implemenation # Maya "optimizes" array attrs with values equal to zero, by removing them. This causes the # plugin to fail until the attribute editor is opened and the data is reset. Highly annoying. # Work around is to catch the jumpToElement and if it can't find the element, we assume a value # of zero. dataPointValue = 0.0 try: dataPoint_mArrayDataHandle.jumpToElement(j) dataPointValue = dataPoint_mArrayDataHandle.inputValue().asFloat() except: pass thisDataPoint[j] = dataPointValue for k in xrange( sampleDimensions ): # there shouldn't be a sparse array for the samples because I only add/remove from the end sampleValue = 0.0 try: sample_mArrayDataHandle.jumpToElement(k) sampleValue = sample_mArrayDataHandle.inputValue().asFloat() except: pass thisSampleSite[k] = sampleValue dataPoints.append( thisDataPoint ) pyFValues.append( thisSampleSite ) # ------------- Done building data points / sample site lists -------------------------------- # R = data.inputValue(RbfBlender.R_input).asFloat() lookup_mDataArrayHandle = data.inputArrayValue( RbfBlender.lookup_input ) lookupValues = list() for m in xrange( 3 ): # always gonna be 3.. lookupValue = 0.0 try: lookup_mDataArrayHandle.jumpToElement(m) lookupValue = lookup_mDataArrayHandle.inputValue().asFloat() except: pass lookupValues.append( lookupValue ) # ----------------- do the math here ---------------- # typeIndex = data.inputValue(RbfBlender.typeIndex).asInt() outValues = computeWeights( pyFValues, dataPoints, lookupValues, RbfBlender.typeDic[typeIndex], R ) # ----------------- done doing math ----------------- # lol output_mArrayDataHandle = data.outputArrayValue( RbfBlender.output ) sampleDimensions = data.inputValue( RbfBlender.sampleDimensions ).asInt() for n in xrange( sampleDimensions ): # actually read the sample dimensions here to avoid update issues output_mArrayDataHandle.jumpToArrayElement( n ) output_n_mDataHandle = output_mArrayDataHandle.outputValue() if outValues[n] > 1.0: outValues[n] = 1.0 elif outValues[n] < 0.0: outValues[n] = 0.0 output_n_mDataHandle.setFloat(outValues[n]) data.setClean(plug)
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 rebuild_solver(self, data): '''recalculate the solver using matrixNN no input or output in this code ''' self.N = data.inputValue(self.NDimension).asInt() self.M = data.inputValue(self.MDimension).asInt() poses_H = data.inputArrayValue(self.poses) pose_ids = OpenMaya.MIntArray() OpenMaya.MPlug(self.thisMObject(), self.poses).getExistingArrayAttributeIndices(pose_ids) self.poseUsed_ids = [] # find the necessary information to create the system self.nKeys = [] mValues = [] self.weights = [] for i in pose_ids: poses_H.jumpToElement(i) pose_H = poses_H.inputValue() state = pose_H.child(self.state).asBool() #wgt = pose_H.child(self.weight).asFloat() #if not (state and wgt>self.epsilon): # continue if not state: continue nKey_H = OpenMaya.MArrayDataHandle(pose_H.child(self.nKey)) nKey = [] mValue_H = OpenMaya.MArrayDataHandle(pose_H.child(self.mValue)) mValue = [] for n in range(self.N): # try in case there is nothing connected ... try: nKey_H.jumpToElement(n) key = nKey_H.inputValue().asFloat() nKey.append(key) except: nKey.append(0.0) # ignore the keys already present if nKey in self.nKeys: OpenMaya.MGlobal.displayWarning('key[%s] %s can not be used more than once' %(i, nKey)) continue for m in range(self.M): try: mValue_H.jumpToElement(m) value = mValue_H.inputValue().asFloat() mValue.append(value) except: mValue.append(0.0) self.nKeys.append(nKey) mValues.append(mValue) #self.weights.append(wgt) self.poseUsed_ids.append(i) poseUsed_num = len(self.poseUsed_ids) if poseUsed_num in (0, 1): OpenMaya.MGlobal.displayError('RbfSolver failed: valid poses number is less than 2') return False # for the continuation need to know the functions used: # Distance function ? # RBF function ? normalize = data.inputValue(self.normalize).asBool() distance_id = data.inputValue(self.distanceMode).asInt() self.distance_function = self.distance_functions[distance_id] rbf_id = data.inputValue(self.rbfMode).asInt() self.rbf_function = self.rbf_functions[rbf_id] # matrixNN to solve systems AX = Y # factorize la and solve la for each m # store the X (m) in self.mX distanceMax = 0.0 mat = MatrixNN() mat.setDimension(poseUsed_num) for i in range(poseUsed_num): for j in range(poseUsed_num): if i == j: # Here the distance of a pose on itself mat.rc[i][j] = 0.0 else: # Distance from each pose to each pose distance = self.distance_function(self.N, self.nKeys[i], self.nKeys[j]) # Stores the maximum distance between 2 poses, this will be used to standardize the system if distance > distanceMax: distanceMax = distance mat.rc[i][j] = distance # Use the scale for smoother more or less # If you want the standardized system, you have to divide the scale by the distanceMax fScale = data.inputValue(self.scale).asFloat() if fScale < self.epsilon: fScale = self.epsilon if normalize: self.fScale = fScale / distanceMax else: self.fScale = fScale # RBF each element for i in range(poseUsed_num): for j in range(poseUsed_num): mat.rc[i][j] = self.rbf_function(mat.rc[i][j] * self.fScale) # factorizeLU and save the ids of the swapped lines LU, Pids = mat.factorize_LU() # for each m of each pose # solv_LU and store the X (m) in self.mX # mX = m * nVector self.mX = [] for m in range(self.M): Y = [mValues[i][m] for i in range(poseUsed_num)] X = mat.solve_LU(LU, Pids, Y) # nVector coeff self.mX.append(X) #*** setClean indicates that the system is solved solved_H = data.outputValue(self.solved) solved_H.setClean() OpenMaya.MGlobal.displayInfo("RbfSolver recomputed using poses: %s" %self.poseUsed_ids) return True
def doIt(self, args): """ This method is called from script when this command is called. It should set up any class data necessary for redo/undo, parse any given arguments, and then call redoIt. """ argData = OpenMaya.MArgDatabase(self.syntax(), args) if argData.isFlagSet(kIndexFlag): self.__isIndex = True # Get the plug specified on the command line. slist = OpenMaya.MSelectionList() argData.getObjects(slist) if slist.length() == 0: print "Must specify an array plug in the form <nodeName>.<multiPlugName>." return plug = OpenMaya.MPlug() slist.getPlug(0, plug) if plug.isNull(): print "Must specify an array plug in the form <nodeName>.<multiPlugName>." return # Construct a data handle containing the data stored in the plug. dh = plug.asMDataHandle() adh = None try: adh = OpenMaya.MArrayDataHandle(dh) except: print "Could not create the array data handle." plug.destructHandle(dh) return # Iterate over the values in the multiPlug. If the index flag has been used, just return # the logical indices of the child plugs. Otherwise, return the plug values. for i in range(adh.elementCount()): try: indx = adh.elementIndex() except: advance(adh) continue if self.__isIndex: self.appendToResult(indx) else: h = adh.outputValue() if h.isNumeric(): if h.numericType() == OpenMaya.MFnNumericData.kBoolean: self.appendToResult(h.asBool()) elif h.numericType() == OpenMaya.MFnNumericData.kShort: self.appendToResult(h.asShort()) elif h.numericType() == OpenMaya.MFnNumericData.kInt: self.appendToResult(h.asInt()) elif h.numericType() == OpenMaya.MFnNumericData.kFloat: self.appendToResult(h.asFloat()) elif h.numericType() == OpenMaya.MFnNumericData.kDouble: self.appendToResult(h.asDouble()) else: print "This sample command only supports boolean, integer, and floating point values." advance(adh) plug.destructHandle(dh)
def compute(self, plug, data): # Input plug filter if plug != vmMultiGeometryConstraint.outTranslate_attr: return OpenMaya.kUnknownParameter # GET : meshes in_meshes = OpenMaya.MArrayDataHandle( data.inputValue(vmMultiGeometryConstraint.inputMeshes)) meshes = [in_meshes.inputValue().asMesh()] for i in xrange(in_meshes.elementCount() - 1): in_meshes.next() meshes.append(in_meshes.inputValue().asMesh()) # GET : Matrices in_matrices = OpenMaya.MArrayDataHandle( data.inputValue(vmMultiGeometryConstraint.inputMatrices)) matrices = [in_matrices.inputValue().asMatrix()] for i in xrange(in_matrices.elementCount() - 1): in_matrices.next() matrices.append(in_matrices.inputValue().asMatrix()) # GET : Input position mtx = data.inputValue( vmMultiGeometryConstraint.inputMatrix_attr).asMatrix() this_position = OpenMaya.MPoint(mtx(3, 0), mtx(3, 1), mtx(3, 2)) closest_delta = self.max_distance closest_point = OpenMaya.MFloatPoint() # Get input meshes count # mesh_plug.getExistingArrayAttributeIndices(self.indices_list) # Main loop for m, mat in zip(meshes, matrices): # # Get Mesh and closestPoint # mfnmesh = OpenMaya.MFnMesh(m) # this_closest_point = OpenMaya.MPoint() # mfnmesh.getClosestPoint(this_position, this_closest_point) # # Compare with before # this_delta = this_closest_point.distanceTo(this_position) # if this_delta < closest_delta: # closest_point = this_closest_point # closest_delta = this_delta # Get Mesh and closestPoint intersector = OpenMaya.MMeshIntersector() intersector.create(m, mat) this_closest_point = OpenMaya.MPointOnMesh() intersector.getClosestPoint(this_position, this_closest_point) this_closest_point = OpenMaya.MPoint(this_closest_point.getPoint()) # Compare with before this_delta = this_closest_point.distanceTo(this_position) if this_delta < closest_delta: closest_point = this_closest_point closest_delta = this_delta # Remember, remember, the fifth of November self.prev_pos = closest_point # for k in xrange(self.indices_list.length()): # mesh_handle.jumpToArrayElement(k) # temp_msh = OpenMaya.MFnMesh(mesh_handle.inputValue().asMesh()) # Set output rotate out_translate_dh = data.outputValue( vmMultiGeometryConstraint.outTranslate_attr) out_translate_dh.set3Float(closest_point.x, closest_point.y, closest_point.z) data.setClean(plug)
def deform(self, dataBlock, geoIterator, local2WorldMatrix, geomIndex): input = ompx.cvar.MPxGeometryFilter_input dataHandleInputArray = dataBlock.outputArrayValue(input) dataHandleInputArray.jumpToElement(geomIndex) dataHandleInputElement = dataHandleInputArray.outputValue() # inputMesh inputGeom = ompx.cvar.MPxGeometryFilter_inputGeom dataHandleInputGeom = dataHandleInputElement.child(inputGeom) inputMesh = dataHandleInputGeom.asMesh() # MFnMesh inputMFnMesh = om.MFnMesh(inputMesh) # 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() # 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.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() # 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.preTimeDict[geomIndex] = currentTime self.initialFlagDict[geomIndex] = True # for stable simulation, check the time difference whether it is 1 frame or not timeDiff = currentTime.value() - self.preTimeDict[geomIndex].value() if timeDiff > 1.0 or timeDiff < 0.0: self.initialFlagDict[geomIndex] = False self.preTimeDict[geomIndex] = om.MTime(currentTime) return # perGeometry hGeo = dataBlock.inputArrayValue(JiggleDeformerNode.perGeo) self.jump2Element(hGeo, geomIndex) hGeo.jumpToElement(geomIndex) hPerGeo = hGeo.inputValue() 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()) # 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() self.jump2Element(hJiggleMap, index) hJiggleMap.jumpToElement(index) self.jiggleMapDict[geomIndex].set( hJiggleMap.inputValue().asFloat(), ii) self.jump2Element(hStiffMap, index) hStiffMap.jumpToElement(index) self.stiffMapDict[geomIndex].set(hStiffMap.inputValue().asFloat(), ii) self.jump2Element(hDampMap, index) hDampMap.jumpToElement(index) self.dampMapDict[geomIndex].set(hDampMap.inputValue().asFloat(), ii) self.weightMapDict[geomIndex].set( self.weightValue(dataBlock, geomIndex, geoIterator.index()), ii) ii += 1 geoIterator.next() # 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 # 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, iterator, localToWorldMatrix, multiIndex): thisNode = self.thisMObject() if not block.inputValue(self.enabled).asBool(): return envelope = block.inputValue(self.envelope).asFloat() if envelope == 0.0: return if not block.inputValue(self.maxDistanceEnabled).asBool(): maxDistance = 0.0 else: maxDistance = block.inputValue( self.maxDistance).asDistance().value() maxDistanceUScaleEnabled = block.inputValue( self.maxDistanceUScaleEnabled).asBool() maxDistanceVScaleEnabled = block.inputValue( self.maxDistanceVScaleEnabled).asBool() if maxDistanceUScaleEnabled or maxDistanceVScaleEnabled: float2PtrUtil = om.MScriptUtil() float2PtrUtil.createFromList([0.0, 0.0], 2) float2Ptr = float2PtrUtil.asFloat2Ptr() if maxDistanceUScaleEnabled: maxDistanceUScaleAttr = om.MRampAttribute(thisNode, self.maxDistanceUScale) uValues = {} if maxDistanceVScaleEnabled: maxDistanceVScaleAttr = om.MRampAttribute(thisNode, self.maxDistanceVScale) vValues = {} falloffEnabled = block.inputValue(self.falloffEnabled).asBool() if falloffEnabled: falloffRampAttr = om.MRampAttribute(thisNode, self.falloff) if falloffEnabled or maxDistanceUScaleEnabled or maxDistanceVScaleEnabled: floatPtrUtil = om.MScriptUtil() floatPtrUtil.createFromDouble(0.0) floatPtr = floatPtrUtil.asFloatPtr() iteratorCount = iterator.count() if iteratorCount == 0: return if len(self.__membership__[multiIndex]) != iteratorCount: self.__membership__[multiIndex] = [] while not iterator.isDone(): index = iterator.index() self.__membership__[multiIndex].append(index) iterator.next() iterator.reset() indices = self.__membership__[multiIndex] if self.__weightsDirty__[multiIndex]: self.__weights__[multiIndex] = [] for index in self.__membership__[multiIndex]: self.__weights__[multiIndex].append( self.weightValue(block, multiIndex, index)) self.__weightsDirty__[multiIndex] = False weights = self.__weights__[multiIndex] if self.__maxDistanceWeightsDirty__[multiIndex]: maxDistanceWeightListArrayHandle = block.inputArrayValue( self.maxDistanceWeightList) JumpToElement(maxDistanceWeightListArrayHandle, multiIndex) maxDistanceWeightListHandle = maxDistanceWeightListArrayHandle.inputValue( ) maxDistanceWeightsArrayHandle = om.MArrayDataHandle( maxDistanceWeightListHandle.child(self.maxDistanceWeights)) self.__maxDistanceWeights__[multiIndex] = [] for index in self.__membership__[multiIndex]: JumpToElement(maxDistanceWeightsArrayHandle, index) self.__maxDistanceWeights__[multiIndex].append( maxDistanceWeightsArrayHandle.inputValue().asFloat()) self.__maxDistanceWeightsDirty__[multiIndex] = False maxDistanceWeights = self.__maxDistanceWeights__[multiIndex] pointsWorldSpace = [] while not iterator.isDone(): pointsWorldSpace.append(iterator.position() * localToWorldMatrix) iterator.next() # loop ptr vars intUtil = om.MScriptUtil() intUtil.createFromInt(0) intPtr = intUtil.asIntPtr() doublePtrUtil = om.MScriptUtil() doublePtrUtil.createFromDouble(0.0) doublePtr = doublePtrUtil.asDoublePtr() doublePtrUtil2 = om.MScriptUtil() doublePtrUtil2.createFromDouble(0.0) doublePtr2 = doublePtrUtil2.asDoublePtr() deltas = {} inputTargetArrayHandle = block.inputArrayValue(self.inputTarget) for i in range(inputTargetArrayHandle.elementCount()): inputTargetArrayHandle.jumpToArrayElement(i) inputTargetHandle = inputTargetArrayHandle.inputValue() if not inputTargetHandle.child(self.targetEnabled).asBool(): continue targetHandle = inputTargetHandle.child(self.target) targetData = targetHandle.data() if targetData.isNull(): continue targetType = targetHandle.type() targetPoint = om.MPoint() if targetType == om.MFnMeshData.kMesh: meshFn = om.MFnMesh(targetData) closestVertex = inputTargetHandle.child( self.closestVertex).asFloat() if closestVertex: tempPoint = om.MPoint() faceVertices = om.MIntArray() def getClosestPoint(startPoint): meshFn.getClosestPoint(startPoint, targetPoint, om.MSpace.kWorld, intPtr) if closestVertex: meshFn.getPolygonVertices( om.MScriptUtil(intPtr).asInt(), faceVertices) shortestDistance = None for vertexId in faceVertices: meshFn.getPoint(vertexId, tempPoint, om.MSpace.kWorld) vertexDistance = (startPoint - tempPoint).length() if shortestDistance is None or vertexDistance < shortestDistance: shortestDistance = vertexDistance closestVertexPoint = om.MPoint(tempPoint) return targetPoint * ( 1.0 - closestVertex) + om.MVector( closestVertexPoint * closestVertex) return targetPoint def setMaxDistanceUvScaleValues(uvPoint): if maxDistanceUScaleEnabled or maxDistanceVScaleEnabled: meshFn.getUVAtPoint(uvPoint, float2Ptr, om.MSpace.kWorld) if maxDistanceUScaleEnabled: uValues[index] = float2PtrUtil.getFloat2ArrayItem( float2Ptr, 0, 0) if maxDistanceVScaleEnabled: vValues[index] = float2PtrUtil.getFloat2ArrayItem( float2Ptr, 0, 1) elif targetType == om.MFnNurbsCurveData.kNurbsCurve: curveFn = om.MFnNurbsCurve(targetData) def getClosestPoint(startPoint): return curveFn.closestPoint(startPoint, doublePtr, 0.00001, om.MSpace.kWorld) def setMaxDistanceUvScaleValues(*args): if maxDistanceUScaleEnabled: uValues[index] = om.MScriptUtil.getDouble( doublePtr) / curveFn.numSpans() if maxDistanceVScaleEnabled and index in vValues: del vValues[index] elif targetType == om.MFnNurbsSurfaceData.kNurbsSurface: surfaceFn = om.MFnNurbsSurface(targetData) def getClosestPoint(startPoint): return surfaceFn.closestPoint(startPoint, doublePtr, doublePtr2, False, 0.00001, om.MSpace.kWorld) def setMaxDistanceUvScaleValues(*args): if maxDistanceUScaleEnabled: uValues[index] = om.MScriptUtil.getDouble( doublePtr) / surfaceFn.numSpansInU() if maxDistanceVScaleEnabled: vValues[index] = om.MScriptUtil.getDouble( doublePtr2) / surfaceFn.numSpansInV() elif targetType == om.MFnMatrixData.kMatrix: position = om.MPoint( om.MFnMatrixData( targetData).transformation().getTranslation( om.MSpace.kWorld)) def getClosestPoint(*args): return position def setMaxDistanceUvScaleValues(*args): if maxDistanceUScaleEnabled and index in uValues: del uValues[index] if maxDistanceVScaleEnabled and index in vValues: del vValues[index] else: raise ValueError('can never happen?') for index, weight, point in izip(indices, weights, pointsWorldSpace): if not weight: continue targetPoint = getClosestPoint(point) delta = targetPoint - point if index in deltas and deltas[index].length() < delta.length(): continue deltas[index] = targetPoint - point setMaxDistanceUvScaleValues(targetPoint) # maxDistance / falloff for vertexId, delta in deltas.iteritems(): listIndex = indices.index(vertexId) if maxDistance: deltaLength = delta.length() vertexMaxDistance = maxDistance * maxDistanceWeights[listIndex] if maxDistanceUScaleEnabled and vertexId in uValues: maxDistanceUScaleAttr.getValueAtPosition( uValues[vertexId], floatPtr) vertexMaxDistance *= om.MScriptUtil.getFloat(floatPtr) if maxDistanceVScaleEnabled and vertexId in vValues: maxDistanceVScaleAttr.getValueAtPosition( vValues[vertexId], floatPtr) vertexMaxDistance *= om.MScriptUtil.getFloat(floatPtr) if deltaLength > vertexMaxDistance: continue if falloffEnabled: lengthMaxDistancePercent = deltaLength / vertexMaxDistance falloffRampAttr.getValueAtPosition( float(1.0 - lengthMaxDistancePercent), floatPtr) falloff = om.MScriptUtil.getFloat(floatPtr) delta *= falloff pointsWorldSpace[ listIndex] += delta * weights[listIndex] * envelope pointsObjectSpace = om.MPointArray() worldToLocalMatrix = localToWorldMatrix.inverse() for point in pointsWorldSpace: pointsObjectSpace.append(point * worldToLocalMatrix) iterator.setAllPositions(pointsObjectSpace)
def compute(self, plug, dataBlock): outsAttr = [self.outputTAttr, self.outputRAttr, self.outputSAttr] if not (plug in outsAttr): return om.kUnknownParameter trsObj = trsClass.trsClass() # _________________________________ IN MATRIX masterTrs = [] arrayDataHandle = om.MArrayDataHandle( dataBlock.inputValue(self.inputMatrixAttr)) for i in range(arrayDataHandle.elementCount() - 1): arrayDataHandle.next() floatMatrix = (arrayDataHandle.inputValue()).asFloatMatrix() masterTrs.append( trsObj.createFromFloatMatrix(MMatrixToNum(floatMatrix))) # _________________________________ IN DYN ATTR dataHandle = dataBlock.inputValue(self.inputTimeAttr) intime = dataHandle.asFloat() dataHandle = dataBlock.inputValue(self.inputActivateAttr) activate = dataHandle.asFloat() dataHandle = dataBlock.inputValue(self.input1Attr) mass = dataHandle.asFloat() dataHandle = dataBlock.inputValue(self.input2Attr) elasticity = dataHandle.asFloat() dataHandle = dataBlock.inputValue(self.input3Attr) damping = dataHandle.asFloat() dataHandle = dataBlock.inputValue(self.input4Attr) gravity = dataHandle.asFloat() # _________________________________ SAVE NEXT EVAL dataHandle = dataBlock.inputValue(self.inputNext1Attr) self.nbrEval = dataHandle.asFloat() dataHandle = dataBlock.inputValue(self.inputNext2Attr) self.lastTime = dataHandle.asFloat() dataHandle = dataBlock.inputValue(self.inputNext3Attr) self.lastSpeed = dataHandle.asFloat3() self.lastSpeed = [ self.lastSpeed[0], self.lastSpeed[1], self.lastSpeed[2] ] self.slavesValues = [] arrayDataHandle = om.MArrayDataHandle( dataBlock.inputValue(self.inputNext4Attr)) for i in range(arrayDataHandle.elementCount() - 1): arrayDataHandle.next() slaveValue = (arrayDataHandle.inputValue()).asFloat3() self.slavesValues.append( [slaveValue[0], slaveValue[1], slaveValue[2]]) #_____________________________________________________________________________________COMPUTE gravityVector = [0, gravity, 0] #_______________ DELTA TIME incrEval = 0.04 self.nbrEval += incrEval curTime = self.nbrEval deltaTime = curTime - self.lastTime self.lastTime = curTime #_______________ DYNAMIC curentFrame = mc.currentTime(query=True) startFrame = mc.playbackOptions(query=True, minTime=True) if (activate == 0) or (curentFrame == startFrame): self.nbrEval = 0 self.lastTime = 0 self.lastSpeed = [0, 0, 0] self.slavesValues = [] for i in range(0, len(masterTrs)): self.slavesValues.append(masterTrs[i][0:3]) for i in range(1, len(masterTrs)): leadPos = masterTrs[i - 1] slavePos = masterTrs[i] baseLengths[i] = ompy.MVector( slavePos[0] - leadPos[0], slavePos[1] - leadPos[1], slavePos[2] - leadPos[2]).length() else: # FOLLOW DYN self.slaveValue[0] = inMatrices[0][0:3] for i in range(1, len(masterTrs)): leadPos = self.slavesValues[i - 1] slavePos = self.slavesValues[i] vLeadSlave = ompy.MVector(slavePos[0] - leadPos[0], slavePos[1] - leadPos[1], slavePos[2] - leadPos[2]) vLeadSlaveAdjust = vLeadSlave * (baseLengths[i] / vLeadSlave.length()) slavePosNew = [ leadPos[0] + vLeadSlaveAdjust.x, leadPos[1] + vLeadSlaveAdjust.y, leadPos[2] + vLeadSlaveAdjust.z ] self.slavesValues[i] = slavePosNew translate = self.slaveValue rotate = [0, 0, 0] scale = [1, 1, 1] #_____________________________________________________________________________________ OUT NEXT nodeName = self.name() mc.undoInfo(swf=0) mc.setAttr(nodeName + '.' + self.kInputNext1AttrName, self.nbrEval) mc.setAttr(nodeName + '.' + self.kInputNext2AttrName, self.lastTime) #mc.setAttr( nodeName +'.'+ self.kInputNext3AttrName , self.lastSpeed[0] , self.lastSpeed[1] , self.lastSpeed[2] , type = 'double3') for i in range(0, len(self.slavesValues)): mc.setAttr(nodeName + '.' + self.kInputNext4AttrName + '[{0}]'.format(i), self.slavesValues[i][0], self.slavesValues[i][1], self.slavesValues[i][2], type='double3') mc.undoInfo(swf=1) #_____________________________________________________________________________________COMPUTE OUT dataHandle = dataBlock.outputValue(self.outputTAttr) dataHandle.set3Double(translate[0], translate[1], translate[2]) dataHandle.setClean() dataHandle = dataBlock.outputValue(self.outputRAttr) dataHandle.set3Double(math.radians(rotate[0]), math.radians(rotate[1]), math.radians(rotate[2])) dataHandle.setClean() dataHandle = dataBlock.outputValue(self.outputSAttr) dataHandle.set3Double(scale[0], scale[1], scale[2]) dataHandle.setClean() dataBlock.setClean(plug)
def compute(self, plug, dataBlock): if (plug == self.weight): # print "============%s===============" % self.name() # NOTE 获取输出阈值 envelope = dataBlock.inputValue(self.envelope).asFloat() thersold = dataBlock.inputValue(self.thersold).asFloat() border = dataBlock.inputValue(self.border).asFloat() jntMatrix = dataBlock.inputValue(self.jntMatrix).asMatrix() jointPoint = OpenMaya.MPoint(jntMatrix(3, 0), jntMatrix(3, 1), jntMatrix(3, 2)) # ! ------------------------------------------- # ! 获取骨骼位置和表情点的位置 # ! ------------------------------------------- expGrpPlugs = OpenMaya.MPlug(self.thisMObject(), self.expGrp) expGrpArrayHandle = dataBlock.inputArrayValue(self.expGrp) weight_list = [] samll_list = [] data_list = [] index_list = OpenMaya.MIntArray() expGrpPlugs.getExistingArrayAttributeIndices(index_list) # NOTE 获取最后的序号值 last_idx = index_list[index_list.length() - 1] el_count = expGrpPlugs.elementByLogicalIndex(last_idx).child( self.expPt).numElements() # NOTE 如果最后的序号没有元素 去掉最后一个元素 index_list = list(index_list) if el_count else list( index_list)[:-1] weight_list = [0 for j in range(index_list[-1])] exp_pt_list = [] for idx in (index_list): expGrpPlug = expGrpPlugs.elementByLogicalIndex(idx) expGrpArrayHandle.jumpToElement(idx) expGrpHandle = expGrpArrayHandle.inputValue() expPtArrayHandle = OpenMaya.MArrayDataHandle( expGrpHandle.child(self.expPt)) expPtArrayHandle.jumpToElement(0) expPoint = OpenMaya.MPoint( *expPtArrayHandle.inputValue().asFloat3()) length = (jointPoint - expPoint).length() data = { "idx": idx, "len": length, "expPoint": expPoint, "expGrpPlug": expGrpPlug, } # print data["expGrpPlug"].child(self.expPt)[0].source().name().replace("editPoints","cv"),round(data["len"],2) data_list.append(data) # NOTE 添加 基准 的数据计算 base_weight if idx == 0: samll_list.append(data) # ! ------------------------------------------- # ! 过滤出最相近的两个点 # ! ------------------------------------------- # NOTE 取出长度最小的三个表情点 for data in heapq.nsmallest(3, data_list, key=lambda s: s['len']): # print data["expGrpPlug"].child(self.expPt)[0].source().name().replace("editPoints","cv"),round(data["len"],2) # NOTE 判断 idx 是否有重复的 避免重复添加 基准data for _data in samll_list: if data["idx"] == _data["idx"]: break else: samll_list.append(data) length_list = [data['len'] for data in samll_list] min_value = min(length_list) remap_list = self.minMaxNorm( length_list, min_val=0 if min_value > 0.1 else min_value, max_val=max(length_list)) base_weight = 1 for data, remap in zip(samll_list, remap_list): idx = data['idx'] weight = 1 if remap < thersold else 1 - remap # print "weight",weight if idx == 0: base_weight = remap basePoint = data['expPoint'] else: expPoint = data['expPoint'] info = self.calcPtInfo(basePoint, jointPoint, expPoint) jnt_len = info["vec_1_len"] exp_len = info["vec_2_len"] weight *= base_weight if jnt_len < thersold: weight = 0 elif data['len'] < thersold: weight = 1 # else: # angle = info["vec_1"]*info["vec_2"]/(jnt_len*exp_len) # reflect_len = jnt_len * math.cos(angle) # _weight = reflect_len / exp_len # _weight = _weight if _weight <= 1 else 1/_weight # weight *= _weight # # print self.name(),math.cos(angle),weight weight_list[idx - 1] = 0 if weight < border else ( weight - border) / (1 - border) weight_list = [ weight * envelope if weight * envelope < 1 else 1 for weight in self.rangeValueFilter(weight_list, 2) ] # NOTE 只保留最大值 max_value = max(weight_list) weight_list = [ 0 if weight < max_value else weight for weight in weight_list ] # NOTE 遍历输出权重值 weightArrayHandle = dataBlock.outputArrayValue(self.weight) weightBuilder = weightArrayHandle.builder() for j, weight in enumerate(weight_list): weightHandle = weightBuilder.addElement(j) weightHandle.setFloat(weight) weightHandle.setClean() # NOTE 设置输出数值 weightArrayHandle.set(weightBuilder) weightArrayHandle.setAllClean() dataBlock.setClean(plug) else: return OpenMaya.kUnknownParameter