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,562 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,563 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

Type a product name

______
icon-svg-close-thick

Cookie preferences

Your privacy is important to us and so is an optimal experience. To help us customize information and build applications, we collect data about your use of this site.

May we collect and use your data?

Learn more about the Third Party Services we use and our Privacy Statement.

Strictly necessary – required for our site to work and to provide services to you

These cookies allow us to record your preferences or login information, respond to your requests or fulfill items in your shopping cart.

Improve your experience – allows us to show you what is relevant to you

These cookies enable us to provide enhanced functionality and personalization. They may be set by us or by third party providers whose services we use to deliver information and experiences tailored to you. If you do not allow these cookies, some or all of these services may not be available for you.

Customize your advertising – permits us to offer targeted advertising to you

These cookies collect data about you based on your activities and interests in order to show you relevant ads and to track effectiveness. By collecting this data, the ads you see will be more tailored to your interests. If you do not allow these cookies, you will experience less targeted advertising.

icon-svg-close-thick

THIRD PARTY SERVICES

Learn more about the Third-Party Services we use in each category, and how we use the data we collect from you online.

icon-svg-hide-thick

icon-svg-show-thick

Strictly necessary – required for our site to work and to provide services to you

Qualtrics
W
Akamai mPulse
W
Digital River
W
Dynatrace
W
Khoros
W
Launch Darkly
W
New Relic
W
Salesforce Live Agent
W
Wistia
W
Tealium
W
Upsellit
W
CJ Affiliates
W
Commission Factory
W
Google Analytics (Strictly Necessary)
W
Typepad Stats
W
Geo Targetly
W
SpeedCurve
W
Qualified
#

icon-svg-hide-thick

icon-svg-show-thick

Improve your experience – allows us to show you what is relevant to you

Google Optimize
W
ClickTale
W
OneSignal
W
Optimizely
W
Amplitude
W
Snowplow
W
UserVoice
W
Clearbit
#
YouTube
#

icon-svg-hide-thick

icon-svg-show-thick

Customize your advertising – permits us to offer targeted advertising to you

Adobe Analytics
W
Google Analytics (Web Analytics)
W
AdWords
W
Marketo
W
Doubleclick
W
HubSpot
W
Twitter
W
Facebook
W
LinkedIn
W
Yahoo! Japan
W
Naver
W
Quantcast
W
Call Tracking
W
Wunderkind
W
ADC Media
W
AgrantSEM
W
Bidtellect
W
Bing
W
G2Crowd
W
NMPI Display
W
VK
W
Adobe Target
W
Google Analytics (Advertising)
W
Trendkite
W
Hotjar
W
6 Sense
W
Terminus
W
StackAdapt
W
The Trade Desk
W
RollWorks
W

Are you sure you want a less customized experience?

We can access your data only if you select "yes" for the categories on the previous screen. This lets us tailor our marketing so that it's more relevant for you. You can change your settings at any time by visiting our privacy statement

Your experience. Your choice.

We care about your privacy. The data we collect helps us understand how you use our products, what information you might be interested in, and what we can improve to make your engagement with Autodesk more rewarding.

May we collect and use your data to tailor your experience?

Explore the benefits of a customized experience by managing your privacy settings for this site or visit our Privacy Statement to learn more about your options.