A way to iterate/enumerate shader properties?

I’m trying to automatically scan materials in my project from an editor script to find usages of a given texture.

I was able to successfully iterate all materials using the assets database. However when it comes to the question of “is this material using this texture” I’ve come across a problem since the answer to that depends on the shader, and each shader has a different set of string properties.

My question is, is there a way to get all the properties of a given shader so that I can iterate each one and check its value?


Edit: Alternatively, is there a place somewhere where I can find all the properties used by Unity’s shaders? or the code of all those shaders so that I can extract a definitive list of all used property names?

EDIT: As of 4.1 ShaderUtils is now a public documented class. You no longer need this code from that version of Unity onwards.

You can get them in an Editor script by using the hidden ShaderUtils class. I’ve written a wrapper which is a C# extension class for material allowing you to get the properties, their count, type and name. Plus useful stuff like all of the referenced textures.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using System.IO;
using System.Collections;
	
public static class ShaderUtilInterface
{
    public static Dictionary<string, MethodInfo> methods = new Dictionary<string, MethodInfo>();

    static ShaderUtilInterface()
    {
        var asm = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a=>a.GetTypes().Any(t=>t.Name == "ShaderUtil"));
		if(asm != null)
		{
			var tp = asm.GetTypes().FirstOrDefault(t=>t.Name == "ShaderUtil");
			foreach(var method in tp.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static))
			{
				methods[method.Name] = method;
			}
		}
    }
	
	public static List<Texture> GetTextures(this Material shader)
	{
		var list = new List<Texture>();
		var count = shader.GetPropertyCount();
		for(var i = 0; i < count; i++)
		{
			if(shader.GetPropertyType(i)==4)
			{
				list.Add((Texture)shader.GetProperty(i));
			}
		}
		return list;
	}
	
	public static int GetPropertyCount(this Material shader)
	{
		return Call<int>("GetPropertyCount", shader.shader);
	}
	
	public static int GetPropertyType(this Material shader, int index)
	{
		return Call<int>("GetPropertyType", shader.shader, index);
	}
	
	public static string GetPropertyName(this Material shader, int index)
	{
		return Call<string>("GetPropertyName", shader.shader, index);
	}
	
	public static void SetProperty(this Material material, int index, object value)
	{
		var name = material.GetPropertyName(index);
		var type = material.GetPropertyType(index);
		switch(type)
		{
		case 0:
			material.SetColor(name, (Color)value);
			break;
		case 1:
			material.SetVector(name, (Vector4) value);
			break;
		case 2:
			material.SetFloat(name, (float)value);
			break;
		case 3:
			material.SetFloat(name, (float)value);
			break;
		case 4:
			material.SetTexture(name, (Texture) value);
			break;
		}
	}


	
	public static object GetProperty(this Material material, int index)
	{
		var name = material.GetPropertyName(index);
		var type = material.GetPropertyType(index);
		switch(type)
		{
		case 0:
			return material.GetColor(name);
			
		case 1:
			return material.GetVector(name);
			
			
		case 2:
		case 3:
			return material.GetFloat(name);
			
		case 4:
			return material.GetTexture(name);
			
		}
	return null;
	}
	
	public static T Call<T>(string name, params object[] parameters)
	{
		return (T)methods[name].Invoke(null, parameters);
	}

}

OK, I should have thought of the 2nd option myself first:

http://www.unity3d.com/support/resources/assets/built-in-shaders


Edit: For anyone reading this who is looking for the “definitive” list of the texture shader property of Unity’s built-in properties:

{ "_BackTex", "_BumpMap", "_BumpSpecMap", "_Control", "_DecalTex",
  "_Detail", "_DownTex", "_FrontTex", "_GlossMap", "_Illum", "_LeftTex",
  "_LightMap", "_LightTextureB0", "_MainTex", "_ParallaxMap", "_RightTex",
  "_ShadowOffset", "_Splat0", "_Splat1", "_Splat2", "_Splat3",
  "_TranslucencyMap", "_UpTex", "_Tex", "_Cube" };

Note that this true as of right now, and could change if Unity’s shaders change in the future.

This is the shell command I used to extract the property names:

pcregrep -r -M 'Properties\s*{.*(

.+)*
}’ -N anycrlf * | grep 2D | awk ‘{print $1}’ | sort | uniq