Hello! I just finished doing a small script that is really helpful to encode proximity data from scalp to cards. The issue I have right now is that the script is really... REALLY heavy, like it takes a long time to process 50k tries. Anyone has tips on how to improve the result? Thanks alot!
import maya.cmds as cmds import math total =  selected = cmds.ls(sl=True) obj = selected furVtx = cmds.ls(obj+'.vtx[*]', fl=True) obj = selected skinVtx = cmds.ls(obj+'.vtx[*]', fl=True) for vertsFur in furVtx: furVtxPos = cmds.xform(vertsFur, q=True, ws=True, t=True) for vertsSkin in skinVtx: skinVtxPos = cmds.xform(vertsSkin, q=True, ws=True, t=True) d = math.sqrt((skinVtxPos - furVtxPos)**2 + (skinVtxPos - furVtxPos)**2 + (skinVtxPos - furVtxPos)**2) #print('Distance between:', vertsFur, vertsSkin, d) total.append(d) r= min(total) total.clear() cmds.select(vertsFur) cmds.polyColorPerVertex(r=r, cdo=True)
I don't do much Maya scripting anymore because I hate it.
Maya is really slow when dealing with lists of vertices and other similar objects.
Using openmaya will help.
Alternatively using the string name representation of the vertices rather than the object itself can help in certain circumstances. Anything to avoid nested loops of actual Maya objects is good basically
I would use Open Maya 2.0 and iterate on MfnMesh points. Should be a lot faster.
You are having a loop inside a loop. If both list of vertices have 50k entries, that means you have to iterate 2,500,000,000 times. And everytime you do a (nested) squareroot operation with list accesses etc.
There is no way that you can use another library and it will be fast all of the sudden. You have to rethink your problem and figure out a way to solve in a different way to achieve actual improvement of performance.
Using openmaya will make it orders of magnitude faster which is usually enough.
As I said above the problem is in the way Maya's standard python API deals with lists of Maya objects - which is slow. Openmaya sidesteps that
Would be very interesting to see what difference it actually makes. :)
Huge per-vertex operations are typically slow when going with just maya.cmds and pymel due to the nature of the programming language (Python). What I would suggest is to use the Maya API instead.
Easiest stepping-stone into that would be the Python bindings (OpenMaya). Create a vertex iterator (MItMeshVertex class) and init it from an MSelectionList of vertices.
Not only do you get vastly faster looping speeds (due to the underlying C++ code running) but you also get access to the mesh function set's (MFnMesh) utility functions which can be used to apply updated component data to all components (in this case: vertices) to the entire mesh, in one single go without having to loop.
Having only previous expereience of high-level programming, it can feel daunting to dive into the Maya API which due to it being more low-level, also has much higher complexity. But the API is powerful, the Python bindings are great and the documentation is up-to-date and well written. Most things you need are found in the function sets (classes by the name of MFn), the iterators (classes by the name MIt), the MSelectionList and MDagPath objects and the MGlobal static class.
The concepts that was the hardest for me to understand was MObjects and how they work with function sets. (MObjects are just generic containers of raw data - and depending on the data they are compatible with only some function sets (MFn)) - that and MPlugs (which are like interfaces to an object's attributes). 90% of the classes in the docs you will most likely never touch. If you can learn all the bold classes mentioned above you will have a very solid foundation of the Maya API.
quick OpenMaya example of using a mesh intersector to get closest point on surface
import maya.OpenMaya as OpenMaya
selectionList = OpenMaya.MSelectionList()
dagPath = OpenMaya.MDagPath()
def distToSurface(src, trg):
srcDagPath = getDagPath(src)
if not srcDagPath:
if not srcDagPath.hasFn(OpenMaya.MFn.kMesh):
trgDagPath = getDagPath(trg)
if not trgDagPath:
if not trgDagPath.hasFn(OpenMaya.MFn.kMesh):
if trgDagPath.apiType() != OpenMaya.MFn.kMesh:
trgNode = trgDagPath.node()
matrix = trgDagPath.inclusiveMatrix()
intersector = OpenMaya.MMeshIntersector()
iterVert = OpenMaya.MItMeshVertex(srcDagPath)
pointInfo = OpenMaya.MPointOnMesh()
colors = OpenMaya.MColorArray()
while not iterVert.isDone():
pos = iterVert.position(OpenMaya.MSpace.kWorld)
hitPoint = OpenMaya.MPoint(pointInfo.getPoint().x, pointInfo.getPoint().y, pointInfo.getPoint().z) * matrix
# TODO: what unit scale ?
dist = pos.distanceTo(hitPoint)
colors[iterVert.index()].r = dist
colors[iterVert.index()].g = 0
colors[iterVert.index()].b = 0
colors[iterVert.index()].a = 1
meshFn = OpenMaya.MFnMesh(srcDagPath)
if not meshFn.numColorSets():
vertices = OpenMaya.MIntArray()
compFn = OpenMaya.MFnSingleIndexedComponent()
In theory 5-10k times faster..
You're absolutely not wrong though, the fastest way to do this would be to do it differently