@@ -262,7 +262,7 @@ public void SetupItems()
262262 faceVisemeMeshField . allowSceneObjects = true ;
263263 AvatarIconField . allowSceneObjects = true ;
264264
265- // AvatarIconField.value = null;
265+ // AvatarIconField.value = null;
266266 animatorField . value = Avatar . Animator ;
267267 faceBlinkMeshField . value = Avatar . FaceBlinkMesh ;
268268 faceVisemeMeshField . value = Avatar . FaceVisemeMesh ;
@@ -382,6 +382,8 @@ private async void EventCallbackAvatarBundle(List<BuildTarget> targets, Texture2
382382 // Add the result label to the UI
383383 uiElementsRoot . Add ( resultLabel ) ;
384384 // BuildReportViewerWindow.ShowWindow();
385+
386+ GameObject . Destroy ( buildRoot ) ;
385387 }
386388 else
387389 {
@@ -395,109 +397,104 @@ private async void EventCallbackAvatarBundle(List<BuildTarget> targets, Texture2
395397 }
396398 }
397399 }
398- #if UNITY_6000_2_OR_NEWER
399- /// <summary>
400- /// Generate Mesh LODs via ModelImporter for all SkinnedMeshRenderers under the given root.
401- /// Requires Unity 6000.2+ where ModelImporter.generateMeshLods exists.
402- /// </summary>
403- /// <param name="root">Root GameObject (e.g., your avatar/prefab in the scene or a prefab asset loaded in memory).</param>
404- /// <param name="lodLimit">
405- /// Maximum mesh LOD to generate. Use -1 to leave the current importer value unchanged.
406- /// </param>
400+ #if UNITY_6000_2_OR_NEWER && UNITY_EDITOR
407401 public void GenerateMeshLODs ( int lodLimit = - 1 )
408402 {
409403 var smrs = Avatar . GetComponentsInChildren < SkinnedMeshRenderer > ( true ) ;
410404 if ( smrs == null || smrs . Length == 0 )
411405 {
412- Debug . LogWarning ( $ "GenerateMeshLODs: No SkinnedMeshRenderer found under.") ;
406+ Debug . LogWarning ( "GenerateMeshLODs: No SkinnedMeshRenderer found under root." ) ;
407+ return ;
413408 }
414409
415- // Collect unique importer asset paths (FBX/OBJ). Multiple meshes often come from the same file.
416- var pathsNeedingReimport = new HashSet < string > ( ) ;
410+ var modelPathsNeedingReimport = new HashSet < string > ( ) ;
411+ var meshAssetsNeedingSave = new HashSet < Mesh > ( ) ; // for .asset meshes (and others without ModelImporter)
417412
418413 foreach ( var smr in smrs )
419414 {
420- if ( smr == null || smr . sharedMesh == null )
421- continue ;
415+ if ( smr == null || smr . sharedMesh == null ) continue ;
422416
423- // Get the asset path for the mesh; for model sub-assets this is the FBX/OBJ path.
424- string meshPath = AssetDatabase . GetAssetPath ( smr . sharedMesh ) ;
425- if ( string . IsNullOrEmpty ( meshPath ) )
426- continue ;
417+ var mesh = smr . sharedMesh ;
418+ string meshPath = AssetDatabase . GetAssetPath ( mesh ) ;
419+ if ( string . IsNullOrEmpty ( meshPath ) ) continue ;
427420
428421 var importer = AssetImporter . GetAtPath ( meshPath ) as ModelImporter ;
429- if ( importer == null )
430- continue ; // Not a model-imported mesh (e.g., .asset mesh), skip.
431-
432- // Set importer flags
433- bool changed = false ;
434422
435- if ( ! importer . generateMeshLods )
423+ if ( importer != null )
436424 {
437- importer . generateMeshLods = true ;
438- changed = true ;
439- }
425+ bool changed = false ;
426+
427+ if ( ! importer . generateMeshLods )
428+ {
429+ importer . generateMeshLods = true ;
430+ changed = true ;
431+ }
440432
441- if ( lodLimit >= 0 && importer . maximumMeshLod != lodLimit )
433+ if ( lodLimit >= 0 && importer . maximumMeshLod != lodLimit )
434+ {
435+ importer . maximumMeshLod = lodLimit ;
436+ changed = true ;
437+ }
438+
439+ if ( changed )
440+ {
441+ modelPathsNeedingReimport . Add ( meshPath ) ;
442+ }
443+ }
444+ else
442445 {
443- importer . maximumMeshLod = lodLimit ;
444- changed = true ;
446+ // .asset Mesh (or otherwise not model-imported):
447+ // Generate Mesh LODs directly on the mesh asset.
448+ // meshLodLimit here = "max number of LOD levels to generate" (see docs).
449+ // 0 => generate none beyond original; negative => auto-stop at ~64 indices. :contentReference[oaicite:3]{index=3}
450+ int meshLodLimit = lodLimit ; // reuse your parameter; adjust semantics if you want
451+ MeshLodUtility . GenerateMeshLods ( mesh , meshLodLimit ) ;
452+
453+ EditorUtility . SetDirty ( mesh ) ;
454+ meshAssetsNeedingSave . Add ( mesh ) ;
445455 }
446456
447- if ( changed )
448- pathsNeedingReimport . Add ( meshPath ) ;
449-
450- // Component-level preferences (do not require reimport)
457+ // Renderer-level knobs (work once mesh actually has Mesh LODs) :contentReference[oaicite:4]{index=4}
451458 smr . meshLodSelectionBias = 0f ;
452459 smr . forceMeshLod = - 1 ;
453460 }
454461
455- if ( pathsNeedingReimport . Count == 0 )
462+ // Reimport model files (FBX/OBJ)
463+ if ( modelPathsNeedingReimport . Count > 0 )
456464 {
457- Debug . Log ( "GenerateMeshLODs: No importer changes detected." ) ;
458- return ;
459- }
460-
461- try
462- {
463- AssetDatabase . StartAssetEditing ( ) ;
464-
465- int i = 0 ;
466- int total = pathsNeedingReimport . Count ;
467- foreach ( var path in pathsNeedingReimport )
465+ try
468466 {
469- if ( EditorUtility . DisplayCancelableProgressBar (
470- "Reimporting Models (LODs)" ,
471- $ "{ i + 1 } /{ total } : { path } ",
472- ( float ) i / total ) )
473- {
474- Debug . LogWarning ( "GenerateMeshLODs: Canceled by user." ) ;
475- break ;
476- }
467+ AssetDatabase . StartAssetEditing ( ) ;
468+ int i = 0 , total = modelPathsNeedingReimport . Count ;
477469
478- var importer = AssetImporter . GetAtPath ( path ) as ModelImporter ;
479- if ( importer != null )
470+ foreach ( var path in modelPathsNeedingReimport )
480471 {
481- // Write settings and reimport this asset immediately.
482- // Either approach works; SaveAndReimport is the simplest.
483- importer . SaveAndReimport ( ) ;
484- // Alternatively:
485- // AssetDatabase.WriteImportSettingsIfDirty(path);
486- // AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
472+ if ( EditorUtility . DisplayCancelableProgressBar (
473+ "Reimporting Models (Mesh LODs)" ,
474+ $ "{ i + 1 } /{ total } : { path } ",
475+ ( float ) i / total ) )
476+ {
477+ Debug . LogWarning ( "GenerateMeshLODs: Canceled by user." ) ;
478+ break ;
479+ }
480+
481+ var mi = AssetImporter . GetAtPath ( path ) as ModelImporter ;
482+ if ( mi != null ) mi . SaveAndReimport ( ) ;
483+ i ++ ;
487484 }
488-
489- i ++ ;
485+ }
486+ finally
487+ {
488+ EditorUtility . ClearProgressBar ( ) ;
489+ AssetDatabase . StopAssetEditing ( ) ;
490490 }
491491 }
492- finally
493- {
494- EditorUtility . ClearProgressBar ( ) ;
495- AssetDatabase . StopAssetEditing ( ) ;
492+
493+ // Save modified .asset meshes
494+ if ( meshAssetsNeedingSave . Count > 0 )
496495 AssetDatabase . SaveAssets ( ) ;
497- // No need for AssetDatabase.Refresh(); reimports were explicit.
498- }
499496
500- Debug . Log ( $ "GenerateMeshLODs: Reimported { pathsNeedingReimport . Count } model asset(s).") ;
497+ Debug . Log ( $ "GenerateMeshLODs: Reimported { modelPathsNeedingReimport . Count } model asset(s), updated { meshAssetsNeedingSave . Count } mesh asset(s).") ;
501498 }
502499#endif
503500 public void AvatarTestInEditorClickFunction ( )
0 commit comments