Materials.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using UnityEngine;
  7. using UnityEngine.Rendering;
  8. namespace TheraBytes.BetterUi
  9. {
  10. public enum MaterialEffect
  11. {
  12. Normal,
  13. Additive,
  14. LinearDodge,
  15. Multiply,
  16. Overlay,
  17. }
  18. [HelpURL("https://documentation.therabytes.de/better-ui/AboutMaterials.html")]
  19. public class Materials : SingletonScriptableObject<Materials>
  20. {
  21. static string FilePath { get { return "TheraBytes/Resources/Materials"; } }
  22. public static readonly StandardMaterial Standard = new StandardMaterial();
  23. public static readonly GrayscaleMaterial Grayscale = new GrayscaleMaterial();
  24. public static readonly ColorOverlayMaterial ColorOverlay = new ColorOverlayMaterial();
  25. public static readonly HueSaturationBrightnessMaterial HueSaturationBrightness = new HueSaturationBrightnessMaterial();
  26. static readonly List<string> materialOrder = new List<string>()
  27. {
  28. Standard,
  29. Grayscale,
  30. ColorOverlay,
  31. HueSaturationBrightness,
  32. };
  33. [Serializable]
  34. public class MaterialInfo
  35. {
  36. public string Name;
  37. public Material Material;
  38. public VertexMaterialData Properties = new VertexMaterialData();
  39. public MaterialEffect Effect;
  40. public override string ToString()
  41. {
  42. return string.Format("{0} ({1})", Name, Effect);
  43. }
  44. }
  45. [SerializeField]
  46. List<MaterialInfo> materials = new List<MaterialInfo>();
  47. private void OnEnable()
  48. {
  49. EnsurePredefinedMaterials();
  50. }
  51. void EnsurePredefinedMaterials()
  52. {
  53. if (materials.Count > 0)
  54. return;
  55. // Add predefined materials
  56. AddIfNotPresent("Standard",
  57. (e) => new MaterialInfo()
  58. {
  59. Material = Resources.Load<Material>("Materials/Standard_" + e.ToString()),
  60. });
  61. AddIfNotPresent("Grayscale",
  62. (e) => new MaterialInfo()
  63. {
  64. Material = Resources.Load<Material>("Materials/Grayscale_" + e.ToString()),
  65. Properties = new VertexMaterialData()
  66. {
  67. FloatProperties = new VertexMaterialData.FloatProperty[]
  68. {
  69. new VertexMaterialData.FloatProperty()
  70. {
  71. Name = "Amount",
  72. Min = 0,
  73. Max = 1,
  74. Value = 1,
  75. PropertyMap = VertexMaterialData.FloatProperty.Mapping.TexcoordX
  76. }
  77. }
  78. },
  79. });
  80. AddIfNotPresent("Hue Saturation Brightness",
  81. (e) => new MaterialInfo()
  82. {
  83. Material = Resources.Load<Material>("Materials/HueSaturationBrightness_" + e.ToString()),
  84. Properties = new VertexMaterialData()
  85. {
  86. FloatProperties = new VertexMaterialData.FloatProperty[]
  87. {
  88. new VertexMaterialData.FloatProperty()
  89. {
  90. Name = "Hue",
  91. Min = 0,
  92. Max = 1,
  93. Value = 0,
  94. PropertyMap = VertexMaterialData.FloatProperty.Mapping.TexcoordX,
  95. },
  96. new VertexMaterialData.FloatProperty()
  97. {
  98. Name = "Saturation",
  99. Value = 1,
  100. PropertyMap = VertexMaterialData.FloatProperty.Mapping.TexcoordY,
  101. },
  102. new VertexMaterialData.FloatProperty()
  103. {
  104. Name = "Brightness",
  105. Value = 1,
  106. PropertyMap = VertexMaterialData.FloatProperty.Mapping.TangentW,
  107. },
  108. }
  109. }
  110. });
  111. AddIfNotPresent("Color Overlay",
  112. (e) => new MaterialInfo()
  113. {
  114. Material = Resources.Load<Material>("Materials/ColorOverlay_" + e.ToString()),
  115. Properties = new VertexMaterialData()
  116. {
  117. FloatProperties = new VertexMaterialData.FloatProperty[]
  118. {
  119. new VertexMaterialData.FloatProperty()
  120. {
  121. Name = "Opacity",
  122. Min = 0,
  123. Max = 1,
  124. Value = 0,
  125. PropertyMap = VertexMaterialData.FloatProperty.Mapping.TexcoordX
  126. }
  127. }
  128. }
  129. });
  130. }
  131. void AddIfNotPresent(string name, Func<MaterialEffect, MaterialInfo> CreateMaterial, params MaterialEffect[] preservedLayerEffects)
  132. {
  133. foreach (var e in Enum.GetValues(typeof(MaterialEffect)))
  134. {
  135. var effect = (MaterialEffect)e;
  136. var info = GetMaterialInfo(name, effect);
  137. if (info == null)
  138. {
  139. info = CreateMaterial(effect);
  140. if (info.Material == null)
  141. {
  142. // on import it is too early to load materials so they are null.
  143. // skip it in such case. It will be done when accessed next time.
  144. continue;
  145. }
  146. info.Name = name;
  147. info.Effect = effect;
  148. materials.Add(info);
  149. }
  150. BlendMode srcMode, dstMode;
  151. float clipThreshold = 0.001f;
  152. bool clip = false;
  153. bool combineAlpha = false;
  154. switch (effect)
  155. {
  156. case MaterialEffect.Normal:
  157. srcMode = BlendMode.SrcAlpha;
  158. dstMode = BlendMode.OneMinusSrcAlpha;
  159. break;
  160. case MaterialEffect.Additive:
  161. srcMode = BlendMode.OneMinusDstColor;
  162. dstMode = BlendMode.One;
  163. combineAlpha = true;
  164. break;
  165. case MaterialEffect.LinearDodge:
  166. srcMode = BlendMode.SrcAlpha | BlendMode.One;
  167. dstMode = BlendMode.One | BlendMode.Zero;
  168. combineAlpha = true;
  169. clip = true;
  170. break;
  171. case MaterialEffect.Multiply:
  172. srcMode = BlendMode.DstColor;
  173. dstMode = BlendMode.Zero;
  174. clip = true;
  175. clipThreshold = 0.5f;
  176. break;
  177. case MaterialEffect.Overlay:
  178. srcMode = BlendMode.DstAlpha;
  179. dstMode = BlendMode.OneMinusDstColor;
  180. clip = true;
  181. clipThreshold = 0.5f;
  182. break;
  183. default: throw new ArgumentException();
  184. }
  185. info.Material.SetInt("SrcBlendMode", (int)srcMode);
  186. info.Material.SetInt("DstBlendMode", (int)dstMode);
  187. info.Material.SetFloat("ClipThreshold", clipThreshold);
  188. #if (UNITY_4 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2 || UNITY_5_3) || UNITY_5_4
  189. // Unity 5.4+ is supported. Use older releases on your own risk.
  190. info.Material.SetInt("CombineAlpha", combineAlpha ? 1 : 0);
  191. info.Material.SetInt("ForceClip", clip ? 1 : 0);
  192. #else // Unity 5.5+
  193. if (combineAlpha)
  194. info.Material.EnableKeyword("COMBINE_ALPHA");
  195. else
  196. info.Material.DisableKeyword("COMBINE_ALPHA");
  197. if (clip)
  198. info.Material.EnableKeyword("FORCE_CLIP");
  199. else
  200. info.Material.DisableKeyword("FORCE_CLIP");
  201. #endif
  202. }
  203. }
  204. IEnumerator SetTogglePropertyDelayed(Material material, string toggleName, bool toggle)
  205. {
  206. yield return null;
  207. material.SetInt(toggleName, (toggle) ? 1 : 0);
  208. }
  209. public MaterialInfo GetMaterialInfo(string name, MaterialEffect e)
  210. {
  211. MaterialInfo result = materials.FirstOrDefault((o) => o.Name == name && o.Effect == e);
  212. return result;
  213. }
  214. public Material GetMaterial(string name)
  215. {
  216. var m = materials.FirstOrDefault((o) => o.Name == name);
  217. if(m != null)
  218. {
  219. return m.Material;
  220. }
  221. return null;
  222. }
  223. public List<string> GetAllMaterialNames()
  224. {
  225. EnsurePredefinedMaterials();
  226. var list = new HashSet<string>(materials
  227. .Select(o => o.Name)).ToList();
  228. list.Sort((a, b) =>
  229. {
  230. if (materialOrder.Contains(a))
  231. {
  232. if (materialOrder.Contains(b))
  233. return materialOrder.IndexOf(a).CompareTo(materialOrder.IndexOf(b));
  234. else
  235. return -1;
  236. }
  237. else
  238. {
  239. return 1;
  240. }
  241. });
  242. return list;
  243. }
  244. public HashSet<MaterialEffect> GetAllMaterialEffects(string name)
  245. {
  246. return new HashSet<MaterialEffect>(materials
  247. .Where(o => o.Name == name)
  248. .Select(o => o.Effect));
  249. }
  250. #if UNITY_EDITOR
  251. public int GetMaterialInfoIndex(string name, MaterialEffect effect)
  252. {
  253. for (int i = 0; i < materials.Count; i++)
  254. {
  255. if (materials[i].Name == name && materials[i].Effect == effect)
  256. return i;
  257. }
  258. return -1;
  259. }
  260. #endif
  261. }
  262. }