Announcements

Between mid-October and November, the content on AREA will be relocated to the Autodesk Community M&E Hub and the Autodesk Community Gallery. Learn more HERE.

Lattice to skincluster convert?

Lattice to skincluster convert?

dg3duy
Collaborator Collaborator
1,554 Views
4 Replies
Message 1 of 5

Lattice to skincluster convert?

dg3duy
Collaborator
Collaborator

There is a way to convert a lattice that affects a geometry into skin clusters. I found a script that I try to use in Maya 2020 and it does not work, can anyone tell me if it is really possible?
lattice.gif
here is what I found on the internet but apparently in my case it doesn't work in maya 2020
https://github.com/subing85/subins_tutorials/tree/master/latticeToSkincluster 

0 Likes
Accepted solutions (1)
1,555 Views
4 Replies
Replies (4)
Message 2 of 5

jmreinhart
Advisor
Advisor
Accepted solution

The code worked fine for me. I did run through it and add some comments and additional description. 

What happens when you try to run it? Do you get an error? Does it do nothing? Or does it do something incorrectly?

 

One thing to note about the conversion from lattice to skinCluster (at least the way that this script does it) is that rotation may not behave as expected.

 

This is an example scene that I ran the scene in. In the below you see what happens when I translate a joint. In RED is the result that the lattice produces originally produced. And in BLACK you can see the result the new skinCluster produced the exact same results.

jmreinhart_0-1673724316798.png

In this second image you see the result of rotating that joint instead. The lattice and skinCluster do not produce the same result. 

jmreinhart_1-1673724467975.png

 

You will end with some useful weights either way but if rotation is involved the results won't be identical. 

If you have a single non-rotating joint per point on the lattice though. Then the conversion will be identical. 

A conversion method that may be better would be to attach a joint to each point of the lattice that has the same influence on the final mesh as that lattice point. 

 

Anyway here is the commented version of the code.

'''
#Lattice weights transfer to skincluster
Data            : April 11, 2017
last modified   : April 15, 2017
Author          : Subin Gopi
subing85@gmail.com
Description     : 

Select a lattice that is modifed by a skinCluster.
This script will convert the deformations done by the lattice,
into skinCluster deformation. 
There will be differences in the result if the lattice is 
deformed by joints that rotate. 

Input           : mesh > lattice > skincluster
Maya version    : Maya 2016
''' 

import maya.api.OpenMaya as om
import maya.api.OpenMayaAnim as oma
import maya.cmds as cmds

