@@ -62,16 +62,6 @@ public static bool OnValidateMenuItem ()
62
62
return true ;
63
63
}
64
64
65
- /// <summary>
66
- /// After a convert-to-model, we normally delete the original object.
67
- /// That can be overridden.
68
- /// </summary>
69
- public enum KeepOriginal {
70
- Default , // Use the export settings.
71
- Keep , // Don't delete, just rename it.
72
- Delete , // Delete the original hierarchy.
73
- }
74
-
75
65
/// <summary>
76
66
/// Gets the export settings.
77
67
/// </summary>
@@ -89,11 +79,9 @@ public static EditorTools.ExportSettings ExportSettings {
89
79
/// <returns>list of instanced Model Prefabs</returns>
90
80
/// <param name="unityGameObjectsToConvert">Unity game objects to convert to Model Prefab instances</param>
91
81
/// <param name="path">Path to save Model Prefab; use FbxExportSettings if null</param>
92
- /// <param name="keepOriginal">If set to <c>true</c> keep original gameobject hierarchy.</param>
93
82
public static GameObject [ ] CreateInstantiatedModelPrefab (
94
83
GameObject [ ] unityGameObjectsToConvert ,
95
- string directoryFullPath = null ,
96
- KeepOriginal keepOriginal = KeepOriginal . Default )
84
+ string directoryFullPath = null )
97
85
{
98
86
if ( directoryFullPath == null ) {
99
87
directoryFullPath = FbxExporters . EditorTools . ExportSettings . GetAbsoluteSavePath ( ) ;
@@ -106,8 +94,7 @@ public static GameObject[] CreateInstantiatedModelPrefab (
106
94
foreach ( var go in toExport ) {
107
95
try {
108
96
wasExported . Add ( Convert ( go ,
109
- directoryFullPath : directoryFullPath ,
110
- keepOriginal : keepOriginal ) ) ;
97
+ directoryFullPath : directoryFullPath ) ) ;
111
98
} catch ( System . Exception xcp ) {
112
99
Debug . LogException ( xcp ) ;
113
100
}
@@ -121,8 +108,6 @@ public static GameObject[] CreateInstantiatedModelPrefab (
121
108
/// This returns a new object; the converted object may be modified or destroyed.
122
109
///
123
110
/// This refreshes the asset database.
124
- ///
125
- /// If "keepOriginal" is set, the converted object is modified but remains in the scene.
126
111
/// </summary>
127
112
/// <returns>The instance that replaces 'toConvert' in the scene.</returns>
128
113
/// <param name="toConvert">GameObject hierarchy to replace with a prefab.</param>
@@ -134,12 +119,10 @@ public static GameObject[] CreateInstantiatedModelPrefab (
134
119
/// to a directory in which to put the fbx file. Ignored if
135
120
/// fbxFullPath is specified. May be null, in which case we use the
136
121
/// export settings.</param>
137
- /// <param name="keepOriginal">If set to <c>true</c>, keep the original in the scene.</param>
138
122
public static GameObject Convert (
139
123
GameObject toConvert ,
140
124
string directoryFullPath = null ,
141
- string fbxFullPath = null ,
142
- KeepOriginal keepOriginal = KeepOriginal . Default )
125
+ string fbxFullPath = null )
143
126
{
144
127
if ( string . IsNullOrEmpty ( fbxFullPath ) ) {
145
128
// Generate a unique filename.
@@ -182,68 +165,28 @@ public static GameObject Convert (
182
165
throw new System . Exception ( "Failed to convert " + toConvert . name ) ; ;
183
166
}
184
167
185
- // Instantiate the FBX file.
186
- var unityGO = PrefabUtility . InstantiatePrefab ( unityMainAsset , toConvert . scene )
187
- as GameObject ;
188
- if ( ! unityGO ) {
189
- throw new System . Exception ( "Failed to convert " + toConvert . name ) ; ;
190
- }
191
-
192
- // Copy the components over to the instance of the FBX.
193
- SetupImportedGameObject ( toConvert , unityGO ) ;
194
-
195
- // temporary quick fix
196
- var temp = toConvert ;
197
- toConvert = unityGO ;
198
- unityGO = temp ;
168
+ // Copy the mesh/materials from the FBX
169
+ UpdateFromFBX ( toConvert , unityMainAsset ) ;
199
170
200
171
// Set up the FbxPrefab component so it will auto-update.
201
172
// Make sure to delete whatever FbxPrefab history we had.
202
- var fbxPrefab = unityGO . GetComponent < FbxPrefab > ( ) ;
173
+ var fbxPrefab = toConvert . GetComponent < FbxPrefab > ( ) ;
203
174
if ( fbxPrefab ) {
204
175
Object . DestroyImmediate ( fbxPrefab ) ;
205
176
}
206
- fbxPrefab = unityGO . AddComponent < FbxPrefab > ( ) ;
177
+ fbxPrefab = toConvert . AddComponent < FbxPrefab > ( ) ;
207
178
fbxPrefab . SetSourceModel ( unityMainAsset ) ;
208
179
209
- // Disconnect from the FBX file.
210
- PrefabUtility . DisconnectPrefabInstance ( unityGO ) ;
211
-
212
180
// Create a prefab from the instantiated and componentized unityGO.
213
181
var prefabFileName = Path . ChangeExtension ( projectRelativePath , ".prefab" ) ;
214
- var prefab = PrefabUtility . CreatePrefab ( prefabFileName , unityGO ) ;
182
+ var prefab = PrefabUtility . CreatePrefab ( prefabFileName , toConvert , ReplacePrefabOptions . ConnectToPrefab ) ;
215
183
if ( ! prefab ) {
216
184
throw new System . Exception (
217
185
string . Format ( "Failed to create prefab asset in [{0}] from fbx [{1}]" ,
218
186
prefabFileName , fbxFullPath ) ) ;
219
187
}
220
188
221
- // Connect to the prefab file.
222
- unityGO = PrefabUtility . ConnectGameObjectToPrefab ( unityGO , prefab ) ;
223
-
224
- // Remove (now redundant) gameobject
225
- bool actuallyKeepOriginal ;
226
- switch ( keepOriginal ) {
227
- case KeepOriginal . Delete :
228
- actuallyKeepOriginal = false ;
229
- break ;
230
- case KeepOriginal . Keep :
231
- actuallyKeepOriginal = true ;
232
- break ;
233
- case KeepOriginal . Default :
234
- default :
235
- actuallyKeepOriginal = ExportSettings . keepOriginalAfterConvert ;
236
- break ;
237
- }
238
- if ( ! actuallyKeepOriginal ) {
239
- Object . DestroyImmediate ( toConvert ) ;
240
- } else {
241
- // rename and put under scene root in case we need to check values
242
- toConvert . name = "_safe_to_delete_" + toConvert . name ;
243
- toConvert . SetActive ( false ) ;
244
- }
245
-
246
- return unityGO ;
189
+ return toConvert ;
247
190
}
248
191
249
192
/// <summary>
@@ -318,73 +261,75 @@ public static void EnforceUniqueNames(IEnumerable<GameObject> exportSet)
318
261
}
319
262
320
263
/// <summary>
321
- /// Sets up the imported GameObject to match the original.
322
- /// - Updates the name to be the same as original (i.e. remove the "(Clone)")
323
- /// - Moves the imported object to the correct position in the hierarchy
324
- /// - Updates the transform of the imported GameObject to match the original
325
- /// - Copy over missing components and component values
264
+ /// Updates the meshes and materials of the exported GameObjects
265
+ /// to link to those imported from the FBX.
326
266
/// </summary>
327
- /// <param name="orig">Original GameObject .</param>
328
- /// <param name="imported">Imported GameObject .</param>
329
- public static void SetupImportedGameObject ( GameObject orig , GameObject imported )
267
+ /// <param name="orig">Original.</param>
268
+ /// <param name="fbx">Fbx .</param>
269
+ public static void UpdateFromFBX ( GameObject orig , GameObject fbx )
330
270
{
331
- Transform importedTransform = imported . transform ;
332
- Transform origTransform = orig . transform ;
333
-
334
- // configure transform and maintain local pose
335
- importedTransform . SetParent ( origTransform . parent , false ) ;
336
- importedTransform . SetSiblingIndex ( origTransform . GetSiblingIndex ( ) ) ;
337
-
338
- // copy the components over, assuming that the hierarchy order is unchanged
339
- if ( origTransform . hierarchyCount != importedTransform . hierarchyCount ) {
340
- Debug . LogWarning ( string . Format ( "Warning: Exported {0} objects, but only imported {1}" ,
341
- origTransform . hierarchyCount , importedTransform . hierarchyCount ) ) ;
271
+ // recurse over orig, for each transform finding the corresponding transform in the FBX
272
+ // and copying the meshes and materials over from the FBX
273
+ var goDict = GetNameToFbxGameObject ( orig , fbx ) ;
274
+ var q = new Queue < Transform > ( ) ;
275
+ q . Enqueue ( orig . transform ) ;
276
+ while ( q . Count > 0 ) {
277
+ var t = q . Dequeue ( ) ;
278
+
279
+ if ( goDict [ t . name ] == null ) {
280
+ Debug . LogWarning ( string . Format ( "Warning: Could not find Object {0} in FBX" , t . name ) ) ;
281
+ continue ;
282
+ }
283
+ CopyComponents ( t . gameObject , goDict [ t . name ] ) ;
284
+ foreach ( Transform child in t ) {
285
+ q . Enqueue ( child ) ;
286
+ }
342
287
}
343
- FixSiblingOrder ( orig . transform , imported . transform ) ;
344
-
345
- // the imported GameObject will have the same name as the file to which it was imported from,
346
- // which might not be the same name as the original GameObject
347
- CopyComponentsRecursive ( orig , imported , namesExpectedMatch : false ) ;
348
288
}
349
289
350
290
/// <summary>
351
- /// Given two hierarchies of nodes whose names match up,
352
- /// make the 'imported' hierarchy have its children be in the same
353
- /// order as the 'orig' hierarchy.
354
- ///
355
- /// The 'orig' hierarchy is not modified.
291
+ /// Gets a dictionary linking exported GameObject name to fbx game object.
356
292
/// </summary>
357
- public static void FixSiblingOrder ( Transform orig , Transform imported ) {
358
- foreach ( Transform origChild in orig ) {
359
- Transform importedChild = imported . Find ( origChild . name ) ;
360
- if ( importedChild == null ) {
361
- Debug . LogWarning ( string . Format (
362
- "Warning: Could not find {0} in parented under {1} in import hierarchy" ,
363
- origChild . name , imported . name
364
- ) ) ;
365
- continue ;
293
+ /// <returns>Dictionary containing the name to fbx game object.</returns>
294
+ /// <param name="orig">Original.</param>
295
+ /// <param name="fbx">Fbx.</param>
296
+ private static Dictionary < string , GameObject > GetNameToFbxGameObject ( GameObject orig , GameObject fbx ) {
297
+ var nameToGO = new Dictionary < string , GameObject > ( ) ;
298
+
299
+ var q = new Queue < Transform > ( ) ;
300
+ q . Enqueue ( orig . transform ) ;
301
+ while ( q . Count > 0 ) {
302
+ var t = q . Dequeue ( ) ;
303
+ nameToGO [ t . name ] = null ;
304
+ foreach ( Transform child in t ) {
305
+ q . Enqueue ( child ) ;
366
306
}
367
- importedChild . SetSiblingIndex ( origChild . GetSiblingIndex ( ) ) ;
368
- FixSiblingOrder ( origChild , importedChild ) ;
369
307
}
370
- }
371
308
372
- private static void CopyComponentsRecursive ( GameObject from , GameObject to , bool namesExpectedMatch = true ) {
373
- if ( namesExpectedMatch && ! to . name . StartsWith ( from . name ) || from . transform . childCount != to . transform . childCount ) {
374
- Debug . LogError ( string . Format ( "Error: hierarchies don't match (From: {0}, To: {1})" , from . name , to . name ) ) ;
375
- return ;
309
+ nameToGO [ orig . name ] = fbx ;
310
+
311
+ var fbxQ = new Queue < Transform > ( ) ;
312
+ foreach ( Transform child in fbx . transform ) {
313
+ fbxQ . Enqueue ( child ) ;
376
314
}
377
315
378
- CopyComponents ( from , to ) ;
379
- for ( int i = 0 ; i < from . transform . childCount ; i ++ ) {
380
- CopyComponentsRecursive ( from . transform . GetChild ( i ) . gameObject , to . transform . GetChild ( i ) . gameObject ) ;
316
+ while ( fbxQ . Count > 0 ) {
317
+ var t = fbxQ . Dequeue ( ) ;
318
+ if ( ! nameToGO . ContainsKey ( t . name ) ) {
319
+ Debug . LogWarning ( string . Format ( "Warning: {0} in FBX but not in converted hierarchy" , t . name ) ) ;
320
+ continue ;
321
+ }
322
+ nameToGO [ t . name ] = t . gameObject ;
323
+ foreach ( Transform child in t ) {
324
+ fbxQ . Enqueue ( child ) ;
325
+ }
381
326
}
382
- }
383
327
328
+ return nameToGO ;
329
+ }
384
330
385
331
/// <summary>
386
- /// Copy components on the 'from' object which is the object
387
- /// in the scene that we imported from the FBX,
332
+ /// Copy components on the 'from' object which is the FBX,
388
333
/// over to the 'to' object which is the object in the
389
334
/// scene we exported.
390
335
///
@@ -430,9 +375,9 @@ public static void CopyComponents(GameObject to, GameObject from){
430
375
} else if ( toComponent is MeshFilter ) {
431
376
EditorJsonUtility . FromJsonOverwrite ( json , toComponent ) ;
432
377
} else if ( toComponent is Renderer ) {
433
- var toRen = toComponent as Renderer ;
434
- var fromRen = component as Renderer ;
435
- toRen . sharedMaterials = fromRen . sharedMaterials ;
378
+ var toRenderer = toComponent as Renderer ;
379
+ var fromRenderer = component as Renderer ;
380
+ toRenderer . sharedMaterials = fromRenderer . sharedMaterials ;
436
381
}
437
382
}
438
383
}
0 commit comments