unity 自动删除未引用的Assets下的资源

随着时间的堆积,项目中Assets文件夹下的资源会变得越来越繁杂,有些贴图、材质啥的可能压根没有使用过,但是又不敢轻易去删除。

这里分享两个插件,用于管理这些资源。

 

一、ResourceChecker

 

这个插件的强大之处就在于它能够查找当前场景中的所有引用个资源,并快速定位,然后把未定位到的资源手动删掉就行了。

代码

 

   1 // Resource Checker
   2 // (c) 2012 Simon Oliver / HandCircus / hello@handcircus.com
   3 // (c) 2015 Brice Clocher / Mangatome / hello@mangatome.net
   4 // Public domain, do with whatever you like, commercial or not
   5 // This comes with no warranty, use at your own risk!
   6 // https://github.com/handcircus/Unity-Resource-Checker
   7 
   8 using System;
   9 using System.Linq;
  10 using UnityEngine;
  11 using UnityEngine.UI;
  12 using UnityEditor;
  13 using System.Collections.Generic;
  14 using System.Reflection;
  15 using Object = UnityEngine.Object;
  16 
  17 public class TextureDetails : IEquatable<TextureDetails>
  18 {
  19     public bool isCubeMap;
  20     public int memSizeKB;
  21     public Texture texture;
  22     public TextureFormat format;
  23     public int mipMapCount;
  24     public List<Object> FoundInMaterials=new List<Object>();
  25     public List<Object> FoundInRenderers=new List<Object>();
  26     public List<Object> FoundInAnimators = new List<Object>();
  27     public List<Object> FoundInScripts = new List<Object>();
  28     public List<Object> FoundInGraphics = new List<Object>();
  29     public bool isSky;
  30     public bool instance;
  31     public bool isgui;
  32     public TextureDetails()
  33     {
  34 
  35     }
  36 
  37     public bool Equals(TextureDetails other)
  38     {
  39         return texture != null && other.texture != null &&
  40             texture.GetNativeTexturePtr() == other.texture.GetNativeTexturePtr();
  41     }
  42 
  43     public override int GetHashCode()
  44     {
  45         return (int)texture.GetNativeTexturePtr();
  46     }
  47 
  48     public override bool Equals(object obj)
  49     {
  50         return Equals(obj as TextureDetails);
  51     }
  52 };
  53 
  54 public class MaterialDetails
  55 {
  56 
  57     public Material material;
  58 
  59     public List<Renderer> FoundInRenderers=new List<Renderer>();
  60     public List<Graphic> FoundInGraphics=new List<Graphic>();
  61     public bool instance;
  62     public bool isgui;
  63     public bool isSky;
  64 
  65     public MaterialDetails()
  66     {
  67         instance = false;
  68         isgui = false;
  69         isSky = false;
  70     }
  71 };
  72 
  73 public class MeshDetails
  74 {
  75 
  76     public Mesh mesh;
  77 
  78     public List<MeshFilter> FoundInMeshFilters=new List<MeshFilter>();
  79     public List<SkinnedMeshRenderer> FoundInSkinnedMeshRenderer=new List<SkinnedMeshRenderer>();
  80     public bool instance;
  81 
  82     public MeshDetails()
  83     {
  84         instance = false;
  85     }
  86 };
  87 
  88 public class MissingGraphic{
  89     public Transform Object;
  90     public string type;
  91     public string name;
  92 }
  93 
  94 public class ResourceChecker : EditorWindow {
  95 
  96 
  97     string[] inspectToolbarStrings = {"Textures", "Materials","Meshes"};
  98     string[] inspectToolbarStrings2 = {"Textures", "Materials","Meshes", "Missing"};
  99 
 100     enum InspectType 
 101     {
 102         Textures,Materials,Meshes,Missing
 103     };
 104 
 105     bool IncludeDisabledObjects=true;
 106     bool IncludeSpriteAnimations=true;
 107     bool IncludeScriptReferences=true;
 108     bool IncludeGuiElements=true;
 109     bool thingsMissing = false;
 110 
 111     InspectType ActiveInspectType=InspectType.Textures;
 112 
 113     float ThumbnailWidth=40;
 114     float ThumbnailHeight=40;
 115 
 116     List<TextureDetails> ActiveTextures=new List<TextureDetails>();
 117     List<MaterialDetails> ActiveMaterials=new List<MaterialDetails>();
 118     List<MeshDetails> ActiveMeshDetails=new List<MeshDetails>();
 119     List<MissingGraphic> MissingObjects = new List<MissingGraphic> ();
 120 
 121     Vector2 textureListScrollPos=new Vector2(0,0);
 122     Vector2 materialListScrollPos=new Vector2(0,0);
 123     Vector2 meshListScrollPos=new Vector2(0,0);
 124     Vector2 missingListScrollPos = new Vector2 (0,0);
 125 
 126     int TotalTextureMemory=0;
 127     int TotalMeshVertices=0;
 128 
 129     bool ctrlPressed=false;
 130 
 131     static int MinWidth=475;
 132     Color defColor;
 133 
 134     bool collectedInPlayingMode;
 135 
 136     [MenuItem ("Window/Resource Checker")]
 137     static void Init ()
 138     {  
 139         ResourceChecker window = (ResourceChecker) EditorWindow.GetWindow (typeof (ResourceChecker));
 140         window.CheckResources();
 141         window.minSize=new Vector2(MinWidth,475);
 142     }
 143 
 144     void OnGUI ()
 145     {
 146         defColor = GUI.color;
 147         IncludeDisabledObjects = GUILayout.Toggle(IncludeDisabledObjects, "Include disabled objects", GUILayout.Width(300));
 148         IncludeSpriteAnimations = GUILayout.Toggle(IncludeSpriteAnimations, "Look in sprite animations", GUILayout.Width(300));
 149         GUI.color = new Color (0.8f, 0.8f, 1.0f, 1.0f);
 150         IncludeScriptReferences = GUILayout.Toggle(IncludeScriptReferences, "Look in behavior fields", GUILayout.Width(300));
 151         GUI.color = new Color (1.0f, 0.95f, 0.8f, 1.0f);
 152         IncludeGuiElements = GUILayout.Toggle(IncludeGuiElements, "Look in GUI elements", GUILayout.Width(300));
 153         GUI.color = defColor;
 154         GUILayout.BeginArea(new Rect(position.width-85,5,100,65));
 155         if (GUILayout.Button("Calculate",GUILayout.Width(80), GUILayout.Height(40)))
 156             CheckResources();
 157         if (GUILayout.Button("CleanUp",GUILayout.Width(80), GUILayout.Height(20)))
 158             Resources.UnloadUnusedAssets();
 159         GUILayout.EndArea();
 160         RemoveDestroyedResources();
 161 
 162         GUILayout.Space(30);
 163         if (thingsMissing == true) {
 164             EditorGUI.HelpBox (new Rect(8,75,300,25),"Some GameObjects are missing graphical elements.", MessageType.Error);
 165         }
 166         GUILayout.BeginHorizontal();
 167         GUILayout.Label("Textures "+ActiveTextures.Count+" - "+FormatSizeString(TotalTextureMemory));
 168         GUILayout.Label("Materials "+ActiveMaterials.Count);
 169         GUILayout.Label("Meshes "+ActiveMeshDetails.Count+" - "+TotalMeshVertices+" verts");
 170         GUILayout.EndHorizontal();
 171         if (thingsMissing == true) {
 172             ActiveInspectType = (InspectType)GUILayout.Toolbar ((int)ActiveInspectType, inspectToolbarStrings2);
 173         } else {
 174             ActiveInspectType = (InspectType)GUILayout.Toolbar ((int)ActiveInspectType, inspectToolbarStrings);
 175         }
 176 
 177         ctrlPressed=Event.current.control || Event.current.command;
 178 
 179         switch (ActiveInspectType)
 180         {
 181         case InspectType.Textures:
 182             ListTextures();
 183             break;
 184         case InspectType.Materials:
 185             ListMaterials();
 186             break;
 187         case InspectType.Meshes:
 188             ListMeshes();
 189             break;
 190         case InspectType.Missing:
 191             ListMissing();
 192             break;
 193         }
 194     }
 195 
 196     private void RemoveDestroyedResources()
 197     {
 198         if (collectedInPlayingMode != Application.isPlaying)
 199         {
 200             ActiveTextures.Clear();
 201             ActiveMaterials.Clear();
 202             ActiveMeshDetails.Clear();
 203             MissingObjects.Clear ();
 204             thingsMissing = false;
 205             collectedInPlayingMode = Application.isPlaying;
 206         }
 207         
 208         ActiveTextures.RemoveAll(x => !x.texture);
 209         ActiveTextures.ForEach(delegate(TextureDetails obj) {
 210             obj.FoundInAnimators.RemoveAll(x => !x);
 211             obj.FoundInMaterials.RemoveAll(x => !x);
 212             obj.FoundInRenderers.RemoveAll(x => !x);
 213             obj.FoundInScripts.RemoveAll(x => !x);
 214             obj.FoundInGraphics.RemoveAll(x => !x);
 215         });
 216 
 217         ActiveMaterials.RemoveAll(x => !x.material);
 218         ActiveMaterials.ForEach(delegate(MaterialDetails obj) {
 219             obj.FoundInRenderers.RemoveAll(x => !x);
 220             obj.FoundInGraphics.RemoveAll(x => !x);
 221         });
 222 
 223         ActiveMeshDetails.RemoveAll(x => !x.mesh);
 224         ActiveMeshDetails.ForEach(delegate(MeshDetails obj) {
 225             obj.FoundInMeshFilters.RemoveAll(x => !x);
 226             obj.FoundInSkinnedMeshRenderer.RemoveAll(x => !x);
 227         });
 228 
 229         TotalTextureMemory = 0;
 230         foreach (TextureDetails tTextureDetails in ActiveTextures) TotalTextureMemory += tTextureDetails.memSizeKB;
 231 
 232         TotalMeshVertices = 0;
 233         foreach (MeshDetails tMeshDetails in ActiveMeshDetails) TotalMeshVertices += tMeshDetails.mesh.vertexCount;
 234     }
 235 
 236     int GetBitsPerPixel(TextureFormat format)
 237     {
 238         switch (format)
 239         {
 240         case TextureFormat.Alpha8: //     Alpha-only texture format.
 241             return 8;
 242         case TextureFormat.ARGB4444: //     A 16 bits/pixel texture format. Texture stores color with an alpha channel.
 243             return 16;
 244         case TextureFormat.RGBA4444: //     A 16 bits/pixel texture format.
 245             return 16;
 246         case TextureFormat.RGB24:    // A color texture format.
 247             return 24;
 248         case TextureFormat.RGBA32:    //Color with an alpha channel texture format.
 249             return 32;
 250         case TextureFormat.ARGB32:    //Color with an alpha channel texture format.
 251             return 32;
 252         case TextureFormat.RGB565:    //     A 16 bit color texture format.
 253             return 16;
 254         case TextureFormat.DXT1:    // Compressed color texture format.
 255             return 4;
 256         case TextureFormat.DXT5:    // Compressed color with alpha channel texture format.
 257             return 8;
 258             /*
 259             case TextureFormat.WiiI4:    // Wii texture format.
 260             case TextureFormat.WiiI8:    // Wii texture format. Intensity 8 bit.
 261             case TextureFormat.WiiIA4:    // Wii texture format. Intensity + Alpha 8 bit (4 + 4).
 262             case TextureFormat.WiiIA8:    // Wii texture format. Intensity + Alpha 16 bit (8 + 8).
 263             case TextureFormat.WiiRGB565:    // Wii texture format. RGB 16 bit (565).
 264             case TextureFormat.WiiRGB5A3:    // Wii texture format. RGBA 16 bit (4443).
 265             case TextureFormat.WiiRGBA8:    // Wii texture format. RGBA 32 bit (8888).
 266             case TextureFormat.WiiCMPR:    //     Compressed Wii texture format. 4 bits/texel, ~RGB8A1 (Outline alpha is not currently supported).
 267                 return 0;  //Not supported yet
 268             */
 269         case TextureFormat.PVRTC_RGB2://     PowerVR (iOS) 2 bits/pixel compressed color texture format.
 270             return 2;
 271         case TextureFormat.PVRTC_RGBA2://     PowerVR (iOS) 2 bits/pixel compressed with alpha channel texture format
 272             return 2;
 273         case TextureFormat.PVRTC_RGB4://     PowerVR (iOS) 4 bits/pixel compressed color texture format.
 274             return 4;
 275         case TextureFormat.PVRTC_RGBA4://     PowerVR (iOS) 4 bits/pixel compressed with alpha channel texture format
 276             return 4;
 277         case TextureFormat.ETC_RGB4://     ETC (GLES2.0) 4 bits/pixel compressed RGB texture format.
 278             return 4;
 279         case TextureFormat.ATC_RGB4://     ATC (ATITC) 4 bits/pixel compressed RGB texture format.
 280             return 4;
 281         case TextureFormat.ATC_RGBA8://     ATC (ATITC) 8 bits/pixel compressed RGB texture format.
 282             return 8;
 283         case TextureFormat.BGRA32://     Format returned by iPhone camera
 284             return 32;
 285             #if !UNITY_5 && !UNITY_5_3_OR_NEWER
 286             case TextureFormat.ATF_RGB_DXT1://     Flash-specific RGB DXT1 compressed color texture format.
 287             case TextureFormat.ATF_RGBA_JPG://     Flash-specific RGBA JPG-compressed color texture format.
 288             case TextureFormat.ATF_RGB_JPG://     Flash-specific RGB JPG-compressed color texture format.
 289             return 0; //Not supported yet  
 290             #endif
 291         }
 292         return 0;
 293     }
 294 
 295     int CalculateTextureSizeBytes(Texture tTexture)
 296     {
 297 
 298         int tWidth=tTexture.width;
 299         int tHeight=tTexture.height;
 300         if (tTexture is Texture2D)
 301         {
 302             Texture2D tTex2D=tTexture as Texture2D;
 303             int bitsPerPixel=GetBitsPerPixel(tTex2D.format);
 304             int mipMapCount=tTex2D.mipmapCount;
 305             int mipLevel=1;
 306             int tSize=0;
 307             while (mipLevel<=mipMapCount)
 308             {
 309                 tSize+=tWidth*tHeight*bitsPerPixel/8;
 310                 tWidth=tWidth/2;
 311                 tHeight=tHeight/2;
 312                 mipLevel++;
 313             }
 314             return tSize;
 315         }
 316         if (tTexture is Texture2DArray)
 317         {
 318             Texture2DArray tTex2D=tTexture as Texture2DArray;
 319             int bitsPerPixel=GetBitsPerPixel(tTex2D.format);
 320             int mipMapCount=10;
 321             int mipLevel=1;
 322             int tSize=0;
 323             while (mipLevel<=mipMapCount)
 324             {
 325                 tSize+=tWidth*tHeight*bitsPerPixel/8;
 326                 tWidth=tWidth/2;
 327                 tHeight=tHeight/2;
 328                 mipLevel++;
 329             }
 330             return tSize*((Texture2DArray)tTex2D).depth;
 331         }
 332         if (tTexture is Cubemap) {
 333             Cubemap tCubemap = tTexture as Cubemap;
 334             int bitsPerPixel = GetBitsPerPixel (tCubemap.format);
 335             return tWidth * tHeight * 6 * bitsPerPixel / 8;
 336         }
 337         return 0;
 338     }
 339 
 340 
 341     void SelectObject(Object selectedObject,bool append)
 342     {
 343         if (append)
 344         {
 345             List<Object> currentSelection=new List<Object>(Selection.objects);
 346             // Allow toggle selection
 347             if (currentSelection.Contains(selectedObject)) currentSelection.Remove(selectedObject);
 348             else currentSelection.Add(selectedObject);
 349 
 350             Selection.objects=currentSelection.ToArray();
 351         }
 352         else Selection.activeObject=selectedObject;
 353     }
 354 
 355     void SelectObjects(List<Object> selectedObjects,bool append)
 356     {
 357         if (append)
 358         {
 359             List<Object> currentSelection=new List<Object>(Selection.objects);
 360             currentSelection.AddRange(selectedObjects);
 361             Selection.objects=currentSelection.ToArray();
 362         }
 363         else Selection.objects=selectedObjects.ToArray();
 364     }
 365 
 366     void ListTextures()
 367     {
 368         textureListScrollPos = EditorGUILayout.BeginScrollView(textureListScrollPos);
 369 
 370         foreach (TextureDetails tDetails in ActiveTextures)
 371         {            
 372 
 373             GUILayout.BeginHorizontal ();
 374             Texture tex = new Texture();
 375             tex = tDetails.texture;
 376             if(tDetails.texture.GetType() == typeof(Texture2DArray) || tDetails.texture.GetType() == typeof(Cubemap)){
 377                 tex = AssetPreview.GetMiniThumbnail(tDetails.texture);
 378             }
 379             GUILayout.Box(tex, GUILayout.Width(ThumbnailWidth), GUILayout.Height(ThumbnailHeight));
 380 
 381             if (tDetails.instance == true)
 382                 GUI.color = new Color (0.8f, 0.8f, defColor.b, 1.0f);
 383             if (tDetails.isgui == true)
 384                 GUI.color = new Color (defColor.r, 0.95f, 0.8f, 1.0f);
 385             if (tDetails.isSky)
 386                 GUI.color = new Color (0.9f, defColor.g, defColor.b, 1.0f);
 387             if(GUILayout.Button(tDetails.texture.name,GUILayout.Width(150)))
 388             {
 389                 SelectObject(tDetails.texture,ctrlPressed);
 390             }
 391             GUI.color = defColor;
 392 
 393             string sizeLabel=""+tDetails.texture.width+"x"+tDetails.texture.height;
 394             if (tDetails.isCubeMap) sizeLabel+="x6";
 395             if (tDetails.texture.GetType () == typeof(Texture2DArray))
 396                 sizeLabel+= "[]\n" + ((Texture2DArray)tDetails.texture).depth+"depths";
 397             sizeLabel+=" - "+tDetails.mipMapCount+"mip\n"+FormatSizeString(tDetails.memSizeKB)+" - "+tDetails.format;
 398 
 399             GUILayout.Label (sizeLabel,GUILayout.Width(120));
 400 
 401             if(GUILayout.Button(tDetails.FoundInMaterials.Count+" Mat",GUILayout.Width(50)))
 402             {
 403                 SelectObjects(tDetails.FoundInMaterials,ctrlPressed);
 404             }
 405 
 406             HashSet<Object> FoundObjects = new HashSet<Object>();
 407             foreach (Renderer renderer in tDetails.FoundInRenderers) FoundObjects.Add(renderer.gameObject);
 408             foreach (Animator animator in tDetails.FoundInAnimators) FoundObjects.Add(animator.gameObject);
 409             foreach (Graphic graphic in tDetails.FoundInGraphics) FoundObjects.Add(graphic.gameObject);
 410             foreach (MonoBehaviour script in tDetails.FoundInScripts) FoundObjects.Add(script.gameObject);
 411             if (GUILayout.Button(FoundObjects.Count+" GO",GUILayout.Width(50)))
 412             {
 413                 SelectObjects(new List<Object>(FoundObjects),ctrlPressed);
 414             }
 415 
 416             GUILayout.EndHorizontal();    
 417         }
 418         if (ActiveTextures.Count>0)
 419         {
 420             EditorGUILayout.Space();
 421             GUILayout.BeginHorizontal ();
 422             //GUILayout.Box(" ",GUILayout.Width(ThumbnailWidth),GUILayout.Height(ThumbnailHeight));
 423             if(GUILayout.Button("Select \n All",GUILayout.Width(ThumbnailWidth*2)))
 424             {
 425                 List<Object> AllTextures=new List<Object>();
 426                 foreach (TextureDetails tDetails in ActiveTextures) AllTextures.Add(tDetails.texture);
 427                 SelectObjects(AllTextures,ctrlPressed);
 428             }
 429             EditorGUILayout.EndHorizontal();
 430         }
 431         EditorGUILayout.EndScrollView();
 432     }
 433 
 434     void ListMaterials()
 435     {
 436         materialListScrollPos = EditorGUILayout.BeginScrollView(materialListScrollPos);
 437 
 438         foreach (MaterialDetails tDetails in ActiveMaterials)
 439         {            
 440             if (tDetails.material!=null)
 441             {
 442                 GUILayout.BeginHorizontal ();
 443 
 444                 GUILayout.Box(AssetPreview.GetAssetPreview(tDetails.material), GUILayout.Width(ThumbnailWidth), GUILayout.Height(ThumbnailHeight));
 445 
 446                 if (tDetails.instance == true)
 447                     GUI.color = new Color (0.8f, 0.8f, defColor.b, 1.0f);
 448                 if (tDetails.isgui == true)
 449                     GUI.color = new Color (defColor.r, 0.95f, 0.8f, 1.0f);
 450                 if (tDetails.isSky)
 451                     GUI.color = new Color (0.9f, defColor.g, defColor.b, 1.0f);
 452                 if(GUILayout.Button(tDetails.material.name,GUILayout.Width(150)))
 453                 {
 454                     SelectObject(tDetails.material,ctrlPressed);
 455                 }
 456                 GUI.color = defColor;
 457 
 458                 string shaderLabel = tDetails.material.shader != null ? tDetails.material.shader.name : "no shader";
 459                 GUILayout.Label (shaderLabel, GUILayout.Width(200));
 460 
 461                 if(GUILayout.Button((tDetails.FoundInRenderers.Count + tDetails.FoundInGraphics.Count) +" GO",GUILayout.Width(50)))
 462                 {
 463                     List<Object> FoundObjects=new List<Object>();
 464                     foreach (Renderer renderer in tDetails.FoundInRenderers) FoundObjects.Add(renderer.gameObject);
 465                     foreach (Graphic graphic in tDetails.FoundInGraphics) FoundObjects.Add(graphic.gameObject);
 466                     SelectObjects(FoundObjects,ctrlPressed);
 467                 }
 468 
 469 
 470                 GUILayout.EndHorizontal();    
 471             }
 472         }
 473         EditorGUILayout.EndScrollView();        
 474     }
 475 
 476     void ListMeshes()
 477     {
 478         meshListScrollPos = EditorGUILayout.BeginScrollView(meshListScrollPos);
 479 
 480         foreach (MeshDetails tDetails in ActiveMeshDetails)
 481         {            
 482             if (tDetails.mesh!=null)
 483             {
 484                 GUILayout.BeginHorizontal ();
 485                 string name = tDetails.mesh.name;
 486                 if (name == null || name.Count() < 1)
 487                     name = tDetails.FoundInMeshFilters[0].gameObject.name;
 488                 if (tDetails.instance == true)
 489                     GUI.color = new Color (0.8f, 0.8f, defColor.b, 1.0f);
 490                 if(GUILayout.Button(name,GUILayout.Width(150)))
 491                 {
 492                     SelectObject(tDetails.mesh,ctrlPressed);
 493                 }
 494                 GUI.color = defColor;
 495                 string sizeLabel=""+tDetails.mesh.vertexCount+" vert";
 496 
 497                 GUILayout.Label (sizeLabel,GUILayout.Width(100));
 498 
 499 
 500                 if(GUILayout.Button(tDetails.FoundInMeshFilters.Count + " GO",GUILayout.Width(50)))
 501                 {
 502                     List<Object> FoundObjects=new List<Object>();
 503                     foreach (MeshFilter meshFilter in tDetails.FoundInMeshFilters) FoundObjects.Add(meshFilter.gameObject);
 504                     SelectObjects(FoundObjects,ctrlPressed);
 505                 }
 506                 if (tDetails.FoundInSkinnedMeshRenderer.Count > 0) {
 507                     if (GUILayout.Button (tDetails.FoundInSkinnedMeshRenderer.Count + " skinned mesh GO", GUILayout.Width (140))) {
 508                         List<Object> FoundObjects = new List<Object> ();
 509                         foreach (SkinnedMeshRenderer skinnedMeshRenderer in tDetails.FoundInSkinnedMeshRenderer)
 510                             FoundObjects.Add (skinnedMeshRenderer.gameObject);
 511                         SelectObjects (FoundObjects, ctrlPressed);
 512                     }
 513                 } else {
 514                     GUI.color = new Color (defColor.r, defColor.g, defColor.b, 0.5f);
 515                     GUILayout.Label("   0 skinned mesh");
 516                     GUI.color = defColor;
 517                 }
 518 
 519 
 520                 GUILayout.EndHorizontal();    
 521             }
 522         }
 523         EditorGUILayout.EndScrollView();        
 524     }
 525 
 526     void ListMissing(){
 527         missingListScrollPos = EditorGUILayout.BeginScrollView(missingListScrollPos);
 528         foreach (MissingGraphic dMissing in MissingObjects) {
 529             GUILayout.BeginHorizontal ();
 530             if (GUILayout.Button (dMissing.name, GUILayout.Width (150)))
 531                 SelectObject (dMissing.Object, ctrlPressed);
 532             GUILayout.Label ("missing ", GUILayout.Width(48));
 533             switch (dMissing.type) {
 534             case "mesh":
 535                 GUI.color = new Color (0.8f, 0.8f, defColor.b, 1.0f);
 536                 break;
 537             case "sprite":
 538                 GUI.color = new Color (defColor.r, 0.8f, 0.8f, 1.0f);
 539                 break;
 540             case "material":
 541                 GUI.color = new Color (0.8f, defColor.g, 0.8f, 1.0f);
 542                 break;
 543             }
 544             GUILayout.Label (dMissing.type);
 545             GUI.color = defColor;
 546             GUILayout.EndHorizontal ();
 547         }
 548         EditorGUILayout.EndScrollView();
 549     }
 550 
 551     string FormatSizeString(int memSizeKB)
 552     {
 553         if (memSizeKB<1024) return ""+memSizeKB+"k";
 554         else
 555         {
 556             float memSizeMB=((float)memSizeKB)/1024.0f;
 557             return memSizeMB.ToString("0.00")+"Mb";
 558         }
 559     }
 560 
 561 
 562     TextureDetails FindTextureDetails(Texture tTexture)
 563     {
 564         foreach (TextureDetails tTextureDetails in ActiveTextures)
 565         {
 566             if (tTextureDetails.texture==tTexture) return tTextureDetails;
 567         }
 568         return null;
 569 
 570     }
 571 
 572     MaterialDetails FindMaterialDetails(Material tMaterial)
 573     {
 574         foreach (MaterialDetails tMaterialDetails in ActiveMaterials)
 575         {
 576             if (tMaterialDetails.material==tMaterial) return tMaterialDetails;
 577         }
 578         return null;
 579 
 580     }
 581 
 582     MeshDetails FindMeshDetails(Mesh tMesh)
 583     {
 584         foreach (MeshDetails tMeshDetails in ActiveMeshDetails)
 585         {
 586             if (tMeshDetails.mesh==tMesh) return tMeshDetails;
 587         }
 588         return null;
 589 
 590     }
 591 
 592 
 593     void CheckResources()
 594     {
 595         ActiveTextures.Clear();
 596         ActiveMaterials.Clear();
 597         ActiveMeshDetails.Clear();
 598         MissingObjects.Clear ();
 599         thingsMissing = false;
 600 
 601         Renderer[] renderers = FindObjects<Renderer>();
 602 
 603         MaterialDetails skyMat = new MaterialDetails ();
 604         skyMat.material = RenderSettings.skybox;
 605         skyMat.isSky = true;
 606         ActiveMaterials.Add (skyMat);
 607 
 608         //Debug.Log("Total renderers "+renderers.Length);
 609         foreach (Renderer renderer in renderers)
 610         {
 611             //Debug.Log("Renderer is "+renderer.name);
 612             foreach (Material material in renderer.sharedMaterials)
 613             {
 614 
 615                 MaterialDetails tMaterialDetails = FindMaterialDetails(material);
 616                 if (tMaterialDetails == null)
 617                 {
 618                     tMaterialDetails = new MaterialDetails();
 619                     tMaterialDetails.material = material;
 620                     ActiveMaterials.Add(tMaterialDetails);
 621                 }
 622                 tMaterialDetails.FoundInRenderers.Add(renderer);
 623             }
 624 
 625             if (renderer is SpriteRenderer)
 626             {
 627                 SpriteRenderer tSpriteRenderer = (SpriteRenderer)renderer;
 628 
 629                 if (tSpriteRenderer.sprite != null) {
 630                     var tSpriteTextureDetail = GetTextureDetail (tSpriteRenderer.sprite.texture, renderer);
 631                     if (!ActiveTextures.Contains (tSpriteTextureDetail)) {
 632                         ActiveTextures.Add (tSpriteTextureDetail);
 633                     }
 634                 } else if (tSpriteRenderer.sprite == null) {
 635                     MissingGraphic tMissing = new MissingGraphic ();
 636                     tMissing.Object = tSpriteRenderer.transform;
 637                     tMissing.type = "sprite";
 638                     tMissing.name = tSpriteRenderer.transform.name;
 639                     MissingObjects.Add (tMissing);
 640                     thingsMissing = true;
 641                 }
 642             }
 643         }
 644 
 645         if (IncludeGuiElements)
 646         {
 647             Graphic[] graphics = FindObjects<Graphic>();
 648 
 649             foreach(Graphic graphic in graphics)
 650             {
 651                 if (graphic.mainTexture)
 652                 {
 653                     var tSpriteTextureDetail = GetTextureDetail(graphic.mainTexture, graphic);
 654                     if (!ActiveTextures.Contains(tSpriteTextureDetail))
 655                     {
 656                         ActiveTextures.Add(tSpriteTextureDetail);
 657                     }
 658                 }
 659 
 660                 if (graphic.materialForRendering)
 661                 {
 662                     MaterialDetails tMaterialDetails = FindMaterialDetails(graphic.materialForRendering);
 663                     if (tMaterialDetails == null)
 664                     {
 665                         tMaterialDetails = new MaterialDetails();
 666                         tMaterialDetails.material = graphic.materialForRendering;
 667                         tMaterialDetails.isgui = true;
 668                         ActiveMaterials.Add(tMaterialDetails);
 669                     }
 670                     tMaterialDetails.FoundInGraphics.Add(graphic);
 671                 }
 672             }
 673         }
 674 
 675         foreach (MaterialDetails tMaterialDetails in ActiveMaterials)
 676         {
 677             Material tMaterial = tMaterialDetails.material;
 678             if (tMaterial != null)
 679             {
 680                 var dependencies = EditorUtility.CollectDependencies(new UnityEngine.Object[] { tMaterial });
 681                 foreach (Object obj in dependencies)
 682                 {
 683                     if (obj is Texture)
 684                     {
 685                         Texture tTexture = obj as Texture;
 686                         var tTextureDetail = GetTextureDetail(tTexture, tMaterial, tMaterialDetails);
 687                         tTextureDetail.isSky = tMaterialDetails.isSky;
 688                         tTextureDetail.instance = tMaterialDetails.instance;
 689                         tTextureDetail.isgui = tMaterialDetails.isgui;
 690                         ActiveTextures.Add(tTextureDetail);
 691                     }
 692                 }
 693 
 694                 //if the texture was downloaded, it won't be included in the editor dependencies
 695                 if (tMaterial.HasProperty ("_MainTex")) {
 696                     if (tMaterial.mainTexture != null && !dependencies.Contains (tMaterial.mainTexture)) {
 697                         var tTextureDetail = GetTextureDetail (tMaterial.mainTexture, tMaterial, tMaterialDetails);
 698                         ActiveTextures.Add (tTextureDetail);
 699                     }
 700                 }
 701             }
 702         }
 703 
 704 
 705         MeshFilter[] meshFilters = FindObjects<MeshFilter>();
 706 
 707         foreach (MeshFilter tMeshFilter in meshFilters)
 708         {
 709             Mesh tMesh = tMeshFilter.sharedMesh;
 710             if (tMesh != null)
 711             {
 712                 MeshDetails tMeshDetails = FindMeshDetails(tMesh);
 713                 if (tMeshDetails == null)
 714                 {
 715                     tMeshDetails = new MeshDetails();
 716                     tMeshDetails.mesh = tMesh;
 717                     ActiveMeshDetails.Add(tMeshDetails);
 718                 }
 719                 tMeshDetails.FoundInMeshFilters.Add(tMeshFilter);
 720             } else if (tMesh == null && tMeshFilter.transform.GetComponent("TextContainer")== null) {
 721                 MissingGraphic tMissing = new MissingGraphic ();
 722                 tMissing.Object = tMeshFilter.transform;
 723                 tMissing.type = "mesh";
 724                 tMissing.name = tMeshFilter.transform.name;
 725                 MissingObjects.Add (tMissing);
 726                 thingsMissing = true;
 727             }
 728 
 729             var meshRenderrer = tMeshFilter.transform.GetComponent<MeshRenderer>();
 730                 
 731             if (meshRenderrer == null || meshRenderrer.sharedMaterial == null) {
 732                 MissingGraphic tMissing = new MissingGraphic ();
 733                 tMissing.Object = tMeshFilter.transform;
 734                 tMissing.type = "material";
 735                 tMissing.name = tMeshFilter.transform.name;
 736                 MissingObjects.Add (tMissing);
 737                 thingsMissing = true;
 738             }
 739         }
 740 
 741         SkinnedMeshRenderer[] skinnedMeshRenderers = FindObjects<SkinnedMeshRenderer>();
 742 
 743         foreach (SkinnedMeshRenderer tSkinnedMeshRenderer in skinnedMeshRenderers)
 744         {
 745             Mesh tMesh = tSkinnedMeshRenderer.sharedMesh;
 746             if (tMesh != null)
 747             {
 748                 MeshDetails tMeshDetails = FindMeshDetails(tMesh);
 749                 if (tMeshDetails == null)
 750                 {
 751                     tMeshDetails = new MeshDetails();
 752                     tMeshDetails.mesh = tMesh;
 753                     ActiveMeshDetails.Add(tMeshDetails);
 754                 }
 755                 tMeshDetails.FoundInSkinnedMeshRenderer.Add(tSkinnedMeshRenderer);
 756             } else if (tMesh == null) {
 757                 MissingGraphic tMissing = new MissingGraphic ();
 758                 tMissing.Object = tSkinnedMeshRenderer.transform;
 759                 tMissing.type = "mesh";
 760                 tMissing.name = tSkinnedMeshRenderer.transform.name;
 761                 MissingObjects.Add (tMissing);
 762                 thingsMissing = true;
 763             }
 764             if (tSkinnedMeshRenderer.sharedMaterial == null) {
 765                 MissingGraphic tMissing = new MissingGraphic ();
 766                 tMissing.Object = tSkinnedMeshRenderer.transform;
 767                 tMissing.type = "material";
 768                 tMissing.name = tSkinnedMeshRenderer.transform.name;
 769                 MissingObjects.Add (tMissing);
 770                 thingsMissing = true;
 771             }
 772         }
 773 
 774         if (IncludeSpriteAnimations)
 775         {
 776             Animator[] animators = FindObjects<Animator>();
 777             foreach (Animator anim in animators)
 778             {
 779                 #if UNITY_4_6 || UNITY_4_5 || UNITY_4_4 || UNITY_4_3
 780                 UnityEditorInternal.AnimatorController ac = anim.runtimeAnimatorController as UnityEditorInternal.AnimatorController;
 781                 #elif UNITY_5 || UNITY_5_3_OR_NEWER
 782                 UnityEditor.Animations.AnimatorController ac = anim.runtimeAnimatorController as UnityEditor.Animations.AnimatorController;
 783                 #endif
 784 
 785                 //Skip animators without layers, this can happen if they don't have an animator controller.
 786                 if (!ac || ac.layers == null || ac.layers.Length == 0)
 787                     continue;
 788 
 789                 for (int x = 0; x < anim.layerCount; x++)
 790                 {
 791                     #if UNITY_4_6 || UNITY_4_5 || UNITY_4_4 || UNITY_4_3
 792                     UnityEditorInternal.StateMachine sm = ac.GetLayer(x).stateMachine;
 793                     int cnt = sm.stateCount;
 794                     #elif UNITY_5 || UNITY_5_3_OR_NEWER
 795                     UnityEditor.Animations.AnimatorStateMachine sm = ac.layers[x].stateMachine;
 796                     int cnt = sm.states.Length;
 797                     #endif
 798 
 799                     for (int i = 0; i < cnt; i++)
 800                     {
 801                         #if UNITY_4_6 || UNITY_4_5 || UNITY_4_4 || UNITY_4_3
 802                         UnityEditorInternal.State state = sm.GetState(i);
 803                         Motion m = state.GetMotion();
 804                         #elif UNITY_5 || UNITY_5_3_OR_NEWER
 805                         UnityEditor.Animations.AnimatorState state = sm.states[i].state;
 806                         Motion m = state.motion;
 807                         #endif
 808                         if (m != null)
 809                         {
 810                             AnimationClip clip = m as AnimationClip;
 811 
 812                             if (clip != null)
 813                             {
 814                                 EditorCurveBinding[] ecbs = AnimationUtility.GetObjectReferenceCurveBindings(clip);
 815 
 816                                 foreach (EditorCurveBinding ecb in ecbs)
 817                                 {
 818                                     if (ecb.propertyName == "m_Sprite")
 819                                     {
 820                                         foreach (ObjectReferenceKeyframe keyframe in AnimationUtility.GetObjectReferenceCurve(clip, ecb))
 821                                         {
 822                                             Sprite tSprite = keyframe.value as Sprite;
 823 
 824                                             if (tSprite != null)
 825                                             {
 826                                                 var tTextureDetail = GetTextureDetail(tSprite.texture, anim);
 827                                                 if (!ActiveTextures.Contains(tTextureDetail))
 828                                                 {
 829                                                     ActiveTextures.Add(tTextureDetail);
 830                                                 }
 831                                             }
 832                                         }
 833                                     }
 834                                 }
 835                             }
 836                         }
 837                     }
 838                 }
 839 
 840             }
 841         }
 842 
 843         if (IncludeScriptReferences)
 844         {
 845             MonoBehaviour[] scripts = FindObjects<MonoBehaviour>();
 846             foreach (MonoBehaviour script in scripts)
 847             {
 848                 BindingFlags flags = BindingFlags.Public | BindingFlags.Instance; // only public non-static fields are bound to by Unity.
 849                 FieldInfo[] fields = script.GetType().GetFields(flags);
 850 
 851                 foreach (FieldInfo field in fields)
 852                 {
 853                     System.Type fieldType = field.FieldType;
 854                     if (fieldType == typeof(Sprite))
 855                     {
 856                         Sprite tSprite = field.GetValue(script) as Sprite;
 857                         if (tSprite != null)
 858                         {
 859                             var tSpriteTextureDetail = GetTextureDetail(tSprite.texture, script);
 860                             if (!ActiveTextures.Contains(tSpriteTextureDetail))
 861                             {
 862                                 ActiveTextures.Add(tSpriteTextureDetail);
 863                             }
 864                         }
 865                     }if (fieldType == typeof(Mesh))
 866                     {
 867                         Mesh tMesh = field.GetValue(script) as Mesh;
 868                         if (tMesh != null)
 869                         {
 870                             MeshDetails tMeshDetails = FindMeshDetails(tMesh);
 871                             if (tMeshDetails == null)
 872                             {
 873                                 tMeshDetails = new MeshDetails();
 874                                 tMeshDetails.mesh = tMesh;
 875                                 tMeshDetails.instance = true;
 876                                 ActiveMeshDetails.Add(tMeshDetails);
 877                             }
 878                         }
 879                     }if (fieldType == typeof(Material))
 880                     {
 881                         Material tMaterial = field.GetValue(script) as Material;
 882                         if (tMaterial != null)
 883                         {
 884                             MaterialDetails tMatDetails = FindMaterialDetails(tMaterial);
 885                             if (tMatDetails == null)
 886                             {
 887                                 tMatDetails = new MaterialDetails();
 888                                 tMatDetails.instance = true;
 889                                 tMatDetails.material = tMaterial;
 890                                 if(!ActiveMaterials.Contains(tMatDetails))
 891                                     ActiveMaterials.Add(tMatDetails);
 892                             }
 893                             if (tMaterial.mainTexture)
 894                             {
 895                                 var tSpriteTextureDetail = GetTextureDetail(tMaterial.mainTexture);
 896                                 if (!ActiveTextures.Contains(tSpriteTextureDetail))
 897                                 {
 898                                     ActiveTextures.Add(tSpriteTextureDetail);
 899                                 }
 900                             }
 901                             var dependencies = EditorUtility.CollectDependencies(new UnityEngine.Object[] { tMaterial });
 902                             foreach (Object obj in dependencies)
 903                             {
 904                                 if (obj is Texture)
 905                                 {
 906                                     Texture tTexture = obj as Texture;
 907                                     var tTextureDetail = GetTextureDetail(tTexture, tMaterial, tMatDetails);
 908                                     if(!ActiveTextures.Contains(tTextureDetail))
 909                                         ActiveTextures.Add(tTextureDetail);
 910                                 }
 911                             }
 912                         }
 913                     }
 914                 }
 915             }
 916         }
 917 
 918         TotalTextureMemory = 0;
 919         foreach (TextureDetails tTextureDetails in ActiveTextures) TotalTextureMemory += tTextureDetails.memSizeKB;
 920 
 921         TotalMeshVertices = 0;
 922         foreach (MeshDetails tMeshDetails in ActiveMeshDetails) TotalMeshVertices += tMeshDetails.mesh.vertexCount;
 923 
 924         // Sort by size, descending
 925         ActiveTextures.Sort(delegate(TextureDetails details1, TextureDetails details2) { return details2.memSizeKB - details1.memSizeKB; });
 926         ActiveTextures = ActiveTextures.Distinct().ToList();
 927         ActiveMeshDetails.Sort(delegate(MeshDetails details1, MeshDetails details2) { return details2.mesh.vertexCount - details1.mesh.vertexCount; });
 928 
 929         collectedInPlayingMode = Application.isPlaying;
 930     }
 931 
 932     private static GameObject[] GetAllRootGameObjects()
 933     {
 934 #if !UNITY_5 && !UNITY_5_3_OR_NEWER
 935         return UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects().ToArray();
 936 #else
 937         List<GameObject> allGo = new List<GameObject>();
 938         for (int sceneIdx = 0; sceneIdx < UnityEngine.SceneManagement.SceneManager.sceneCount; ++sceneIdx){
 939             allGo.AddRange( UnityEngine.SceneManagement.SceneManager.GetSceneAt(sceneIdx).GetRootGameObjects().ToArray() );
 940         }
 941         return allGo.ToArray();
 942 #endif
 943     }
 944 
 945     private T[] FindObjects<T>() where T : Object
 946     {
 947         if (IncludeDisabledObjects) {
 948             List<T> meshfilters = new List<T> ();
 949             GameObject[] allGo = GetAllRootGameObjects();
 950             foreach (GameObject go in allGo) {
 951                 Transform[] tgo = go.GetComponentsInChildren<Transform> (true).ToArray ();
 952                 foreach (Transform tr in tgo) {
 953                     if (tr.GetComponent<T> ())
 954                         meshfilters.Add (tr.GetComponent<T> ());
 955                 }
 956             }
 957             return (T[])meshfilters.ToArray ();
 958         }
 959         else
 960             return (T[])FindObjectsOfType(typeof(T));
 961     }
 962 
 963     private TextureDetails GetTextureDetail(Texture tTexture, Material tMaterial, MaterialDetails tMaterialDetails)
 964     {
 965         TextureDetails tTextureDetails = GetTextureDetail(tTexture);
 966 
 967         tTextureDetails.FoundInMaterials.Add(tMaterial);
 968         foreach (Renderer renderer in tMaterialDetails.FoundInRenderers)
 969         {
 970             if (!tTextureDetails.FoundInRenderers.Contains(renderer)) tTextureDetails.FoundInRenderers.Add(renderer);
 971         }
 972         return tTextureDetails;
 973     }
 974 
 975     private TextureDetails GetTextureDetail(Texture tTexture, Renderer renderer)
 976     {
 977         TextureDetails tTextureDetails = GetTextureDetail(tTexture);
 978 
 979         tTextureDetails.FoundInRenderers.Add(renderer);
 980         return tTextureDetails;
 981     }
 982 
 983     private TextureDetails GetTextureDetail(Texture tTexture, Animator animator)
 984     {
 985         TextureDetails tTextureDetails = GetTextureDetail(tTexture);
 986 
 987         tTextureDetails.FoundInAnimators.Add(animator);
 988         return tTextureDetails;
 989     }
 990 
 991     private TextureDetails GetTextureDetail(Texture tTexture, Graphic graphic)
 992     {
 993         TextureDetails tTextureDetails = GetTextureDetail(tTexture);
 994 
 995         tTextureDetails.FoundInGraphics.Add(graphic);
 996         return tTextureDetails;
 997     }
 998 
 999     private TextureDetails GetTextureDetail(Texture tTexture, MonoBehaviour script)
1000     {
1001         TextureDetails tTextureDetails = GetTextureDetail(tTexture);
1002 
1003         tTextureDetails.FoundInScripts.Add(script);
1004         return tTextureDetails;
1005     }
1006 
1007     private TextureDetails GetTextureDetail(Texture tTexture)
1008     {
1009         TextureDetails tTextureDetails = FindTextureDetails(tTexture);
1010         if (tTextureDetails == null)
1011         {
1012             tTextureDetails = new TextureDetails();
1013             tTextureDetails.texture = tTexture;
1014             tTextureDetails.isCubeMap = tTexture is Cubemap;
1015 
1016             int memSize = CalculateTextureSizeBytes(tTexture);
1017 
1018             TextureFormat tFormat = TextureFormat.RGBA32;
1019             int tMipMapCount = 1;
1020             if (tTexture is Texture2D)
1021             {
1022                 tFormat = (tTexture as Texture2D).format;
1023                 tMipMapCount = (tTexture as Texture2D).mipmapCount;
1024             }
1025             if (tTexture is Cubemap)
1026             {
1027                 tFormat = (tTexture as Cubemap).format;
1028                 memSize = 8 * tTexture.height * tTexture.width;
1029             }
1030             if(tTexture is Texture2DArray){
1031                 tFormat = (tTexture as Texture2DArray).format;
1032                 tMipMapCount = 10;
1033             }
1034 
1035             tTextureDetails.memSizeKB = memSize / 1024;
1036             tTextureDetails.format = tFormat;
1037             tTextureDetails.mipMapCount = tMipMapCount;
1038 
1039         }
1040 
1041         return tTextureDetails;
1042     }
1043 
1044 }
ResourceChecker

 

