Saturday, October 28, 2017

mesh snap, join, and split maya script

Hi,

I was working on merging a separate eye lid to existing face mesh and thought these tools would be handy so I wrote them.
use at your own risk.

first i wanted a way for the outer border of the eyelids to automatically snap to existing edges of the face.  So here is the snap script at work:





i wanted a way to quickly join the split eyelid mesh with existing face:



it should also work with joining multiple meshes:





finally wanted a way to split areas off of separate eyelid mesh i didn't need by edgeloop:
here is the personal script i wrote:

"""useful for merging split eyelids/or lips onto existing mesh

@author Nathaniel Anozie
Modify at your own risk
last updated: 10/28/2017 -- initial release

application:
facial modeling
body modeling

for maya
wip for blender

description naSnapToMesh:
snaps given vertices to closest vertex on mesh, will use selection if no vertices specified. should support a selected edgeloop.
usage:
import naSeam
naSeam.naSnapToMesh('polySurface1')
"""

import maya.cmds as cmds

def naSnapToMesh(mesh, vertices=[]):
    """snaps given vertices to closest vertex on mesh, will use selection if no vertices specified.
    should support a selected edgeloop.
    #mesh = 'polySurface2' #this would be the entire face mesh, place want to merge to
    #vertices = ['polySurface1.vtx[0]', 'polySurface1.vtx[2]'] #these would be eyelid boundary vertices
    """
    if not vertices:
        selection = cmds.filterExpand(cmds.polyListComponentConversion(toVertex=True),sm=31)
        vertices = selection
        
    if not vertices:
        print 'could not find vertices to snap'
        return
        
    cpmNode = cmds.createNode('closestPointOnMesh')
    cmds.connectAttr(mesh+'.worldMesh[0]', cpmNode+'.inMesh')
    indexExternal = 2
    for vtxExternal in vertices:
        cmds.select(cpmNode,replace=True)
        cmds.select(vtxExternal,replace=True)
        posExternal = cmds.xform( vtxExternal, translation=True, query=True, ws=True)
        cmds.setAttr( cpmNode+'.inPositionX', posExternal[0] )
        cmds.setAttr( cpmNode+'.inPositionY', posExternal[1] )
        cmds.setAttr( cpmNode+'.inPositionZ', posExternal[2] )
        vtxIndex = cmds.getAttr( cpmNode+'.result.closestVertexIndex' )
        vtx = mesh+'.vtx[%s]'%(vtxIndex)
        vtxPos = cmds.xform( vtx, translation=True, query=True, ws=True)
        #actual moving of external mesh to meet mesh
        cmds.xform( vtxExternal, translation=vtxPos, ws=True)
    cmds.delete(cpmNode)


def naJoin(meshes=[]):
    """
    merges given or selected meshes
    """
    if not meshes:
        meshes = cmds.ls(selection=True) #should check all selected are meshes
    
    if not meshes:
        print 'no meshes to combine'
        return
        
    def _join(meshA,meshB):
        #meshA = 'polySurface2'
        #meshB = 'polySurface1'
        meshCombine = cmds.polyUnite(meshA,meshB) #combine meshes
        vertices = cmds.polyListComponentConversion(meshCombine,toVertex=True)
        cmds.polyMergeVertex(vertices)#merge all vertices
        meshC = [x for x in meshCombine if cmds.objectType(x) != 'polyUnite']
        cmds.delete(meshCombine, ch=True)#clean mesh
        return meshC[0]
        
    meshA = meshes[0]
    for meshB in meshes[1:]:
        meshA = _join(meshA,meshB)

def naSplit():
    """
    split by selected edge loop. note select loop one inside then where want split to accomodate face conversion from selection.
    result meshes get parented to world.  i think works on one mesh at a time.
    """
    edges = cmds.ls(selection=True)
    faces = cmds.polyListComponentConversion(edges, toFace=True)
    cmds.polyChipOff(faces,dup=False)
    meshParent = faces[0].split('.')[0]
    mesh = cmds.listRelatives(meshParent,children=True,type='mesh')[0]
    sepResult = cmds.polySeparate(mesh)
    for x in sepResult:
        if not cmds.objExists(x):
            continue
        if cmds.objectType(x) != 'polySeparate':
            cmds.delete(x,ch=True)
            cmds.parent(x,world=True)
    cmds.delete(meshParent) 
 
 
hope you find it helpful.
 
Happy Scripting!
Nate