Skip to content

Commit 289caac

Browse files
author
Benoit Hudson
committed
Merge branch 'master' into UNI-21512-document-exporters
Not a straightforward merge for the README.
2 parents 8262c69 + 13eea1d commit 289caac

File tree

7 files changed

+736
-83
lines changed

7 files changed

+736
-83
lines changed

Assets/FbxExporters/Editor/ConvertToModel.cs

Lines changed: 101 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ public void Dispose () { }
3232
[MenuItem (MenuItemName1, false)]
3333
public static void OnMenuItem ()
3434
{
35-
OnConvertInPlace ();
35+
GameObject [] unityActiveGOs = Selection.GetFiltered<GameObject> (SelectionMode.Editable | SelectionMode.TopLevel);
36+
OnConvertInPlace (unityActiveGOs);
3637
}
3738

3839
/// <summary>
@@ -45,28 +46,44 @@ public static bool OnValidateMenuItem ()
4546
}
4647

4748
// Add a menu item called "Export Model..." to a GameObject's context menu.
49+
// OnContextItem gets called once per selected object
50+
// (if the parent and child are selected, then OnContextItem will only be called on the parent)
4851
[MenuItem (MenuItemName2, false, 30)]
4952
static void OnContextItem (MenuCommand command)
5053
{
51-
OnConvertInPlace ();
54+
if (command == null || command.context == null) {
55+
Debug.LogError ("Error: No GameObject selected");
56+
return;
57+
}
58+
GameObject selected = command.context as GameObject;
59+
if (selected == null) {
60+
Debug.LogError (string.Format("Error: {0} is not a GameObject and cannot be converted", command.context.name));
61+
return;
62+
}
63+
OnConvertInPlace (new GameObject[]{selected});
5264
}
5365

