// =========================================================================== // Copyright 2018 Autodesk, Inc. All rights reserved. // // Use of this software is subject to the terms of the Autodesk license // agreement provided at the time of installation or download, or which // otherwise accompanies this software in either electronic or hard copy form. // =========================================================================== global string $gPreviousMoBuSent[] = {}; global int $gPreviousMoBuScriptJob = -1; // // Check whether the previously sent object list contains items still // in the scene // proc string[] validatePreviousMoBuSendList() { global string $gPreviousMoBuSent[]; string $stillAround[] = validatePreviousSendList($gPreviousMoBuSent); return $stillAround; } // // Clear the saved list of previously sent items. Usually called by FileNew. // global proc clearPreviousMoBuSendList() { global string $gPreviousMoBuSent[]; clear($gPreviousMoBuSent); } proc int AddCharOrRigToSelection(string $characterOrRig) { string $hipsBone = hikGetSkNode( $characterOrRig, 1 ); if( $hipsBone != "" ) { string $selection[] = `ls -sl $hipsBone`; if( size( $selection ) > 0 ) //if hips bone is selected, it mean that the character is wanted { //if one bone of the character is selected all bone will due to some selection expension... select -add $characterOrRig; return 1; } } return 0; } // // Modify the selection list so that it includes the hierarchy and other // associated nodes that we want to export. // global proc int augmentSelectionForOneClickMoBu( string $action, int $restrictedUpdate ) { // Reset the tool to "Select" to prevent other contexts from doing unnecessary processing // setToolTo selectSuperContext; // Identify relevant selected items // this includes, transforms, constraints, meshes, HIK charater definition and rigs string $sel[]; if( `pluginInfo -q -l "mayaHIK"` ) { $sel = `ls -sl -type dagNode -type HIKCharacterNode -type HIKCharacterNode`; } else { $sel = `ls -sl -type dagNode`; } if (size($sel) == 0) { // // Nothing was selected. See if there is a previous selection and // ask if they want to send that. // // Eventually we want to give the option to suppress the dialog. // So the optionVars are there for that. // string $cancelInfoMsg = (uiRes("m_doMotionFlow.kSendCancelled")); $sel = validatePreviousMoBuSendList(); if (size($sel) > 0 && (! oneClickDefaultSendPreviousSelection())) { string $doSend = `layoutDialog -ui "createOneClickSelectionDialog(1)"`; if ($doSend != "Yes") { print $cancelInfoMsg; return 0; } } if (size($sel) == 0) { // There was no previous selection, ask if they want to send // everything. // $sel = getEntireSceneNoCameras(); if (! oneClickDefaultSendEntireScene()) { if (size($sel) > 0) { string $doSend = `layoutDialog -ui "createOneClickSelectionDialog(0)"`; if ($doSend != "Yes") { print $cancelInfoMsg; return 0; } } } } } if (size($sel) == 0) { error((uiRes("m_doMotionFlow.kNothingToSend"))); return 0; } for ($obj in $sel) { // select the top item in the hierarchy for all selected items // oneClickSelectRoot( $obj ); } string $constraintsSel[] = `ls -sl -type constraint`; select -hierarchy; if( $restrictedUpdate ) { // select -hierarchy causes meshes to be really selected instead of their associated transform // From there we can find skinCluster associated to selected meshes and then the influences string $meshes[] = `ls -sl -type mesh`; $sel = `ls -sl`; if( size( $meshes ) > 0 ) { string $skinClusters[] = `listConnections -type skinCluster -s 1 -d 0 $meshes`; if( size( $skinClusters ) > 0 ) { string $allInfluences[] = `listConnections -s 1 -d 0 -type transform $skinClusters`; string $influences[] = stringArrayRemoveDuplicates($allInfluences); if( size( $influences ) > 0 ) { for( $influence in $influences) { oneClickSelectRoot( $influence ); } string $updatedSel[] = `ls -sl`; if (size($updatedSel) > size($sel)) { select -hierarchy; } } } } if( `pluginInfo -q -l "mayaHIK"` ) { // Now that hierarchies are selected, for every character check if the skeleton or the rig are selected string $characters[] = `ls -type HIKCharacterNode`; for( $character in $characters ) { string $rig = hikGetControlRig($character); int $characterAdded = 0; if( size( $rig ) != 0 ) { if(AddCharOrRigToSelection($rig)) { $characterAdded = 1; select -add $character; // always add Character if the rig is selected to get solving property updated string $hipsBone = hikGetSkNode( $character, 1 ); if( $hipsBone != "" ) // add SKeleton because Mobu does not support to update only the character { oneClickSelectRoot( $hipsBone ); } } } if(!$characterAdded)//added because the rig was added, this ensure that properties get updated { AddCharOrRigToSelection($character); //already added } } // If this code is going to be used for "sendNew" and not just "update" // we will need to ensure that completecharacters gets selected on sendNew. // Also in that case,if not selected the Rig should bes selected in RigInput active if( $action != "update" ) { string $selectedCharacters[] = `ls -sl -type HIKCharacterNode`; for( $character in $selectedCharacters ) { if( (hikIsCharacterInputTypeRig( $character ) ) && (hikIsCharacterEnabled( $character )) ) { string $controlRig = hikGetControlRig( $character ); if( $controlRig != "" ) { string $hipsBone = hikGetSkNode( $controlRig, 1 ); if( $hipsBone != "" ) { oneClickSelectRoot( $hipsBone ); select -add $controlRig; } } } } string $selectedControlSets[] = `ls -sl -type HIKControlSetNode`; for( $rig in $selectedControlSets ) { string $character = hikGetCharacterDefinition( $rig ); if( $character != "" ) { string $hipsBone = hikGetSkNode( $character, 1 ); if( $hipsBone != "" ) { oneClickSelectRoot( $hipsBone ); select -add $character; } } } select -hierarchy; } } if( $action != "update" ) { addSkinRelatedToSelection(); addBlendShapeTargetsForSelection(); } // Some source constraits are added by select -hierarchy // Keep these new selected constraints only if all the // associated targets are also selected // oneClickConstraintTargetValidation($constraintsSel); } else { // Now add all dag nodes in the "history" and "future" of the // selection -- this gets things like constraint targets, skinning, // blendShape targets etc. We don't need to grab the history nodes // themselves since FBX export will do the appropriate thing. // string $allFuture[] = `listHistory -future 1`; string $allHistory[] = `listHistory`; select -add `ls -type "dagNode" $allFuture`; select -add `ls -type "dagNode" $allHistory`; addSkinRelatedToSelection(); // Select all the character and controlset nodes of the scene // This is for backward compatibility. FBX plugin 2012.0 assumed all nodes were selected // even if they were not. Newwer plugins require these nodes to be selected to export them select -add `ls -type HIKCharacterNode -type HIKControlSetNode`; } global string $gPreviousMoBuSent[]; $gPreviousMoBuSent = `ls -sl`; global int $gPreviousMoBuScriptJob; if ($gPreviousMoBuScriptJob < 0) { $gPreviousMoBuScriptJob = `scriptJob -permanent -e deleteAll "clearPreviousMoBuSendList"`; } return 1; } // // Description: // This is the actual function invoked by the "Send to MotionBuilder" // menu items. // // Input arguments: // $version: The version of this option box. Used to know how to // interpret the $args array. // // $args[0] = $action. Available values are: // sendNew, sendNewUpdate, update, add, receive, selectPrevious // $args[1] = During "receive": The filename to receive. During "sendNew", // optionally used to specify if textures should be embed or not // in the created fbx file // $args[2] = During "receive": If true, do a file new. During "sendNew", // optionally used to specify the active camera. // $args[3] = During "receive": If true, do an add vs merge. During "sendNew", // During "sendNew" optionally used to specify whether the active // camera is a default camera in which case it will be duplicated so // that fbx send it. // // Return: // For receive, returns "Success" or "Failure" based on the result of the operation. // For all other operations, returns the filename that was sent to MotionBuilder. // global proc string doMotionFlow(string $args[]) { if (! `exists validatePreviousSendList`) { source "oneClickUtilities.mel"; } string $action = $args[0]; if ($action == "sendNew" || $action == "sendNewUpdate" || $action == "update" || $action == "add") { int $restrictedUpdate = getOneClickRestrictedUpdateVal(); if (!augmentSelectionForOneClickMoBu( $action, $restrictedUpdate )) { // User cancelled the operation. // return ""; } // Current conclusion: Never include connections. It causes FBX to // pulls in constraints even if the source targets are not // selected which is not desired. // int $includeConnections = 0; int $embedTextures = false; if( size($args) >= 2 ) { $embedTextures = $args[1]; } string $camName = ""; int $isDefaultCam = 0; if (size($args) >= 4 && size($args[2]) > 0) { $camName = $args[2]; // $isDefaultCam is not set to $args[3] but rather letf to false // Historically a typo prevented this assignement to be performed // and Yang-hai Eakes confirmed that this faulty behavior is in // fact be the expected behavior } string $filename; $filename = doOneClickSendOperation("FBXLoadMBExportPresetFile", "MotionBuilder_to_Maya_", $restrictedUpdate, $camName, $isDefaultCam, $includeConnections, $embedTextures ); return $filename; } else if ($action == "receive") { string $filename = $args[1]; int $newScene = $args[2]; int $addFlag = $args[3]; string $result = doOneClickReceiveOperation("FBXLoadMBImportPresetFile", $filename, $newScene, $addFlag, !$newScene ); return $result; } else if ($action == "selectPrevious") { string $previousItems[] = validatePreviousMoBuSendList(); if (size($previousItems) > 0) { select -r $previousItems; } else { error((uiRes("m_doMotionFlow.kPreviousItemsNoLongerInScene"))); } } else { warning((uiRes("m_doMotionFlow.kInvalidAction"))); } return ""; }