Selecting Every N-th Face in Maya

So I stumbled across this post on Reddit from a week ago that asked how to select every n-th face in Maya. There is a way to select every other n-th edge but faces seemed more complicated and it got me thinking in some possibilities.

This is the code I came up with after thinking about it:

from maya import cmds

sel = cmds.ls(orderedSelection=True)
faces_list = cmds.ls(cmds.polyListComponentConversion(sel, toFace=True), flatten=True)
if cmds.objectType(sel[0]) == "transform":
    found_faces_dict = {}
else:
    found_faces_dict = {sel[0]:cmds.ls(cmds.polyListComponentConversion(sel[0], toEdge=True), flatten=True)}

for face in faces_list:
    connected_edges_list = cmds.ls(cmds.polyListComponentConversion(face, toEdge=True), flatten=True)
    if not len(found_faces_dict):
        found_faces_dict[face] = connected_edges_list
        continue
    else:
        match_count = 0
        for found_face in found_faces_dict:
            found_edge_list = found_faces_dict[found_face]
            for fedge in found_edge_list:
                if fedge in connected_edges_list:
                    match_count += 1
        if not match_count:
            found_faces_dict[face] = connected_edges_list

cmds.select(clear=True)
for face in faces_list:
    if face in found_faces_dict:
        cmds.select(face, add=True)

My solution is based on the rule that for a face to be selected it can’t share any immediate edges with previously selected faces. Seems to work well in random shapes I tested!

I used orderedSelection so the first face you select is always included and you have some control over the result. If the whole object is selected then it starts by selecting f[0].

This selects every other face but to select every 2nd or 3rd face in an edge loop or selection of faces I thought I could traverse the topology to find connected faces and skip N like this:

from maya import cmds

every_other = 5 # replace for number of faces to skip

sel = cmds.ls(orderedSelection=True)
faces_list = cmds.ls(cmds.polyListComponentConversion(sel, toFace=True), flatten=True)
faces_list.remove(sel[0])

cmds.select(sel[0])
every_other_count = 0

current_face = sel[0]
count = 0
while len(faces_list) and count < 1000:
    connected_edges_list = cmds.ls(cmds.polyListComponentConversion(current_face, toEdge=True), flatten=True)
    found_face = False
    for edge in connected_edges_list:
        connected_faces = cmds.ls(cmds.polyListComponentConversion(edge, toFace=True), flatten=True)
        for face in connected_faces:
            if face in faces_list:
                faces_list.remove(face)
                current_face = face
                if every_other_count == every_other:
                    every_other_count = 0
                    cmds.select(face, add=True)
                else:
                    every_other_count += 1
                found_face = True
                break
        if found_face:
            found_face = False
            break
    count += 1

Works as expected when you have a selection that doesn’t loop like in the example above.
On cylinders that do a round loop sometimes the traversal goes to the opposite direction.
In random selections that have unconnected faces the while loop just never exits so I added a count variable for not hanging Maya forever.

Fun study! Learning a couple things.

Node-based matrix twist calculator python snippet

Following on Vasil Shotarov’s awesome tutorial, I’ve scripted a setup to read angles and have been using it a lot lately. Pretty stable and saves me a lot of time!

def quatTwistReader(name, axis='x'):
    # returns grp, reader, quaternionNode
    reader = cmds.group(empty=True, name=name+"_twist_reader")
    reader_grp = cmds.group(reader, name=reader+"_grp")
    mm = cmds.createNode("multMatrix", name=name+"_mm")
    cmds.connectAttr(reader+".worldMatrix[0]", mm+".matrixIn[0]")
    cmds.connectAttr(reader_grp+".worldInverseMatrix[0]", mm+".matrixIn[1]")
    dm = cmds.createNode("decomposeMatrix", name=name+"_dm")
    cmds.connectAttr(mm+".matrixSum", dm+".inputMatrix")
    qte = cmds.createNode("quatToEuler", name=name+"_qte")
    cmds.connectAttr(dm+".outputQuat"+axis.upper(), qte+".inputQuat"+axis.upper())
    cmds.connectAttr(dm+".outputQuatW", qte+".inputQuatW")

    return reader_grp, reader, qte

Usage example of a wrist twist:

STEP 1
Run quatTwistReader(“l_wrist”, “x”). Double-check your rig for the desired axis you want to extract but it’s usually X as in the axis that goes along a chain.

STEP 2
Parent constrain the top “l_wrist_twist_reader_grp” (reader_grp variable) result to your hierarchy so the reader is always in the correct orientation. For the wrist it should constrained to the last bendy joint of the forearm, right before the hand.

STEP 3
Orient constrain the hand joint to command the “l_wrist_twist_reader” (reader variable).

STEP 4
Use the “outputRotateX” of the “l_wrist_qte” (qte variable – quatToEuler node) for your objective, it should be outputting only the twisting in the X axis.

STEP 5
Profit 😎


Tip: if you’re getting flips before 180 and everything is aligned properly, try changing the inputRotateOrder in the quatToEuler node to match your ctrls/jnts

Fixing Maya’s camera focus

Sometimes Maya camera gets corrupted and when you try to focus on objects it just goes really far away and usually this behavior persists on all scenes you open from there on.

A quick way that has worked for me to fix it is to first close all open Maya sessions, then find your userPrefs.mel file and search for this line:

-fv "defaultFitFactor" 0

Just change the value to 1 and it should fix your issue.

If you don’t want to edit the file directly you can run the following MEL command inside Maya:

optionVar -fv "defaultFitFactor" 1;

Or the alternative Python command:

from maya import cmds
cmds.optionVar( fv=('defaultFitFactor', 1) )

When applying any of these fixes make sure there is only the current Maya session running or you might overwrite the fix by closing a Maya session that still has the old value set.