Hi All,
I have written the following code for a specific case. I want to copy the weight of a vertex to a Nurbs Surface CV in basically the same location.
However I have multiple Nurbs Surfaces under one transform that are all connected to one skinCluster.
import maya.api.OpenMaya as om
import maya.api.OpenMayaAnim as oma
from maya import cmds
import time
def geo_weights_to_surface(source, target, tol=0.005, space=om.MSpace.kWorld):
start = time.time()
# Mesh
mesh_sel = om.MSelectionList().add(source)
mesh_dag_path = mesh_sel.getDagPath(0)
mesh_dag_path.extendToShape()
mesh_node = om.MFnDependencyNode(mesh_dag_path.node())
mesh_attr = mesh_node.attribute('inMesh')
mesh_plug = mesh_node.findPlug(mesh_attr, 0)
mesh_sc_array = mesh_plug.connectedTo(True, False)
mesh_sc_node = mesh_sc_array[0].node()
mesh_sc = oma.MFnSkinCluster(mesh_sc_node)
mesh_influences = mesh_sc.influenceObjects()
# Surface
surf_sel = om.MSelectionList().add(target)
surf_dag_path = surf_sel.getDagPath(0)
shape_nr = surf_dag_path.numberOfShapesDirectlyBelow()
# Append shapes to array
shapes = om.MDagPathArray()
for idx in range(shape_nr):
dag_path = surf_sel.getDagPath(0)
dag_path.extendToShape(idx)
shapes.append(dag_path)
mesh_itr = om.MItMeshVertex(mesh_dag_path)
while not mesh_itr.isDone():
vtx_pos = mesh_itr.position(space)
vtx = mesh_itr.currentItem()
for item in range(len(shapes)):
surf_itr = om.MItSurfaceCV(shapes[item])
while not surf_itr.isDone():
while not surf_itr.isRowDone():
cv_pos = surf_itr.position(space)
check = cv_pos.isEquivalent(vtx_pos, tol)
if check:
surf_dag_path = surf_sel.getDagPath(0)
surf_dag_path.extendToShape(item)
shape_node = om.MFnDependencyNode(surf_dag_path.node())
surf_attr = shape_node.attribute('create')
surf_plug = shape_node.findPlug(surf_attr, 0)
surf_sc_array = surf_plug.connectedTo(True, False)
surf_sc_node = surf_sc_array[0].node()
surf_sc = oma.MFnSkinCluster(surf_sc_node)
for mesh_inf in range(len(mesh_influences)):
mesh_inf_idx = mesh_sc.indexForInfluenceObject(
mesh_influences[mesh_inf])
vtx_weight = mesh_sc.getWeights(mesh_dag_path, vtx, mesh_inf_idx)
vtx_blend_weight = mesh_sc.getBlendWeights(mesh_dag_path, vtx)
cv_uv = surf_itr.uvIndices()
cv_component = om.MFnNurbsSurface(surf_dag_path).cv(cv_uv[0],
cv_uv[1])
surf_inf_idx = surf_sc.indexForInfluenceObject(
mesh_influences[mesh_inf])
surf_sc.setWeights(surf_dag_path, cv_component, surf_inf_idx,
vtx_weight[0], normalize=True)
surf_sc.setBlendWeights(surf_dag_path, cv_component,
vtx_blend_weight)
surf_itr.next()
surf_itr.nextRow()
mesh_itr.next()
print 'Copying weights took', time.time() - start, 'seconds.'
The code does exactly what I want, but I think I've made it quite slow by adding the surface iterator inside of the vertex iterator.
What would be the most efficient way to make it faster? Separate the loops?
Thanks in advance!
def geo_weights_to_surface(source, target, tol=0.005, space=om.MSpace.kWorld):
start = time.time()
# Mesh
mesh_sel = om.MSelectionList().add(source)
mesh_dag_path = mesh_sel.getDagPath(0)
mesh_dag_path.extendToShape()
mesh = om.MFnMesh(mesh_dag_path)
mesh_node = om.MFnDependencyNode(mesh_dag_path.node())
mesh_attr = mesh_node.attribute('inMesh')
mesh_plug = mesh_node.findPlug(mesh_attr, 0)
mesh_sc_array = mesh_plug.connectedTo(True, False)
mesh_sc_node = mesh_sc_array[0].node()
mesh_sc = oma.MFnSkinCluster(mesh_sc_node)
mesh_influences = mesh_sc.influenceObjects()
# Surface
surf_sel = om.MSelectionList().add(target)
surf_dag_path = surf_sel.getDagPath(0)
shape_nr = surf_dag_path.numberOfShapesDirectlyBelow()
# Append shapes to array
shapes = om.MDagPathArray()
for idx in range(shape_nr):
dag_path = surf_sel.getDagPath(0)
dag_path.extendToShape(idx)
shapes.append(dag_path)
for item in range(len(shapes)):
surf_dag_path = surf_sel.getDagPath(0)
surf_dag_path.extendToShape(item)
shape_node = om.MFnDependencyNode(surf_dag_path.node())
surf_attr = shape_node.attribute('create')
surf_plug = shape_node.findPlug(surf_attr, 0)
surf_sc_array = surf_plug.connectedTo(True, False)
surf_sc_node = surf_sc_array[0].node()
surf_sc = oma.MFnSkinCluster(surf_sc_node)
surf = om.MFnNurbsSurface(shapes[item])
surf_itr = om.MItSurfaceCV(shapes[item])
while not surf_itr.isDone():
while not surf_itr.isRowDone():
pos = surf_itr.position()
float_pos = om.MFloatPoint(pos.x, pos.y, pos.z)
uvs = surf_itr.uvIndices()
cv_normal = surf.normal(uvs[0], uvs[1], space=space)
dir_vector = om.MFloatVector(cv_normal.x, cv_normal.y, cv_normal.z)
facenr = mesh.closestIntersection(float_pos, dir_vector, space, 0.05, True)[2]
face_sel = om.MSelectionList().add(source + '.f[' + str(facenr) + ']')
face_component = face_sel.getComponent(0)[1]
face_itr = om.MItMeshFaceVertex(mesh_dag_path, face_component)
while not face_itr.isDone():
if face_itr.position().isEquivalent(pos, tol):
vtx_idx = face_itr.vertexId()
idx_sel = om.MSelectionList().add(source + '.f[' + str(vtx_idx) + ']')
vtx = idx_sel.getComponent(0)[1]
for mesh_inf in range(len(mesh_influences)):
mesh_inf_idx = mesh_sc.indexForInfluenceObject(
mesh_influences[mesh_inf])
vtx_weight = mesh_sc.getWeights(mesh_dag_path, vtx, mesh_inf_idx)
vtx_blend_weight = mesh_sc.getBlendWeights(mesh_dag_path, vtx)
cv_uv = surf_itr.uvIndices()
cv_component = om.MFnNurbsSurface(surf_dag_path).cv(cv_uv[0], cv_uv[1])
surf_inf_idx = surf_sc.indexForInfluenceObject(
mesh_influences[mesh_inf])
surf_sc.setWeights(surf_dag_path, cv_component, surf_inf_idx,
vtx_weight[0], normalize=True)
surf_sc.setBlendWeights(surf_dag_path, cv_component, vtx_blend_weight)
face_itr.next()
surf_itr.next()
surf_itr.nextRow()
face_itr = om.MItMeshPolygon(mesh_dag_path) # Do this only once per mesh
face_itr.setIndex(facenr) # Do this in your "while not surf_itr.isRowDone()" loop