I'm glad that helped.
You're still doing a lot of work for every vertex of every polygon (meaning
most verts are hit many times), and also for every influence object for
each of those verts.
I'm not completely clear on what you're doing there, but I think you can
still make it significantly faster if you want to.
I think you could use hitTriangle, hitBary1 and hitBary2 (returned from
mesh.closestIntersection) to get 3 vertices and their relative distances to
your hit location, rather than getting all the verts for each polygon. Then
you could choose the closest vert and avoid a bunch of work.
If you do want to average the skinning from multiple verts, you could look
up all your verts' skinning influences and weights first, so you don't have
to look each vert up once for every polygon it is part of. That might make
it 2x faster or more if you're lucky.
You can move indexForInfluenceObject out of the loops and save a lot of
calls to that. I assume (but I'm not sure) that a dict lookup would be
faster than that call. You can move cv_uv and cv_component out of that loop
too since they will return the same thing every time.
When you call surf_sc.setWeights you have normalize=True. It would be
faster to leave that false and then normalize all weights after you're
done. It's also possible this is the slowest call in your whole algorithm
and it might be worth trying to build your own lists and do a single call
to setWeights right at the end. You could use the cprofile module to
measure your algorithm and find out which function calls are taking the
most time.
You can get away without composing strings for your faces or verts. That
should be faster too. Here's an example for a face. There's an equivalent
for vertices and for face-vertices too.
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
On Friday, 13 September 2019 19:05:02 UTC+10, Jesse K. wrote:
>
> 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.'
>
>
>
--
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 [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/python_inside_maya/ecaec038-6ae3-4c46-bb11-07fdb6590813%40googlegroups.com.