using UnityEngine; using UnityEngine.UI; using UnityEngine.Serialization; namespace Coffee.UIExtensions { /// /// Transition effect. /// [AddComponentMenu("UI/UIEffect/UITransitionEffect", 5)] public class UITransitionEffect : UIEffectBase { //################################ // Constant or Static Members. //################################ public const string shaderName = "UI/Hidden/UI-Effect-Transition"; static readonly ParameterTexture _ptex = new ParameterTexture(8, 128, "_ParamTex"); /// /// Effect mode. /// public enum EffectMode { Fade = 1, Cutoff = 2, Dissolve = 3, } //################################ // Serialize Members. //################################ [Tooltip("Effect mode.")] [SerializeField] EffectMode m_EffectMode = EffectMode.Cutoff; [Tooltip("Effect factor between 0(hidden) and 1(shown).")] [SerializeField][Range(0, 1)] float m_EffectFactor = 1; [Tooltip("Transition texture (single channel texture).")] [SerializeField] Texture m_TransitionTexture; [Header("Advanced Option")] [Tooltip("The area for effect.")] [SerializeField] EffectArea m_EffectArea = EffectArea.RectTransform; [Tooltip("Keep effect aspect ratio.")] [SerializeField] bool m_KeepAspectRatio; [Tooltip("Dissolve edge width.")] [SerializeField] [Range(0, 1)] float m_DissolveWidth = 0.5f; [Tooltip("Dissolve edge softness.")] [SerializeField] [Range(0, 1)] float m_DissolveSoftness = 0.5f; [Tooltip("Dissolve edge color.")] [SerializeField] [ColorUsage(false)] Color m_DissolveColor = new Color(0.0f, 0.25f, 1.0f); [Tooltip("Disable graphic's raycast target on hidden.")] [SerializeField] bool m_PassRayOnHidden; [Header("Effect Player")] [SerializeField] EffectPlayer m_Player; //################################ // Public Members. //################################ /// /// Effect factor between 0(no effect) and 1(complete effect). /// public float effectFactor { get { return m_EffectFactor; } set { value = Mathf.Clamp(value, 0, 1); if (!Mathf.Approximately(m_EffectFactor, value)) { m_EffectFactor = value; SetDirty(); } } } /// /// Transition texture. /// public Texture transitionTexture { get { return m_TransitionTexture; } set { if (m_TransitionTexture != value) { m_TransitionTexture = value; if (graphic) { ModifyMaterial(); } } } } /// /// Effect mode. /// public EffectMode effectMode { get { return m_EffectMode; } } /// /// Keep aspect ratio. /// public bool keepAspectRatio { get { return m_KeepAspectRatio; } set { if (m_KeepAspectRatio != value) { m_KeepAspectRatio = value; targetGraphic.SetVerticesDirty(); } } } /// /// Gets the parameter texture. /// public override ParameterTexture ptex { get { return _ptex; } } /// /// Dissolve edge width. /// public float dissolveWidth { get { return m_DissolveWidth; } set { value = Mathf.Clamp(value, 0, 1); if (!Mathf.Approximately(m_DissolveWidth, value)) { m_DissolveWidth = value; SetDirty(); } } } /// /// Dissolve edge softness. /// public float dissolveSoftness { get { return m_DissolveSoftness; } set { value = Mathf.Clamp(value, 0, 1); if (!Mathf.Approximately(m_DissolveSoftness, value)) { m_DissolveSoftness = value; SetDirty(); } } } /// /// Dissolve edge color. /// public Color dissolveColor { get { return m_DissolveColor; } set { if (m_DissolveColor != value) { m_DissolveColor = value; SetDirty(); } } } /// /// Duration for showing/hiding. /// public float duration { get { return _player.duration; } set { _player.duration = Mathf.Max(value, 0.1f); } } /// /// Disable graphic's raycast target on hidden. /// public bool passRayOnHidden { get { return m_PassRayOnHidden; } set { m_PassRayOnHidden = value; } } /// /// Update mode for showing/hiding. /// public AnimatorUpdateMode updateMode { get { return _player.updateMode; } set { _player.updateMode = value; } } /// /// Show transition. /// public void Show(bool reset = true) { _player.loop = false; _player.Play(reset, f => effectFactor = f); } /// /// Hide transition. /// public void Hide(bool reset = true) { _player.loop = false; _player.Play(reset, f => effectFactor = 1 - f); } /// /// Modifies the material. /// public override void ModifyMaterial() { if (isTMPro) { return; } ulong hash = (m_TransitionTexture ? (uint)m_TransitionTexture.GetInstanceID() : 0) + ((ulong)2 << 32) + ((ulong)m_EffectMode << 36); if (_materialCache != null && (_materialCache.hash != hash || !isActiveAndEnabled || !m_EffectMaterial)) { MaterialCache.Unregister(_materialCache); _materialCache = null; } if (!isActiveAndEnabled || !m_EffectMaterial) { material = null; } else if (!m_TransitionTexture) { material = m_EffectMaterial; } else if (_materialCache != null && _materialCache.hash == hash) { material = _materialCache.material; } else { _materialCache = MaterialCache.Register(hash, m_TransitionTexture, () => { var mat = new Material(m_EffectMaterial); mat.name += "_" + m_TransitionTexture.name; mat.SetTexture("_NoiseTex", m_TransitionTexture); return mat; }); material = _materialCache.material; } } /// /// Modifies the mesh. /// public override void ModifyMesh(VertexHelper vh) { if (!isActiveAndEnabled) { return; } bool isText = isTMPro || graphic is Text; float normalizedIndex = ptex.GetNormalizedIndex (this); // rect. var tex = transitionTexture; var aspectRatio = m_KeepAspectRatio && tex ? ((float)tex.width) / tex.height : -1; Rect rect = m_EffectArea.GetEffectArea (vh, rectTransform.rect, aspectRatio); // Set prameters to vertex. UIVertex vertex = default(UIVertex); float x, y; int count = vh.currentVertCount; for (int i = 0; i < count; i++) { vh.PopulateUIVertex(ref vertex, i); m_EffectArea.GetPositionFactor (i, rect, vertex.position, isText, isTMPro, out x, out y); vertex.uv0 = new Vector2 ( Packer.ToFloat (vertex.uv0.x, vertex.uv0.y), Packer.ToFloat (x, y, normalizedIndex) ); vh.SetUIVertex(vertex, i); } } //################################ // Protected Members. //################################ /// /// This function is called when the object becomes enabled and active. /// protected override void OnEnable() { base.OnEnable(); _player.OnEnable(null); _player.loop = false; } /// /// This function is called when the behaviour becomes disabled () or inactive. /// protected override void OnDisable() { base.OnDisable (); MaterialCache.Unregister(_materialCache); _materialCache = null; _player.OnDisable(); } protected override void SetDirty() { foreach (var m in materials) { ptex.RegisterMaterial (m); } ptex.SetData(this, 0, m_EffectFactor); // param1.x : effect factor if (m_EffectMode == EffectMode.Dissolve) { ptex.SetData(this, 1, m_DissolveWidth); // param1.y : width ptex.SetData(this, 2, m_DissolveSoftness); // param1.z : softness ptex.SetData(this, 4, m_DissolveColor.r); // param2.x : red ptex.SetData(this, 5, m_DissolveColor.g); // param2.y : green ptex.SetData(this, 6, m_DissolveColor.b); // param2.z : blue } // Disable graphic's raycastTarget on hidden. if (m_PassRayOnHidden) { targetGraphic.raycastTarget = 0 < m_EffectFactor; } } #if UNITY_EDITOR /// /// Gets the material. /// /// The material. protected override Material GetMaterial() { return MaterialResolver.GetOrGenerateMaterialVariant(Shader.Find(shaderName), m_EffectMode); } #endif //################################ // Private Members. //################################ MaterialCache _materialCache = null; EffectPlayer _player{ get { return m_Player ?? (m_Player = new EffectPlayer()); } } } }