@@ -16,15 +16,10 @@ namespace FbxExporters
16
16
{
17
17
namespace Editor
18
18
{
19
- public class ConvertToModel : System . IDisposable
19
+ public static class ConvertToModel
20
20
{
21
21
const string MenuItemName1 = "GameObject/Convert To Prefab" ;
22
22
23
- /// <summary>
24
- /// Clean up this class on garbage collection
25
- /// </summary>
26
- public void Dispose ( ) { }
27
-
28
23
// Add a menu item called "Export Model..." to a GameObject's context menu.
29
24
// OnContextItem gets called once per selected object
30
25
// (if the parent and child are selected, then OnContextItem will only be called on the parent)
@@ -66,113 +61,140 @@ public static bool OnValidateMenuItem ()
66
61
}
67
62
68
63
/// <summary>
69
- /// Create an instantiated model prefab from an game object hierarchy.
64
+ /// Create instantiated model prefabs from a selection of objects.
65
+ ///
66
+ /// Every hierarchy in the selection will be exported, under the name of the root.
67
+ ///
68
+ /// If an object and one of its descendents are both selected, the descendent is not promoted to be a prefab -- we only export the root.
70
69
/// </summary>
71
70
/// <returns>list of instanced Model Prefabs</returns>
72
71
/// <param name="unityGameObjectsToConvert">Unity game objects to convert to Model Prefab instances</param>
73
72
/// <param name="path">Path to save Model Prefab; use FbxExportSettings if null</param>
74
73
/// <param name="keepOriginal">If set to <c>true</c> keep original gameobject hierarchy.</param>
75
- public static GameObject [ ] CreateInstantiatedModelPrefab ( GameObject [ ] unityGameObjectsToConvert , string path = null , bool keepOriginal = true )
74
+ public static GameObject [ ] CreateInstantiatedModelPrefab ( GameObject [ ] unityGameObjectsToConvert , string directoryFullPath = null , bool keepOriginal = true )
76
75
{
77
- if ( path == null ) {
78
- path = FbxExporters . EditorTools . ExportSettings . GetAbsoluteSavePath ( ) ;
76
+ if ( directoryFullPath == null ) {
77
+ directoryFullPath = FbxExporters . EditorTools . ExportSettings . GetAbsoluteSavePath ( ) ;
79
78
} else {
80
- path = Path . GetFullPath ( path ) ;
79
+ directoryFullPath = Path . GetFullPath ( directoryFullPath ) ;
81
80
}
82
81
83
- List < GameObject > result = new List < GameObject > ( ) ;
84
-
85
- var exportSet = ModelExporter . RemoveRedundantObjects ( unityGameObjectsToConvert ) ;
86
- GameObject [ ] gosToExport = new GameObject [ exportSet . Count ] ;
87
- exportSet . CopyTo ( gosToExport ) ;
88
-
89
- EnforceUniqueNames ( gosToExport ) ;
90
-
91
- // find common ancestor root & filePath;
92
- string [ ] filePaths = new string [ gosToExport . Length ] ;
93
-
94
- for ( int n = 0 ; n < gosToExport . Length ; n ++ ) {
95
- var filename = ModelExporter . ConvertToValidFilename ( gosToExport [ n ] . name + ".fbx" ) ;
96
- var filePath = Path . Combine ( path , filename ) ;
97
- if ( File . Exists ( filePath ) ) {
98
- filePath = IncrementFileName ( path , filename ) ;
82
+ var toExport = ModelExporter . RemoveRedundantObjects ( unityGameObjectsToConvert ) ;
83
+ var wasExported = new List < GameObject > ( ) ;
84
+ foreach ( var go in toExport ) {
85
+ try {
86
+ wasExported . Add ( CreateInstantiatedModelPrefab ( go ,
87
+ directoryFullPath : directoryFullPath ,
88
+ keepOriginal : keepOriginal ) ) ;
89
+ } catch ( System . Exception xcp ) {
90
+ Debug . LogException ( xcp ) ;
99
91
}
100
- filePaths [ n ] = filePath ;
101
92
}
93
+ return wasExported . ToArray ( ) ;
94
+ }
102
95
103
- string [ ] fbxFileNames = new string [ filePaths . Length ] ;
96
+ /// <summary>
97
+ /// Convert one object (and the hierarchy below it) to an auto-updating prefab.
98
+ ///
99
+ /// This returns a new object; the converted object may be modified or destroyed.
100
+ ///
101
+ /// This refreshes the asset database.
102
+ ///
103
+ /// If "keepOriginal" is set, the converted object is modified but remains in the scene.
104
+ /// </summary>
105
+ /// <returns>The instance that replaces 'toConvert' in the scene.</returns>
106
+ /// <param name="toConvert">GameObject hierarchy to replace with a prefab.</param>
107
+ /// <param name="fbxFullPath">Absolute platform-specific path to the fbx file. May be null, in which case we construct a path from the object name and the directoryFullPath.</param>
108
+ /// <param name="directoryFullPath">Absolute platform-specific path to a directory in which to put the fbx file. Ignored if fbxFullPath is specified. May be null, in which case we use the export settings.</param>
109
+ /// <param name="keepOriginal">If set to <c>true</c>, keep the original in the scene.</param>
110
+ public static GameObject CreateInstantiatedModelPrefab (
111
+ GameObject toConvert ,
112
+ string directoryFullPath = null ,
113
+ string fbxFullPath = null ,
114
+ bool keepOriginal = true )
115
+ {
116
+ // Generate a unique filename.
117
+ if ( string . IsNullOrEmpty ( fbxFullPath ) ) {
118
+ if ( string . IsNullOrEmpty ( directoryFullPath ) ) {
119
+ directoryFullPath = FbxExporters . EditorTools . ExportSettings . GetAbsoluteSavePath ( ) ;
120
+ } else {
121
+ directoryFullPath = Path . GetFullPath ( directoryFullPath ) ;
122
+ }
123
+ var fbxBasename = ModelExporter . ConvertToValidFilename ( toConvert . name + ".fbx" ) ;
104
124
105
- for ( int j = 0 ; j < gosToExport . Length ; j ++ ) {
106
- fbxFileNames [ j ] = FbxExporters . Editor . ModelExporter . ExportObjects ( filePaths [ j ] ,
107
- new UnityEngine . Object [ ] { gosToExport [ j ] } ) as string ;
125
+ fbxFullPath = Path . Combine ( directoryFullPath , fbxBasename ) ;
126
+ if ( File . Exists ( fbxFullPath ) ) {
127
+ fbxFullPath = IncrementFileName ( directoryFullPath , fbxFullPath ) ;
128
+ }
108
129
}
130
+ var assetRelativePath = FbxExporters . EditorTools . ExportSettings . ConvertToAssetRelativePath ( fbxFullPath ) ;
131
+ var projectRelativePath = "Assets/" + assetRelativePath ;
132
+ if ( string . IsNullOrEmpty ( assetRelativePath ) ) {
133
+ throw new System . Exception ( "Path " + fbxFullPath + " must be in the Assets folder." ) ;
134
+ }
135
+
136
+ // Make sure that the object names in the hierarchy are unique.
137
+ // The import back in to Unity would do this automatically but we prefer to control it so that the Maya artist can see the same names as exist in Unity.
138
+ EnforceUniqueNames ( new GameObject [ ] { toConvert } ) ;
109
139
110
- for ( int i = 0 ; i < fbxFileNames . Length ; i ++ )
140
+ // Export to FBX. It refreshes the database.
111
141
{
112
- var fbxFileName = fbxFileNames [ i ] ;
113
- if ( fbxFileName == null ) {
114
- Debug . LogWarning ( string . Format ( "Warning: Export failed for GameObject {0}" , gosToExport [ i ] . name ) ) ;
115
- continue ;
142
+ var fbxActualPath = ModelExporter . ExportObject ( fbxFullPath , toConvert ) ;
143
+ if ( fbxActualPath != fbxFullPath ) {
144
+ throw new System . Exception ( "Failed to convert " + toConvert . name ) ;
116
145
}
146
+ }
117
147
118
- // make filepath relative
119
- var assetRelativePath = FbxExporters . EditorTools . ExportSettings . ConvertToAssetRelativePath ( fbxFileName ) ;
120
- var projectRelativePath = "Assets/" + assetRelativePath ;
121
-
122
- // refresh the assetdata base so that we can query for the model
123
- AssetDatabase . Refresh ( ) ;
124
-
125
- // Replace w Model asset. LoadMainAssetAtPath wants a path
126
- // relative to the project, not relative to the assets
127
- // folder.
128
- var unityMainAsset = AssetDatabase . LoadMainAssetAtPath ( projectRelativePath ) as GameObject ;
148
+ // Munge the path: we'll be using APIs that need a path relative to the assets folder.
129
149
130
- if ( ! unityMainAsset ) {
131
- continue ;
132
- }
133
150
134
- // Instantiate the FBX file.
135
- Object unityObj = PrefabUtility . InstantiatePrefab ( unityMainAsset , gosToExport [ i ] . scene ) ;
136
- GameObject unityGO = unityObj as GameObject ;
137
- if ( ! unityGO ) {
138
- continue ;
139
- }
151
+ // Replace w Model asset. LoadMainAssetAtPath wants a path
152
+ // relative to the project, not relative to the assets
153
+ // folder.
154
+ Debug . Log ( projectRelativePath ) ;
155
+ var unityMainAsset = AssetDatabase . LoadMainAssetAtPath ( projectRelativePath ) as GameObject ;
156
+ if ( ! unityMainAsset ) {
157
+ throw new System . Exception ( "Failed to convert " + toConvert . name ) ; ;
158
+ }
140
159
141
- // Copy the components over to the instance of the FBX.
142
- SetupImportedGameObject ( gosToExport [ i ] , unityGO ) ;
160
+ // Instantiate the FBX file.
161
+ var unityGO = PrefabUtility . InstantiatePrefab ( unityMainAsset , toConvert . scene )
162
+ as GameObject ;
163
+ if ( ! unityGO ) {
164
+ throw new System . Exception ( "Failed to convert " + toConvert . name ) ; ;
165
+ }
143
166
144
- // Set up the FbxPrefab component so we can auto-update.
145
- var fbxPrefab = unityGO . AddComponent < FbxPrefab > ( ) ;
146
- fbxPrefab . SetSourceModel ( unityMainAsset ) ;
167
+ // Copy the components over to the instance of the FBX.
168
+ SetupImportedGameObject ( toConvert , unityGO ) ;
147
169
148
- // Disconnect from the FBX file.
149
- PrefabUtility . DisconnectPrefabInstance ( unityGO ) ;
170
+ // Set up the FbxPrefab component so it will auto-update.
171
+ var fbxPrefab = unityGO . AddComponent < FbxPrefab > ( ) ;
172
+ fbxPrefab . SetSourceModel ( unityMainAsset ) ;
150
173
151
- // Create a prefab from the instantiated and componentized unityGO.
152
- var prefabFileName = Path . ChangeExtension ( projectRelativePath , ".prefab" ) ;
153
- var prefab = PrefabUtility . CreatePrefab ( prefabFileName , unityGO ) ;
154
- if ( ! prefab ) {
155
- throw new System . Exception (
156
- string . Format ( "Failed to create prefab asset in [{0}] from fbx [{1}]" ,
157
- prefabFileName , fbxFileName ) ) ;
158
- }
159
- // Connect to the prefab file.
160
- unityGO = PrefabUtility . ConnectGameObjectToPrefab ( unityGO , prefab ) ;
174
+ // Disconnect from the FBX file.
175
+ PrefabUtility . DisconnectPrefabInstance ( unityGO ) ;
161
176
162
- // Remove (now redundant) gameobject
163
- if ( ! keepOriginal ) {
164
- Object . DestroyImmediate ( unityGameObjectsToConvert [ i ] ) ;
165
- } else {
166
- // rename and put under scene root in case we need to check values
167
- gosToExport [ i ] . name = "_safe_to_delete_" + gosToExport [ i ] . name ;
168
- gosToExport [ i ] . SetActive ( false ) ;
169
- }
177
+ // Create a prefab from the instantiated and componentized unityGO.
178
+ var prefabFileName = Path . ChangeExtension ( projectRelativePath , ".prefab" ) ;
179
+ var prefab = PrefabUtility . CreatePrefab ( prefabFileName , unityGO ) ;
180
+ if ( ! prefab ) {
181
+ throw new System . Exception (
182
+ string . Format ( "Failed to create prefab asset in [{0}] from fbx [{1}]" ,
183
+ prefabFileName , fbxFullPath ) ) ;
184
+ }
185
+ // Connect to the prefab file.
186
+ unityGO = PrefabUtility . ConnectGameObjectToPrefab ( unityGO , prefab ) ;
170
187
171
- // add the instanced prefab
172
- result . Add ( unityGO ) ;
188
+ // Remove (now redundant) gameobject
189
+ if ( ! keepOriginal ) {
190
+ Object . DestroyImmediate ( toConvert ) ;
191
+ } else {
192
+ // rename and put under scene root in case we need to check values
193
+ toConvert . name = "_safe_to_delete_" + toConvert . name ;
194
+ toConvert . SetActive ( false ) ;
173
195
}
174
196
175
- return result . ToArray ( ) ;
197
+ return unityGO ;
176
198
}
177
199
178
200
/// <summary>
@@ -217,7 +239,7 @@ public static string IncrementFileName(string path, string filename)
217
239
/// e.g. Sphere becomes Sphere 1
218
240
/// </summary>
219
241
/// <param name="exportSet">Export set.</param>
220
- public static void EnforceUniqueNames ( GameObject [ ] exportSet )
242
+ public static void EnforceUniqueNames ( IEnumerable < GameObject > exportSet )
221
243
{
222
244
Dictionary < string , int > NameToIndexMap = new Dictionary < string , int > ( ) ;
223
245
string format = "{0} {1}" ;
0 commit comments