ShinyEffectForUGUI.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.Serialization;
  5. using UnityEngine.UI;
  6. using System.Collections;
  7. #if UNITY_EDITOR
  8. using System.IO;
  9. using System.Linq;
  10. using UnityEditor;
  11. #endif
  12. namespace Coffee.UIExtensions
  13. {
  14. /// <summary>
  15. /// UIEffect.
  16. /// </summary>
  17. [ExecuteInEditMode]
  18. [DisallowMultipleComponent]
  19. public class ShinyEffectForUGUI : BaseMeshEffect
  20. #if UNITY_EDITOR
  21. , ISerializationCallbackReceiver
  22. #endif
  23. {
  24. //################################
  25. // Constant or Static Members.
  26. //################################
  27. public const string shaderName = "UI/Hidden/UI-Effect-Shiny";
  28. //################################
  29. // Serialize Members.
  30. //################################
  31. [SerializeField][Range(0, 1)] float m_Location = 0;
  32. [SerializeField][Range(0, 1)] float m_Width = 0.25f;
  33. [SerializeField][Range(0.01f, 1)] float m_Softness = 1f;
  34. [FormerlySerializedAs("m_Alpha")]
  35. [SerializeField][Range(0, 1)] float m_Brightness = 1f;
  36. [SerializeField][Range(-180, 180)] float m_Rotation;
  37. [SerializeField][Range(0, 1)] float m_Highlight = 1;
  38. [SerializeField] Material m_EffectMaterial;
  39. //################################
  40. // Public Members.
  41. //################################
  42. /// <summary>
  43. /// Graphic affected by the UIEffect.
  44. /// </summary>
  45. new public Graphic graphic { get { return base.graphic; } }
  46. /// <summary>
  47. /// Location for shiny effect.
  48. /// </summary>
  49. public float location{ get { return m_Location; } set { m_Location = Mathf.Clamp(value, 0, 1); _SetDirty(); } }
  50. /// <summary>
  51. /// Width for shiny effect.
  52. /// </summary>
  53. public float width { get { return m_Width; } set { m_Width = Mathf.Clamp(value, 0, 1); _SetDirty(); } }
  54. /// <summary>
  55. /// Softness for shiny effect.
  56. /// </summary>
  57. public float softness { get { return m_Softness; } set { m_Softness = Mathf.Clamp(value, 0.01f, 1); _SetDirty(); } }
  58. /// <summary>
  59. /// Alpha for shiny effect.
  60. /// </summary>
  61. [System.Obsolete ("Use brightness instead (UnityUpgradable) -> brightness")]
  62. public float alpha { get { return m_Brightness; } set { m_Brightness = Mathf.Clamp(value, 0, 1); _SetDirty(); } }
  63. /// <summary>
  64. /// Brightness for shiny effect.
  65. /// </summary>
  66. public float brightness { get { return m_Brightness; } set { m_Brightness = Mathf.Clamp(value, 0, 1); _SetDirty(); } }
  67. /// <summary>
  68. /// Highlight factor for shiny effect.
  69. /// </summary>
  70. public float highlight { get { return m_Highlight; } set { m_Highlight = Mathf.Clamp(value, 0, 1); _SetDirty(); } }
  71. /// <summary>
  72. /// Rotation for shiny effect.
  73. /// </summary>
  74. public float rotation
  75. {
  76. get
  77. {
  78. return m_Rotation;
  79. }
  80. set { if (!Mathf.Approximately(m_Rotation, value)) { m_Rotation = value; _SetDirty(); } }
  81. }
  82. /// <summary>
  83. /// Effect material.
  84. /// </summary>
  85. public virtual Material effectMaterial { get { return m_EffectMaterial; } }
  86. /// <summary>
  87. /// This function is called when the object becomes enabled and active.
  88. /// </summary>
  89. protected override void OnEnable()
  90. {
  91. graphic.material = effectMaterial;
  92. base.OnEnable();
  93. }
  94. /// <summary>
  95. /// This function is called when the behaviour becomes disabled () or inactive.
  96. /// </summary>
  97. protected override void OnDisable()
  98. {
  99. graphic.material = null;
  100. base.OnDisable();
  101. }
  102. #if UNITY_EDITOR
  103. public void OnBeforeSerialize()
  104. {
  105. }
  106. public void OnAfterDeserialize()
  107. {
  108. var obj = this;
  109. EditorApplication.delayCall += () =>
  110. {
  111. if (Application.isPlaying || !obj)
  112. return;
  113. var mat = GetMaterial(shaderName);
  114. if(m_EffectMaterial == mat && graphic.material == mat)
  115. return;
  116. graphic.material = m_EffectMaterial = mat;
  117. EditorUtility.SetDirty(this);
  118. EditorUtility.SetDirty(graphic);
  119. EditorApplication.delayCall +=AssetDatabase.SaveAssets;
  120. };
  121. }
  122. public static Material GetMaterial(string shaderName)
  123. {
  124. string name = Path.GetFileName (shaderName);
  125. return AssetDatabase.FindAssets("t:Material " + name)
  126. .Select(x => AssetDatabase.GUIDToAssetPath(x))
  127. .SelectMany(x => AssetDatabase.LoadAllAssetsAtPath(x))
  128. .OfType<Material>()
  129. .FirstOrDefault(x => x.name == name);
  130. }
  131. #endif
  132. /// <summary>
  133. /// Modifies the mesh.
  134. /// </summary>
  135. public override void ModifyMesh(VertexHelper vh)
  136. {
  137. if (!IsActive())
  138. return;
  139. // rect.
  140. Rect rect = graphic.rectTransform.rect;
  141. // rotation.
  142. float rad = rotation * Mathf.Deg2Rad;
  143. Vector2 dir = new Vector2(Mathf.Cos(rad), Mathf.Sin(rad));
  144. dir.x *= rect.height / rect.width;
  145. dir = dir.normalized;
  146. // Calculate vertex position.
  147. UIVertex vertex = default(UIVertex);
  148. Vector2 nomalizedPos;
  149. Matrix2x3 localMatrix = new Matrix2x3(rect, dir.x, dir.y); // Get local matrix.
  150. for (int i = 0; i < vh.currentVertCount; i++)
  151. {
  152. vh.PopulateUIVertex(ref vertex, i);
  153. // Normalize vertex position by local matrix.
  154. nomalizedPos = localMatrix * vertex.position;
  155. vertex.uv1 = new Vector2(
  156. _PackToFloat(Mathf.Clamp01(nomalizedPos.y), softness, width, brightness),
  157. _PackToFloat(location, highlight)
  158. );
  159. vh.SetUIVertex(vertex, i);
  160. }
  161. }
  162. /// <summary>
  163. /// Play effect.
  164. /// </summary>
  165. public void Play()
  166. {
  167. Play(1);
  168. }
  169. /// <summary>
  170. /// Play effect.
  171. /// </summary>
  172. public void Play(float duration)
  173. {
  174. StopAllCoroutines();
  175. StartCoroutine(CoPlay(duration, AnimatorUpdateMode.Normal));
  176. }
  177. /// <summary>
  178. /// Play effect.
  179. /// </summary>
  180. public void Play(float duration, AnimatorUpdateMode updateMode)
  181. {
  182. StopAllCoroutines();
  183. StartCoroutine(CoPlay(duration, updateMode));
  184. }
  185. //################################
  186. // Private Members.
  187. //################################
  188. /// <summary>
  189. /// Mark the UIEffect as dirty.
  190. /// </summary>
  191. void _SetDirty()
  192. {
  193. if(graphic)
  194. graphic.SetVerticesDirty();
  195. }
  196. IEnumerator CoPlay(float duration, AnimatorUpdateMode updateMode = AnimatorUpdateMode.Normal)
  197. {
  198. float time = 0;
  199. while (time < duration)
  200. {
  201. location = time / duration;
  202. time += updateMode == AnimatorUpdateMode.UnscaledTime
  203. ? Time.unscaledDeltaTime
  204. : Time.deltaTime;
  205. yield return null;
  206. }
  207. }
  208. /// <summary>
  209. /// Pack 4 low-precision [0-1] floats values to a float.
  210. /// Each value [0-1] has 64 steps(6 bits).
  211. /// </summary>
  212. static float _PackToFloat(float x, float y, float z, float w)
  213. {
  214. const int PRECISION = (1 << 6) - 1;
  215. return (Mathf.FloorToInt(w * PRECISION) << 18)
  216. + (Mathf.FloorToInt(z * PRECISION) << 12)
  217. + (Mathf.FloorToInt(y * PRECISION) << 6)
  218. + Mathf.FloorToInt(x * PRECISION);
  219. }
  220. /// <summary>
  221. /// Pack 2 low-precision [0-1] floats values to a float.
  222. /// Each value [0-1] has 4096 steps(12 bits).
  223. /// </summary>
  224. static float _PackToFloat(float x, float y)
  225. {
  226. const int PRECISION = (1 << 12) - 1;
  227. return (Mathf.FloorToInt(y * PRECISION) << 12)
  228. + Mathf.FloorToInt(x * PRECISION);
  229. }
  230. /// <summary>
  231. /// Matrix2x3.
  232. /// </summary>
  233. struct Matrix2x3
  234. {
  235. public float m00, m01, m02, m10, m11, m12;
  236. public Matrix2x3(Rect rect, float cos, float sin)
  237. {
  238. const float center = 0.5f;
  239. float dx = -rect.xMin / rect.width - center;
  240. float dy = -rect.yMin / rect.height - center;
  241. m00 = cos / rect.width;
  242. m01 = -sin / rect.height;
  243. m02 = dx * cos - dy * sin + center;
  244. m10 = sin / rect.width;
  245. m11 = cos / rect.height;
  246. m12 = dx * sin + dy * cos + center;
  247. }
  248. public static Vector2 operator*(Matrix2x3 m, Vector2 v)
  249. {
  250. return new Vector2(
  251. (m.m00 * v.x) + (m.m01 * v.y) + m.m02,
  252. (m.m10 * v.x) + (m.m11 * v.y) + m.m12
  253. );
  254. }
  255. }
  256. }
  257. }