def convertLatticeToSkinCluster():
    # Get the selection in the scene
    selectList = cmds.ls (sl=1)
    # Get the first item (the ffd node) from the first selected item (the lattice)
    latticeShape = cmds.listRelatives (selectList[0], type='lattice')[0]
    ffd = cmds.listConnections (latticeShape, type='ffd')[0]
    # Get the skinCluster that affects the lattice
    skincluster = cmds.listConnections (latticeShape, type='skinCluster')[0]
    # Get the geometry that the lattice affects
    geometry = cmds.lattice (latticeShape, q=1, g=1)[0]# NOTE: This only handles one geometry 
    # Get the joints that affect the lattice
    jointList = cmds.skinCluster (skincluster, q=1, inf=1)

    # Convert the geometry from as string to a DagPath 
    meshMSelection = om.MSelectionList ()
    meshMSelection.add (geometry)
    meshDagPath = meshMSelection.getDagPath (0)

    # Get the original position of the vertices of the mesh
    mFnMesh = om.MFnMesh (meshDagPath)
    geoPosition = mFnMesh.getPoints (om.MSpace.kObject)

    # Get the weights
    weightList = []
    # For each each joint
    for index in range (len(jointList)) :    
        # Check if the joint has a parent or a child 
        jntParent = cmds.listRelatives (jointList[index], p=1)
        jntChild = cmds.listRelatives (jointList[index], c=1)
        
        # If it has a parent then parent the joint to the world
        # NOTE : we do this because if the joint moves it's children
        # then the weights we calculate would include the weights
        # of the children.

        if jntParent :
            cmds.parent (jointList[index], w=1)

        # If it has a child then parent the child to the world
        if jntChild :
            cmds.parent (jntChild[0], w=1)

        # Convert the joint from a string to a DagPath
        jointMSelection = om.MSelectionList ()
        jointMSelection.add (jointList[index])
        jointDagPath = jointMSelection.getDagPath (0)
        
        # Get the worldspace position of the joint
        mFnTransform = om.MFnTransform (jointDagPath)
        world = mFnTransform.translation (om.MSpace.kWorld)
        # Move it by one unit
        moveWorld = om.MVector (world.x + 1, world.y, world.z)
        mFnTransform.setTranslation (moveWorld, om.MSpace.kWorld)
        
        # Get the positions of the vertices of the mesh after the joint is moved
        movePosition = mFnMesh.getPoints (om.MSpace.kObject)    
        jointWeights = []       
        # The distance each point moved is equal the to influence the joint
        # has on the mesh via the lattice.
        for vertexIndex in range (len(movePosition)) :
            length = movePosition[vertexIndex] - geoPosition[vertexIndex]
            weight = length.length ()
            jointWeights.append (weight)       

        # Store the weights for this joint
        weightList.append (jointWeights)  

        # Move the joint back to where it was  
        mFnTransform.setTranslation (world, om.MSpace.kWorld)
        
        # Put the joints back in the original heirarchy
        if jntParent :
            cmds.parent (jointList[index], jntParent[0])
        if jntChild :
            cmds.parent (jntChild[0], jointList[index])      

    # Skin the mesh
    # NOTE : this assumes this assumes the mesh is not already skinned
    geoSkinCluster = cmds.skinCluster (jointList, geometry)[0]

    # Get the skinCluster as an MObject and create a functionSet for it
    skinMSelection = om.MSelectionList ()    
    skinMSelection.add (geoSkinCluster)
    skinMObject = skinMSelection.getDependNode (0)
    mfnSkinCluster = oma.MFnSkinCluster (skinMObject)   

    # Get the vertex components using the API
    vertexIndexList = range (len(geoPosition))
    mfnIndexComp = om.MFnSingleIndexedComponent ()
    vertexComp = mfnIndexComp.create (om.MFn.kMeshVertComponent)
    mfnIndexComp.addElements (vertexIndexList)

    # Get the index of each of the influences
    # The order of these indices will match the 
    influenceObjects = mfnSkinCluster.influenceObjects ()
    influenceList = om.MIntArray ()
    for eachInfluenceObject in influenceObjects :
        currentIndex = mfnSkinCluster.indexForInfluenceObject (eachInfluenceObject)
        influenceList.append (currentIndex)    

    # Convert the weights from a python list of lists to an MDoubleArray
    # So that we can set the weights using the functionSet
    mWeightList = om.MDoubleArray ()
    for wIndex in range (len(weightList[0])) :
        for jntIndex in range (len(weightList)) :  
            mWeightList.append (weightList[jntIndex][wIndex]) 

    # Set the weights on the mesh
    mfnSkinCluster.setWeights (meshDagPath, vertexComp, influenceList, mWeightList)

    # Turn off the lattice and the skinCluster that affects the lattice
    cmds.setAttr ('%s.envelope' % skincluster, 0)
    cmds.setAttr ('%s.envelope' % ffd, 0)

 

Message 3 of 5

dg3duy
Collaborator
Collaborator

@jmreinhart Tell me the exact steps you used to use it, I have a character that uses lattice in the skirt skirt and applying the script does nothing. I know that I should do a basic test that so far I could not do, thank you for your time in responding and have tested the code.

0 Likes
Message 4 of 5

jmreinhart
Advisor
Advisor

Follow the steps that are in the description for the script 

Select a lattice that is modifed by a skinCluster.
This script will convert the deformations done by the lattice,
into skinCluster deformation. 
There will be differences in the result if the lattice is 
deformed by joints that rotate. 

 If it's doing nothing then maybe you are not calling the code properly. You need to load the script in your script editor and execute it. Then run the function that the code defines.

convertLatticeToSkinCluster()

 

Message 5 of 5

dg3duy
Collaborator
Collaborator

I was missing the most basic step to execute this line.🙈 

convertLatticeToSkinCluster(

 

0 Likes