Level One Magic
"Any sufficiently advanced technology is indistinguishable from magic." - Arthur C. Clarke
FBXMayaExport.mel
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////
// find all meshes that contain a specific texture
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////
global proc string[] getMeshesWithTexture(string $fileNode)
{
    string $meshes[] = {};
    string $materials[] = `connectionInfo -dfs ($fileNode + ".outColor")`;
    for($material in $materials)
    {
        $material = basenameEx($material);
        string $shaders[] = `connectionInfo -dfs ($material + ".outColor")`;
        for($shader in $shaders)
        {
            $shader = basenameEx($shader);
            string $shapes[] = `sets -q -no $shader`;
            for($shape in $shapes)
            {
                string $parents[] = `listRelatives -p -f $shape`;
                $meshes[size($meshes)] = $parents[0];
            }
        }
    }
    return $meshes;
}

// ///////////////////////////////////////////////////////////////////////////////////////////////////////////
// find all file nodes with animated textures
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////
global proc string[] getAnimatedFileNodes()
{
    string $animated[] = {};
    string $fileNodes[] = `ls -typ "file"`;
    for($fileNode in $fileNodes)
    {
        string $conn = `connectionInfo -sfd ($fileNode + ".translateFrame")`;
        if($conn != "")
            if(size(`keyframe -q -tc (basenameEx($conn))`) > 0)
            {
                $animated[size($animated)] = $fileNode;
                $animated[size($animated)] = basenameEx($conn);
            }
    }
    return $animated;
}

// ///////////////////////////////////////////////////////////////////////////////////////////////////////////
// Get the values of the animation
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////
global proc float[] getScrollValues(string $place2d)
{
    float $value[] = { 0.0, 0.0, 0.0 };
    float $keyTimes[] = `keyframe -q -tc ($place2d + ".translateFrameU")`;
    if(size($keyTimes) == 2)
    {
        float $keyValues[] = `keyframe -q -vc ($place2d + ".translateFrameU")`;
        $value[0] = 24.0 / ($keyTimes[1] - $keyTimes[0]) * $keyValues[1];
    }
    $keyTimes = `keyframe -q -tc ($place2d + ".translateFrameV")`;
    if(size($keyTimes) == 2)
    {
        float $keyValues[] = `keyframe -q -vc ($place2d + ".translateFrameV")`;
        $value[1] = 24.0 / ($keyTimes[1] - $keyTimes[0]) * $keyValues[1];
    }
    $keyTimes = `keyframe -q -tc ($place2d + ".rotateFrame")`;
    if(size($keyTimes) == 2)
    {
        float $keyValues[] = `keyframe -q -vc ($place2d + ".rotateFrame")`;
        $value[2] = 24.0 / ($keyTimes[1] - $keyTimes[0]) * ($keyValues[1]/360);
    }
    return $value;
}

// ///////////////////////////////////////////////////////////////////////////////////////////////////////////
// Assign attributes for scrolling UVs
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////
global proc setScrollValues(float $value[], string $meshes[])
{
    for($mesh in $meshes)
    {
        if(`objExists ($mesh + ".scrollUV")` == 0)
        {
            addAttr -k 1 -ln "scrollUV" -at double3 -nc 3 -h 0 $mesh;
            addAttr -k 1 -ln "scrollUVU" -at double -h 0 -p "scrollUV" $mesh;
            addAttr -k 1 -ln "scrollUVV" -at double -h 0 -p "scrollUV" $mesh;
            addAttr -k 1 -ln "scrollUVH" -at double -h 0 -p "scrollUV" $mesh;
        }
        setAttr -type double3 ($mesh + ".scrollUV") $value[0] $value[1] $value[2];
    }
}

