using System; using System.Collections; using UnityEngine; using UnityEngine.UI; namespace BF { [RequireComponent(typeof(MaskableGraphic))] [ExecuteInEditMode] [DisallowMultipleComponent] public class UIDynamicShinyEffect : BaseMeshEffect { [SerializeField] [Range(0, 1)] float location = 0; [SerializeField] [Range(0, 1)] float width = 0.25f; [SerializeField] [Range(0.01f, 1)] float softness = 1f; [SerializeField] [Range(-180, 180)] float rotation; [SerializeField] [Range(0, 1)] float highlight = 1; [SerializeField] bool isRepeat = false; [SerializeField] [Range(1, 10)] float intervalTime = 1f; [SerializeField] [Range(1, 10)] float duration = 1f; float counter = 0f; public float Location { get { return location; } set { location = Mathf.Clamp(value, 0, 1); SetDirty(); } } public float Width { get { return width; } set { width = Mathf.Clamp(value, 0, 1); SetDirty(); } } public float Softness { get { return softness; } set { softness = Mathf.Clamp(value, 0.01f, 1); SetDirty(); } } public float Highlight { get { return highlight; } set { highlight = Mathf.Clamp(value, 0, 1); SetDirty(); } } public float Rotation { get { return rotation; } set { if (!Mathf.Approximately(rotation, value)) { rotation = value; SetDirty(); } } } public Material effectmat; protected override void OnEnable() { base.OnEnable(); if (effectmat == null) { effectmat = new Material(Shader.Find("BF/UI/UIDynamicShiny")); } graphic.material = effectmat; } protected override void OnDisable() { base.OnDisable(); graphic.material = BFMain.Instance.RenderMgr.UIDefaultMat; } public override void ModifyMesh(VertexHelper vh) { if (!IsActive()) { return; } var rect = graphic.rectTransform.rect; var rad = Rotation * Mathf.Deg2Rad; var dir = new Vector2(Mathf.Cos(rad), Mathf.Sin(rad)); dir.x *= rect.height / rect.width; dir = dir.normalized; var vertex = new UIVertex(); Vector2 nomalizedPos; var localMatrix = new Matrix2x3(rect, dir.x, dir.y); for (var i = 0; i < vh.currentVertCount; i++) { vh.PopulateUIVertex(ref vertex, i); nomalizedPos = localMatrix * vertex.position; vertex.uv1 = new Vector2( PackToFloat(Mathf.Clamp01(nomalizedPos.y), Softness, Width), PackToFloat(Location, Highlight) ); vh.SetUIVertex(vertex, i); } } public void SetMarterial(Material material) { effectmat = material; } void SetDirty() { if (graphic) { graphic.SetVerticesDirty(); } } public void SetRepeat(float duration, float intervalTime) { isRepeat = true; this.duration = Math.Max(1.0f, duration); this.intervalTime = Math.Max(1.0f, intervalTime); } public void CancelRepeat() { isRepeat = false; } public void Play(float durationParam) { StopAllCoroutines(); StartCoroutine(CoPlay(durationParam)); } IEnumerator CoPlay(float durationParam) { var time = 0f; while (time < durationParam) { Location = time / durationParam; time += Time.deltaTime; yield return null; } } void Update() { if (!isRepeat) { return; } if (counter <= 0f) { Play(duration); } counter += Time.deltaTime; if (counter > duration + intervalTime) { counter = 0; } } /// /// 降低精度 把3个float合成一个float,shader中再拆出来 /// float PackToFloat(float x, float y, float z) { const int precision = (1 << 6) - 1; return (Mathf.FloorToInt(z * precision) << 12) + (Mathf.FloorToInt(y * precision) << 6) + Mathf.FloorToInt(x * precision); } float PackToFloat(float x, float y) { const int precision = (1 << 12) - 1; return (Mathf.FloorToInt(y * precision) << 12) + Mathf.FloorToInt(x * precision); } struct Matrix2x3 { public float m00, m01, m02, m10, m11, m12; public Matrix2x3(Rect rect, float cos, float sin) { const float center = 0.5f; var dx = -rect.xMin / rect.width - center; var dy = -rect.yMin / rect.height - center; m00 = cos / rect.width; m01 = -sin / rect.height; m02 = dx * cos - dy * sin + center; m10 = sin / rect.width; m11 = cos / rect.height; m12 = dx * sin + dy * cos + center; } public static Vector2 operator * (Matrix2x3 m, Vector2 v) { return new Vector2( (m.m00 * v.x) + (m.m01 * v.y) + m.m02, (m.m10 * v.x) + (m.m11 * v.y) + m.m12 ); } } } }