Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Resource Checker (FREE) - List Texture/Material/Mesh Memory use in scene

Discussion in 'Assets and Asset Store' started by SimonOliver, Apr 13, 2012.

  1. SimonOliver

    SimonOliver

    Joined:
    Jul 16, 2007
    Posts:
    30


    Hey,

    I've been trying to find the best way to list currently used textures in a given scene, and the amount of memory they consume (profiler not providing a breakdown of texture memory). Also wanted to see where active textures are being used, by which GameObjects, which materials and the number of materials/meshes currently used in the scene.

    I couldn't find a workflow that best suits this, so knocked up a quick Editor extension that might help if you are looking to do something similar. You can download from here:

    https://github.com/handcircus/Unity-Resource-Checker

    Newish to Unity so there might be a really obvious way of doing this already that I'm not aware of. Anyway, its public domain, so do whatever you like with it, hope its of use to some of you :)

    ------

    Resource checker is designed to help bring visibility to resource use in your scenes (ie what assets are using up memory,
    which meshes are a bit too detailed, where are my materials and textures being used).

    It should also be useful to check for redundant materials, textures you forget you're using, textures that can be compressed or reduced in size.

    To use, just create an "Editor" folder within "Assets" in your project if you don't already have one, and drop ResourceChecker.cs in there.

    In Unity you'll see a new option under "Window" -> "Resource Checker"

    To use, once the window is open, just click 'Refresh' and it will list all active textures, materials and meshes in the scene

    Textures
    --------

    - Textures are listed in descending memory size
    - Click the texture name to open the asset in the project window
    - The size of the texture, compression type and dimensions are show
    - Click the 'X Mat' button to select all materials that use this texture in the scene
    - Click the 'X GO' to select all game objects in the scene that use this texture

    Materials
    ---------

    - Click the material name to open the material asset in the project window
    - Click the 'X GO' to select all game objects in the scene that use this material

    Meshes
    ------
    - Meshes are listed in descending vertex count
    - Click the mesh name to open the mesh in the project window
    - Click the 'X GO' to select all game objects in the scene that use this mesh

    Its probably got a bunch of bugs and weird issues - feel free to help improve, fix up!
     
    tinoow, orimM123, cmod and 16 others like this.
  2. yuriythebest

    yuriythebest

    Joined:
    Nov 21, 2009
    Posts:
    1,121
    wow dude! this is epic- while something similar exists in the Profiler this looks amazing
     
  3. hima

    hima

    Joined:
    Oct 1, 2010
    Posts:
    183
    This is going to be very useful. Thank you for making it free and opensource!
     
  4. Wild-Factor

    Wild-Factor

    Joined:
    Oct 11, 2010
    Posts:
    607
    Thanks It's probably very useffull for non-pro user.
     
  5. SimonOliver

    SimonOliver

    Joined:
    Jul 16, 2007
    Posts:
    30
    Cool, glad its of use! Will try to get up to the store soon too.

    In terms of profiler, I couldn't see any breakdown of memory use by asset, just a total of all textures, all meshes. Is there an option in the profiler that lets you dig deeper to see how that chunk of memory is split up?
     
  6. Lars-Steenhoff

    Lars-Steenhoff

    Joined:
    Aug 7, 2007
    Posts:
    3,521
    Really nice plugin!

    I'm using it now to reduce my texture settings from 1024 to 512, do you have a way to sort by texture size and to select all textures at once to mass change them?

    Thanks
     
  7. SimonOliver

    SimonOliver

    Joined:
    Jul 16, 2007
    Posts:
    30
    At the moment it sorts by size of Texture in memory (so if you are using similar compression on most assets, this will be the same result as sorting by texture size, except for cubemaps). I can definitely add a sort alphabetically or just by texture size easily enough. Multi-selection should be easy enough to do too, so do you mean ctrl-select for multi-selection, or a "select all" button or both?
     
  8. Lars-Steenhoff

    Lars-Steenhoff

    Joined:
    Aug 7, 2007
    Posts:
    3,521
    I think control select, and shift select range will suffice, sort by texture properties would be nice, ( 256, 512,1024 etc )
     
  9. SimonOliver

    SimonOliver

    Joined:
    Jul 16, 2007
    Posts:
    30
    Just added Ctrl select, and a select all button at the bottom. Also list mip levels and some size calculation bugs fixed
     
  10. yuriythebest

    yuriythebest

    Joined:
    Nov 21, 2009
    Posts:
    1,121
    I made a small hack/modification- now this will update every second.. sorta.. I think :)
    (there is probably a MUCH prettier way of doing this)
    Thank you again handcircus !!

    Code (csharp):
    1. // Resource Checker
    2. // (c) 2012 Simon Oliver / HandCircus / hello@handcircus.com
    3. // Public domain, do with whatever you like, commercial or not
    4. // This comes with no warranty, use at your own risk!
    5. // https://github.com/handcircus/Unity-Resource-Checker
    6.  
    7. using UnityEngine;
    8. using UnityEditor;
    9. using System.Collections.Generic;
    10.  
    11.  
    12. public class TextureDetails
    13. {
    14.     public bool isCubeMap;
    15.     public int memSizeKB;
    16.     public Texture texture;
    17.     public TextureFormat format;
    18.     public int mipMapCount;
    19.     public List<Object> FoundInMaterials=new List<Object>();
    20.     public List<Object> FoundInRenderers=new List<Object>();
    21.     public TextureDetails()
    22.     {
    23.  
    24.     }
    25. };
    26.  
    27. public class MaterialDetails
    28. {
    29.  
    30.     public Material material;
    31.  
    32.     public List<Renderer> FoundInRenderers=new List<Renderer>();
    33.  
    34.     public MaterialDetails()
    35.     {
    36.  
    37.     }
    38. };
    39.  
    40. public class MeshDetails
    41. {
    42.  
    43.     public Mesh mesh;
    44.  
    45.     public List<MeshFilter> FoundInMeshFilters=new List<MeshFilter>();
    46.  
    47.     public MeshDetails()
    48.     {
    49.  
    50.     }
    51. };
    52.  
    53. public  class ResourceChecker : EditorWindow {
    54.  
    55.     float timer=0;
    56.     string[] inspectToolbarStrings = {"Textures", "Materials","Meshes"};
    57.  
    58.     enum InspectType
    59.     {
    60.         Textures,Materials,Meshes
    61.     };
    62.  
    63.     InspectType ActiveInspectType=InspectType.Textures;
    64.  
    65.     float ThumbnailWidth=40;
    66.     float ThumbnailHeight=40;
    67.  
    68.     static List<TextureDetails> ActiveTextures=new List<TextureDetails>();
    69.     static List<MaterialDetails> ActiveMaterials=new List<MaterialDetails>();
    70.     static List<MeshDetails> ActiveMeshDetails=new List<MeshDetails>();
    71.  
    72.     static Vector2 textureListScrollPos=new Vector2(0,0);
    73.     static Vector2 materialListScrollPos=new Vector2(0,0);
    74.     static Vector2 meshListScrollPos=new Vector2(0,0);
    75.  
    76.     static int TotalTextureMemory=0;
    77.     static int TotalMeshVertices=0;
    78.  
    79.     bool ctrlPressed=false;
    80.  
    81.     static int MinWidth=455;
    82.      static ResourceChecker window;
    83.     [MenuItem ("Window/Resource Checker")]
    84.     static void Init ()
    85.     {  
    86.         TotalTextureMemory=0;
    87.         TotalMeshVertices=0;
    88.         textureListScrollPos=new Vector2(0,0);
    89.         materialListScrollPos=new Vector2(0,0);
    90.         meshListScrollPos=new Vector2(0,0);
    91.         ActiveTextures=new List<TextureDetails>();
    92.         ActiveMaterials=new List<MaterialDetails>();
    93.         ActiveMeshDetails=new List<MeshDetails>();
    94.         window = (ResourceChecker) EditorWindow.GetWindow (typeof (ResourceChecker));
    95.         window.CheckResources();
    96.         window.minSize=new Vector2(MinWidth,300);
    97.     }
    98.    
    99.     void Update()
    100.     {
    101.         timer+=Time.deltaTime;
    102.         if(timer>1)
    103.         {
    104.             Init ();
    105.             timer=0;
    106.         }
    107.        
    108.     }
    109.    
    110.     void OnGUI ()
    111.     {
    112.         if (GUILayout.Button("Refresh")) CheckResources();
    113.         GUILayout.BeginHorizontal();
    114.         GUILayout.Label("Materials "+ActiveMaterials.Count);
    115.         GUILayout.Label("Textures "+ActiveTextures.Count+" - "+FormatSizeString(TotalTextureMemory));
    116.         GUILayout.Label("Meshes "+ActiveMeshDetails.Count+" - "+TotalMeshVertices+" verts");
    117.         GUILayout.EndHorizontal();
    118.         ActiveInspectType=(InspectType)GUILayout.Toolbar((int)ActiveInspectType,inspectToolbarStrings);
    119.  
    120.         ctrlPressed=Event.current.control || Event.current.command;
    121.  
    122.         switch (ActiveInspectType)
    123.         {
    124.             case InspectType.Textures:
    125.                 ListTextures();
    126.                 break;
    127.             case InspectType.Materials:
    128.                 ListMaterials();
    129.                 break;
    130.             case InspectType.Meshes:
    131.                 ListMeshes();
    132.                 break; 
    133.  
    134.  
    135.         }
    136.     }
    137.  
    138.  
    139.     int GetBitsPerPixel(TextureFormat format)
    140.     {
    141.         switch (format)
    142.         {
    143.             case TextureFormat.Alpha8: //    Alpha-only texture format.
    144.                 return 8;
    145.             case TextureFormat.ARGB4444: //  A 16 bits/pixel texture format. Texture stores color with an alpha channel.
    146.                 return 16;
    147.             case TextureFormat.RGB24:   // A color texture format.
    148.                 return 24;
    149.             case TextureFormat.RGBA32:  //Color with an alpha channel texture format.
    150.                 return 32;
    151.             case TextureFormat.ARGB32:  //Color with an alpha channel texture format.
    152.                 return 32;
    153.             case TextureFormat.RGB565:  //   A 16 bit color texture format.
    154.                 return 16;
    155.             case TextureFormat.DXT1:    // Compressed color texture format.
    156.                 return 4;
    157.             case TextureFormat.DXT5:    // Compressed color with alpha channel texture format.
    158.                 return 8;
    159.             /*
    160.             case TextureFormat.WiiI4:   // Wii texture format.
    161.             case TextureFormat.WiiI8:   // Wii texture format. Intensity 8 bit.
    162.             case TextureFormat.WiiIA4:  // Wii texture format. Intensity + Alpha 8 bit (4 + 4).
    163.             case TextureFormat.WiiIA8:  // Wii texture format. Intensity + Alpha 16 bit (8 + 8).
    164.             case TextureFormat.WiiRGB565:   // Wii texture format. RGB 16 bit (565).
    165.             case TextureFormat.WiiRGB5A3:   // Wii texture format. RGBA 16 bit (4443).
    166.             case TextureFormat.WiiRGBA8:    // Wii texture format. RGBA 32 bit (8888).
    167.             case TextureFormat.WiiCMPR: //   Compressed Wii texture format. 4 bits/texel, ~RGB8A1 (Outline alpha is not currently supported).
    168.                 return 0;  //Not supported yet
    169.             */
    170.             case TextureFormat.PVRTC_RGB2://     PowerVR (iOS) 2 bits/pixel compressed color texture format.
    171.                 return 2;
    172.             case TextureFormat.PVRTC_RGBA2://    PowerVR (iOS) 2 bits/pixel compressed with alpha channel texture format
    173.                 return 2;
    174.             case TextureFormat.PVRTC_RGB4://     PowerVR (iOS) 4 bits/pixel compressed color texture format.
    175.                 return 4;
    176.             case TextureFormat.PVRTC_RGBA4://    PowerVR (iOS) 4 bits/pixel compressed with alpha channel texture format
    177.                 return 4;
    178.             case TextureFormat.ETC_RGB4://   ETC (GLES2.0) 4 bits/pixel compressed RGB texture format.
    179.                 return 4;
    180.             case TextureFormat.ATC_RGB4://   ATC (ATITC) 4 bits/pixel compressed RGB texture format.
    181.                 return 4;
    182.             case TextureFormat.ATC_RGBA8://  ATC (ATITC) 8 bits/pixel compressed RGB texture format.
    183.                 return 8;
    184.             case TextureFormat.BGRA32://     Format returned by iPhone camera
    185.                 return 32;
    186.             case TextureFormat.ATF_RGB_DXT1://   Flash-specific RGB DXT1 compressed color texture format.
    187.             case TextureFormat.ATF_RGBA_JPG://   Flash-specific RGBA JPG-compressed color texture format.
    188.             case TextureFormat.ATF_RGB_JPG://    Flash-specific RGB JPG-compressed color texture format.
    189.                 return 0; //Not supported yet
    190.         }
    191.         return 0;
    192.     }
    193.  
    194.     int CalculateTextureSizeBytes(Texture tTexture)
    195.     {
    196.  
    197.         int tWidth=tTexture.width;
    198.         int tHeight=tTexture.height;
    199.         if (tTexture is Texture2D)
    200.         {
    201.             Texture2D tTex2D=tTexture as Texture2D;
    202.             int bitsPerPixel=GetBitsPerPixel(tTex2D.format);
    203.             int mipMapCount=tTex2D.mipmapCount;
    204.             int mipLevel=1;
    205.             int tSize=0;
    206.             while (mipLevel<=mipMapCount)
    207.             {
    208.                 tSize+=tWidth*tHeight*bitsPerPixel/8;
    209.                 tWidth=tWidth/2;
    210.                 tHeight=tHeight/2;
    211.                 mipLevel++;
    212.             }
    213.             return tSize;
    214.         }
    215.  
    216.         if (tTexture is Cubemap)
    217.         {
    218.             Cubemap tCubemap=tTexture as Cubemap;
    219.             int bitsPerPixel=GetBitsPerPixel(tCubemap.format);
    220.             return tWidth*tHeight*6*bitsPerPixel/8;
    221.         }
    222.         return 0;
    223.     }
    224.  
    225.  
    226.     void SelectObject(Object selectedObject,bool append)
    227.     {
    228.         if (append)
    229.         {
    230.             List<Object> currentSelection=new List<Object>(Selection.objects);
    231.             // Allow toggle selection
    232.             if (currentSelection.Contains(selectedObject)) currentSelection.Remove(selectedObject);
    233.             else currentSelection.Add(selectedObject);
    234.  
    235.             Selection.objects=currentSelection.ToArray();
    236.         }
    237.         else Selection.activeObject=selectedObject;
    238.     }
    239.  
    240.     void SelectObjects(List<Object> selectedObjects,bool append)
    241.     {
    242.         if (append)
    243.         {
    244.             List<Object> currentSelection=new List<Object>(Selection.objects);
    245.             currentSelection.AddRange(selectedObjects);
    246.             Selection.objects=currentSelection.ToArray();
    247.         }
    248.         else Selection.objects=selectedObjects.ToArray();
    249.     }
    250.  
    251.     void ListTextures()
    252.     {
    253.         textureListScrollPos = EditorGUILayout.BeginScrollView(textureListScrollPos);
    254.         try
    255.         {
    256.         foreach (TextureDetails tDetails in ActiveTextures)
    257.         {          
    258.  
    259.             GUILayout.BeginHorizontal ();
    260.             GUILayout.Box(tDetails.texture, GUILayout.Width(ThumbnailWidth), GUILayout.Height(ThumbnailHeight));
    261.            
    262.             if(tDetails.texture==null)
    263.                 Init();
    264.            
    265.             if(tDetails!=null)
    266.             try
    267.             {  
    268.                 if(tDetails.texture!=null)
    269.                 if(GUILayout.Button(tDetails.texture.name,GUILayout.Width(150)))
    270.                 {
    271.                     SelectObject(tDetails.texture,ctrlPressed);
    272.                
    273.                
    274.                     string sizeLabel=""+tDetails.texture.width+"x"+tDetails.texture.height;
    275.                     if (tDetails.isCubeMap) sizeLabel+="x6";
    276.                     sizeLabel+=" - "+tDetails.mipMapCount+"mip";
    277.                     sizeLabel+="\n"+FormatSizeString(tDetails.memSizeKB)+" - "+tDetails.format+"";
    278.        
    279.                     GUILayout.Label (sizeLabel,GUILayout.Width(120));
    280.                 }
    281.                 if(GUILayout.Button(tDetails.FoundInMaterials.Count+" Mat",GUILayout.Width(50)))
    282.                 {
    283.                     SelectObjects(tDetails.FoundInMaterials,ctrlPressed);
    284.                 }
    285.    
    286.                 if(GUILayout.Button(tDetails.FoundInRenderers.Count+" GO",GUILayout.Width(50)))
    287.                 {
    288.                     List<Object> FoundObjects=new List<Object>();
    289.                     foreach (Renderer renderer in tDetails.FoundInRenderers) FoundObjects.Add(renderer.gameObject);
    290.                     SelectObjects(FoundObjects,ctrlPressed);
    291.                 }
    292.    
    293.                 GUILayout.EndHorizontal(); 
    294.             }
    295.             catch
    296.             {
    297.                
    298.             }
    299.         }
    300.         if (ActiveTextures.Count>0)
    301.         {
    302.             GUILayout.BeginHorizontal ();
    303.             GUILayout.Box(" ",GUILayout.Width(ThumbnailWidth),GUILayout.Height(ThumbnailHeight));
    304.  
    305.             if(GUILayout.Button("Select All",GUILayout.Width(150)))
    306.             {
    307.                 List<Object> AllTextures=new List<Object>();
    308.                 foreach (TextureDetails tDetails in ActiveTextures) AllTextures.Add(tDetails.texture);
    309.                 SelectObjects(AllTextures,ctrlPressed);
    310.             }
    311.             EditorGUILayout.EndHorizontal();
    312.            
    313.         }
    314.                 }
    315.         catch{}
    316.         EditorGUILayout.EndScrollView();
    317.    
    318.     }
    319.  
    320.     void ListMaterials()
    321.     {
    322.         materialListScrollPos = EditorGUILayout.BeginScrollView(materialListScrollPos);
    323.  
    324.         foreach (MaterialDetails tDetails in ActiveMaterials)
    325.         {          
    326.             if (tDetails.material!=null)
    327.             {
    328.                 GUILayout.BeginHorizontal ();
    329.  
    330.                 if (tDetails.material.mainTexture!=null) GUILayout.Box(tDetails.material.mainTexture, GUILayout.Width(ThumbnailWidth), GUILayout.Height(ThumbnailHeight));
    331.                 else   
    332.                 {
    333.                     GUILayout.Box("n/a",GUILayout.Width(ThumbnailWidth),GUILayout.Height(ThumbnailHeight));
    334.                 }
    335.  
    336.                 if(GUILayout.Button(tDetails.material.name,GUILayout.Width(150)))
    337.                 {;
    338.                     SelectObject(tDetails.material,ctrlPressed);
    339.                 }
    340.  
    341.                 if(GUILayout.Button(tDetails.FoundInRenderers.Count+" GO",GUILayout.Width(50)))
    342.                 {
    343.                     List<Object> FoundObjects=new List<Object>();
    344.                     foreach (Renderer renderer in tDetails.FoundInRenderers) FoundObjects.Add(renderer.gameObject);
    345.                     SelectObjects(FoundObjects,ctrlPressed);
    346.                 }
    347.  
    348.  
    349.                 GUILayout.EndHorizontal(); 
    350.             }
    351.         }
    352.         EditorGUILayout.EndScrollView();       
    353.     }
    354.  
    355.     void ListMeshes()
    356.     {
    357.         meshListScrollPos = EditorGUILayout.BeginScrollView(meshListScrollPos);
    358.  
    359.         foreach (MeshDetails tDetails in ActiveMeshDetails)
    360.         {          
    361.             if (tDetails.mesh!=null)
    362.             {
    363.                 GUILayout.BeginHorizontal ();
    364.                 /*
    365.                 if (tDetails.material.mainTexture!=null) GUILayout.Box(tDetails.material.mainTexture, GUILayout.Width(ThumbnailWidth), GUILayout.Height(ThumbnailHeight));
    366.                 else   
    367.                 {
    368.                     GUILayout.Box("n/a",GUILayout.Width(ThumbnailWidth),GUILayout.Height(ThumbnailHeight));
    369.                 }
    370.                 */
    371.  
    372.                 if(GUILayout.Button(tDetails.mesh.name,GUILayout.Width(150)))
    373.                 {
    374.                     SelectObject(tDetails.mesh,ctrlPressed);
    375.                 }
    376.                 string sizeLabel=""+tDetails.mesh.vertexCount+" vert";
    377.  
    378.                 GUILayout.Label (sizeLabel,GUILayout.Width(100));
    379.  
    380.  
    381.                 if(GUILayout.Button(tDetails.FoundInMeshFilters.Count+" GO",GUILayout.Width(50)))
    382.                 {
    383.                     List<Object> FoundObjects=new List<Object>();
    384.                     foreach (MeshFilter meshFilter in tDetails.FoundInMeshFilters) FoundObjects.Add(meshFilter.gameObject);
    385.                     SelectObjects(FoundObjects,ctrlPressed);
    386.                 }
    387.  
    388.  
    389.                 GUILayout.EndHorizontal(); 
    390.             }
    391.         }
    392.         EditorGUILayout.EndScrollView();       
    393.     }
    394.  
    395.     string FormatSizeString(int memSizeKB)
    396.     {
    397.         if (memSizeKB<1024) return ""+memSizeKB+"k";
    398.         else
    399.         {
    400.             float memSizeMB=((float)memSizeKB)/1024.0f;
    401.             return memSizeMB.ToString("0.00")+"Mb";
    402.         }
    403.     }
    404.  
    405.  
    406.     TextureDetails FindTextureDetails(Texture tTexture)
    407.     {
    408.         foreach (TextureDetails tTextureDetails in ActiveTextures)
    409.         {
    410.             if (tTextureDetails.texture==tTexture) return tTextureDetails;
    411.         }
    412.         return null;
    413.  
    414.     }
    415.  
    416.     MaterialDetails FindMaterialDetails(Material tMaterial)
    417.     {
    418.         foreach (MaterialDetails tMaterialDetails in ActiveMaterials)
    419.         {
    420.             if (tMaterialDetails.material==tMaterial) return tMaterialDetails;
    421.         }
    422.         return null;
    423.  
    424.     }
    425.  
    426.     MeshDetails FindMeshDetails(Mesh tMesh)
    427.     {
    428.         foreach (MeshDetails tMeshDetails in ActiveMeshDetails)
    429.         {
    430.             if (tMeshDetails.mesh==tMesh) return tMeshDetails;
    431.         }
    432.         return null;
    433.  
    434.     }
    435.  
    436.  
    437.     void CheckResources()
    438.     {
    439.         ActiveTextures.Clear();
    440.         ActiveMaterials.Clear();
    441.         ActiveMeshDetails.Clear();
    442.  
    443.         Renderer[] renderers = (Renderer[]) FindObjectsOfType(typeof(Renderer));
    444.         //Debug.Log("Total renderers "+renderers.Length);
    445.         foreach (Renderer renderer in renderers)
    446.         {
    447.             //Debug.Log("Renderer is "+renderer.name);
    448.             foreach (Material material in renderer.sharedMaterials)
    449.             {
    450.  
    451.                 MaterialDetails tMaterialDetails=FindMaterialDetails(material);
    452.                 if (tMaterialDetails==null)
    453.                 {
    454.                     tMaterialDetails=new MaterialDetails();
    455.                     tMaterialDetails.material=material;
    456.                     ActiveMaterials.Add(tMaterialDetails);
    457.                 }
    458.                 tMaterialDetails.FoundInRenderers.Add(renderer);
    459.             }
    460.         }
    461.  
    462.         foreach (MaterialDetails tMaterialDetails in ActiveMaterials)
    463.         {
    464.             Material tMaterial=tMaterialDetails.material;
    465.             foreach (Object obj in EditorUtility.CollectDependencies(new UnityEngine.Object[] {tMaterial}))
    466.             {
    467.                 if (obj is Texture)
    468.                 {
    469.                     Texture tTexture=obj as Texture;
    470.                     TextureDetails tTextureDetails=FindTextureDetails(tTexture);
    471.                     if (tTextureDetails==null)
    472.                     {
    473.                         tTextureDetails=new TextureDetails();
    474.                         tTextureDetails.texture=tTexture;
    475.                         tTextureDetails.isCubeMap=tTexture is Cubemap;
    476.  
    477.                         int memSize=CalculateTextureSizeBytes(tTexture);
    478.  
    479.                         tTextureDetails.memSizeKB=memSize/1024;
    480.                         TextureFormat tFormat=TextureFormat.RGBA32;
    481.                         int tMipMapCount=1;
    482.                         if (tTexture is Texture2D)
    483.                         {
    484.                             tFormat=(tTexture as Texture2D).format;
    485.                             tMipMapCount=(tTexture as Texture2D).mipmapCount;
    486.                         }
    487.                         if (tTexture is Cubemap)
    488.                         {
    489.                             tFormat=(tTexture as Cubemap).format;
    490.                         }
    491.  
    492.                         tTextureDetails.format=tFormat;
    493.                         tTextureDetails.mipMapCount=tMipMapCount;
    494.                         ActiveTextures.Add(tTextureDetails);
    495.                     }
    496.                     tTextureDetails.FoundInMaterials.Add(tMaterial);
    497.                     foreach (Renderer renderer in tMaterialDetails.FoundInRenderers)
    498.                     {
    499.                         if (!tTextureDetails.FoundInRenderers.Contains( renderer)) tTextureDetails.FoundInRenderers.Add(renderer);
    500.                     }
    501.                 }
    502.             }
    503.         }
    504.  
    505.  
    506.         MeshFilter[] meshFilters = (MeshFilter[]) FindObjectsOfType(typeof(MeshFilter));
    507.  
    508.         foreach (MeshFilter tMeshFilter in meshFilters)
    509.         {
    510.             Mesh tMesh=tMeshFilter.sharedMesh;
    511.             if (tMesh!=null)
    512.             {
    513.                 MeshDetails tMeshDetails=FindMeshDetails(tMesh);
    514.                 if (tMeshDetails==null)
    515.                 {
    516.                     tMeshDetails=new MeshDetails();
    517.                     tMeshDetails.mesh=tMesh;
    518.                     ActiveMeshDetails.Add(tMeshDetails);
    519.                 }
    520.                 tMeshDetails.FoundInMeshFilters.Add(tMeshFilter);
    521.             }
    522.         }
    523.  
    524.  
    525.         TotalTextureMemory=0;
    526.         foreach (TextureDetails tTextureDetails in ActiveTextures) TotalTextureMemory+=tTextureDetails.memSizeKB;
    527.  
    528.         TotalMeshVertices=0;
    529.         foreach (MeshDetails tMeshDetails in ActiveMeshDetails) TotalMeshVertices+=tMeshDetails.mesh.vertexCount;
    530.  
    531.         // Sort by size, descending
    532.         ActiveTextures.Sort(delegate(TextureDetails details1, TextureDetails details2) {return details2.memSizeKB-details1.memSizeKB;});
    533.         ActiveMeshDetails.Sort(delegate(MeshDetails details1, MeshDetails details2) {return details2.mesh.vertexCount-details1.mesh.vertexCount;});
    534.  
    535.     }
    536.  
    537.  
    538. }
     
    Last edited: May 3, 2012
  11. rextr09

    rextr09

    Joined:
    Dec 22, 2011
    Posts:
    416
    Thanks for this great tool, it's so useful.
    I have a question about texture sizes. Even though I set the "Texture Quality" = "Half Res" in Quality settings, the tool still displays the full resolution. Is this normal?
     
  12. yuriythebest

    yuriythebest

    Joined:
    Nov 21, 2009
    Posts:
    1,121
    I think this is the case because in the Unity Editor they are fully loaded into memory.. I think, while when in standalone they might not be. That or the script just looks at the original texture size.

    This script is amazing though, especially for mobile development, where an accidentally loaded texture atlas can be the difference between your app working and not
     
  13. rextr09

    rextr09

    Joined:
    Dec 22, 2011
    Posts:
    416
    OK, thanks...
    And yes this is amazing.... using this tool I have spot and reduced all my 1024*1024 textures to 256*256 without much affecting overall quality.
     
  14. Rush-Rage-Games

    Rush-Rage-Games

    Joined:
    Sep 9, 2010
    Posts:
    1,997
  15. gmayer

    gmayer

    Joined:
    May 15, 2012
    Posts:
    4
    Amazing work man!
    Thanks!!
     
  16. AShim-3D

    AShim-3D

    Joined:
    Jul 13, 2012
    Posts:
    34
    Add support SkinnedMeshRenderer, see on GitHub
     
  17. 3ddf

    3ddf

    Joined:
    Mar 18, 2010
    Posts:
    6
    Really useful, thanks!
     
  18. moproductions

    moproductions

    Joined:
    Sep 28, 2010
    Posts:
    88
    Quick question for the thread. When loading up a scene directly the Profiler says I'm using 1068 textures using 53.2 MB.
    When loading the same scene from another scene, the Profiler says I'm using 1071 textures using 70.4 MB.

    I used this tool (which is FANTASTIC, btw) in both cases, but the tool said that I was using the exact same amount of resources (textures, materials, objects).

    I think the tool is working properly, but that means that there's some (large) textures still around somewhere eating up memory.
    Is there a way that I can track down those 3 extra textures lurking around in memory that the tool isn't catching?

    Thanks
    -Mo
     
  19. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Freaking amazing utility. Can't believe I never used it before. Now it is an integral part of our pipeline.
     
  20. joshimoo

    joshimoo

    Joined:
    Jun 23, 2011
    Posts:
    266
    Looks very good, wish the profiler had a texture breakdown like this =)
     
  21. Lars-Steenhoff

    Lars-Steenhoff

    Joined:
    Aug 7, 2007
    Posts:
    3,521
    This is one of the must have tools that I use daily to optimise my game, it would be nice to see an asset store version too.
     
  22. hike1

    hike1

    Joined:
    Sep 6, 2009
    Posts:
    401
    Thanks!
     
  23. pedroathumanspot

    pedroathumanspot

    Joined:
    Oct 30, 2012
    Posts:
    9
    Hi!

    Bummer. It seems I can't get this script to work. :neutral: I already copied the ResourceChecker.cs script to the Assets/Editor folder - and it loads right - but don't display any texture, or material, or mesh. It makes some sense because I'm using NGUI - and all my textures are loaded at runtime, to save memory - but is quite strange that even when I'm hitting 'Refresh' on runtime it still gives me nothing. (I mean, the NGUI UITexture has some Texture2D encapsulated, right?)

    Even so, I guess I'm going to try and port ResourceChecker to NGUI. By any chance, is any work underway to do this?

    Cheers.
     
  24. rextr09

    rextr09

    Joined:
    Dec 22, 2011
    Posts:
    416
    Yes, I think this is not compatible with NGUI.
     
  25. sparrow

    sparrow

    Joined:
    May 6, 2012
    Posts:
    17
    Thank you, something like this is a must have in the profiler. This was incredibly helpful
     
  26. Sisso

    Sisso

    Joined:
    Sep 29, 2009
    Posts:
    196
    You can see what is used by ngui if you change ResourceChecker search in all loaded resources instead scene objects. Replace

    Code (csharp):
    1. FindObjectsOfType(typeof(Renderer))
    By

    Code (csharp):
    1. Resources.FindObjectsOfTypeAll(typeof(Renderer))
     
  27. stevesan

    stevesan

    Joined:
    Aug 14, 2011
    Posts:
    65
    How about lightmaps? Probably pretty easy to add :)
     
  28. bchevalier

    bchevalier

    Joined:
    Feb 13, 2013
    Posts:
    42
    Hi guys,

    this tool is awesome ! it seems to work properly on my side, but I'm having warnings like that one whenever I refresh :



    Any ideas ? I'm using Unity 4.3 pro

    Thanks !
    ben
     
  29. larku

    larku

    Joined:
    Mar 14, 2013
    Posts:
    1,422
    Yep on line 455 add an extra check so it reads like:

    Code (csharp):
    1. if (tMaterial != null && tMaterial.mainTexture != null && !dependencies.Contains(tMaterial.mainTexture))
     
    Last edited: Sep 20, 2014
  30. nDman

    nDman

    Joined:
    Nov 1, 2013
    Posts:
    8
    Hi,
    This is an excellent tool, thanks to make it available.

    I get this error on unity 4.0.1:

     
  31. Meceka

    Meceka

    Joined:
    Dec 23, 2013
    Posts:
    423
    Hello, thanks for sharing this great asset. But it's not compatible with Unity 5. It can't compile because of these errors;

    Assets/Editor/ResourceChecker.cs(167,44): error CS0117: `UnityEngine.TextureFormat' does not contain a definition for `ATF_RGB_DXT1'

    Assets/Editor/ResourceChecker.cs(168,44): error CS0117: `UnityEngine.TextureFormat' does not contain a definition for `ATF_RGBA_JPG'

    Assets/Editor/ResourceChecker.cs(168,44): error CS0117: `UnityEngine.TextureFormat' does not contain a definition for `ATF_RGBA_JPG'

    Can you please update or share a fix, thanks.
     
  32. larku

    larku

    Joined:
    Mar 14, 2013
    Posts:
    1,422
    You can most likely just remove/comment out those cases in the switch statement since those cases just return 0 any way (which it will still do when they are removed)...
     
  33. idurvesh

    idurvesh

    Joined:
    Jun 9, 2014
    Posts:
    495
    Unity 5 update plz
     
  34. larku

    larku

    Joined:
    Mar 14, 2013
    Posts:
    1,422
    It works fine in Unity 5, just remove those three offending cases. They were unused anyway so there is no issue removing them.
     
    idurvesh likes this.
  35. idurvesh

    idurvesh

    Joined:
    Jun 9, 2014
    Posts:
    495
    Awesome.
     
  36. wightwhale

    wightwhale

    Joined:
    Jul 28, 2011
    Posts:
    397
    I don't think this checks for uGUI textures. Anyone know how to add them?
     
  37. Ben-BearFish

    Ben-BearFish

    Joined:
    Sep 6, 2011
    Posts:
    1,204
    The script needs to be modified to use the CanvasRenderer because uGUI CanvasRenderers are different than Unity's gameobject Renderers. The script currently only checks for Renderers in the scene.
     
  38. Mangatome

    Mangatome

    Joined:
    Mar 5, 2014
    Posts:
    13
    For anyone still using Unity 4.6 Personal (no profiler!), I've updated this great script with Sprite support. Sprites being loaded when they are referenced from animations and behaviors, the script also counts these. I've also fixed Unity 5 compatibility and added the possibility to count disabled objects.

    All of that at https://github.com/Mangatome/Unity-Resource-Checker until OP merges my pull request.
     
  39. ChiuanWei

    ChiuanWei

    Joined:
    Jan 29, 2012
    Posts:
    131
    cool! star!
     
  40. AndyNeoman

    AndyNeoman

    Joined:
    Sep 28, 2014
    Posts:
    938
    Awesome asset - thanks to the OP - has the mangatone merge took place yet or should I try that version too.

    Also I have a question regarding disabled and internal tick box. Are these assets loaded into memory and taking space or are they just in the build. Will they affect the current scene speed/load times as they appear to be assets from other scenes in my app.

    Thanks again great work integrated into our workflow. :)
     
  41. Mangatome

    Mangatome

    Joined:
    Mar 5, 2014
    Posts:
    13
    The merge was carried out by handcircus at https://github.com/handcircus/Unity-Resource-Checker, so if you follow that repo it should be up-to-date.

    Regarding your question, "disabled and internal" calls Resources.FindObjectsOfTypeAll(Type) in order to discover disabled GameObjects in the scene. This method has the side-effect of also listing internal engine objects, and objects that are in memory in the editor. (See doc: http://docs.unity3d.com/ScriptReference/Resources.FindObjectsOfTypeAll.html

    Both the editor (at least 4.6.x) and the Resource Checker script are not very concerned about freeing memory, so if you check "disabled and internal" you'll sometimes see assets from scenes that are not the current opened scene. When that happens to me and I need a more accurate count from the script, I just close and restart Unity.

    To sum up, you can see three kinds of objects listed if you check "disabled and internal":
    1. Your own assets from the opened scene.
    2. Your own assets from other scenes. They have probably been loaded but not freed by the editor, from a previously opened scene. Restart Unity and they won't appear in the count.
    3. Engine stuff (I've seen namely materials). I don't think you can optimize that, so just ignore it.
     
    Last edited: Nov 28, 2015
    AndyNeoman likes this.
  42. Nikolay-Lezhnev

    Nikolay-Lezhnev

    Joined:
    Nov 8, 2012
    Posts:
    6
    Great script, thank you very much!

    I've got latest version from github, then I made two fixes:
    1. Skipping texture duplicates with same GetNativeTextureID()
    2. Skipping prefabs from library:
    PrefabUtility.GetPrefabType(x) != PrefabType.Prefab && PrefabUtility.GetPrefabType(x) != PrefabType.ModelPrefab);

    It gave me more accurate results, I compared Android build and Editor with target platform == android. In build I've tested memory by Unity Profiler, in Editor I've used Resource Checker, and I got difference in complete texture size less than 10% in our project.
     

    Attached Files:

    Meceka likes this.
  43. angelsm85

    angelsm85

    Joined:
    Oct 27, 2015
    Posts:
    63
    When I build my game it appears this error: "Assets/ResourceChecker.cs(11,7): error CS0246: The type or namespace name `UnityEditor' could not be found. Are you missing a using directive or an assembly reference?"
    How can I fix it?
    Thanks!
     
  44. Sisso

    Sisso

    Joined:
    Sep 29, 2009
    Posts:
    196
    This is a editor extension script (create window to use inside unity3d editor, not in play mode). So it should be inside of an editor folder. (ex: Assets/Editor, Assets/AnyLib/Blalbla/Editor).

    The namespace UnityEditor is only available if you put this file in one of those folders.

    You should take a look on theses references:

    http://docs.unity3d.com/Manual/SpecialFolders.html

    http://docs.unity3d.com/Manual/ExtendingTheEditor.html

    PS: Profile is now available on free mode too.
     
  45. angelsm85

    angelsm85

    Joined:
    Oct 27, 2015
    Posts:
    63
    Thank you so much!!
     
  46. fred_gds

    fred_gds

    Joined:
    Sep 20, 2012
    Posts:
    184
    Just came across this. I wish I would have found this earlier!!! Thank you.
     
  47. znelson

    znelson

    Joined:
    May 9, 2016
    Posts:
    1
    This is really great, thanks!
     
  48. minev

    minev

    Joined:
    Nov 19, 2014
    Posts:
    34
    Great add-on!
     
  49. Sandler

    Sandler

    Joined:
    Nov 6, 2015
    Posts:
    241
    This is awesome great work!
     
  50. alexandresk

    alexandresk

    Joined:
    Jul 11, 2013
    Posts:
    51
    Thank you for this.