ProcedurM2Image.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. 
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.Sprites;
  5. using UnityEngine.UI;
  6. /* Author: Josh H.
  7. * Procedural UI Image
  8. * assetstore.joshh@gmail.com for feedback or questions
  9. */
  10. namespace UnityEngine.UI
  11. {
  12. public class ProcedurM2Image : RawImage
  13. {
  14. protected override void OnPopulateMesh(VertexHelper toFill)
  15. {
  16. //note: Sliced and Tiled have no effect to this currently.
  17. GenerateSimpleSprite(toFill);
  18. }
  19. private Vector4 GetDrawingDimensions(bool shouldPreserveAspect)
  20. {
  21. var padding = sprite == null ? Vector4.zero : DataUtility.GetPadding(sprite);
  22. Rect r = GetPixelAdjustedRect();
  23. var size = sprite == null ? new Vector2(r.width, r.height) : new Vector2(sprite.rect.width, sprite.rect.height);
  24. //Debug.Log(string.Format("r:{2}, size:{0}, padding:{1}", size, padding, r));
  25. int spriteW = Mathf.RoundToInt(size.x);
  26. int spriteH = Mathf.RoundToInt(size.y);
  27. if (shouldPreserveAspect && size.sqrMagnitude > 0.0f)
  28. {
  29. var spriteRatio = size.x / size.y;
  30. var rectRatio = r.width / r.height;
  31. if (spriteRatio > rectRatio)
  32. {
  33. var oldHeight = r.height;
  34. r.height = r.width * (1.0f / spriteRatio);
  35. r.y += (oldHeight - r.height) * rectTransform.pivot.y;
  36. }
  37. else
  38. {
  39. var oldWidth = r.width;
  40. r.width = r.height * spriteRatio;
  41. r.x += (oldWidth - r.width) * rectTransform.pivot.x;
  42. }
  43. }
  44. var v = new Vector4(
  45. padding.x / spriteW,
  46. padding.y / spriteH,
  47. (spriteW - padding.z) / spriteW,
  48. (spriteH - padding.w) / spriteH);
  49. v = new Vector4(
  50. r.x + r.width * v.x,
  51. r.y + r.height * v.y,
  52. r.x + r.width * v.z,
  53. r.y + r.height * v.w
  54. );
  55. return v;
  56. }
  57. //每个角最大的三角形数,一般5-8个就有不错的圆角效果,设置Max防止不必要的性能浪费
  58. const int MaxTriangleNum = 20;
  59. const int MinTriangleNum = 1;
  60. [SerializeField]
  61. public float Radius = 10;
  62. //使用几个三角形去填充每个角的四分之一圆
  63. [Range(MinTriangleNum, MaxTriangleNum)]
  64. int TriangleNum = 4;
  65. private Texture2D TextureToTexture2D(Texture texture)
  66. {
  67. Texture2D texture2d = texture as Texture2D;
  68. return texture2d;
  69. }
  70. static Sprite sprite;
  71. private VertexHelper nvh;
  72. /// <summary>
  73. /// Generates the Verticies needed.
  74. /// </summary>
  75. /// <param name="vh">vertex helper</param>
  76. void GenerateSimpleSprite(VertexHelper vh)
  77. {
  78. if (texture != null && sprite == null)
  79. {
  80. sprite = Sprite.Create(TextureToTexture2D(texture), new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
  81. }
  82. Vector4 v = GetDrawingDimensions(false);
  83. Vector4 uv = sprite != null ? DataUtility.GetOuterUV(sprite) : Vector4.zero;
  84. var color32 = color;
  85. vh.Clear();
  86. if(this.GetComponent<RawImageDeviceManager>())
  87. {
  88. Radius = this.GetComponent<RawImageDeviceManager>().Radius;
  89. }
  90. //对radius的值做限制,必须在0-较小的边的1/2的范围内
  91. float radius = Radius;
  92. if (radius > (v.z - v.x) / 2) radius = (v.z - v.x) / 2;
  93. if (radius > (v.w - v.y) / 2) radius = (v.w - v.y) / 2;
  94. if (radius < 0) radius = 0;
  95. //计算出uv中对应的半径值坐标轴的半径
  96. float uvRadiusX = radius / (v.z - v.x);
  97. float uvRadiusY = radius / (v.w - v.y);
  98. //0,1
  99. vh.AddVert(new Vector3(v.x, v.w - radius), color32, new Vector2(uv.x, uv.w - uvRadiusY));
  100. vh.AddVert(new Vector3(v.x, v.y + radius), color32, new Vector2(uv.x, uv.y + uvRadiusY));
  101. //2,3,4,5
  102. vh.AddVert(new Vector3(v.x + radius, v.w), color32, new Vector2(uv.x + uvRadiusX, uv.w));
  103. vh.AddVert(new Vector3(v.x + radius, v.w - radius), color32, new Vector2(uv.x + uvRadiusX, uv.w - uvRadiusY));
  104. vh.AddVert(new Vector3(v.x + radius, v.y + radius), color32, new Vector2(uv.x + uvRadiusX, uv.y + uvRadiusY));
  105. vh.AddVert(new Vector3(v.x + radius, v.y), color32, new Vector2(uv.x + uvRadiusX, uv.y));
  106. //6,7,8,9
  107. vh.AddVert(new Vector3(v.z - radius, v.w), color32, new Vector2(uv.z - uvRadiusX, uv.w));
  108. vh.AddVert(new Vector3(v.z - radius, v.w - radius), color32, new Vector2(uv.z - uvRadiusX, uv.w - uvRadiusY));
  109. vh.AddVert(new Vector3(v.z - radius, v.y + radius), color32, new Vector2(uv.z - uvRadiusX, uv.y + uvRadiusY));
  110. vh.AddVert(new Vector3(v.z - radius, v.y), color32, new Vector2(uv.z - uvRadiusX, uv.y));
  111. //10,11
  112. vh.AddVert(new Vector3(v.z, v.w - radius), color32, new Vector2(uv.z, uv.w - uvRadiusY));
  113. vh.AddVert(new Vector3(v.z, v.y + radius), color32, new Vector2(uv.z, uv.y + uvRadiusY));
  114. //左边的矩形
  115. vh.AddTriangle(1, 0, 3);
  116. vh.AddTriangle(1, 3, 4);
  117. //中间的矩形
  118. vh.AddTriangle(5, 2, 6);
  119. vh.AddTriangle(5, 6, 9);
  120. //右边的矩形
  121. vh.AddTriangle(8, 7, 10);
  122. vh.AddTriangle(8, 10, 11);
  123. //开始构造四个角
  124. List<Vector2> vCenterList = new List<Vector2>();
  125. List<Vector2> uvCenterList = new List<Vector2>();
  126. List<int> vCenterVertList = new List<int>();
  127. //右上角的圆心
  128. vCenterList.Add(new Vector2(v.z - radius, v.w - radius));
  129. uvCenterList.Add(new Vector2(uv.z - uvRadiusX, uv.w - uvRadiusY));
  130. vCenterVertList.Add(7);
  131. //左上角的圆心
  132. vCenterList.Add(new Vector2(v.x + radius, v.w - radius));
  133. uvCenterList.Add(new Vector2(uv.x + uvRadiusX, uv.w - uvRadiusY));
  134. vCenterVertList.Add(3);
  135. //左下角的圆心
  136. vCenterList.Add(new Vector2(v.x + radius, v.y + radius));
  137. uvCenterList.Add(new Vector2(uv.x + uvRadiusX, uv.y + uvRadiusY));
  138. vCenterVertList.Add(4);
  139. //右下角的圆心
  140. vCenterList.Add(new Vector2(v.z - radius, v.y + radius));
  141. uvCenterList.Add(new Vector2(uv.z - uvRadiusX, uv.y + uvRadiusY));
  142. vCenterVertList.Add(8);
  143. //每个三角形的顶角
  144. float degreeDelta = (float)(Mathf.PI / 2 / TriangleNum);
  145. //当前的角度
  146. float curDegree = 0;
  147. for (int i = 0; i < vCenterVertList.Count; i++)
  148. {
  149. int preVertNum = vh.currentVertCount;
  150. for (int j = 0; j <= TriangleNum; j++)
  151. {
  152. float cosA = Mathf.Cos(curDegree);
  153. float sinA = Mathf.Sin(curDegree);
  154. Vector3 vPosition = new Vector3(vCenterList[i].x + cosA * radius, vCenterList[i].y + sinA * radius);
  155. Vector3 uvPosition = new Vector2(uvCenterList[i].x + cosA * uvRadiusX, uvCenterList[i].y + sinA * uvRadiusY);
  156. vh.AddVert(vPosition, color32, uvPosition);
  157. curDegree += degreeDelta;
  158. }
  159. curDegree -= degreeDelta;
  160. for (int j = 0; j <= TriangleNum - 1; j++)
  161. {
  162. vh.AddTriangle(vCenterVertList[i], preVertNum + j + 1, preVertNum + j);
  163. }
  164. }
  165. }
  166. }
  167. }