下载地址:https://github.com/handcircus/Unity-Resource-Checker

使用:Unity导航菜单栏中选择 Windows -> Resource Checker ,点击即可

 

二、UnityAssetCleaner 

超级diao炸天的插件,强烈推荐使用,有三种清理资源的模式,更重要的是,它把assets下的资源删除后,

自动将删除的文件备份一个package包,这样再也不用担心误删有用的资源啦,误删了,大不了再把package包导进来呗。

代码:

  1 /**
  2     asset cleaner
  3     Copyright (c) 2015 Tatsuhiko Yamamura
  4 
  5     This software is released under the MIT License.
  6     http://opensource.org/licenses/mit-license.php
  7 */
  8 using UnityEngine;
  9 using System.Collections;
 10 using System.Collections.Generic;
 11 using System.Linq;
 12 using UnityEditor;
 13 using System.IO;
 14 using System.Text.RegularExpressions;
 15 
 16 namespace AssetClean
 17 {
 18     public class AssetCollector
 19     {
 20         public List<string> deleteFileList = new List<string> ();
 21         ClassReferenceCollection classCollection = new ClassReferenceCollection ();
 22         ShaderReferenceCollection shaderCollection = new ShaderReferenceCollection ();
 23 
 24         public bool useCodeStrip = true;
 25         public bool saveEditorExtensions = true;
 26 
 27         public void Collection ()
 28         {
 29             try {
 30                 deleteFileList.Clear ();
 31 
 32                 if( useCodeStrip ){
 33                     classCollection.Collection ();
 34                 }
 35                 shaderCollection.Collection ();
 36 
 37                 // Find assets
 38                 var files = Directory.GetFiles ("Assets", "*.*", SearchOption.AllDirectories)
 39                     .Where (item => Path.GetExtension (item) != ".meta")
 40                     .Where (item => Path.GetExtension (item) != ".js")
 41                     .Where (item => Path.GetExtension (item) != ".dll")
 42                     .Where (item => Regex.IsMatch (item, "[\\/\\\\]Gizmos[\\/\\\\]") == false)
 43                     .Where (item => Regex.IsMatch (item, "[\\/\\\\]Plugins[\\/\\\\]Android[\\/\\\\]") == false)
 44                     .Where (item => Regex.IsMatch (item, "[\\/\\\\]Plugins[\\/\\\\]iOS[\\/\\\\]") == false)
 45                     .Where (item => Regex.IsMatch (item, "[\\/\\\\]Resources[\\/\\\\]") == false);
 46 
 47                 if( useCodeStrip == false ){
 48                     files = files.Where( item => Path.GetExtension(item) != ".cs");
 49                 }
 50 
 51                 foreach (var path in files) {
 52                     var guid = AssetDatabase.AssetPathToGUID (path);
 53                     deleteFileList.Add (guid);
 54                 }
 55                 EditorUtility.DisplayProgressBar ("checking", "collection all files", 0.2f);
 56                 UnregistReferenceFromResources();
 57                 
 58                 EditorUtility.DisplayProgressBar ("checking", "check reference from resources", 0.4f);
 59                 UnregistReferenceFromScenes();
 60 
 61                 EditorUtility.DisplayProgressBar ("checking", "check reference from scenes", 0.6f);
 62                 if( saveEditorExtensions ){
 63                     UnregistEditorCodes();
 64                 }
 65             } finally {
 66                 EditorUtility.ClearProgressBar ();
 67             }
 68         }
 69         void UnregistReferenceFromResources()
 70         {
 71             var resourcesFiles = Directory.GetFiles ("Assets", "*.*", SearchOption.AllDirectories)
 72                 .Where (item => Regex.IsMatch (item, "[\\/\\\\]Resources[\\/\\\\]") == true)
 73                     .Where (item => Path.GetExtension (item) != ".meta")
 74                     .ToArray ();
 75             foreach (var path in AssetDatabase.GetDependencies (resourcesFiles)) {
 76                 UnregistFromDelteList (AssetDatabase.AssetPathToGUID(path));
 77             }
 78         }
 79         
 80         void UnregistReferenceFromScenes()
 81         {
 82             // Exclude objects that reference from scenes.
 83             var scenes = EditorBuildSettings.scenes
 84                 .Where (item => item.enabled == true)
 85                     .Select (item => item.path)
 86                     .ToArray ();
 87             foreach (var path in AssetDatabase.GetDependencies (scenes)) {
 88                 if( saveEditorExtensions == false ){
 89                     Debug.Log(path);
 90                 }
 91                 UnregistFromDelteList (AssetDatabase.AssetPathToGUID(path));
 92             } 
 93         }
 94 
 95         void UnregistEditorCodes()
 96         {
 97             // Exclude objects that reference from Editor API
 98             var editorcodes = Directory.GetFiles ("Assets", "*.cs", SearchOption.AllDirectories)
 99                 .Where (item => Regex.IsMatch (item, "[\\/\\\\]Editor[\\/\\\\]") == true)
100                     .ToArray ();
101             
102             var undeleteClassList = classCollection.codeFileList
103                 .Where (codefile => codefile.Value.Any( guid => deleteFileList.Contains(guid)) == false)
104                     .Select( item => item.Key );
105             
106             EditorUtility.DisplayProgressBar ("checking", "check reference from editor codes", 0.8f);
107             
108             foreach (var path in editorcodes) {
109                 var code = File.ReadAllText (path);
110                 code = Regex.Replace(code, "//.*[\\n\\r]", "");
111                 code = Regex.Replace(code, "/\\*.*[\\n\\r]\\*/", "");
112                 if (Regex.IsMatch (code, "(\\[MenuItem|AssetPostprocessor|EditorWindow)")) {
113                     UnregistFromDelteList ( AssetDatabase.AssetPathToGUID(path));
114                     continue;
115                 }
116                 
117                 foreach (var undeleteClass in undeleteClassList) {
118                     if (Regex.IsMatch (code, string.Format ("\\[CustomEditor.*\\(\\s*{0}\\s*\\).*\\]", undeleteClass.Name))) {
119                         UnregistFromDelteList (path);
120                         continue;
121                     }
122                 }
123             }
124         }
125 
126         void UnregistFromDelteList (string guid)
127         {
128             if (deleteFileList.Contains (guid) == false) {
129                 return;
130             }
131             deleteFileList.Remove (guid);
132             
133             if (classCollection.references.ContainsKey (guid) == true) {
134                 
135                 foreach (var type in classCollection.references[guid]) {
136                     var codePaths = classCollection.codeFileList [type];
137                     foreach( var codePath in codePaths){
138                         UnregistFromDelteList (codePath);
139                     }
140                 }
141             }
142             
143             if (shaderCollection.shaderFileList.ContainsValue (guid)) {
144                 var shader = shaderCollection.shaderFileList.First (item => item.Value == guid);
145                 var shaderAssets = shaderCollection.shaderReferenceList [shader.Key];
146                 foreach (var shaderPath in shaderAssets) {
147                     UnregistFromDelteList (shaderPath);
148                 }
149             }
150         }
151     }
152 }
AssetCollector
  1 /**
  2     asset cleaner
  3     Copyright (c) 2015 Tatsuhiko Yamamura
  4 
  5     This software is released under the MIT License.
  6     http://opensource.org/licenses/mit-license.php
  7 */
  8 using UnityEngine;
  9 using System.Collections;
 10 using System.Collections.Generic;
 11 using System.Text.RegularExpressions;
 12 using UnityEditor;
 13 using System.IO;
 14 using System.Reflection;
 15 using System.Linq;
 16 
 17 namespace AssetClean
 18 {
 19     public class ClassReferenceCollection
 20     {
 21         // type : guid
 22         public Dictionary<System.Type, List<string>> codeFileList = new Dictionary<System.Type, List<string>> ();
 23         // guid : types
 24         public Dictionary<string, List<System.Type>> references = new Dictionary<string, List<System.Type>> ();
 25 
 26         public void Collection ()
 27         {
 28             references.Clear ();
 29             EditorUtility.DisplayProgressBar ("checking", "collection all type", 0);
 30 
 31             // Connect the files and class.
 32             var codes = Directory.GetFiles ("Assets", "*.cs", SearchOption.AllDirectories);
 33             // connect each classes.
 34             var firstPassList = new List<string>();
 35             if( Directory.Exists ("Assets/Plugins") )
 36                 firstPassList.AddRange( Directory.GetFiles ("Assets/Plugins", "*.cs", SearchOption.AllDirectories));
 37             if( Directory.Exists ("Assets/Standard Assets") )
 38                 firstPassList.AddRange( Directory.GetFiles ("Assets/Standard Assets", "*.cs", SearchOption.AllDirectories));
 39 
 40             var allFirstpassTypes = collectionAllFastspassClasses ();
 41             CollectionCodeFileDictionary (allFirstpassTypes, firstPassList.ToArray());
 42 
 43 
 44             var alltypes = CollectionAllClasses ();
 45             CollectionCodeFileDictionary (alltypes, codes.ToArray());
 46             alltypes.AddRange (allFirstpassTypes);
 47 
 48             int count = 0;
 49             foreach (var codepath in firstPassList) {
 50                 CollectionReferenceClasses (AssetDatabase.AssetPathToGUID (codepath), allFirstpassTypes);
 51                 EditorUtility.DisplayProgressBar ("checking", "analytics codes", ((float)++count / codes.Length) * 0.5f + 0.5f);
 52             }
 53             count = 0;
 54             foreach (var codepath in codes) {
 55                 CollectionReferenceClasses (AssetDatabase.AssetPathToGUID (codepath), alltypes);
 56                 EditorUtility.DisplayProgressBar ("checking", "analytics codes", ((float)++count / codes.Length) * 0.5f);
 57             }
 58         }
 59 
 60         void CollectionCodeFileDictionary (List<System.Type> alltypes, string[] codes)
 61         {
 62             float count = 1;
 63             foreach (var codePath in codes) {
 64                 EditorUtility.DisplayProgressBar ("checking", "search files", count++ / codes.Length);
 65 
 66                 // connect file and classes.
 67                 var code = System.IO.File.ReadAllText (codePath);
 68                 code = Regex.Replace(code, "//.*[\\n\\r]", "");
 69                 code = Regex.Replace(code, "/\\*.*[\\n\\r]\\*/", "");
 70 
 71                 foreach (var type in alltypes) {
 72 
 73                     if( codeFileList.ContainsKey(type ) == false ){
 74                         codeFileList.Add(type, new List<string>());
 75                     }
 76                     var list = codeFileList[type];
 77                 
 78                     if (string.IsNullOrEmpty (type.Namespace) == false) {
 79                         var namespacepattern = string.Format ("namespace[\\s.]{0}[{{\\s\\n]", type.Namespace);
 80                         if (Regex.IsMatch (code, namespacepattern) == false) {
 81                             continue;
 82                         }
 83                     }
 84 
 85                     string typeName = type.IsGenericTypeDefinition ? type.GetGenericTypeDefinition ().Name.Split ('`') [0] : type.Name;
 86                     if (Regex.IsMatch (code, string.Format ("class\\s*{0}?[\\s:<{{]", typeName))) {
 87                         list.Add( AssetDatabase.AssetPathToGUID(codePath) );
 88                         continue;
 89                     }
 90 
 91                     if (Regex.IsMatch (code, string.Format ("struct\\s*{0}[\\s:<{{]", typeName))) {
 92                         list.Add( AssetDatabase.AssetPathToGUID(codePath) );
 93                         continue;
 94                     }
 95                 
 96                     if (Regex.IsMatch (code, string.Format ("enum\\s*{0}[\\s{{]", type.Name))) {
 97                         list.Add( AssetDatabase.AssetPathToGUID(codePath) );
 98                         continue;
 99                     }
100                 
101                     if (Regex.IsMatch (code, string.Format ("delegate\\s*{0}\\s\\(", type.Name))) {
102                         list.Add( AssetDatabase.AssetPathToGUID(codePath) );
103                         continue;
104                     }
105                 }
106             }
107         }
108 
109         List<System.Type> CollectionAllClasses ()
110         {
111             List<System.Type> alltypes = new List<System.Type> ();
112         
113             if (File.Exists ("Library/ScriptAssemblies/Assembly-CSharp.dll"))
114                 alltypes.AddRange (Assembly.LoadFile ("Library/ScriptAssemblies/Assembly-CSharp.dll").GetTypes ());
115             if (File.Exists ("Library/ScriptAssemblies/Assembly-CSharp-Editor.dll"))
116                 alltypes.AddRange (Assembly.LoadFile ("Library/ScriptAssemblies/Assembly-CSharp-Editor.dll").GetTypes ());
117 
118             return alltypes    .ToList ();
119         }
120 
121         List<System.Type> collectionAllFastspassClasses()
122         {
123             List<System.Type> alltypes = new List<System.Type> ();
124             if (File.Exists ("Library/ScriptAssemblies/Assembly-CSharp-firstpass.dll"))
125                 alltypes.AddRange (Assembly.LoadFile ("Library/ScriptAssemblies/Assembly-CSharp-firstpass.dll").GetTypes ());
126             if (File.Exists ("Library/ScriptAssemblies/Assembly-CSharp-Editor-firstpass.dll"))
127                 alltypes.AddRange (Assembly.LoadFile ("Library/ScriptAssemblies/Assembly-CSharp-Editor-firstpass.dll").GetTypes ());
128             return alltypes;
129         }
130         
131         void CollectionReferenceClasses (string guid, List<System.Type> types)
132         {
133             var codePath = AssetDatabase.GUIDToAssetPath(guid);
134             if (string.IsNullOrEmpty (codePath) || references.ContainsKey (guid) || File.Exists(codePath)==false) {
135                 return;
136             }
137 
138             var code = System.IO.File.ReadAllText (codePath);
139             code = Regex.Replace(code, "//.*[\\n\\r]", "");
140             code = Regex.Replace(code, "/\\*.*[\\n\\r]\\*/", "");
141 
142             var list = new List<System.Type> ();
143             references [guid] = list;
144 
145             foreach (var type in types) {
146     
147                 if (string.IsNullOrEmpty (type.Namespace) == false) {
148                     var namespacepattern = string.Format ("[namespace|using][\\s\\.]{0}[{{\\s\\r\\n\\r;]", type.Namespace);
149                     if (Regex.IsMatch (code, namespacepattern) == false) {
150                         continue;
151                     }
152                 }
153 
154                 if (codeFileList.ContainsKey (type) == false) {
155                     continue;
156                 }
157 
158                 string match = string.Empty;
159                 if (type.IsGenericTypeDefinition) {
160                     string typeName = type.GetGenericTypeDefinition ().Name.Split ('`') [0];
161                     match = string.Format ("[\\]\\[\\.\\s<(]{0}[\\.\\s\\n\\r>,<(){{]", typeName);
162                 } else {
163                     match = string.Format ("[\\]\\[\\.\\s<(]{0}[\\.\\s\\n\\r>,<(){{\\]]", type.Name.Replace("Attribute", ""));
164                 }
165                 if (Regex.IsMatch (code, match)) {
166                     list.Add (type);
167                     var typeGuid =  codeFileList[type];
168                     foreach( var referenceGuid in typeGuid){
169                         CollectionReferenceClasses (referenceGuid, types);
170                     }
171                 }
172             }
173         }
174     }
175 }
ClassReferenceCollection
  1 /**
  2     asset cleaner
  3     Copyright (c) 2015 Tatsuhiko Yamamura
  4 
  5     This software is released under the MIT License.
  6     http://opensource.org/licenses/mit-license.php
  7 */
  8 using UnityEngine;
  9 using System.Collections;
 10 using System.Collections.Generic;
 11 using UnityEditor;
 12 using System.IO;
 13 using System.Linq;
 14 
 15 namespace AssetClean
 16 {
 17     public class FindUnusedAssets : EditorWindow
 18     {
 19         AssetCollector collection = new AssetCollector ();
 20         List<DeleteAsset> deleteAssets = new List<DeleteAsset> ();
 21         Vector2 scroll;
 22 
 23         [MenuItem("Assets/Delete Unused Assets/only resource", false, 50)]
 24         static void InitWithoutCode ()
 25         {
 26             var window = FindUnusedAssets.CreateInstance<FindUnusedAssets> ();
 27             window.collection.useCodeStrip = false;
 28             window.collection.Collection ();
 29             window.CopyDeleteFileList (window.collection.deleteFileList);
 30             
 31             window.Show ();
 32         }
 33 
 34         [MenuItem("Assets/Delete Unused Assets/unused by editor", false, 51)]
 35         static void InitWithout ()
 36         {
 37             var window = FindUnusedAssets.CreateInstance<FindUnusedAssets> ();
 38             window.collection.Collection ();
 39             window.CopyDeleteFileList (window.collection.deleteFileList);
 40             
 41             window.Show ();
 42         }
 43 
 44         [MenuItem("Assets/Delete Unused Assets/unused by game", false, 52)]
 45         static void Init ()
 46         {
 47             var window = FindUnusedAssets.CreateInstance<FindUnusedAssets> ();
 48             window.collection.saveEditorExtensions = false;
 49             window.collection.Collection ();
 50             window.CopyDeleteFileList (window.collection.deleteFileList);
 51             
 52             window.Show ();
 53         }
 54         
 55         void OnGUI ()
 56         {
 57             using (var horizonal = new EditorGUILayout.HorizontalScope("box")) {
 58                 EditorGUILayout.LabelField ("delete unreference assets from buildsettings and resources");
 59 
 60                 if (GUILayout.Button ("Delete", GUILayout.Width (120), GUILayout.Height (40)) && deleteAssets.Count != 0) {
 61                     RemoveFiles ();
 62                     Close ();
 63                 }
 64             }
 65 
 66             using (var scrollScope = new EditorGUILayout.ScrollViewScope(scroll)) {
 67                 scroll = scrollScope.scrollPosition;
 68                 foreach (var asset in deleteAssets) {
 69                     if (string.IsNullOrEmpty (asset.path)) {
 70                         continue;
 71                     }
 72 
 73                     using (var horizonal = new EditorGUILayout.HorizontalScope()) {
 74                         asset.isDelete = EditorGUILayout.Toggle (asset.isDelete, GUILayout.Width (20));
 75                         var icon = AssetDatabase.GetCachedIcon (asset.path);
 76                         GUILayout.Label (icon, GUILayout.Width (20), GUILayout.Height (20));
 77                         if (GUILayout.Button (asset.path, EditorStyles.largeLabel)) {
 78                             Selection.activeObject = AssetDatabase.LoadAssetAtPath<Object> (asset.path);
 79                         }
 80                     }
 81                 }
 82             }
 83 
 84         }
 85 
 86          static void CleanDir()
 87          {
 88             RemoveEmptyDirectry ("Assets");
 89             AssetDatabase.Refresh ();
 90         }
 91 
 92         void CopyDeleteFileList(IEnumerable<string> deleteFileList)
 93         {
 94             foreach (var asset in deleteFileList) {
 95                 var filePath = AssetDatabase.GUIDToAssetPath (asset);
 96                 if (string.IsNullOrEmpty (filePath) == false) {
 97                     deleteAssets.Add (new DeleteAsset (){ path = filePath});
 98                 }
 99             }
100         }
101 
102         void RemoveFiles ()
103         {
104             try {
105                 string exportDirectry = "BackupUnusedAssets";
106                 Directory.CreateDirectory (exportDirectry);
107                 var files = deleteAssets.Where (item => item.isDelete == true).Select (item => item.path).ToArray ();
108                 string backupPackageName = exportDirectry + "/package" + System.DateTime.Now.ToString ("yyyyMMddHHmmss") + ".unitypackage";
109                 EditorUtility.DisplayProgressBar ("export package", backupPackageName, 0);
110                 AssetDatabase.ExportPackage (files, backupPackageName);
111 
112                 int i = 0;
113                 int length = deleteAssets.Count;
114 
115                 foreach (var assetPath in files) {
116                     i++;
117                     EditorUtility.DisplayProgressBar ("delete unused assets", assetPath, (float)i / length);
118                     AssetDatabase.DeleteAsset (assetPath);
119                 }
120 
121                 EditorUtility.DisplayProgressBar ("clean directory", "", 1);
122                 foreach (var dir in Directory.GetDirectories("Assets")) {
123                     RemoveEmptyDirectry (dir);
124                 }
125 
126                 System.Diagnostics.Process.Start (exportDirectry);
127 
128                 AssetDatabase.Refresh ();
129             }
130             catch( System.Exception e ){
131                 Debug.Log(e.Message);
132             }finally {
133                 EditorUtility.ClearProgressBar ();
134             }
135         }
136 
137         static void RemoveEmptyDirectry (string path)
138         {
139             var dirs = Directory.GetDirectories (path);
140             foreach (var dir in dirs) {
141                 RemoveEmptyDirectry (dir);
142             }
143 
144             var files = Directory.GetFiles (path, "*", SearchOption.TopDirectoryOnly).Where (item => Path.GetExtension (item) != ".meta");
145             if (files.Count () == 0 && Directory.GetDirectories (path).Count () == 0) {
146                 var metaFile = AssetDatabase.GetTextMetaFilePathFromAssetPath(path);
147                 UnityEditor.FileUtil.DeleteFileOrDirectory (path);
148                 UnityEditor.FileUtil.DeleteFileOrDirectory (metaFile);
149             }
150         }
151 
152         class DeleteAsset
153         {
154             public bool isDelete = true;
155             public string path;
156         }
157     }
158 }
FindUnusedAssets
 1 /**
 2     asset cleaner
 3     Copyright (c) 2015 Tatsuhiko Yamamura
 4 
 5     This software is released under the MIT License.
 6     http://opensource.org/licenses/mit-license.php
 7 */
 8 using UnityEngine;
 9 using System.Collections;
