Skip to content

Instantly share code, notes, and snippets.

@zclongpop123
Created December 8, 2021 07:30
Show Gist options
  • Save zclongpop123/f16f1e52a780e39fb1603bdf5bb556a7 to your computer and use it in GitHub Desktop.
Save zclongpop123/f16f1e52a780e39fb1603bdf5bb556a7 to your computer and use it in GitHub Desktop.
Smooth绑定模型
from maya import cmds,mel
import maya.api.OpenMaya as om
import maya.api.OpenMayaAnim as oma
# info
# only use for Catmull-Clark subdivision !!!!
# make sure both mesh was bound to the same skeleton !!!!
# step 1. select source mesh
# step 2. select smooth mesh
# step 3. run script
# create by jmelon 2019/11/30
# have fun :)
def convert_str_to_depend_node(name):
selection_list = om.MGlobal.getSelectionListByName(name)
return selection_list.getDependNode(0)
def convert_str_to_Component(name):
selection_list = om.MGlobal.getSelectionListByName(name)
return selection_list.getComponent(0)
def getSkinCluster(mesh):
skin_cluster = mel.eval('findRelatedSkinCluster("{}")'.format(mesh))
if skin_cluster:
return skin_cluster, convert_str_to_depend_node(skin_cluster)
def GetWeightMap(shape, skin, pCount):
comp = convert_str_to_Component(shape.fullPathName())
jointCount = len(skin.influenceObjects())
weightMap = list()
weights = skin.getWeights(comp[0], comp[1])[0]
for i in range(0, pCount* jointCount, jointCount):
weightMap.append( [i for i in weights[i:i+ jointCount] ] )
return weightMap
#----------------
def GetEdgeFacesMap(mesh):
edgeIter = om.MItMeshEdge(mesh)
edgeFaces = list()
while not edgeIter.isDone():
edgeFaces.append(edgeIter.getConnectedFaces())
edgeIter.next()
return edgeFaces
def GetVertexEdgesMap(mesh):
vIter = om.MItMeshVertex(mesh)
vertexEdges = list()
while not vIter.isDone():
vertexEdges.append(vIter.getConnectedEdges())
vIter.next()
return vertexEdges
def GetFaceVertexMap(Mesh):
fIter = om.MItMeshPolygon(Mesh)
faceVertices = list()
while not fIter.isDone():
faceVertices.append(fIter.getVertices())
fIter.next(1)
return faceVertices
def GetVertexVertices(mesh):
vIter = om.MItMeshVertex(mesh)
vv = list()
while not vIter.isDone():
vv.append( vIter.getConnectedVertices() )
vIter.next()
return vv
def GetVertexAroundVertices(mesh, fvRel):
vIter = om.MItMeshVertex(mesh)
vv = list()
va = list()
while not vIter.isDone():
vv.append( vIter.getConnectedVertices() )
vt = list()
fArray = vIter.getConnectedFaces()
for face in fArray:
vt += fvRel[face]
t = set(vt)- set(vv[-1])
t.remove(vIter.index())
va.append( list( t) )
vIter.next()
return [vv, va ]
# #-------------------
def FindEdgeFromPoints(points, edgeRel):
edge0 = edgeRel[points[0]]
edge1 = edgeRel[points[1]]
isc = set(edge0)&set(edge1)
if len(isc) == 1:
return list(isc)[0]
else:
print "error"
return False
def FindAroundPoints(points, vRel, bound):
ap = list()
for point in points:
ap += vRel[point]
ap = set(ap)
return list( x for x in ap if x < bound )
def SmoothWeight():
cmds.progressWindow( title='SmoothWeight',
progress=0,
status='begin',
isInterruptable= False )
selectList = om.MGlobal.getActiveSelectionList()
source = selectList.getDagPath(0)
smooth = selectList.getDagPath(1)
sourceCount = om.MFnMesh(source).numVertices
smoothCount = om.MFnMesh(smooth).numVertices
sourcePtSet = set(range(sourceCount))
relatetionMap = dict()
IE = list() # inner edge points
IF = list() # inner face points
EE = list() # edge points
ieRelMap = list() # n x []*4, 2edge + 4 surd
eeRelMap = list() # n x []*2
ifRelMap = list() # n x []*4
#
cmds.progressWindow( edit=True, progress=5, status=("Initialization data" ) )
#
edgeFacesMap = GetEdgeFacesMap(source)
vertexEdgesMap = GetVertexEdgesMap(source)
faceVerticesMap = GetFaceVertexMap(source)
VertexVerticesMap = GetVertexAroundVertices(source, faceVerticesMap) # [vv, va ]
subVertexVerticesMap = GetVertexVertices(smooth)
#
cmds.progressWindow( edit=True, progress=10, status=("Initialization data" ) )
#
# get source weight map
skinName, skinNode = getSkinCluster(source)
skin = oma.MFnSkinCluster( skinNode )
sourceWeights = GetWeightMap(source, skin, sourceCount) #
jointCount = len(skin.influenceObjects())
# bind smooth mesh ----------------------------
# if your smooth mesh already bind joints, comment out
cmds.select(d=True)
js = cmds.skinCluster(skinName, query= True, inf=source.fullPathName())
cmds.skinCluster(js, smooth.fullPathName(), tsb= True)
#--------------------------------------------------
#split edge and inner points , get IFRELSHAPE
vIter = om.MItMeshVertex(smooth)
for index in xrange(sourceCount, smoothCount):
nearVertice = subVertexVerticesMap[index]
around = list()
for nIndex in nearVertice:
if nIndex < sourceCount:
around.append(nIndex)
if len(around) == 0:
IF.append(index)
ifRelMap.append( FindAroundPoints(nearVertice, subVertexVerticesMap, sourceCount) )
else:
relatetionMap.update( {index: around } )
#split IE and EE
for index in relatetionMap.keys():
edge = FindEdgeFromPoints( relatetionMap[index], vertexEdgesMap)
connectFaces = edgeFacesMap[edge]
if len(connectFaces) == 2:
IE.append(index)
ieRelMap.append( relatetionMap[index] + list( set( faceVerticesMap[ connectFaces[0] ] ) ^ set( faceVerticesMap[connectFaces[1] ] ) ) )
else:
EE.append(index)
eeRelMap.append( relatetionMap[index] )
#
cmds.progressWindow( edit=True, progress=30, status=("Caculate Source Weight" ) )
#
smWeightMap = [ [0.0]*jointCount for i in range(smoothCount) ]
for index in xrange(sourceCount):
around = VertexVerticesMap[0][index]
subAround = VertexVerticesMap[1][index]
count = len(around)
if count > 2 :
smWeightMap[index]= [ i* 0.55 for i in sourceWeights[index] ]
subCount = len(subAround)
mult = (0.35 / count) if subCount != 0 else (0.45/count)
for pt in around:
smWeightMap[index] = [ i+j*mult for i, j in zip(smWeightMap[index], sourceWeights[pt]) ]
smult = (0.1 / subCount) if subCount != 0 else 0
for pt in subAround:
smWeightMap[index] = [ i+j*smult for i, j in zip(smWeightMap[index], sourceWeights[pt]) ]
else:
smWeightMap[index] = [ i* 0.75 for i in sourceWeights[index] ]
for pt in around:
smWeightMap[index] = [ i+ j*0.125 for i, j in zip(smWeightMap[index], sourceWeights[pt]) ]
#
cmds.progressWindow( edit=True, progress=60, status=("Caculate New Weight" ) )
#
# get new points weight map
for index in xrange(len(IE)):
around = ieRelMap[index]
pt = IE[index]
smWeightMap[pt] = [ (i+j)*0.375 for i, j in zip(sourceWeights[around[0]], sourceWeights[around[1]]) ]
count = len(around)
mult = 0.25/(count-2)
for sub in xrange(2, count):
smWeightMap[pt] = [ i+j*mult for i, j in zip(smWeightMap[pt], sourceWeights[ around[sub]]) ]
for index in xrange(len(EE)):
around = eeRelMap[index]
pt = EE[index]
smWeightMap[pt] = [ (i+ j)*0.5 for i, j in zip(sourceWeights[around[0]], sourceWeights[around[1]]) ]
for index in xrange(len(IF)):
around = ifRelMap[index]
pt = IF[index]
count = len(around)
for sub in around:
smWeightMap[pt] = [ i+ j/count for i, j in zip( smWeightMap[pt], sourceWeights[sub]) ]
#
cmds.progressWindow( edit=True, progress=80, status=("Set WeightMap" ) )
#
# set weight
singleIdComp = om.MFnSingleIndexedComponent()
vertexComp = singleIdComp.create( om.MFn.kMeshVertComponent )
singleIdComp.addElements( range(smoothCount) )
influence = convert_List_I_to_MArray( range(jointCount) )
vWeights = convert_List_D_to_MArray( smWeightMap )
sskinName, sskinNode = getSkinCluster(smooth)
sskin = oma.MFnSkinCluster( sskinNode )
sskin.setWeights(smooth, vertexComp, influence, vWeights, normalize=True)
#
cmds.progressWindow( edit=True, progress=100, status=("Finish" ) )
cmds.progressWindow(endProgress=1)
#
return
def convert_List_I_to_MArray(userList):
count = len(userList)
mArray = om.MIntArray().setLength(count)
mArray[:] = userList[:]
return mArray
def convert_List_D_to_MArray(userList):
jCount = len(userList[0])
pCount = len(userList)
count = jCount* pCount
mArray = om.MDoubleArray().setLength(count)
t = []*count
for i in xrange(pCount):
start = i*jCount
t[start : (start+ jCount) ] = userList[i][:]
for i in xrange(count):
mArray[i] = t[i]
return mArray
def SmoothWeightApplyFunc(*args):
sel = cmds.ls(sl=True)
if sel:
for ii in sel:
skin = mel.eval('findRelatedSkinCluster("{}")'.format(ii))
shape = cmds.listRelatives(ii, c=1, type="mesh")[0]
if cmds.objectType(shape) == 'mesh' and skin != '':
target = cmds.duplicate(ii,n=ii+'_smoothLv')[0]
cmds.polySmooth(target,mth=0,sdt=2,kb=1,ksb=1,khe=1)
cmds.DeleteHistory(target)
cmds.select(ii,target,r=True)
print ii,target
SmoothWeight()
cmds.select(cl=True)
else:
cmds.warning('please check your object, it must be mesh or it had been skincluster')
def showWindow(*args):
global SW_Window
SW_Window = "SW_Window"
if cmds.window(SW_Window, ex=1):
cmds.deleteUI(SW_Window, wnd=1)
cmds.window(SW_Window, title="Smooth Weight Apply Func Window", width=400)
cmds.columnLayout(adjustableColumn=True)
cmds.text(u"\n 选择模型执行,会生成一个新的smooth一次的模型 \n")
cmds.button(label=u"Apply", c=SmoothWeightApplyFunc)
cmds.showWindow(SW_Window)
showWindow()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment