Skip to content

Commit e366f21

Browse files
authored
Merge pull request #334 from Unity-Technologies/UNI-41138-connect-UI-to-exporter
Uni 41138 connect ui to exporter
2 parents df46dee + e85eda6 commit e366f21

20 files changed

+1249
-376
lines changed

Assets/FbxExporters/Editor/ConvertToModel.cs

Lines changed: 38 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@
44
using UnityEngine.SceneManagement;
55
using UnityEditor;
66
using Unity.FbxSdk;
7+
using System.Linq;
78

89
namespace FbxExporters
910
{
1011
namespace Editor
1112
{
1213
public static class ConvertToModel
1314
{
14-
const string MenuItemName1 = "GameObject/Convert To Linked Prefab Instance";
15+
const string MenuItemName1 = "GameObject/Convert To Linked Prefab Instance...";
1516

1617
/// <summary>
1718
/// OnContextItem is called either:
@@ -73,26 +74,11 @@ public static EditorTools.ExportSettings ExportSettings {
7374
/// <param name="unityGameObjectsToConvert">Unity game objects to convert to Model Prefab instances</param>
7475
/// <param name="path">Path to save Model Prefab; use FbxExportSettings if null</param>
7576
public static GameObject[] CreateInstantiatedModelPrefab (
76-
GameObject [] unityGameObjectsToConvert,
77-
string directoryFullPath = null)
77+
GameObject [] unityGameObjectsToConvert)
7878
{
79-
if (directoryFullPath == null) {
80-
directoryFullPath = FbxExporters.EditorTools.ExportSettings.GetAbsoluteSavePath();
81-
} else {
82-
directoryFullPath = Path.GetFullPath(directoryFullPath);
83-
}
84-
8579
var toExport = ModelExporter.RemoveRedundantObjects (unityGameObjectsToConvert);
86-
var wasExported = new List<GameObject>();
87-
foreach(var go in toExport) {
88-
try {
89-
wasExported.Add(Convert(go,
90-
directoryFullPath: directoryFullPath));
91-
} catch(System.Exception xcp) {
92-
Debug.LogException(xcp);
93-
}
94-
}
95-
return wasExported.ToArray();
80+
ConvertToPrefabEditorWindow.Init (toExport);
81+
return toExport.ToArray();
9682
}
9783

9884
/// <summary>
@@ -114,8 +100,12 @@ public static GameObject[] CreateInstantiatedModelPrefab (
114100
/// export settings.</param>
115101
public static GameObject Convert (
116102
GameObject toConvert,
117-
string directoryFullPath = null,
118-
string fbxFullPath = null)
103+
string fbxDirectoryFullPath = null,
104+
string fbxFullPath = null,
105+
string prefabDirectoryFullPath = null,
106+
string prefabFullPath = null,
107+
EditorTools.IExportOptions exportOptions = null
108+
)
119109
{
120110
// Only create the prefab (no FBX export) if we have selected the root of a model prefab instance.
121111
// Children of model prefab instances will also have "model prefab instance"
@@ -142,23 +132,19 @@ public static GameObject Convert (
142132

143133
if (string.IsNullOrEmpty(fbxFullPath)) {
144134
// Generate a unique filename.
145-
if (string.IsNullOrEmpty (directoryFullPath)) {
146-
directoryFullPath = FbxExporters.EditorTools.ExportSettings.GetAbsoluteSavePath ();
135+
if (string.IsNullOrEmpty (fbxDirectoryFullPath)) {
136+
fbxDirectoryFullPath = FbxExporters.EditorTools.ExportSettings.GetFbxAbsoluteSavePath();
147137
} else {
148-
directoryFullPath = Path.GetFullPath (directoryFullPath);
138+
fbxDirectoryFullPath = Path.GetFullPath (fbxDirectoryFullPath);
149139
}
150140
var fbxBasename = ModelExporter.ConvertToValidFilename (toConvert.name + ".fbx");
151141

152-
fbxFullPath = Path.Combine (directoryFullPath, fbxBasename);
142+
fbxFullPath = Path.Combine (fbxDirectoryFullPath, fbxBasename);
153143
if (File.Exists (fbxFullPath)) {
154-
fbxFullPath = IncrementFileName (directoryFullPath, fbxFullPath);
144+
fbxFullPath = IncrementFileName (fbxDirectoryFullPath, fbxFullPath);
155145
}
156146
}
157-
var assetRelativePath = FbxExporters.EditorTools.ExportSettings.ConvertToAssetRelativePath(fbxFullPath);
158-
var projectRelativePath = "Assets/" + assetRelativePath;
159-
if (string.IsNullOrEmpty(assetRelativePath)) {
160-
throw new System.Exception("Path " + fbxFullPath + " must be in the Assets folder.");
161-
}
147+
var projectRelativePath = EditorTools.ExportSettings.GetProjectRelativePath (fbxFullPath);
162148

163149
// Make sure that the object names in the hierarchy are unique.
164150
// The import back in to Unity would do this automatically but
@@ -168,7 +154,10 @@ public static GameObject Convert (
168154

169155
// Export to FBX. It refreshes the database.
170156
{
171-
var fbxActualPath = ModelExporter.ExportObject (fbxFullPath, toConvert, lodExportType: EditorTools.ExportSettings.LODExportType.All);
157+
var fbxActualPath = ModelExporter.ExportObject (
158+
fbxFullPath, toConvert,
159+
exportOptions != null ? exportOptions : new EditorTools.ConvertToPrefabSettingsSerialize()
160+
);
172161
if (fbxActualPath != fbxFullPath) {
173162
throw new System.Exception ("Failed to convert " + toConvert.name);
174163
}
@@ -184,13 +173,28 @@ public static GameObject Convert (
184173
// Copy the mesh/materials from the FBX
185174
UpdateFromSourceRecursive (toConvert, unityMainAsset);
186175

187-
SetupFbxPrefab (toConvert, unityMainAsset, projectRelativePath, fbxFullPath);
176+
if (string.IsNullOrEmpty(prefabFullPath)) {
177+
// Generate a unique filename.
178+
if (string.IsNullOrEmpty (prefabDirectoryFullPath)) {
179+
fbxDirectoryFullPath = FbxExporters.EditorTools.ExportSettings.GetPrefabAbsoluteSavePath();
180+
} else {
181+
fbxDirectoryFullPath = Path.GetFullPath (prefabDirectoryFullPath);
182+
}
183+
var prefabBasename = ModelExporter.ConvertToValidFilename (toConvert.name + ".prefab");
184+
185+
prefabFullPath = Path.Combine (prefabDirectoryFullPath, prefabBasename);
186+
if (File.Exists (prefabFullPath)) {
187+
prefabFullPath = IncrementFileName (prefabDirectoryFullPath, prefabFullPath);
188+
}
189+
}
190+
var prefabProjectRelativePath = EditorTools.ExportSettings.GetProjectRelativePath (prefabFullPath);
191+
192+
SetupFbxPrefab (toConvert, unityMainAsset, prefabProjectRelativePath, fbxFullPath);
188193

189194
toConvert.name = Path.GetFileNameWithoutExtension (fbxFullPath);
190195
return toConvert;
191196
}
192197

193-
194198
/// <summary>
195199
/// Create the prefab and connect it to the given fbx asset.
196200
/// </summary>
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
using System.Collections;
2+
using System.Collections.Generic;
3+
using UnityEngine;
4+
using UnityEditor;
5+
using FbxExporters.EditorTools;
6+
using UnityEditor.Presets;
7+
using System.Linq;
8+
9+
namespace FbxExporters
10+
{
11+
namespace Editor
12+
{
13+
public class ConvertToPrefabEditorWindow : ExportOptionsEditorWindow
14+
{
15+
protected override GUIContent WindowTitle { get { return new GUIContent ("Convert Options"); }}
16+
protected override float MinWindowHeight { get { return 280; } } // determined by trial and error
17+
protected override string ExportButtonName { get { return "Convert"; } }
18+
private GameObject[] m_toConvert;
19+
private string m_prefabFileName = "";
20+
21+
private float m_prefabExtLabelWidth;
22+
23+
public static void Init (IEnumerable<GameObject> toConvert)
24+
{
25+
ConvertToPrefabEditorWindow window = CreateWindow<ConvertToPrefabEditorWindow> ();
26+
window.InitializeWindow ();
27+
window.SetGameObjectsToConvert (toConvert);
28+
window.Show ();
29+
}
30+
31+
protected void SetGameObjectsToConvert(IEnumerable<GameObject> toConvert){
32+
m_toConvert = toConvert.OrderBy (go => go.name).ToArray ();
33+
34+
if (m_toConvert.Length == 1) {
35+
m_prefabFileName = m_toConvert [0].name;
36+
} else if (m_toConvert.Length > 1) {
37+
m_prefabFileName = "(automatic)";
38+
}
39+
this.SetFilename (m_prefabFileName);
40+
}
41+
42+
protected override void OnEnable ()
43+
{
44+
base.OnEnable ();
45+
if (!m_innerEditor) {
46+
m_innerEditor = UnityEditor.Editor.CreateEditor (ExportSettings.instance.convertToPrefabSettings);
47+
}
48+
m_prefabExtLabelWidth = m_fbxExtLabelStyle.CalcSize (new GUIContent (".prefab")).x;
49+
}
50+
51+
protected override void Export ()
52+
{
53+
var fbxDirPath = ExportSettings.GetFbxAbsoluteSavePath ();
54+
var fbxPath = System.IO.Path.Combine (fbxDirPath, m_exportFileName + ".fbx");
55+
56+
var prefabDirPath = ExportSettings.GetPrefabAbsoluteSavePath ();
57+
var prefabPath = System.IO.Path.Combine (prefabDirPath, m_prefabFileName + ".prefab");
58+
59+
// check if file already exists, give a warning if it does
60+
if (!OverwriteExistingFile (fbxPath) || !OverwriteExistingFile (prefabPath)) {
61+
return;
62+
}
63+
64+
if (m_toConvert == null) {
65+
Debug.LogError ("FbxExporter: missing object for conversion");
66+
return;
67+
}
68+
69+
if (m_toConvert.Length == 1) {
70+
ConvertToModel.Convert (
71+
m_toConvert[0], fbxFullPath: fbxPath, prefabFullPath: prefabPath, exportOptions: ExportSettings.instance.convertToPrefabSettings.info
72+
);
73+
return;
74+
}
75+
76+
foreach (var go in m_toConvert) {
77+
ConvertToModel.Convert (
78+
go, fbxDirectoryFullPath: fbxDirPath, prefabDirectoryFullPath: prefabDirPath, exportOptions: ExportSettings.instance.convertToPrefabSettings.info
79+
);
80+
}
81+
}
82+
83+
protected override bool DisableNameSelection ()
84+
{
85+
return m_toConvert.Length > 1;
86+
}
87+
88+
protected override void ShowPresetReceiver ()
89+
{
90+
ShowPresetReceiver (ExportSettings.instance.convertToPrefabSettings);
91+
}
92+
93+
protected override void CreateCustomUI ()
94+
{
95+
GUILayout.BeginHorizontal ();
96+
EditorGUILayout.LabelField(new GUIContent(
97+
"Prefab Name:",
98+
"Filename to save prefab to."),GUILayout.Width(LabelWidth-TextFieldAlignOffset));
99+
100+
EditorGUI.BeginDisabledGroup (DisableNameSelection());
101+
// Show the export name with an uneditable ".prefab" at the end
102+
//-------------------------------------
103+
EditorGUILayout.BeginVertical ();
104+
EditorGUILayout.BeginHorizontal(EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight));
105+
EditorGUI.indentLevel--;
106+
// continually resize to contents
107+
var textFieldSize = m_nameTextFieldStyle.CalcSize (new GUIContent(m_prefabFileName));
108+
m_prefabFileName = EditorGUILayout.TextField (m_prefabFileName, m_nameTextFieldStyle, GUILayout.Width(textFieldSize.x + 5), GUILayout.MinWidth(5));
109+
m_prefabFileName = ModelExporter.ConvertToValidFilename (m_prefabFileName);
110+
111+
EditorGUILayout.LabelField ("<color=#808080ff>.prefab</color>", m_fbxExtLabelStyle, GUILayout.Width(m_prefabExtLabelWidth));
112+
EditorGUI.indentLevel++;
113+
114+
EditorGUILayout.EndHorizontal();
115+
EditorGUILayout.EndVertical ();
116+
//-----------------------------------
117+
EditorGUI.EndDisabledGroup ();
118+
GUILayout.EndHorizontal ();
119+
120+
GUILayout.BeginHorizontal();
121+
EditorGUILayout.LabelField(new GUIContent(
122+
"Prefab Path:",
123+
"Relative path for saving Linked Prefabs."),GUILayout.Width(LabelWidth - FieldOffset));
124+
125+
var pathLabels = ExportSettings.GetRelativePrefabSavePaths();
126+
127+
ExportSettings.instance.selectedPrefabPath = EditorGUILayout.Popup (ExportSettings.instance.selectedPrefabPath, pathLabels, GUILayout.MinWidth(SelectableLabelMinWidth));
128+
129+
if (GUILayout.Button(new GUIContent("...", "Browse to a new location to save prefab to"), EditorStyles.miniButton, GUILayout.Width(BrowseButtonWidth)))
130+
{
131+
string initialPath = Application.dataPath;
132+
133+
string fullPath = EditorUtility.OpenFolderPanel(
134+
"Select Linked Prefab Save Path", initialPath, null
135+
);
136+
137+
// Unless the user canceled, make sure they chose something in the Assets folder.
138+
if (!string.IsNullOrEmpty(fullPath))
139+
{
140+
var relativePath = ExportSettings.ConvertToAssetRelativePath(fullPath);
141+
if (string.IsNullOrEmpty(relativePath))
142+
{
143+
Debug.LogWarning("Please select a location in the Assets folder");
144+
}
145+
else
146+
{
147+
ExportSettings.AddPrefabSavePath(relativePath);
148+
149+
// Make sure focus is removed from the selectable label
150+
// otherwise it won't update
151+
GUIUtility.hotControl = 0;
152+
GUIUtility.keyboardControl = 0;
153+
}
154+
}
155+
}
156+
GUILayout.EndHorizontal();
157+
}
158+
}
159+
}
160+
}

Assets/FbxExporters/Editor/ConvertToPrefabEditorWindow.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
using UnityEditor;
2+
using UnityEngine;
3+
4+
namespace FbxExporters.EditorTools
5+
{
6+
[CustomEditor (typeof(ConvertToPrefabSettings))]
7+
public class ConvertToPrefabSettingsEditor : UnityEditor.Editor
8+
{
9+
private const float LabelWidth = 175;
10+
private const float FieldOffset = 18;
11+
12+
private string[] exportFormatOptions = new string[]{ "ASCII", "Binary" };
13+
private string[] includeOptions = new string[]{"Model(s) + Animation"};
14+
private string[] lodOptions = new string[]{"All Levels"};
15+
16+
private string[] objPositionOptions { get { return new string[]{"Local Pivot"}; }}
17+
18+
public override void OnInspectorGUI ()
19+
{
20+
var exportSettings = ((ConvertToPrefabSettings)target).info;
21+
22+
EditorGUIUtility.labelWidth = LabelWidth;
23+
24+
GUILayout.BeginHorizontal();
25+
EditorGUILayout.LabelField(new GUIContent("Export Format", "Export the FBX file in the standard binary format." +
26+
" Select ASCII to export the FBX file in ASCII format."), GUILayout.Width(LabelWidth - FieldOffset));
27+
exportSettings.exportFormat = (ExportSettings.ExportFormat)EditorGUILayout.Popup((int)exportSettings.exportFormat, exportFormatOptions);
28+
GUILayout.EndHorizontal();
29+
30+
GUILayout.BeginHorizontal();
31+
EditorGUILayout.LabelField(new GUIContent("Include", "Select whether to export models, animation or both."), GUILayout.Width(LabelWidth - FieldOffset));
32+
// always greyed out, show only to let user know what will happen
33+
EditorGUI.BeginDisabledGroup(true);
34+
EditorGUILayout.Popup(0, includeOptions);
35+
EditorGUI.EndDisabledGroup ();
36+
GUILayout.EndHorizontal();
37+
38+
GUILayout.BeginHorizontal();
39+
EditorGUILayout.LabelField(new GUIContent("LOD level", "Select which LOD to export."), GUILayout.Width(LabelWidth - FieldOffset));
40+
// always greyed out, show only to let user know what will happen
41+
EditorGUI.BeginDisabledGroup(true);
42+
EditorGUILayout.Popup(0, lodOptions);
43+
EditorGUI.EndDisabledGroup ();
44+
GUILayout.EndHorizontal();
45+
46+
GUILayout.BeginHorizontal();
47+
EditorGUILayout.LabelField(new GUIContent("Object(s) Position", "Select an option for exporting object's transform."), GUILayout.Width(LabelWidth - FieldOffset));
48+
// always greyed out, show only to let user know what will happen
49+
EditorGUI.BeginDisabledGroup(true);
50+
EditorGUILayout.Popup(0, objPositionOptions);
51+
EditorGUI.EndDisabledGroup ();
52+
GUILayout.EndHorizontal();
53+
54+
// TODO: add implementation for these options, grey out in the meantime
55+
EditorGUI.BeginDisabledGroup (true);
56+
GUILayout.BeginHorizontal();
57+
EditorGUILayout.LabelField(new GUIContent("Transfer Root Motion To", "Select bone to transfer root motion animation to."), GUILayout.Width(LabelWidth - FieldOffset));
58+
EditorGUILayout.Popup(0, new string[]{"<None>"});
59+
GUILayout.EndHorizontal();
60+
61+
exportSettings.animatedSkinnedMesh = EditorGUILayout.Toggle ("Animated Skinned Mesh", exportSettings.animatedSkinnedMesh);
62+
EditorGUI.EndDisabledGroup ();
63+
64+
exportSettings.mayaCompatibleNaming = EditorGUILayout.Toggle (
65+
new GUIContent ("Compatible Naming:",
66+
"In Maya some symbols such as spaces and accents get replaced when importing an FBX " +
67+
"(e.g. \"foo bar\" becomes \"fooFBXASC032bar\"). " +
68+
"On export, convert the names of GameObjects so they are Maya compatible." +
69+
(exportSettings.mayaCompatibleNaming ? "" :
70+
"\n\nWARNING: Disabling this feature may result in lost material connections," +
71+
" and unexpected character replacements in Maya.")
72+
),
73+
exportSettings.mayaCompatibleNaming);
74+
}
75+
}
76+
77+
public class ConvertToPrefabSettings : ExportOptionsSettingsBase<ConvertToPrefabSettingsSerialize>
78+
{}
79+
80+
[System.Serializable]
81+
public class ConvertToPrefabSettingsSerialize : ExportOptionsSettingsSerializeBase
82+
{
83+
public override ExportSettings.Include ModelAnimIncludeOption { get { return ExportSettings.Include.ModelAndAnim; } }
84+
public override ExportSettings.LODExportType LODExportType { get { return ExportSettings.LODExportType.All; } }
85+
public override ExportSettings.ObjectPosition ObjectPosition { get { return ExportSettings.ObjectPosition.Reset; } }
86+
public override bool ExportUnrendered { get { return true; } }
87+
}
88+
}

0 commit comments

Comments
 (0)