// ///////////////////////////////////////////////////////////////////////////////////////////////////////////
// Apply scrolling UVs to meshes
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////
global proc setUVScroll()
{
    string $nodes[] = getAnimatedFileNodes();
    string $fileNodes[] = {};
    string $place2dNodes[] = {};
    int $count = 0;
    for($i=0;$i    {
        $fileNodes[$count] = $nodes[$i];
        $place2dNodes[$count] = $nodes[$i+1];
        $count++;
        $i++;
    }
    for($i=0;$i        setScrollValues(getScrollValues($place2dNodes[$i]), getMeshesWithTexture($fileNodes[$i]));
}

// ///////////////////////////////////////////////////////////////////////////////////////////////////////////
// find all root nodes
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////
global proc string[] findRoots()
{
    string $transforms[] = `ls -l -typ "transform"`;
    string $roots[] = {};
    for($trans in $transforms)
        $roots[size($roots)] = rootOf($trans);
    return stringArrayRemoveDuplicates($roots);
}

// ///////////////////////////////////////////////////////////////////////////////////////////////////////////
// traverse children and delete any that are tagged for ignore
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////
global proc pruneChildren(string $parent)
{
    if (!`objExists $parent`)
        return;
    if(`objExists ($parent + ".ignoreInUnity")`)
        if(`getAttr ($parent + ".ignoreInUnity")` == true)
            delete $parent;
    if (`objExists $parent`)
    {
        string $children[] = `listRelatives -c -typ "transform" -f $parent`;
        if(size($children) > 0)
            for($child in $children)
                pruneChildren($child);
    }
}

// ///////////////////////////////////////////////////////////////////////////////////////////////////////////
// delete any transforms that should not be exported
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////
global proc removeTransforms()
{
    for($node in findRoots())
        pruneChildren($node);
}

// ///////////////////////////////////////////////////////////////////////////////////////////////////////////
// populate info nodes for materials
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////
global proc populateMaterialInfoNode(string $nodeName, string $file)
{
    float $ru = `getAttr ($file + ".repeatU")`;
    float $rv = `getAttr ($file + ".repeatV")`;
    float $ou = `getAttr ($file + ".offsetU")`;
    float $ov = `getAttr ($file + ".offsetV")`;
    if($ru != 1)
    {
        addAttr -k 1 -ln "unityMaterialRepeatU" -at double -h 0 $nodeName;
        setAttr ($nodeName + ".unityMaterialRepeatU") $ru;
    }
    if($rv != 1)
    {
        addAttr -k 1 -ln "unityMaterialRepeatV" -at double -h 0 $nodeName;
        setAttr ($nodeName + ".unityMaterialRepeatV") $rv;
    }
    if($ou != 0)
    {
        addAttr -k 1 -ln "unityMaterialOffsetU" -at double -h 0 $nodeName;
        setAttr ($nodeName + ".unityMaterialOffsetU") $ou;
    }
    if($ov != 0)
    {
        addAttr -k 1 -ln "unityMaterialOffsetV" -at double -h 0 $nodeName;
        setAttr ($nodeName + ".unityMaterialOffsetV") $ov;
    }
    float $colorGain[] = `getAttr ($file + ".colorGain")`;
    if($colorGain[0] != 1 || $colorGain[1] != 1 ||$colorGain[2] != 1)
    {
        addAttr -k 1 -ln "unityMaterialColorGain" -at double3 -nc 3 -h 0 $nodeName;
        addAttr -k 1 -ln "unityMaterialColorGainR" -at double -h 0 -p "unityMaterialColorGain" $nodeName;
        addAttr -k 1 -ln "unityMaterialColorGainG" -at double -h 0 -p "unityMaterialColorGain" $nodeName;
        addAttr -k 1 -ln "unityMaterialColorGainB" -at double -h 0 -p "unityMaterialColorGain" $nodeName;
        setAttr ($nodeName + ".unityMaterialColorGain") $colorGain[0] $colorGain[1] $colorGain[2];
    }
}

// ///////////////////////////////////////////////////////////////////////////////////////////////////////////
// rename all materials according to their associated filename
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////
global proc renameMaterials()
{
    string $fileList[] = stringArrayRemoveDuplicates(`ls -type "file"`);
    string $layeredTextures[];
    string $layeredTextureNames[];
    for($file in $fileList)
    {
        string $path = `getAttr ($file + ".fileTextureName")`;
        if($path != "")
        {
            string $fileName = basenameEx($path);
            if(`getAttr ($file + ".fileHasAlpha")` == 1)
                $fileName = $fileName + "_RGBA";
            string $materialList[] = stringArrayRemoveDuplicates(`connectionInfo -dfs ($file + ".outColor")`);
            if(size($materialList) > 0)
            {
                for($material in $materialList)
                {
                    if(`nodeType $material` != "layeredTexture")
                    {
                        $material = basenameEx($material);
                        string $newMaterialName;
                        if($material != "lambert1" && $material != "particleCloud1")
                        {
                            // Rename material node
                            string $nodeType = "_" + `nodeType $material`;
                            $newMaterialName = `rename $material ($fileName + $nodeType)`;
                            string $newGroup = `group -em -n ($newMaterialName + "_info")`;
                            populateMaterialInfoNode($newGroup, $file);
                        }
                    }
                }
            }
        }
    }
}

// ///////////////////////////////////////////////////////////////////////////////////////////////////////////
// Create user attributes on lights
// ///////////////////////////////////////////////////////////////////////////////////////////////////////////
global proc createLightAttributes()
{
    string $lights[] = `ls -typ "light"`;
    for($light in $lights)
    {
        $parents = `listRelatives -p -f $light`;
        if(`objectType $light` == "spotLight" || `objectType $light` == "pointLight")
        {
            $decay = `getAttr ($light + ".decayRate")`;
            if($decay != 2)
            {
                addAttr -k 1 -ln "unityLightError" -at short -h 0 $parents[0];
                setAttr ($parents[0] + ".unityLightError") 1;
            }
        }
        $color = `getAttr ($light + ".color")`;
        addAttr -k 1 -ln "unityLightColor" -at double3 -nc 3 -h 0 $parents[0];
        addAttr -k 1 -ln "unityLightColorR" -at double -h 0 -p "unityLightColor" $parents[0];
        addAttr -k 1 -ln "unityLightColorG" -at double -h 0 -p "unityLightColor" $parents[0];
        addAttr -k 1 -ln "unityLightColorB" -at double -h 0 -p "unityLightColor" $parents[0];
        setAttr ($parents[0] + ".unityLightColor") $color[0] $color[1] $color[2];
        $intensity = `getAttr ($light + ".intensity")`;
        addAttr -k 1 -ln "unityLightIntensity" -at double -h 0 $parents[0];
        setAttr ($parents[0] + ".unityLightIntensity") $intensity;
        if(`objExists ($light + ".coneAngle")` == 1)
        {
            $coneAngle = `getAttr ($light + ".coneAngle")`;
            addAttr -k 1 -ln "unityLightConeAngle" -at double -h 0 $parents[0];
            setAttr ($parents[0] + ".unityLightConeAngle") $coneAngle;
        }
    }
}

proc simplifyTransformKeyframes(float $tTol, float $vTol)
{
    string $transforms[] = `ls -typ "transform"`;
    for($transform in $transforms)
    {
        string $attrs[] = `listAnimatable $transform`;
        for($attr in $attrs)
        {
            string $curve = `connectionInfo -sfd $attr`;
            if($curve != "")
            simplify -time ":" -timeTolerance $tTol -floatTolerance $tTol -valueTolerance $vTol `basenameEx($curve)`;
        }
        delete -staticChannels -unitlessAnimationCurves false -hierarchy 0 -controlPoints 0 -shape 0 $transform;
    }
}


global proc FBXMayaExport() {
    while (1)
    {   
        if (`filetest -r "!//UNITY_TEMP//!/CommandPipe"`)
        {
            $exportNormals = 0;
            $exportTangents = 0;
            $bakeCommand = "";
        
            // Parse settings
            $waitpipe = `fopen "!//UNITY_TEMP//!/CommandPipe" "r"`;
            $filename = `fgetline $waitpipe`;
            
            for ($i = 0; $i < 3; ++$i) 
            {
                $cmd = `fgetline $waitpipe`;
                
                if ($cmd == "exportNormals\n")
                    $exportNormals = 1;
                else if ($cmd == "exportTangents\n")
                    $exportTangents = 1;
                else if (startsWith($cmd, "bake"))
                    $bakeCommand = $cmd;            
            }
            
            fclose $waitpipe;
            
            if (endsWith ($filename, "\n"))
            {
                $filename = strip ($filename);
                
                print "Starting maya loading and fbx conversion \n";
                
                if ( `file -q -exists $filename` )
                {               
                    file -force -o $filename;
                    currentUnit -l "centimeter";

                    if (`exists FBXResetExport`)
                    {
                        print "Resetting export options to the default values.\n";
                        FBXResetExport(); 
                    }
                    
                    if (getApplicationVersionAsFloat() >= 2012)
                    {
                        print "Setting FBX version to FBX201100.\n";
                        // Ensure we are using a version of FBX that Unity can currently support
                        FBXExportFileVersion FBX201100; 
                    }

                    if ($bakeCommand != "")
                    {
                        if ( `exists FBXExportBakeComplexAnimation` )
                            FBXExportBakeComplexAnimation -v true;
                        $allObjects = stringArrayToString (`ls -dag`, " ");
                        $cmd = "";
                            
                        if ($bakeCommand == "bake\n")
                        {
                            $cmd = "bakeResults -simulation true -t \"";
                            $cmd = $cmd + `playbackOptions -query -minTime` + ":";
                            $cmd = $cmd + `playbackOptions -query -maxTime` + "\" ";
                        }
                        else
                        {
                            $bakeCommand = substring($bakeCommand, 6, size($bakeCommand));
                            $bakeCommand = strip ($bakeCommand);
                            $cmd = ("bakeResults -simulation true -t \"" + $bakeCommand + "\" ");
                        }
                        
                        $cmd = $cmd + "-hierarchy below -sampleBy 1 -disableImplicitControl true";
                        $cmd = $cmd + " -preserveOutsideKeys true -sparseAnimCurveBake false -controlPoints false";
                        $cmd = $cmd + " -shape false " + $allObjects;
                        evalEcho($cmd);
                    }
                    
                    FBXExportEmbeddedTextures -v false;
                    FBXExportHardEdges -v $exportNormals;
                    
                    if (`exists FBXExportTangents`)
                    {
                        FBXExportTangents -v $exportTangents;
                    }
                                    
                    FBXExportApplyConstantKeyReducer -v false;
                    // Disable constraints
                    if (`exists FBXExportConstraint`)
                    {
                        FBXExportConstraint -v false;
                    }
                    if (`exists FBXExportConstraints`)
                    {
                        FBXExportConstraints -v false;
                    }

                    // Set up all the new export settings to sane values!
                    if (`exists FBXExportUpAxis`)
                    {
                        FBXExportUpAxis Y;
                    }
                    if (`exists FBXExportAxisConversionMethod`)
                    {
                        FBXExportAxisConversionMethod convertAnimation;
                    }
                    if (`exists FBXExportConvertUnitString`) // This command should take precedence over the following
                    {
                        FBXExportConvertUnitString cm;
                    }
                    else if (`exists FBXConvertUnitString`) // This command is deprecated in 2011
                    {
                        FBXConvertUnitString cm;
                    }
                    if (`exists FBXExportScaleFactor`)
                    {
                        FBXExportScaleFactor 1;
                    }
                    if(`objExists "unityExportScriptNode"` == 1)
                    {
                        scriptNode -eb unityExportScriptNode;
                    }
                    FBXExportShowUI -v false;

                    /////////////////////////////
                    // ADDED BELOW
                    
                    removeTransforms();
                    simplifyTransformKeyframes(0.05, 0.01);
                    renameMaterials();
                    setUVScroll();
                    createLightAttributes();
                
                    // ADDED ABOVE
                    /////////////////////////////
                    FBXExport -f "!//UNITY_TEMP//!/ExportedFBXFile.fbx";
                }
                else
                    print "Could not open Maya file.";

                // TODO: We should use sysFile, so we don't have to have two separate mel scripts for OSX/Windows
                system ("del \"!//UNITY_TEMP_WIN//!\\CommandPipe\"");

                $donepipe = `fopen "!//UNITY_TEMP//!/SyncPipe" "w"`;
                fwrite $donepipe "Done";
                fclose $donepipe;
                print "Finished maya loading and fbx conversion \n";
            }
        }
    }
}

FBXMayaExport();

Back to Main

© 2003-2013 Andrew Kelts