Retargeting Unity Animations with Python

Hey there,

 

I'm Jeremias Meister, a technical artist at ICAROS based in Munich. At ICAROS, we develop mostly VR Games using Unity 3D.

 

Sometimes, we also tend to buy Assets from the Asset-Store if we think it is a well-placed investment in time, money and gained creativity. We bought an Asset containing around 40 Animations for our newest project, including models, textures, blendshapes, materials, and scripts. The Asset came with a huge overload of features, which we didn't really need. Mainly we were interested in the animations, probably the model as well. I imported the Asset into Maya and cleaned all the unneeded blendshapes, fixed some UV layouts, and reapplied the skinning afterward to export a fine model for our use. But while cleaning the Asset, Maya got rid of all the white space in the joint naming conventions and had some ugly FBX string conversion issues.

 

That's where Python came in handy. In Maya,  already had a rename Script to fix all the FBX naming issues.

name = "".join(o)
new_name = name.replace("FBXASC195FBXASC182", "oe")
new_name = new_name.replace("FBXASC195FBXASC164","ae")
new_name = new_name.replace("FBXASC045","")
new_name = new_name.replace("FBXASC032b","")
new_name = new_name.replace("FBXASC032","")
new_name = new_name.replace("FBXASC195FBXASC188","ue")
new_name = new_name.replace("FBXASC195FBXASC159","ss")    
cmds.rename(name,new_name)

This was quite simple but very effective when running it through a loop over my entire joint hierarchy.

 

 

 

The Export of the cleaned FBX brought me to the next issue. Maya got rid of some formatting in the Joint Hierarchy names, which resulted in animations not being read correctly in Unity anymore. 

 

Luckily Unity .anim files are written in clear text, which makes editing possible.

 path: CG/Pelvis/RThigh/RCalf/RHorseLink/RFoot
  - curve:
      serializedVersion: 2
      m_Curve:
      - serializedVersion: 3
        time: 0
        value: {x: 0.15276116, y: 0.15276143, z: -0.69040847, w: 0.6904087}
        inSlope: {x: 0, y: 0, z: 0, w: 0}
        outSlope: {x: 0, y: 0, z: 0, w: 0}
        tangentMode: 0
        weightedMode: 0
        inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334, w: 0.33333334}
        outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334, w: 0.33333334}
      - serializedVersion: 3
        time: 1.3000001
        value: {x: 0.15276136, y: 0.15276125, z: -0.6904085, w: 0.6904086}
        inSlope: {x: 0.00000022351765, y: 0.0000008940706, z: 0, w: 0}
        outSlope: {x: 0.00000022351765, y: 0.0000008940706, z: 0, w: 0}
        tangentMode: 0
        weightedMode: 0
        inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334, w: 0.33333334}
        outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334, w: 0.33333334}
      - serializedVersion: 3
...

As said, I was able to read out all the 40+ animation files with Python and fix the naming issues I had easily.

import os
import glob


def openFile(filename):
    rawString = ""
    with open(filename,"r") as f:
        rawString = f.read()
    return rawString


def writeFile(inputstring,filename):
    with open(filename, "w") as f:
        f.write(inputstring)


def getFiles(folderpath):
    if not folderpath.endswith("/"):
        folderpath = folderpath + "/"
    files = [f for f in glob.glob(folderpath + "**/*.*", recursive=True)]
    animationfiles = []
    for file in files:
        if file.endswith(".anim"):
            fullpath = file
            animationfiles.append(fullpath)
    return animationfiles




def cleanFiles(folder):
    filelist = getFiles(folder)
    for path in filelist:
        path = path.replace("\\","/")
        print(path)
        myString = openFile(path)
        '''the following part may need change depending on the animations that get cleaned. here we are cleaning the malbers dragon rig and its animations'''
        myString = myString.replace("Chest Extra 1","ChestExtra1")
        myString = myString.replace("L ","L").replace("L","L ",1)
        myString = myString.replace("L\n      ","L")
        myString = myString.replace("R ","R")
        myString = myString.replace("R\n      ","R")


        myString = myString.replace("Eye L","EyeL")
        myString = myString.replace("Eye R","EyeR")
        myString = myString.replace("Wing L","WingL")
        myString = myString.replace("Wing R","WingR")
        myString = myString.replace("Finger ","Finger")
        myString = myString.replace("Wing\n      ","Wing")




        writeFile(myString,path)

As you can see, some of the original names even had line breaks included or multiple white spaces. 

 

 

 

To be said at the end, though, I recommend to be really careful and probably use some file versioning like git before editing the animation files. It is quite easy to break something and make the file unusable. 

 

I hope this is interesting for someone :)

 

have a nice day,

 

cheers

 

Jere

Write a comment

Comments: 0