Finding Unity Editor icon assets

During creating Visual Studio Code C# theme for Unity, I wanted to create an Icon Theme that uses Unity Editor icon assets. To have a seamless development experience, I suppose the best is to have the same icons in Visual Studio Code that Unity uses in the Project window.

TL;DR

If you just need some Unity Editor icon asset name for your next Unity Editor Tool project, simply get this snippet below.

Get SaveEditorDefaultResources.cs at

Locate Unity Editor icon assets

When I was developing an Animation Curve editing / remapping tool, I stumbled upon an API that gives you an Icon for a given type called EditorGUIUtility.ObjectContent. This gives you a GUIContent object that contains an image property. A Texture2D holding the appropriate icon for the given asset. This is the very content I need in the Visual Studio Code Icon Theme.

Next step is to track down the location this method is looking up. Quickly headed to the MattRix/UnityDecompiled repository maintained by Matt Rix to see what is under the hood.

See MattRix/UnityDecompiled at

Immediately you’ll find ObjectContent method that uses AssetPreview.GetMiniThumbnail, AssetPreview.GetMiniTypeThumbnail to get the texture.

public static GUIContent ObjectContent(UnityEngine.Object obj, Type type)
{
	if (obj)
	{
		EditorGUIUtility.s_ObjectContent.text = EditorGUIUtility.GetObjectNameWithInfo(obj);
		EditorGUIUtility.s_ObjectContent.image = AssetPreview.GetMiniThumbnail(obj);
	}
	else if (type != null)
	{
		EditorGUIUtility.s_ObjectContent.text = EditorGUIUtility.GetTypeNameWithInfo(type.Name);
		EditorGUIUtility.s_ObjectContent.image = AssetPreview.GetMiniTypeThumbnail(type);
	}
	else
	{
		EditorGUIUtility.s_ObjectContent.text = "";
		EditorGUIUtility.s_ObjectContent.image = null;
	}
	return EditorGUIUtility.s_ObjectContent;
}
See EditorGUIUtility.cs at

Tracking down AssetPreview.GetMiniTypeThumbnail it leads you to a method called LoadIcon, actually LoadIconForSkin in particular.

public static Texture2D GetMiniTypeThumbnail(Type type)
{
	Texture2D result;
	if (typeof(MonoBehaviour).IsAssignableFrom(type))
	{
		result = EditorGUIUtility.LoadIcon(type.FullName.Replace('.', '/') + " Icon");
	}
	else
	{
		result = AssetPreview.INTERNAL_GetMiniTypeThumbnailFromType(type);
	}
	return result;
}
See AssetPreview.cs at

You can see the filename format for the name of a given type at type.FullName.Replace(‘.’, ‘/’) + ” Icon”. May be useful later on (UPDATE: it is not).

That leads us back to EditorGUIUtility again. So icon locations probably resides somewhere here.

internal static Texture2D LoadIcon(string name)
{
	return EditorGUIUtility.LoadIconForSkin(name, EditorGUIUtility.skinIndex);
}

private static Texture2D LoadGeneratedIconOrNormalIcon(string name)
{
	Texture2D texture2D = EditorGUIUtility.Load(EditorResourcesUtility.generatedIconsPath + name + ".asset") as Texture2D;
	if (!texture2D)
	{
		texture2D = (EditorGUIUtility.Load(EditorResourcesUtility.iconsPath + name + ".png") as Texture2D);
	}
	if (!texture2D)
	{
		texture2D = (EditorGUIUtility.Load(name) as Texture2D);
	}
	return texture2D;
}

internal static Texture2D LoadIconForSkin(string name, int skinIndex)
{
	Texture2D result;
	if (string.IsNullOrEmpty(name))
	{
		result = null;
	}
	else if (skinIndex == 0)
	{
		result = EditorGUIUtility.LoadGeneratedIconOrNormalIcon(name);
	}
	else
	{
		string text = "d_" + Path.GetFileName(name);
		string directoryName = Path.GetDirectoryName(name);
		if (!string.IsNullOrEmpty(directoryName))
		{
			text = string.Format("{0}/{1}", directoryName, text);
		}
		Texture2D texture2D = EditorGUIUtility.LoadGeneratedIconOrNormalIcon(text);
		if (!texture2D)
		{
			texture2D = EditorGUIUtility.LoadGeneratedIconOrNormalIcon(name);
		}
		result = texture2D;
	}
	return result;
}
See EditorGUIUtility.cs at

Every call ultimately ends up in LoadGeneratedIconOrNormalIcon, that has some interesting API called EditorResourcesUtility.generatedIconsPath and EditorResourcesUtility.iconsPath (can be found in UnityEditor assembly in UnityEditorInternal namespace).

They are internal APIs, but using Mono Runtime they can be gently invoked with the snippet below. It is the same technique I used to invoke LogEntries.Clean in a previous #UnityTips tweet.

string generatedIconsPath
{
	get
	{
		return Type.GetType("UnityEditorInternal.EditorResourcesUtility,UnityEditor.dll")
			.GetProperty("generatedIconsPath", BindingFlags.Static | BindingFlags.Public)
			.GetValue(null,null) as string;
	}
}