10 using System.Collections.Generic;
11 using System.IO;
12 using System.Text.RegularExpressions;
13 using UnityEditor;
14 
15 namespace AssetClean
16 {
17     public class ShaderReferenceCollection
18     {
19         // shader name / shader file guid
20         public Dictionary<string, string> shaderFileList = new Dictionary<string, string> ();
21         public Dictionary<string, List<string> > shaderReferenceList = new Dictionary<string, List<string>> ();
22 
23         public void Collection ()
24         {
25             CollectionShaderFiles ();
26             CheckReference ();
27         }
28 
29         void CollectionShaderFiles ()
30         {
31             var shaderFiles = Directory.GetFiles ("Assets", "*.shader", SearchOption.AllDirectories);
32             foreach (var shaderFilePath in shaderFiles) {
33                 var code = File.ReadAllText (shaderFilePath);
34                 var match = Regex.Match (code, "Shader \"(?<name>.*)\"");
35                 if (match.Success) {
36                     var shaderName = match.Groups ["name"].ToString ();
37                     if (shaderFileList.ContainsKey (shaderName) == false) {
38                         shaderFileList.Add (shaderName, AssetDatabase.AssetPathToGUID(shaderFilePath));
39                     }
40                 }
41             }
42         
43             var cgFiles = Directory.GetFiles ("Assets", "*.cg", SearchOption.AllDirectories);
44             foreach (var cgFilePath in cgFiles) {
45                 var file = Path.GetFileName (cgFilePath);
46                 shaderFileList.Add (file, cgFilePath);
47             }
48 
49             var cgincFiles = Directory.GetFiles ("Assets", "*.cginc", SearchOption.AllDirectories);
50             foreach (var cgincPath in cgincFiles) {
51                 var file = Path.GetFileName (cgincPath);
52                 shaderFileList.Add (file, cgincPath);
53             }
54         }
55 
56         void CheckReference ()
57         {
58             foreach (var shader in shaderFileList) {
59                 var shaderFilePath = AssetDatabase.GUIDToAssetPath(shader.Value);
60                 var shaderName = shader.Key;
61             
62                 List<string> referenceList = new List<string> ();
63                 shaderReferenceList.Add (shaderName, referenceList);
64             
65                 var code = File.ReadAllText (shaderFilePath);
66             
67                 foreach (var checkingShaderName in shaderFileList.Keys) {
68                     if (Regex.IsMatch (code, string.Format ("{0}", checkingShaderName))) {
69                         var filePath = shaderFileList [checkingShaderName];
70                         referenceList.Add (filePath);
71                     }
72                 }
73             }
74         }
75     }
76 }
ShaderReferenceCollection

下载地址:https://github.com/unity-cn/Tool-UnityAssetCleaner

使用:Unity导航菜单栏中选择 Assets-> Delete Unused Assets

三种模式,选择一个合适的,然后点击Delete,轻松搞定

 

posted on 2017-09-15 14:34  Jason_c  阅读(6627)  评论(0编辑  收藏  举报