import math from maya import OpenMaya, cmds # ---------------------------------------------------------------------------- def getSelectedMeshes(): """ Get all selected meshes, the current selection will be looped and checked if any of the selected transforms contain a mesh node. If this is the case the transform will be added to the selection list. :return: Parents nodes of all selected meshes :rtype: list """ # get selection selection = cmds.ls(sl=True, l=True) extendedSelection = [] # extend selection for sel in selection: extendedSelection.extend( cmds.listRelatives(sel, s=True, ni=True, f=True) ) # return parent of meshes return list(set([ cmds.listRelatives(m, p=True, f=True)[0] for m in extendedSelection if cmds.nodeType(m) == "mesh" ])) # ---------------------------------------------------------------------------- def setLaplacianSmooth( dag, index, space, sourceL, targetL, blendshapeL, smooth ): """ Laplacian smoothing algorithm, where the average of the neighbouring points are used to smooth the target vertices, based on the factor between the average length of both the source and the target mesh. :param OpenMaya.MDagPath dag: :param int index: Component index :param OpenMaya.MSpace space: :param float sourceL: :param float targetL: :param float blendshapeL: :param float smooth: """ # calculate factor component = asComponent(index) avgL = getAverageLength(dag, component, space) targetF = blendshapeL/sourceL if sourceL and targetL else 1 blendshapeF = avgL/targetL if sourceL and blendshapeL else 1 factor = abs((1-targetF/blendshapeF)*smooth) factor = max(min(factor, 1), 0) # ignore if there is not smooth factor if not factor: return # get average position component = asComponent(index) vtx = OpenMaya.MItMeshVertex(dag, component) origP, avgP = getAveragePosition(dag, component, space) # get new position avgP = avgP * factor origP = origP * (1-factor) newP = avgP + OpenMaya.MVector(origP) # set new position vtx.setPosition(newP, space) def getAveragePosition(dag, component, space): """ Get average position of connected vertices. :param OpenMaya.MDagPath dag: :param OpenMaya.MFnSingleIndexedComponent component: :param OpenMaya.MSpace space: :return: Average length of the connected edges :rtype: OpenMaya.MPoint """ averagePos = OpenMaya.MPoint() # get connected vertices connected = OpenMaya.MIntArray() iterate = OpenMaya.MItMeshVertex(dag, component) iterate.getConnectedVertices(connected) # get original position originalPos = iterate.position(space) # ignore if no vertices are connected if not connected.length(): return averagePos # get average component = asComponent(connected) iterate = OpenMaya.MItMeshVertex(dag, component) while not iterate.isDone(): averagePos += OpenMaya.MVector(iterate.position(space)) iterate.next() averagePos = averagePos/connected.length() return originalPos, averagePos def getAverageLength(dag, component, space): """ Get average length of connected edges. :param OpenMaya.MDagPath dag: :param OpenMaya.MFnSingleIndexedComponent component: :param OpenMaya.MSpace space: :return: Average length of the connected edges :rtype: float """ total = 0 lengthUtil = OpenMaya.MScriptUtil() lengthPtr = lengthUtil.asDoublePtr() # get connected edges connected = OpenMaya.MIntArray() iterate = OpenMaya.MItMeshVertex(dag, component) iterate.getConnectedEdges(connected) # ignore if no edges are connected if not connected.length(): return 0 # get average component = asComponent(connected, OpenMaya.MFn.kMeshEdgeComponent) iterate = OpenMaya.MItMeshEdge(dag, component) while not iterate.isDone(): iterate.getLength(lengthPtr, space) total += lengthUtil.getDouble(lengthPtr) iterate.next() return total/connected.length() # ---------------------------------------------------------------------------- def getBasename(name): """ Strip the parent and namespace data of the provided string. :param str name: :return: Base name of parsed object :rtype: str """ return name.split("|")[-1].split(":")[-1] # ---------------------------------------------------------------------------- def asMIntArray(index): """ index -> OpenMaya.MIntArray :param int/OpenMaya.MIntArray index: indices :return: Array of indices :rtype: OpenMaya.MIntArray """ if type(index) != OpenMaya.MIntArray: array = OpenMaya.MIntArray() array.append(index) return array return index def asComponent(index, t=OpenMaya.MFn.kMeshVertComponent): """ index -> OpenMaya.MFn.kComponent Based on the input type it will create a component type for this tool the following components are being used. * OpenMaya.MFn.kMeshVertComponent * OpenMaya.MFn.kMeshEdgeComponent :param int/OpenMaya.MIntArray index: indices to create component for :param OpenMaya.MFn.kComponent t: can be all of OpenMaya component types. :return: Initialized components :rtype: OpenMaya.MFnSingleIndexedComponent """ # convert input to an MIntArray if it not already is one array = asMIntArray(index) # initialize component component = OpenMaya.MFnSingleIndexedComponent().create(t) OpenMaya.MFnSingleIndexedComponent(component).addElements(array) return component # ---------------------------------------------------------------------------- def asMObject(path): """ str -> OpenMaya.MObject :param str path: Path to Maya object :rtype: OpenMaya.MObject """ selectionList = OpenMaya.MSelectionList() selectionList.add(path) obj = OpenMaya.MObject() selectionList.getDependNode(0, obj) return obj def asMDagPath(obj): """ OpenMaya.MObject -> OpenMaya.MDagPath :param OpenMaya.MObject obj: :rtype: OpenMaya.MDagPath """ return OpenMaya.MDagPath.getAPathTo(obj) def asMFnMesh(dag): """ OpenMaya.MDagPath -> OpenMaya.MfnMesh :param OpenMaya.MDagPath dag: :rtype: OpenMaya.MfnMesh """ return OpenMaya.MFnMesh(dag)