Creating a curve-based wireframe

maya
python

#1

I am trying to ‘extract and convert’ all the edges of the polygon (based on selection) into curves, then parent the curves as one. This is like a curve-based wireframe model.

While Maya has a functionality that allows all edges to be converted into curves, but the functionality - “Polygon Edges to Curves”, it works but not very ideal in my case as I would want all the created curves to be combined into one.

import maya.cmds as cmds
import pymel.core as pm

edges = cmds.filterExpand(cmds.polyListComponentConversion(te=1),sm=32,ex=1)
cur_list = []
for edge in edges:
    vtx = cmds.ls(cmds.polyListComponentConversion(edge,fe=1,tv=1),fl=1)
    p1 = cmds.pointPosition(vtx[0])
    p2 = cmds.pointPosition(vtx[1])
    created_curve = cmds.curve(d=1,p=(p1,p2))
    cur_list.append(created_curve)

# Select all the newly created curves
for cur in cur_list:
    cmds.select(cur, add=True)

# Get list of objects
shape_list = pm.ls(pm.listRelatives(c=True))
grp_list = pm.ls(pm.group(em=True, n='curve#'))
list_all = []
for obj in grp_list:
    list_all.extend(shape_list)
    list_all.extend(grp_list)

# Parent (shape) objects to one Curve
pm.select(list_all)
pm.parent(r=True, s=True)

While this code of mine does work, but if I tried to use it on a higher subdivision polygon, for example, create a normal pSphere and sets both its “Subdivisions Axis” and “Subdivisions Height” to 100, and execute the code I wrote.
What happens here is that:

  • Maya seems to be hanging
  • Took a very long while to be process (seems to be more than 1 hour plus before that current maya session of mine crashes.)

What can be done to minimize this long processing time? I am assuming that part of this ‘long’ time is due to the commands that I am using it to derive the vertex and creating them?


#2

Right off the bat I’d take a look at the selection commands you’re using. Those can get time consuming, and aren’t really necessary for this script.

edges = cmds.filterExpand(cmds.polyListComponentConversion(te=1),sm=32,ex=1)
cur_list = []
for edge in edges:
    vtx = cmds.ls(cmds.polyListComponentConversion(edge,fe=1,tv=1),fl=1)
    p1 = cmds.pointPosition(vtx[0])
    p2 = cmds.pointPosition(vtx[1])
    created_curve = cmds.curve(d=1,p=(p1,p2))
    cur_list.append(created_curve)

    # Parent shape objects to one transform
    pm.parent(pm.listRelatives(cur_list, c=True), pm.group(em=True, n='curve#'), r=True, s=True)

I tested both versions on a 10x10x10 cube. The new version was ~13 seconds, while the new one ran in ~1.8.

There might also be improvements to make in creating the curves, but I’m not very familiar with manipulating geometry in code.


#3

Oh, I had meant to explain the selection speed thing a bit better. Adding or removing objects from selections can be time consuming, especially if you’re doing it a lot. It’s generally better to select a lot of things at once rather than repeatedly modifying a selection.

So this:

pm.select(cur_list)

is much faster than this:

for cur in cur_list:
    pm.select(cur, add=True)

That change alone took almost 11 seconds off the execution time of the 10x10x10 box test I ran.

It’s even better if you don’t need to change the selection at all. The parent command you used at the end can operate on an argument list, so I used that instead of the current selection and shaved off a little more time.


#4

@Zackaroni I definitely agree with your improvements. But for some reason, your script took 7 seconds to run on my computer, but it was also leaving a lot of separate groups, unless I missed something. I think xenas wants them all combined in one transform, if I understand correctly. By changing pm.listRelatives() to this:

for each in curve_list:
    pm.parent(each.getShape(), parentTransform, r=True, s=True) # shape parent
    pm.delete(each) # delete the old transform

It went down to 3 seconds from 7 seconds.

This script uses shape parenting to combine every new curve under a single transform. Note that I also use a list comprehension to get all the point positions instead of using separate variables for p1 and p2. (I guess each edge should only ever have 2 points, but I don’t know! But the curve command can just take a list of any length anyway.)

import time
import pymel.core as pm

timeStart = time.clock()

curve_list = []
edges = cmds.filterExpand(cmds.polyListComponentConversion(te=1),sm=32,ex=1)
for edge in edges:
    points = cmds.ls(cmds.polyListComponentConversion(edge,fe=1,tv=1),fl=1)
    pointPositions = [cmds.pointPosition(pnt) for pnt in points]
    created_curve = pm.curve(d=1,p=pointPositions)
    curve_list.append(created_curve)

parentTransform = pm.group(em=True, n='edge_results') # the parent group for all curves
for each in curve_list:
    pm.parent(each.getShape(), parentTransform, r=True, s=True) # shape parent
    pm.delete(each) # delete the old transform

# stop the timer
timeStop = time.clock()
print('Execution time: %s seconds.'%(timeStop-timeStart))

If more speed enhancements are needed, it would likely be necessary to use OpenMaya. I also tried using a generator function instead of appending the curves to a list, and saw no speed improvement. That might help if you are doing thousands of edges.