#if UNITY_EDITOR using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using UnityEditor; using UnityEngine; namespace Coffee.UIExtensions { public class MaterialResolver { static readonly StringBuilder s_StringBuilder = new StringBuilder(); static readonly Dictionary s_MaterialMap = new Dictionary(); public static Material GetOrGenerateMaterialVariant(Shader shader, params object[] append) { if (!shader) { return null; } Material mat = null; string variantName = GetVariantName(shader, append); if (s_MaterialMap.TryGetValue(variantName, out mat) && mat) { return mat; } string[] keywords = append.Where(x => 0 < (int)x) .Select(x => x.ToString().ToUpper()) .ToArray(); mat = GetMaterial(shader, append); if (mat) { if (!mat.shaderKeywords.OrderBy(x => x).SequenceEqual(keywords.OrderBy(x => x))) { mat.shaderKeywords = keywords; EditorUtility.SetDirty(mat); if (!Application.isPlaying) { EditorApplication.delayCall += AssetDatabase.SaveAssets; } } return mat; } if (s_MaterialMap.TryGetValue(variantName, out mat) && mat) { return mat; } Debug.Log("Generate material : " + variantName); mat = new Material(shader); mat.shaderKeywords = keywords; mat.name = variantName; mat.hideFlags |= HideFlags.NotEditable; s_MaterialMap[variantName] = mat; bool isMainAsset = append.Cast().All(x => x == 0); EditorApplication.delayCall += () => SaveMaterial(mat, shader, isMainAsset); return mat; } static void SaveMaterial(Material mat, Shader shader, bool isMainAsset) { string materialPath = GetDefaultMaterialPath(shader); #if UIEFFECT_SEPARATE string dir = Path.GetDirectoryName(materialPath); materialPath = Path.Combine(Path.Combine(dir, "Separated"), mat.name + ".mat"); isMainAsset = true; #endif if (isMainAsset) { Directory.CreateDirectory(Path.GetDirectoryName(materialPath)); AssetDatabase.CreateAsset(mat, materialPath); } else { GetOrGenerateMaterialVariant(shader); mat.hideFlags |= HideFlags.HideInHierarchy; AssetDatabase.AddObjectToAsset(mat, materialPath); } AssetDatabase.SaveAssets(); } public static Material GetMaterial(Shader shader, params object[] append) { string variantName = GetVariantName(shader, append); return AssetDatabase.FindAssets("t:Material " + Path.GetFileName(shader.name)) .Select(x => AssetDatabase.GUIDToAssetPath(x)) .SelectMany(x => AssetDatabase.LoadAllAssetsAtPath(x)) .OfType() .FirstOrDefault(x => x.name == variantName); } public static string GetDefaultMaterialPath(Shader shader) { var name = Path.GetFileName(shader.name); return AssetDatabase.FindAssets("t:Material " + name) .Select(x => AssetDatabase.GUIDToAssetPath(x)) .FirstOrDefault(x => Path.GetFileNameWithoutExtension(x) == name) ?? ("Assets/" + name + ".mat"); } public static string GetVariantName(Shader shader, params object[] append) { s_StringBuilder.Length = 0; #if UIEFFECT_SEPARATE s_StringBuilder.Append("[Separated] "); #endif s_StringBuilder.Append(Path.GetFileName(shader.name)); foreach (object mode in append.Where(x => 0 < (int)x)) { s_StringBuilder.Append("-"); s_StringBuilder.Append(mode.ToString()); } return s_StringBuilder.ToString(); } } } #endif