54-
private static List<GameObject> OnConvertInPlace ()
66+
private static List<GameObject> OnConvertInPlace (GameObject [] unityActiveGOs)
5567
{
5668
List<GameObject> result = new List<GameObject> ();
5769

58-
GameObject [] unityActiveGOs = Selection.GetFiltered<GameObject> (SelectionMode.Editable | SelectionMode.TopLevel);
59-
6070
var exportSet = ModelExporter.RemoveRedundantObjects (unityActiveGOs);
6171
GameObject[] gosToExport = new GameObject[exportSet.Count];
6272
exportSet.CopyTo (gosToExport);
6373

74+
EnforceUniqueNames (gosToExport);
75+
6476
// find common ancestor root & filePath;
6577
string[] filePaths = new string[gosToExport.Length];
6678
string dirPath = Path.Combine (Application.dataPath, "Objects");
6779

6880
for(int n = 0; n < gosToExport.Length; n++){
69-
filePaths[n] = Path.Combine (dirPath, gosToExport[n].name + ".fbx");
81+
var filename = ModelExporter.ConvertToValidFilename (gosToExport [n].name + ".fbx");
82+
var filePath = Path.Combine (dirPath, filename);
83+
if (File.Exists (filePath)) {
84+
filePath = IncrementFileName (dirPath, filename);
85+
}
86+
filePaths[n] = filePath;
7087
}
7188

7289
string[] fbxFileNames = new string[filePaths.Length];
@@ -81,7 +98,7 @@ private static List<GameObject> OnConvertInPlace ()
8198
{
8299
var fbxFileName = fbxFileNames [i];
83100
if (fbxFileName == null) {
84-
Debug.Log (string.Format ("Warning: Export failed for GameObject {0}", gosToExport [i].name));
101+
Debug.LogWarning (string.Format ("Warning: Export failed for GameObject {0}", gosToExport [i].name));
85102
continue;
86103
}
87104

@@ -98,7 +115,7 @@ private static List<GameObject> OnConvertInPlace ()
98115
Object unityMainAsset = AssetDatabase.LoadMainAssetAtPath (fbxFileName);
99116

100117
if (unityMainAsset != null) {
101-
Object unityObj = PrefabUtility.InstantiateAttachedAsset (unityMainAsset);
118+
Object unityObj = PrefabUtility.InstantiatePrefab (unityMainAsset);
102119
GameObject unityGO = unityObj as GameObject;
103120
if (unityGO != null)
104121
{
@@ -126,6 +143,66 @@ private static List<GameObject> OnConvertInPlace ()
126143
return result;
127144
}
128145

146+
/// <summary>
147+
/// Check if the file exists, and if it does, then increment the name.
148+
/// e.g. if filename is Sphere.fbx and it already exists, change it to Sphere 1.fbx.
149+
/// </summary>
150+
/// <returns>new file name.</returns>
151+
/// <param name="filename">Filename.</param>
152+
private static string IncrementFileName(string path, string filename)
153+
{
154+
string fileWithoutExt = Path.GetFileNameWithoutExtension (filename);
155+
string ext = Path.GetExtension (filename);
156+
157+
int index = 1;
158+
string file = null;
159+
do {
160+
file = string.Format ("{0} {1}{2}", fileWithoutExt, index, ext);
161+
file = Path.Combine(path, file);
162+
index++;
163+
} while (File.Exists (file));
164+
165+
return file;
166+
}
167+
168+
/// <summary>
169+
/// Enforces that all object names be unique before exporting.
170+
/// If an object with a duplicate name is found, then it is incremented.
171+
/// e.g. Sphere becomes Sphere 1
172+
/// </summary>
173+
/// <param name="exportSet">Export set.</param>
174+
private static void EnforceUniqueNames(GameObject[] exportSet)
175+
{
176+
Dictionary<string, int> NameToIndexMap = new Dictionary<string, int> ();
177+
string format = "{0} {1}";
178+
179+
Queue<GameObject> queue = new Queue<GameObject> (exportSet);
180+
181+
while(queue.Count > 0){
182+
var go = queue.Dequeue ();
183+
var name = go.name;
184+
if (NameToIndexMap.ContainsKey (name)) {
185+
go.name = string.Format (format, name, NameToIndexMap [name]);
186+
NameToIndexMap [name]++;
187+
} else {
188+
NameToIndexMap [name] = 1;
189+
}
190+
191+
foreach (Transform child in go.transform) {
192+
queue.Enqueue (child.gameObject);
193+
}
194+
}
195+
}
196+
197+
/// <summary>
198+
/// Sets up the imported GameObject to match the original.
199+
/// - Updates the name to be the same as original (i.e. remove the "(Clone)")
200+
/// - Moves the imported object to the correct position in the hierarchy
201+
/// - Updates the transform of the imported GameObject to match the original
202+
/// - Copy over missing components and component values
203+
/// </summary>
204+
/// <param name="orig">Original GameObject.</param>
205+
/// <param name="imported">Imported GameObject.</param>
129206
private static void SetupImportedGameObject(GameObject orig, GameObject imported)
130207
{
131208
Transform importedTransform = imported.transform;
@@ -154,9 +231,25 @@ private static void SetupImportedGameObject(GameObject orig, GameObject imported
154231
Debug.LogWarning (string.Format ("Warning: Exported {0} objects, but only imported {1}",
155232
origTransform.hierarchyCount, importedTransform.hierarchyCount));
156233
}
234+
FixSiblingOrder (orig.transform, imported.transform);
157235
CopyComponentsRecursive (orig, imported);
158236
}
159237

238+
private static void FixSiblingOrder(Transform orig, Transform imported){
239+
foreach (Transform origChild in orig) {
240+
Transform importedChild = imported.Find (origChild.name);
241+
if (importedChild == null) {
242+
Debug.LogWarning (string.Format(
243+
"Warning: Could not find {0} in parented under {1} in import hierarchy",
244+
origChild.name, imported.name
245+
));
246+
continue;
247+
}
248+
importedChild.SetSiblingIndex (origChild.GetSiblingIndex ());
249+
FixSiblingOrder (origChild, importedChild);
250+
}
251+
}
252+
160253
private static void CopyComponentsRecursive(GameObject from, GameObject to){
161254
if (!to.name.StartsWith(from.name) || from.transform.childCount != to.transform.childCount) {
162255
Debug.LogError (string.Format("Error: hierarchies don't match (From: {0}, To: {1})", from.name, to.name));

Assets/FbxExporters/Editor/FbxExportSettings.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,21 @@ public class ExportSettingsEditor : UnityEditor.Editor {
1111
public override void OnInspectorGUI() {
1212
ExportSettings exportSettings = (ExportSettings)target;
1313

14+
// Increasing the label width so that none of the text gets cut off
15+
EditorGUIUtility.labelWidth = 300;
16+
1417
exportSettings.weldVertices = EditorGUILayout.Toggle ("Weld Vertices:", exportSettings.weldVertices);
1518
exportSettings.embedTextures = EditorGUILayout.Toggle ("Embed Textures:", exportSettings.embedTextures);
19+
exportSettings.mayaCompatibleNames = EditorGUILayout.Toggle (
20+
new GUIContent("Convert to Maya Compatible Naming:",
21+
"In Maya some symbols such as spaces and accents get replaced when importing an FBX " +
22+
"(e.g. \"foo bar\" becomes \"fooFBXASC032bar\"). " +
23+
"On export, convert the names of GameObjects so they are Maya compatible." +
24+
(exportSettings.mayaCompatibleNames? "" :
25+
"\n\nWARNING: Disabling this feature may result in lost material connections," +
26+
" and unexpected character replacements in Maya.")
27+
),
28+
exportSettings.mayaCompatibleNames);
1629

1730
if (GUI.changed) {
1831
EditorUtility.SetDirty (exportSettings);
@@ -26,6 +39,7 @@ public class ExportSettings : FbxExporters.EditorTools.ScriptableSingleton<Expor
2639
{
2740
public bool weldVertices = true;
2841
public bool embedTextures = false;
42+
public bool mayaCompatibleNames = true;
2943

3044
[MenuItem("Edit/Project Settings/Fbx Export", priority = 300)]
3145
static void ShowManager()

0 commit comments

Comments
 (0)