Hi Michael!

Thanks so much for the tip. I had a look at the function you mentioned and 
wrote this as improvement using that. From what I've tested it performs on 
meshes up to 900k faces in roughly 0.7 seconds compared to roughly 8 
seconds for the old version.
I'm pretty sure this is still not the fastest way to do this, but it's 
already way faster than it was before. So if you have any other improvement 
points I'd like to hear it!

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()

    print 'Copying weights took', time.time() - start, 'seconds.'



On Thursday, September 12, 2019 at 2:40:37 AM UTC+2, Michael Boon wrote:
>
> Yeah that will be very slow for large meshes. I'm not sure if there's a 
> straightforward way to fix it.
> You could double the speed by keeping a list of booleans to mark when a cv 
> has been paired with a vert, so you don't check that cv again, but I expect 
> that doubling the speed is not good enough.
> You might want to look into MFnMesh.closestIntersection. For any cv (and 
> its surface normal), that should get you the closest point on the mesh 
> without needing to check all the verts. Then you can use the returned 
> triangle and barycentric coordinates to get the closest vertex quickly.
>
> It's also possible there's a faster way built-in, using some part of the 
> Transfer Attributes functionality. I'm not sure.
>
> On Tuesday, 3 September 2019 22:42:19 UTC+10, Jesse K. wrote:
>>
>>
>>
>> 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!
>>
>>

-- 
You received this message because you are subscribed to the Google Groups 
"Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to python_inside_maya+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/python_inside_maya/5c57a6f4-8cff-419d-bba4-ad7968f59e2e%40googlegroups.com.

Reply via email to