string iconsPath
{
	get
	{
		return Type.GetType("UnityEditorInternal.EditorResourcesUtility,UnityEditor.dll")
			.GetProperty("iconsPath", BindingFlags.Static | BindingFlags.Public)
			.GetValue(null,null) as string;
	}
}	
See SaveEditorDefaultResources.cs at

The method that uses these paths is documented, so you can easily use EditorGUIUtility.Load to load a single asset from the Editor bundle. But having a single icon is not what I want, I need actually the whole bundle content. So this needs a peek into EditorGUIUtility.Load itself.

The method implementation contains a method that I really like. It is EditorGUIUtility.GetEditorAssetBundle(). This is all I need here. The way I found it was a bit quirky, as this method is not documented publicly, but it can give me all the Unity Editor icon assets probably.

[GeneratedByOldBindingsGenerator]
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern AssetBundle GetEditorAssetBundle();
See EditorGUIUtility.cs at

It is an internal call as well, but like the icon paths before, this method also can be invoked using Reflection.

AssetBundle GetEditorAssetBundle()
{
	return Type.GetType("UnityEditor.EditorGUIUtility,UnityEditor.dll")
		.GetMethod("GetEditorAssetBundle", BindingFlags.Static | BindingFlags.NonPublic) // internal
		.Invoke(null,null) as AssetBundle;
}
See SaveEditorDefaultResources.cs at

There you go, this method gives you an UnityEditor.AssetBundle, which is a public API, thus documented fairly amount. After a bit of nudging it gives you a list of all the 3534 Unity Editor Asset file (!), which is now something usable at last. The icons I’m looking for must be really somewhere around here.

...
icons/processed/projector gizmo.asset, Projector Gizmo, UnityEngine.Texture2D
icons/processed/projector icon.asset, Projector Icon, UnityEngine.Texture2D
icons/processed/raycastcollider icon.asset, RaycastCollider Icon, UnityEngine.Texture2D
icons/processed/recttransform icon.asset, RectTransform Icon, UnityEngine.Texture2D
icons/processed/reflectionprobe gizmo.asset, ReflectionProbe Gizmo, UnityEngine.Texture2D
icons/processed/reflectionprobe icon.asset, ReflectionProbe Icon, UnityEngine.Texture2D
icons/processed/relativejoint2d icon.asset, RelativeJoint2D Icon, UnityEngine.Texture2D
icons/processed/rendertexture icon.asset, RenderTexture Icon, UnityEngine.Texture2D
icons/processed/reverbfilter icon.asset, ReverbFilter Icon, UnityEngine.Texture2D
icons/processed/rigidbody icon.asset, RigidBody Icon, UnityEngine.Texture2D
icons/processed/rigidbody2d icon.asset, RigidBody2D Icon, UnityEngine.Texture2D
icons/processed/sceneasset icon.asset, SceneAsset Icon, UnityEngine.Texture2D
icons/processed/sceneset icon.asset, SceneSet Icon, UnityEngine.Texture2D
icons/processed/scriptableobject icon.asset, ScriptableObject Icon, UnityEngine.Texture2D
icons/processed/search icon.asset, Search Icon, UnityEngine.Texture2D
icons/processed/shader icon.asset, Shader Icon, UnityEngine.Texture2D
icons/processed/shadervariantcollection icon.asset, ShaderVariantCollection Icon, UnityEngine.Texture2D
icons/processed/skinnedmeshrenderer icon.asset, SkinnedMeshRenderer Icon, UnityEngine.Texture2D
icons/processed/skybox icon.asset, Skybox Icon, UnityEngine.Texture2D
...
See full list in AllEditorAssetNames.txt at

Exporting Unity Editor icon assets to PNG image files

Now I have to export the actual images (with their respective names). In the bundle there is a fair amount of Unity Editor icon assets stored in PNG images directly, but some of the icons seems stored in a more generic asset format.

As I need icons only (for now), I process Texture2D assets only. However, EncodeToPNG reports it cannot access texture data (probably the asset is marked being read-only).

After making a copy using GetRawTextureData then LoadRawTextureData, I could use EncodeToPNG seamlessly.

Beside 56 texture with some quirky format, the rest 3286 Unity Editor image asset has been exported and ready to be included in a Visual Studio Code Icon Theme!

Having a closer look on the Unity Editor icon assets they are all feels some kind of eclectic 90’s-ish style. That feels really off to me considering the Visual Studio Code C# theme I’m going to extend with those icons. See more on eppz! (C# theme for Unity) below. There is a scenario actually where I won’t use the icons at all. In any way, spending some time around in Unity Editor assemblies definitely worth the experience!

DISCLAIMER. THE INFORMATION ON THIS BLOG (INCLUDING BUT NOT LIMITED TO ARTICLES, IMAGES, CODE SNIPPETS, SOURCE CODES, EXAMPLE PROJECTS, ETC.) IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE INFORMATION ON THIS BLOG (INCLUDING BUT NOT LIMITED TO ARTICLES, IMAGES, CODE SNIPPETS, SOURCE CODES, EXAMPLE PROJECTS, ETC.).