Last active
October 11, 2021 14:00
-
-
Save noisecrime/2f70b5d4ea827cb5965d38504ad1591c to your computer and use it in GitHub Desktop.
Unity: Quick update to original 'Unity-Resource-Checker' to use native Unity methods for obtaining the memory size of textures.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Resource Checker | |
// (c) 2012 Simon Oliver / HandCircus / [email protected] | |
// (c) 2015 Brice Clocher / Mangatome / [email protected] | |
// Public domain, do with whatever you like, commercial or not | |
// This comes with no warranty, use at your own risk! | |
// https://github.com/handcircus/Unity-Resource-Checker | |
// (c) 2019 NoiseCrime | |
// Quick update to use native Unity methods to obtain the size of textures. | |
// Looking through the code much has changed since this class was first created | |
// as such it requires a full rewrite to fix various issues and robustly deal | |
// with all texture types. It would also be nice to streamline the code into | |
// seperate files etc. | |
// https://gist.github.com/noisecrime/2f70b5d4ea827cb5965d38504ad1591c | |
using System; | |
using System.Linq; | |
using UnityEngine; | |
using UnityEngine.UI; | |
using UnityEditor; | |
using System.Collections.Generic; | |
using System.Reflection; | |
using Object = UnityEngine.Object; | |
using UnityEngine.Assertions; | |
/// <summary> | |
/// <see cref="UnityEditor.TextureUtil"/> Accessor | |
/// </summary> | |
/// <author>Seibe TAKAHASHI</author> | |
/// <remarks> | |
/// https://gist.github.com/seibe/762f8f2e3c4e06a8f894f812127e3e33 | |
/// (c) 2017 Seibe TAKAHASHI. | |
/// This code is released under the MIT License. | |
/// http://opensource.org/licenses/mit-license.php | |
/// </remarks> | |
public static class UnityTextureUtil | |
{ | |
private static readonly System.Type cType; | |
private static MethodInfo mMethod_GetMipmapCount; | |
private static MethodInfo mMethod_GetTextureFormat; | |
private static MethodInfo mMethod_GetRuntimeMemorySizeLong; | |
private static MethodInfo mMethod_GetStorageMemorySizeLong; | |
private static MethodInfo mMethod_IsNonPowerOfTwo; | |
static UnityTextureUtil() | |
{ | |
cType = Assembly.Load("UnityEditor.dll").GetType("UnityEditor.TextureUtil"); | |
Assert.IsNotNull(cType); | |
} | |
public static int GetMipmapCount(Texture texture) | |
{ | |
if (mMethod_GetMipmapCount == null) | |
mMethod_GetMipmapCount = cType.GetMethod("GetMipmapCount", BindingFlags.Static | BindingFlags.Public); | |
Assert.IsNotNull(mMethod_GetMipmapCount); | |
return (int)mMethod_GetMipmapCount.Invoke(null, new[] { texture }); | |
} | |
public static TextureFormat GetTextureFormat(Texture texture) | |
{ | |
if (mMethod_GetTextureFormat == null) | |
mMethod_GetTextureFormat = cType.GetMethod("GetTextureFormat", BindingFlags.Static | BindingFlags.Public); | |
Assert.IsNotNull(mMethod_GetTextureFormat); | |
return (TextureFormat)mMethod_GetTextureFormat.Invoke(null, new[] { texture }); | |
} | |
public static long GetRuntimeMemorySizeLong(Texture texture) | |
{ | |
if (mMethod_GetRuntimeMemorySizeLong == null) | |
mMethod_GetRuntimeMemorySizeLong = cType.GetMethod("GetRuntimeMemorySizeLong", BindingFlags.Static | BindingFlags.Public); | |
Assert.IsNotNull(mMethod_GetRuntimeMemorySizeLong); | |
return (long)mMethod_GetRuntimeMemorySizeLong.Invoke(null, new[] { texture }); | |
} | |
public static long GetStorageMemorySizeLong(Texture texture) | |
{ | |
if (mMethod_GetStorageMemorySizeLong == null) | |
mMethod_GetStorageMemorySizeLong = cType.GetMethod("GetStorageMemorySizeLong", BindingFlags.Static | BindingFlags.Public); | |
Assert.IsNotNull(mMethod_GetStorageMemorySizeLong); | |
return (long)mMethod_GetStorageMemorySizeLong.Invoke(null, new[] { texture }); | |
} | |
public static bool IsNonPowerOfTwo(Texture2D texture) | |
{ | |
if (mMethod_IsNonPowerOfTwo == null) | |
mMethod_IsNonPowerOfTwo = cType.GetMethod("IsNonPowerOfTwo", BindingFlags.Static | BindingFlags.Public); | |
Assert.IsNotNull(mMethod_IsNonPowerOfTwo); | |
return (bool)mMethod_IsNonPowerOfTwo.Invoke(null, new[] { texture }); | |
} | |
} | |
public class TextureDetails : IEquatable<TextureDetails> | |
{ | |
public bool isCubeMap; | |
public int memSizeKB; | |
public Texture texture; | |
public TextureFormat format; | |
public int mipMapCount; | |
public List<Object> FoundInMaterials=new List<Object>(); | |
public List<Object> FoundInRenderers=new List<Object>(); | |
public List<Object> FoundInAnimators = new List<Object>(); | |
public List<Object> FoundInScripts = new List<Object>(); | |
public List<Object> FoundInGraphics = new List<Object>(); | |
public List<Object> FoundInButtons = new List<Object>(); | |
public bool isSky; | |
public bool instance; | |
public bool isgui; | |
public TextureDetails() | |
{ | |
} | |
public bool Equals(TextureDetails other) | |
{ | |
return texture != null && other.texture != null && | |
texture.GetNativeTexturePtr() == other.texture.GetNativeTexturePtr(); | |
} | |
public override int GetHashCode() | |
{ | |
return (int)texture.GetNativeTexturePtr(); | |
} | |
public override bool Equals(object obj) | |
{ | |
return Equals(obj as TextureDetails); | |
} | |
}; | |
public class MaterialDetails | |
{ | |
public Material material; | |
public List<Renderer> FoundInRenderers=new List<Renderer>(); | |
public List<Graphic> FoundInGraphics=new List<Graphic>(); | |
public bool instance; | |
public bool isgui; | |
public bool isSky; | |
public MaterialDetails() | |
{ | |
instance = false; | |
isgui = false; | |
isSky = false; | |
} | |
}; | |
public class MeshDetails | |
{ | |
public Mesh mesh; | |
public List<MeshFilter> FoundInMeshFilters=new List<MeshFilter>(); | |
public List<SkinnedMeshRenderer> FoundInSkinnedMeshRenderer=new List<SkinnedMeshRenderer>(); | |
public bool instance; | |
public MeshDetails() | |
{ | |
instance = false; | |
} | |
}; | |
public class MissingGraphic{ | |
public Transform Object; | |
public string type; | |
public string name; | |
} | |
public class ResourceChecker : EditorWindow { | |
string[] inspectToolbarStrings = {"Textures", "Materials","Meshes"}; | |
string[] inspectToolbarStrings2 = {"Textures", "Materials","Meshes", "Missing"}; | |
enum InspectType | |
{ | |
Textures,Materials,Meshes,Missing | |
}; | |
bool IncludeDisabledObjects=true; | |
bool IncludeSpriteAnimations=true; | |
bool IncludeScriptReferences=true; | |
bool IncludeGuiElements=true; | |
bool thingsMissing = false; | |
InspectType ActiveInspectType=InspectType.Textures; | |
float ThumbnailWidth=40; | |
float ThumbnailHeight=40; | |
List<TextureDetails> ActiveTextures=new List<TextureDetails>(); | |
List<MaterialDetails> ActiveMaterials=new List<MaterialDetails>(); | |
List<MeshDetails> ActiveMeshDetails=new List<MeshDetails>(); | |
List<MissingGraphic> MissingObjects = new List<MissingGraphic> (); | |
Vector2 textureListScrollPos=new Vector2(0,0); | |
Vector2 materialListScrollPos=new Vector2(0,0); | |
Vector2 meshListScrollPos=new Vector2(0,0); | |
Vector2 missingListScrollPos = new Vector2 (0,0); | |
int TotalTextureMemory=0; | |
int TotalMeshVertices=0; | |
bool ctrlPressed=false; | |
static int MinWidth=475; | |
Color defColor; | |
bool collectedInPlayingMode; | |
[MenuItem ("Window/Resource Checker")] | |
static void Init () | |
{ | |
ResourceChecker window = (ResourceChecker) EditorWindow.GetWindow (typeof (ResourceChecker)); | |
window.CheckResources(); | |
window.minSize=new Vector2(MinWidth,475); | |
} | |
void OnGUI () | |
{ | |
defColor = GUI.color; | |
IncludeDisabledObjects = GUILayout.Toggle(IncludeDisabledObjects, "Include disabled objects", GUILayout.Width(300)); | |
IncludeSpriteAnimations = GUILayout.Toggle(IncludeSpriteAnimations, "Look in sprite animations", GUILayout.Width(300)); | |
GUI.color = new Color (0.8f, 0.8f, 1.0f, 1.0f); | |
IncludeScriptReferences = GUILayout.Toggle(IncludeScriptReferences, "Look in behavior fields", GUILayout.Width(300)); | |
GUI.color = new Color (1.0f, 0.95f, 0.8f, 1.0f); | |
IncludeGuiElements = GUILayout.Toggle(IncludeGuiElements, "Look in GUI elements", GUILayout.Width(300)); | |
GUI.color = defColor; | |
GUILayout.BeginArea(new Rect(position.width-85,5,100,65)); | |
if (GUILayout.Button("Calculate",GUILayout.Width(80), GUILayout.Height(40))) | |
CheckResources(); | |
if (GUILayout.Button("CleanUp",GUILayout.Width(80), GUILayout.Height(20))) | |
Resources.UnloadUnusedAssets(); | |
GUILayout.EndArea(); | |
RemoveDestroyedResources(); | |
GUILayout.Space(30); | |
if (thingsMissing == true) { | |
EditorGUI.HelpBox (new Rect(8,75,300,25),"Some GameObjects are missing graphical elements.", MessageType.Error); | |
} | |
GUILayout.BeginHorizontal(); | |
GUILayout.Label("Textures "+ActiveTextures.Count+" - "+FormatSizeString(TotalTextureMemory)); | |
GUILayout.Label("Materials "+ActiveMaterials.Count); | |
GUILayout.Label("Meshes "+ActiveMeshDetails.Count+" - "+TotalMeshVertices+" verts"); | |
GUILayout.EndHorizontal(); | |
if (thingsMissing == true) { | |
ActiveInspectType = (InspectType)GUILayout.Toolbar ((int)ActiveInspectType, inspectToolbarStrings2); | |
} else { | |
ActiveInspectType = (InspectType)GUILayout.Toolbar ((int)ActiveInspectType, inspectToolbarStrings); | |
} | |
ctrlPressed=Event.current.control || Event.current.command; | |
switch (ActiveInspectType) | |
{ | |
case InspectType.Textures: | |
ListTextures(); | |
break; | |
case InspectType.Materials: | |
ListMaterials(); | |
break; | |
case InspectType.Meshes: | |
ListMeshes(); | |
break; | |
case InspectType.Missing: | |
ListMissing(); | |
break; | |
} | |
} | |
private void RemoveDestroyedResources() | |
{ | |
if (collectedInPlayingMode != Application.isPlaying) | |
{ | |
ActiveTextures.Clear(); | |
ActiveMaterials.Clear(); | |
ActiveMeshDetails.Clear(); | |
MissingObjects.Clear (); | |
thingsMissing = false; | |
collectedInPlayingMode = Application.isPlaying; | |
} | |
ActiveTextures.RemoveAll(x => !x.texture); | |
ActiveTextures.ForEach(delegate(TextureDetails obj) { | |
obj.FoundInAnimators.RemoveAll(x => !x); | |
obj.FoundInMaterials.RemoveAll(x => !x); | |
obj.FoundInRenderers.RemoveAll(x => !x); | |
obj.FoundInScripts.RemoveAll(x => !x); | |
obj.FoundInGraphics.RemoveAll(x => !x); | |
}); | |
ActiveMaterials.RemoveAll(x => !x.material); | |
ActiveMaterials.ForEach(delegate(MaterialDetails obj) { | |
obj.FoundInRenderers.RemoveAll(x => !x); | |
obj.FoundInGraphics.RemoveAll(x => !x); | |
}); | |
ActiveMeshDetails.RemoveAll(x => !x.mesh); | |
ActiveMeshDetails.ForEach(delegate(MeshDetails obj) { | |
obj.FoundInMeshFilters.RemoveAll(x => !x); | |
obj.FoundInSkinnedMeshRenderer.RemoveAll(x => !x); | |
}); | |
TotalTextureMemory = 0; | |
foreach (TextureDetails tTextureDetails in ActiveTextures) TotalTextureMemory += tTextureDetails.memSizeKB; | |
TotalMeshVertices = 0; | |
foreach (MeshDetails tMeshDetails in ActiveMeshDetails) TotalMeshVertices += tMeshDetails.mesh.vertexCount; | |
} | |
void SelectObject(Object selectedObject,bool append) | |
{ | |
if (append) | |
{ | |
List<Object> currentSelection=new List<Object>(Selection.objects); | |
// Allow toggle selection | |
if (currentSelection.Contains(selectedObject)) currentSelection.Remove(selectedObject); | |
else currentSelection.Add(selectedObject); | |
Selection.objects=currentSelection.ToArray(); | |
} | |
else Selection.activeObject=selectedObject; | |
} | |
void SelectObjects(List<Object> selectedObjects,bool append) | |
{ | |
if (append) | |
{ | |
List<Object> currentSelection=new List<Object>(Selection.objects); | |
currentSelection.AddRange(selectedObjects); | |
Selection.objects=currentSelection.ToArray(); | |
} | |
else Selection.objects=selectedObjects.ToArray(); | |
} | |
void ListTextures() | |
{ | |
textureListScrollPos = EditorGUILayout.BeginScrollView(textureListScrollPos); | |
foreach (TextureDetails tDetails in ActiveTextures) | |
{ | |
GUILayout.BeginHorizontal (); | |
Texture tex =tDetails.texture; | |
if(tDetails.texture.GetType() == typeof(Texture2DArray) || tDetails.texture.GetType() == typeof(Cubemap)){ | |
tex = AssetPreview.GetMiniThumbnail(tDetails.texture); | |
} | |
GUILayout.Box(tex, GUILayout.Width(ThumbnailWidth), GUILayout.Height(ThumbnailHeight)); | |
if (tDetails.instance == true) | |
GUI.color = new Color (0.8f, 0.8f, defColor.b, 1.0f); | |
if (tDetails.isgui == true) | |
GUI.color = new Color (defColor.r, 0.95f, 0.8f, 1.0f); | |
if (tDetails.isSky) | |
GUI.color = new Color (0.9f, defColor.g, defColor.b, 1.0f); | |
if(GUILayout.Button(tDetails.texture.name,GUILayout.Width(150))) | |
{ | |
SelectObject(tDetails.texture,ctrlPressed); | |
} | |
GUI.color = defColor; | |
string sizeLabel=""+tDetails.texture.width+"x"+tDetails.texture.height; | |
if (tDetails.isCubeMap) sizeLabel+="x6"; | |
if (tDetails.texture.GetType () == typeof(Texture2DArray)) | |
sizeLabel+= "[]\n" + ((Texture2DArray)tDetails.texture).depth+"depths"; | |
sizeLabel+=" - "+tDetails.mipMapCount+"mip\n"+FormatSizeString(tDetails.memSizeKB)+" - "+tDetails.format; | |
GUILayout.Label (sizeLabel,GUILayout.Width(120)); | |
if(GUILayout.Button(tDetails.FoundInMaterials.Count+" Mat",GUILayout.Width(50))) | |
{ | |
SelectObjects(tDetails.FoundInMaterials,ctrlPressed); | |
} | |
HashSet<Object> FoundObjects = new HashSet<Object>(); | |
foreach (Renderer renderer in tDetails.FoundInRenderers) FoundObjects.Add(renderer.gameObject); | |
foreach (Animator animator in tDetails.FoundInAnimators) FoundObjects.Add(animator.gameObject); | |
foreach (Graphic graphic in tDetails.FoundInGraphics) FoundObjects.Add(graphic.gameObject); | |
foreach (Button button in tDetails.FoundInButtons) FoundObjects.Add(button.gameObject); | |
foreach (MonoBehaviour script in tDetails.FoundInScripts) FoundObjects.Add(script.gameObject); | |
if (GUILayout.Button(FoundObjects.Count+" GO",GUILayout.Width(50))) | |
{ | |
SelectObjects(new List<Object>(FoundObjects),ctrlPressed); | |
} | |
GUILayout.EndHorizontal(); | |
} | |
if (ActiveTextures.Count>0) | |
{ | |
EditorGUILayout.Space(); | |
GUILayout.BeginHorizontal (); | |
//GUILayout.Box(" ",GUILayout.Width(ThumbnailWidth),GUILayout.Height(ThumbnailHeight)); | |
if(GUILayout.Button("Select \n All",GUILayout.Width(ThumbnailWidth*2))) | |
{ | |
List<Object> AllTextures=new List<Object>(); | |
foreach (TextureDetails tDetails in ActiveTextures) AllTextures.Add(tDetails.texture); | |
SelectObjects(AllTextures,ctrlPressed); | |
} | |
EditorGUILayout.EndHorizontal(); | |
} | |
EditorGUILayout.EndScrollView(); | |
} | |
void ListMaterials() | |
{ | |
materialListScrollPos = EditorGUILayout.BeginScrollView(materialListScrollPos); | |
foreach (MaterialDetails tDetails in ActiveMaterials) | |
{ | |
if (tDetails.material!=null) | |
{ | |
GUILayout.BeginHorizontal (); | |
GUILayout.Box(AssetPreview.GetAssetPreview(tDetails.material), GUILayout.Width(ThumbnailWidth), GUILayout.Height(ThumbnailHeight)); | |
if (tDetails.instance == true) | |
GUI.color = new Color (0.8f, 0.8f, defColor.b, 1.0f); | |
if (tDetails.isgui == true) | |
GUI.color = new Color (defColor.r, 0.95f, 0.8f, 1.0f); | |
if (tDetails.isSky) | |
GUI.color = new Color (0.9f, defColor.g, defColor.b, 1.0f); | |
if(GUILayout.Button(tDetails.material.name,GUILayout.Width(150))) | |
{ | |
SelectObject(tDetails.material,ctrlPressed); | |
} | |
GUI.color = defColor; | |
string shaderLabel = tDetails.material.shader != null ? tDetails.material.shader.name : "no shader"; | |
GUILayout.Label (shaderLabel, GUILayout.Width(200)); | |
if(GUILayout.Button((tDetails.FoundInRenderers.Count + tDetails.FoundInGraphics.Count) +" GO",GUILayout.Width(50))) | |
{ | |
List<Object> FoundObjects=new List<Object>(); | |
foreach (Renderer renderer in tDetails.FoundInRenderers) FoundObjects.Add(renderer.gameObject); | |
foreach (Graphic graphic in tDetails.FoundInGraphics) FoundObjects.Add(graphic.gameObject); | |
SelectObjects(FoundObjects,ctrlPressed); | |
} | |
GUILayout.EndHorizontal(); | |
} | |
} | |
EditorGUILayout.EndScrollView(); | |
} | |
void ListMeshes() | |
{ | |
meshListScrollPos = EditorGUILayout.BeginScrollView(meshListScrollPos); | |
foreach (MeshDetails tDetails in ActiveMeshDetails) | |
{ | |
if (tDetails.mesh!=null) | |
{ | |
GUILayout.BeginHorizontal (); | |
string name = tDetails.mesh.name; | |
if (name == null || name.Count() < 1) | |
name = tDetails.FoundInMeshFilters[0].gameObject.name; | |
if (tDetails.instance == true) | |
GUI.color = new Color (0.8f, 0.8f, defColor.b, 1.0f); | |
if(GUILayout.Button(name,GUILayout.Width(150))) | |
{ | |
SelectObject(tDetails.mesh,ctrlPressed); | |
} | |
GUI.color = defColor; | |
string sizeLabel=""+tDetails.mesh.vertexCount+" vert"; | |
GUILayout.Label (sizeLabel,GUILayout.Width(100)); | |
if(GUILayout.Button(tDetails.FoundInMeshFilters.Count + " GO",GUILayout.Width(50))) | |
{ | |
List<Object> FoundObjects=new List<Object>(); | |
foreach (MeshFilter meshFilter in tDetails.FoundInMeshFilters) FoundObjects.Add(meshFilter.gameObject); | |
SelectObjects(FoundObjects,ctrlPressed); | |
} | |
if (tDetails.FoundInSkinnedMeshRenderer.Count > 0) { | |
if (GUILayout.Button (tDetails.FoundInSkinnedMeshRenderer.Count + " skinned mesh GO", GUILayout.Width (140))) { | |
List<Object> FoundObjects = new List<Object> (); | |
foreach (SkinnedMeshRenderer skinnedMeshRenderer in tDetails.FoundInSkinnedMeshRenderer) | |
FoundObjects.Add (skinnedMeshRenderer.gameObject); | |
SelectObjects (FoundObjects, ctrlPressed); | |
} | |
} else { | |
GUI.color = new Color (defColor.r, defColor.g, defColor.b, 0.5f); | |
GUILayout.Label(" 0 skinned mesh"); | |
GUI.color = defColor; | |
} | |
GUILayout.EndHorizontal(); | |
} | |
} | |
EditorGUILayout.EndScrollView(); | |
} | |
void ListMissing(){ | |
missingListScrollPos = EditorGUILayout.BeginScrollView(missingListScrollPos); | |
foreach (MissingGraphic dMissing in MissingObjects) { | |
GUILayout.BeginHorizontal (); | |
if (GUILayout.Button (dMissing.name, GUILayout.Width (150))) | |
SelectObject (dMissing.Object, ctrlPressed); | |
GUILayout.Label ("missing ", GUILayout.Width(48)); | |
switch (dMissing.type) { | |
case "mesh": | |
GUI.color = new Color (0.8f, 0.8f, defColor.b, 1.0f); | |
break; | |
case "sprite": | |
GUI.color = new Color (defColor.r, 0.8f, 0.8f, 1.0f); | |
break; | |
case "material": | |
GUI.color = new Color (0.8f, defColor.g, 0.8f, 1.0f); | |
break; | |
} | |
GUILayout.Label (dMissing.type); | |
GUI.color = defColor; | |
GUILayout.EndHorizontal (); | |
} | |
EditorGUILayout.EndScrollView(); | |
} | |
string FormatSizeString(int memSizeKB) | |
{ | |
if (memSizeKB<1024) return ""+memSizeKB+"k"; | |
else | |
{ | |
float memSizeMB=((float)memSizeKB)/1024.0f; | |
return memSizeMB.ToString("0.00")+"Mb"; | |
} | |
} | |
TextureDetails FindTextureDetails(Texture tTexture) | |
{ | |
foreach (TextureDetails tTextureDetails in ActiveTextures) | |
{ | |
if (tTextureDetails.texture==tTexture) return tTextureDetails; | |
} | |
return null; | |
} | |
MaterialDetails FindMaterialDetails(Material tMaterial) | |
{ | |
foreach (MaterialDetails tMaterialDetails in ActiveMaterials) | |
{ | |
if (tMaterialDetails.material==tMaterial) return tMaterialDetails; | |
} | |
return null; | |
} | |
MeshDetails FindMeshDetails(Mesh tMesh) | |
{ | |
foreach (MeshDetails tMeshDetails in ActiveMeshDetails) | |
{ | |
if (tMeshDetails.mesh==tMesh) return tMeshDetails; | |
} | |
return null; | |
} | |
void CheckResources() | |
{ | |
ActiveTextures.Clear(); | |
ActiveMaterials.Clear(); | |
ActiveMeshDetails.Clear(); | |
MissingObjects.Clear (); | |
thingsMissing = false; | |
Renderer[] renderers = FindObjects<Renderer>(); | |
MaterialDetails skyMat = new MaterialDetails (); | |
skyMat.material = RenderSettings.skybox; | |
skyMat.isSky = true; | |
ActiveMaterials.Add (skyMat); | |
//Debug.Log("Total renderers "+renderers.Length); | |
foreach (Renderer renderer in renderers) | |
{ | |
//Debug.Log("Renderer is "+renderer.name); | |
foreach (Material material in renderer.sharedMaterials) | |
{ | |
MaterialDetails tMaterialDetails = FindMaterialDetails(material); | |
if (tMaterialDetails == null) | |
{ | |
tMaterialDetails = new MaterialDetails(); | |
tMaterialDetails.material = material; | |
ActiveMaterials.Add(tMaterialDetails); | |
} | |
tMaterialDetails.FoundInRenderers.Add(renderer); | |
} | |
if (renderer is SpriteRenderer) | |
{ | |
SpriteRenderer tSpriteRenderer = (SpriteRenderer)renderer; | |
if (tSpriteRenderer.sprite != null) { | |
var tSpriteTextureDetail = GetTextureDetail (tSpriteRenderer.sprite.texture, renderer); | |
if (!ActiveTextures.Contains (tSpriteTextureDetail)) { | |
ActiveTextures.Add (tSpriteTextureDetail); | |
} | |
} else if (tSpriteRenderer.sprite == null) { | |
MissingGraphic tMissing = new MissingGraphic (); | |
tMissing.Object = tSpriteRenderer.transform; | |
tMissing.type = "sprite"; | |
tMissing.name = tSpriteRenderer.transform.name; | |
MissingObjects.Add (tMissing); | |
thingsMissing = true; | |
} | |
} | |
} | |
if (IncludeGuiElements) | |
{ | |
Graphic[] graphics = FindObjects<Graphic>(); | |
foreach(Graphic graphic in graphics) | |
{ | |
if (graphic.mainTexture) | |
{ | |
var tSpriteTextureDetail = GetTextureDetail(graphic.mainTexture, graphic); | |
if (!ActiveTextures.Contains(tSpriteTextureDetail)) | |
{ | |
ActiveTextures.Add(tSpriteTextureDetail); | |
} | |
} | |
if (graphic.materialForRendering) | |
{ | |
MaterialDetails tMaterialDetails = FindMaterialDetails(graphic.materialForRendering); | |
if (tMaterialDetails == null) | |
{ | |
tMaterialDetails = new MaterialDetails(); | |
tMaterialDetails.material = graphic.materialForRendering; | |
tMaterialDetails.isgui = true; | |
ActiveMaterials.Add(tMaterialDetails); | |
} | |
tMaterialDetails.FoundInGraphics.Add(graphic); | |
} | |
} | |
Button[] buttons = FindObjects<Button>(); | |
foreach (Button button in buttons) | |
{ | |
CheckButtonSpriteState(button, button.spriteState.disabledSprite); | |
CheckButtonSpriteState(button, button.spriteState.highlightedSprite); | |
CheckButtonSpriteState(button, button.spriteState.pressedSprite); | |
} | |
} | |
foreach (MaterialDetails tMaterialDetails in ActiveMaterials) | |
{ | |
Material tMaterial = tMaterialDetails.material; | |
if (tMaterial != null) | |
{ | |
var dependencies = EditorUtility.CollectDependencies(new UnityEngine.Object[] { tMaterial }); | |
foreach (Object obj in dependencies) | |
{ | |
if (obj is Texture) | |
{ | |
Texture tTexture = obj as Texture; | |
var tTextureDetail = GetTextureDetail(tTexture, tMaterial, tMaterialDetails); | |
tTextureDetail.isSky = tMaterialDetails.isSky; | |
tTextureDetail.instance = tMaterialDetails.instance; | |
tTextureDetail.isgui = tMaterialDetails.isgui; | |
ActiveTextures.Add(tTextureDetail); | |
} | |
} | |
//if the texture was downloaded, it won't be included in the editor dependencies | |
if (tMaterial.HasProperty ("_MainTex")) { | |
if (tMaterial.mainTexture != null && !dependencies.Contains (tMaterial.mainTexture)) { | |
var tTextureDetail = GetTextureDetail (tMaterial.mainTexture, tMaterial, tMaterialDetails); | |
ActiveTextures.Add (tTextureDetail); | |
} | |
} | |
} | |
} | |
MeshFilter[] meshFilters = FindObjects<MeshFilter>(); | |
foreach (MeshFilter tMeshFilter in meshFilters) | |
{ | |
Mesh tMesh = tMeshFilter.sharedMesh; | |
if (tMesh != null) | |
{ | |
MeshDetails tMeshDetails = FindMeshDetails(tMesh); | |
if (tMeshDetails == null) | |
{ | |
tMeshDetails = new MeshDetails(); | |
tMeshDetails.mesh = tMesh; | |
ActiveMeshDetails.Add(tMeshDetails); | |
} | |
tMeshDetails.FoundInMeshFilters.Add(tMeshFilter); | |
} else if (tMesh == null && tMeshFilter.transform.GetComponent("TextContainer")== null) { | |
MissingGraphic tMissing = new MissingGraphic (); | |
tMissing.Object = tMeshFilter.transform; | |
tMissing.type = "mesh"; | |
tMissing.name = tMeshFilter.transform.name; | |
MissingObjects.Add (tMissing); | |
thingsMissing = true; | |
} | |
var meshRenderrer = tMeshFilter.transform.GetComponent<MeshRenderer>(); | |
if (meshRenderrer == null || meshRenderrer.sharedMaterial == null) { | |
MissingGraphic tMissing = new MissingGraphic (); | |
tMissing.Object = tMeshFilter.transform; | |
tMissing.type = "material"; | |
tMissing.name = tMeshFilter.transform.name; | |
MissingObjects.Add (tMissing); | |
thingsMissing = true; | |
} | |
} | |
SkinnedMeshRenderer[] skinnedMeshRenderers = FindObjects<SkinnedMeshRenderer>(); | |
foreach (SkinnedMeshRenderer tSkinnedMeshRenderer in skinnedMeshRenderers) | |
{ | |
Mesh tMesh = tSkinnedMeshRenderer.sharedMesh; | |
if (tMesh != null) | |
{ | |
MeshDetails tMeshDetails = FindMeshDetails(tMesh); | |
if (tMeshDetails == null) | |
{ | |
tMeshDetails = new MeshDetails(); | |
tMeshDetails.mesh = tMesh; | |
ActiveMeshDetails.Add(tMeshDetails); | |
} | |
tMeshDetails.FoundInSkinnedMeshRenderer.Add(tSkinnedMeshRenderer); | |
} else if (tMesh == null) { | |
MissingGraphic tMissing = new MissingGraphic (); | |
tMissing.Object = tSkinnedMeshRenderer.transform; | |
tMissing.type = "mesh"; | |
tMissing.name = tSkinnedMeshRenderer.transform.name; | |
MissingObjects.Add (tMissing); | |
thingsMissing = true; | |
} | |
if (tSkinnedMeshRenderer.sharedMaterial == null) { | |
MissingGraphic tMissing = new MissingGraphic (); | |
tMissing.Object = tSkinnedMeshRenderer.transform; | |
tMissing.type = "material"; | |
tMissing.name = tSkinnedMeshRenderer.transform.name; | |
MissingObjects.Add (tMissing); | |
thingsMissing = true; | |
} | |
} | |
if (IncludeSpriteAnimations) | |
{ | |
Animator[] animators = FindObjects<Animator>(); | |
foreach (Animator anim in animators) | |
{ | |
#if UNITY_4_6 || UNITY_4_5 || UNITY_4_4 || UNITY_4_3 | |
UnityEditorInternal.AnimatorController ac = anim.runtimeAnimatorController as UnityEditorInternal.AnimatorController; | |
#elif UNITY_5 || UNITY_5_3_OR_NEWER | |
UnityEditor.Animations.AnimatorController ac = anim.runtimeAnimatorController as UnityEditor.Animations.AnimatorController; | |
#endif | |
//Skip animators without layers, this can happen if they don't have an animator controller. | |
if (!ac || ac.layers == null || ac.layers.Length == 0) | |
continue; | |
for (int x = 0; x < anim.layerCount; x++) | |
{ | |
UnityEditor.Animations.AnimatorStateMachine sm = ac.layers[x].stateMachine; | |
int cnt = sm.states.Length; | |
for (int i = 0; i < cnt; i++) | |
{ | |
UnityEditor.Animations.AnimatorState state = sm.states[i].state; | |
Motion m = state.motion; | |
if (m != null) | |
{ | |
AnimationClip clip = m as AnimationClip; | |
if (clip != null) | |
{ | |
EditorCurveBinding[] ecbs = AnimationUtility.GetObjectReferenceCurveBindings(clip); | |
foreach (EditorCurveBinding ecb in ecbs) | |
{ | |
if (ecb.propertyName == "m_Sprite") | |
{ | |
foreach (ObjectReferenceKeyframe keyframe in AnimationUtility.GetObjectReferenceCurve(clip, ecb)) | |
{ | |
Sprite tSprite = keyframe.value as Sprite; | |
if (tSprite != null) | |
{ | |
var tTextureDetail = GetTextureDetail(tSprite.texture, anim); | |
if (!ActiveTextures.Contains(tTextureDetail)) | |
{ | |
ActiveTextures.Add(tTextureDetail); | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
if (IncludeScriptReferences) | |
{ | |
MonoBehaviour[] scripts = FindObjects<MonoBehaviour>(); | |
foreach (MonoBehaviour script in scripts) | |
{ | |
BindingFlags flags = BindingFlags.Public | BindingFlags.Instance; // only public non-static fields are bound to by Unity. | |
FieldInfo[] fields = script.GetType().GetFields(flags); | |
foreach (FieldInfo field in fields) | |
{ | |
System.Type fieldType = field.FieldType; | |
if (fieldType == typeof(Sprite)) | |
{ | |
Sprite tSprite = field.GetValue(script) as Sprite; | |
if (tSprite != null) | |
{ | |
var tSpriteTextureDetail = GetTextureDetail(tSprite.texture, script); | |
if (!ActiveTextures.Contains(tSpriteTextureDetail)) | |
{ | |
ActiveTextures.Add(tSpriteTextureDetail); | |
} | |
} | |
}if (fieldType == typeof(Mesh)) | |
{ | |
Mesh tMesh = field.GetValue(script) as Mesh; | |
if (tMesh != null) | |
{ | |
MeshDetails tMeshDetails = FindMeshDetails(tMesh); | |
if (tMeshDetails == null) | |
{ | |
tMeshDetails = new MeshDetails(); | |
tMeshDetails.mesh = tMesh; | |
tMeshDetails.instance = true; | |
ActiveMeshDetails.Add(tMeshDetails); | |
} | |
} | |
}if (fieldType == typeof(Material)) | |
{ | |
Material tMaterial = field.GetValue(script) as Material; | |
if (tMaterial != null) | |
{ | |
MaterialDetails tMatDetails = FindMaterialDetails(tMaterial); | |
if (tMatDetails == null) | |
{ | |
tMatDetails = new MaterialDetails(); | |
tMatDetails.instance = true; | |
tMatDetails.material = tMaterial; | |
if(!ActiveMaterials.Contains(tMatDetails)) | |
ActiveMaterials.Add(tMatDetails); | |
} | |
if (tMaterial.mainTexture) | |
{ | |
var tSpriteTextureDetail = GetTextureDetail(tMaterial.mainTexture); | |
if (!ActiveTextures.Contains(tSpriteTextureDetail)) | |
{ | |
ActiveTextures.Add(tSpriteTextureDetail); | |
} | |
} | |
var dependencies = EditorUtility.CollectDependencies(new UnityEngine.Object[] { tMaterial }); | |
foreach (Object obj in dependencies) | |
{ | |
if (obj is Texture) | |
{ | |
Texture tTexture = obj as Texture; | |
var tTextureDetail = GetTextureDetail(tTexture, tMaterial, tMatDetails); | |
if(!ActiveTextures.Contains(tTextureDetail)) | |
ActiveTextures.Add(tTextureDetail); | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
TotalTextureMemory = 0; | |
foreach (TextureDetails tTextureDetails in ActiveTextures) TotalTextureMemory += tTextureDetails.memSizeKB; | |
TotalMeshVertices = 0; | |
foreach (MeshDetails tMeshDetails in ActiveMeshDetails) TotalMeshVertices += tMeshDetails.mesh.vertexCount; | |
// Sort by size, descending | |
ActiveTextures.Sort(delegate(TextureDetails details1, TextureDetails details2) { return details2.memSizeKB - details1.memSizeKB; }); | |
ActiveTextures = ActiveTextures.Distinct().ToList(); | |
ActiveMeshDetails.Sort(delegate(MeshDetails details1, MeshDetails details2) { return details2.mesh.vertexCount - details1.mesh.vertexCount; }); | |
collectedInPlayingMode = Application.isPlaying; | |
} | |
private void CheckButtonSpriteState(Button button, Sprite sprite) | |
{ | |
if (sprite == null) return; | |
var texture = sprite.texture; | |
var tButtonTextureDetail = GetTextureDetail(texture, button); | |
if (!ActiveTextures.Contains(tButtonTextureDetail)) | |
{ | |
ActiveTextures.Add(tButtonTextureDetail); | |
} | |
} | |
private static GameObject[] GetAllRootGameObjects() | |
{ | |
#if !UNITY_5 && !UNITY_5_3_OR_NEWER | |
return UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects().ToArray(); | |
#else | |
List<GameObject> allGo = new List<GameObject>(); | |
for (int sceneIdx = 0; sceneIdx < UnityEngine.SceneManagement.SceneManager.sceneCount; ++sceneIdx){ | |
allGo.AddRange( UnityEngine.SceneManagement.SceneManager.GetSceneAt(sceneIdx).GetRootGameObjects().ToArray() ); | |
} | |
return allGo.ToArray(); | |
#endif | |
} | |
private T[] FindObjects<T>() where T : Object | |
{ | |
if (IncludeDisabledObjects) { | |
List<T> meshfilters = new List<T> (); | |
GameObject[] allGo = GetAllRootGameObjects(); | |
foreach (GameObject go in allGo) { | |
Transform[] tgo = go.GetComponentsInChildren<Transform> (true).ToArray (); | |
foreach (Transform tr in tgo) { | |
if (tr.GetComponent<T> ()) | |
meshfilters.Add (tr.GetComponent<T> ()); | |
} | |
} | |
return (T[])meshfilters.ToArray (); | |
} | |
else | |
return (T[])FindObjectsOfType(typeof(T)); | |
} | |
private TextureDetails GetTextureDetail(Texture tTexture, Material tMaterial, MaterialDetails tMaterialDetails) | |
{ | |
TextureDetails tTextureDetails = GetTextureDetail(tTexture); | |
tTextureDetails.FoundInMaterials.Add(tMaterial); | |
foreach (Renderer renderer in tMaterialDetails.FoundInRenderers) | |
{ | |
if (!tTextureDetails.FoundInRenderers.Contains(renderer)) tTextureDetails.FoundInRenderers.Add(renderer); | |
} | |
return tTextureDetails; | |
} | |
private TextureDetails GetTextureDetail(Texture tTexture, Renderer renderer) | |
{ | |
TextureDetails tTextureDetails = GetTextureDetail(tTexture); | |
tTextureDetails.FoundInRenderers.Add(renderer); | |
return tTextureDetails; | |
} | |
private TextureDetails GetTextureDetail(Texture tTexture, Animator animator) | |
{ | |
TextureDetails tTextureDetails = GetTextureDetail(tTexture); | |
tTextureDetails.FoundInAnimators.Add(animator); | |
return tTextureDetails; | |
} | |
private TextureDetails GetTextureDetail(Texture tTexture, Graphic graphic) | |
{ | |
TextureDetails tTextureDetails = GetTextureDetail(tTexture); | |
tTextureDetails.FoundInGraphics.Add(graphic); | |
return tTextureDetails; | |
} | |
private TextureDetails GetTextureDetail(Texture tTexture, MonoBehaviour script) | |
{ | |
TextureDetails tTextureDetails = GetTextureDetail(tTexture); | |
tTextureDetails.FoundInScripts.Add(script); | |
return tTextureDetails; | |
} | |
private TextureDetails GetTextureDetail(Texture tTexture, Button button) | |
{ | |
TextureDetails tTextureDetails = GetTextureDetail(tTexture); | |
if (!tTextureDetails.FoundInButtons.Contains(button)) | |
{ | |
tTextureDetails.FoundInButtons.Add(button); | |
} | |
return tTextureDetails; | |
} | |
private TextureDetails GetTextureDetail(Texture tTexture) | |
{ | |
TextureDetails tTextureDetails = FindTextureDetails(tTexture); | |
if (tTextureDetails == null) | |
{ | |
tTextureDetails = new TextureDetails(); | |
tTextureDetails.texture = tTexture; | |
tTextureDetails.isCubeMap = tTexture is Cubemap; | |
TextureFormat tFormat = TextureFormat.RGBA32; | |
int tMipMapCount = 1; | |
if (tTexture is Texture3D) | |
{ | |
tFormat = (tTexture as Texture3D).format; | |
} | |
if (tTexture is Texture2D) | |
{ | |
tFormat = (tTexture as Texture2D).format; | |
tMipMapCount = (tTexture as Texture2D).mipmapCount; | |
} | |
if(tTexture is Texture2DArray) | |
{ | |
tFormat = (tTexture as Texture2DArray).format; | |
tMipMapCount = 10; | |
} | |
if (tTexture is Cubemap) | |
{ | |
tFormat = (tTexture as Cubemap).format; | |
tMipMapCount = (tTexture as Cubemap).mipmapCount; | |
} | |
if (tTexture is CubemapArray) | |
{ | |
tFormat = (tTexture as CubemapArray).format; | |
tMipMapCount = 10; | |
} | |
if ( tTexture is RenderTexture ) | |
tTextureDetails.memSizeKB = ( int )( UnityTextureUtil.GetRuntimeMemorySizeLong( tTexture ) / 1024 ); | |
else | |
tTextureDetails.memSizeKB = ( int )( UnityTextureUtil.GetStorageMemorySizeLong( tTexture ) / 1024 ); | |
tTextureDetails.format = tFormat; | |
tTextureDetails.mipMapCount = tMipMapCount; | |
} | |
return tTextureDetails; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment