LineMesh.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. namespace FairyGUI
  4. {
  5. /// <summary>
  6. ///
  7. /// Inspired by kim ki won (http://mypi.ruliweb.daum.net/mypi.htm?id=newtypekorea)
  8. /// </summary>
  9. public class LineMesh : IMeshFactory
  10. {
  11. /// <summary>
  12. ///
  13. /// </summary>
  14. public GPath path;
  15. /// <summary>
  16. ///
  17. /// </summary>
  18. public float lineWidth;
  19. /// <summary>
  20. ///
  21. /// </summary>
  22. public AnimationCurve lineWidthCurve;
  23. /// <summary>
  24. ///
  25. /// </summary>
  26. public Gradient gradient;
  27. /// <summary>
  28. ///
  29. /// </summary>
  30. public bool roundEdge;
  31. /// <summary>
  32. ///
  33. /// </summary>
  34. public float fillStart;
  35. /// <summary>
  36. ///
  37. /// </summary>
  38. public float fillEnd;
  39. /// <summary>
  40. ///
  41. /// </summary>
  42. public float pointDensity;
  43. /// <summary>
  44. ///
  45. /// </summary>
  46. public bool repeatFill;
  47. static List<Vector3> points = new List<Vector3>();
  48. static List<float> ts = new List<float>();
  49. public LineMesh()
  50. {
  51. path = new GPath();
  52. lineWidth = 2;
  53. fillStart = 0;
  54. fillEnd = 1;
  55. pointDensity = 0.1f;
  56. }
  57. public void OnPopulateMesh(VertexBuffer vb)
  58. {
  59. Vector2 uvMin = vb.uvRect.position;
  60. Vector2 uvMax = new Vector2(vb.uvRect.xMax, vb.uvRect.yMax);
  61. float uvRatio = path.length / vb.textureSize.x;
  62. int segCount = path.segmentCount;
  63. float t = 0;
  64. float lw = lineWidth;
  65. float u;
  66. for (int si = 0; si < segCount; si++)
  67. {
  68. float ratio = path.GetSegmentLength(si) / path.length;
  69. float t0 = Mathf.Clamp(fillStart - t, 0, ratio) / ratio;
  70. float t1 = Mathf.Clamp(fillEnd - t, 0, ratio) / ratio;
  71. if (t0 >= t1)
  72. {
  73. t += ratio;
  74. continue;
  75. }
  76. points.Clear();
  77. ts.Clear();
  78. path.GetPointsInSegment(si, t0, t1, points, ts, pointDensity);
  79. int cnt = points.Count;
  80. Color c0 = vb.vertexColor;
  81. Color c1 = vb.vertexColor;
  82. if (gradient != null)
  83. c0 = gradient.Evaluate(t);
  84. if (lineWidthCurve != null)
  85. lw = lineWidthCurve.Evaluate(t);
  86. if (roundEdge && si == 0 && t0 == 0)
  87. DrawRoundEdge(vb, points[0], points[1], lw, c0, uvMin);
  88. int vertCount = vb.currentVertCount;
  89. for (int i = 1; i < cnt; i++)
  90. {
  91. Vector3 p0 = points[i - 1];
  92. Vector3 p1 = points[i];
  93. int k = vertCount + (i - 1) * 2;
  94. float tc = t + ratio * ts[i];
  95. Vector3 lineVector = p1 - p0;
  96. Vector3 widthVector = Vector3.Cross(lineVector, new Vector3(0, 0, 1));
  97. widthVector.Normalize();
  98. if (i == 1)
  99. {
  100. if (repeatFill)
  101. u = tc * uvRatio * uvMax.x;
  102. else
  103. u = Mathf.Lerp(uvMin.x, uvMax.x, t + ratio * ts[i - 1]);
  104. vb.AddVert(p0 - widthVector * lw * 0.5f, c0, new Vector2(u, uvMax.y));
  105. vb.AddVert(p0 + widthVector * lw * 0.5f, c0, new Vector2(u, uvMin.y));
  106. if (si != 0) //joint
  107. {
  108. vb.AddTriangle(k - 2, k - 1, k + 1);
  109. vb.AddTriangle(k - 2, k + 1, k);
  110. }
  111. }
  112. if (gradient != null)
  113. c1 = gradient.Evaluate(tc);
  114. if (lineWidthCurve != null)
  115. lw = lineWidthCurve.Evaluate(tc);
  116. if (repeatFill)
  117. u = tc * uvRatio * uvMax.x;
  118. else
  119. u = Mathf.Lerp(uvMin.x, uvMax.x, tc);
  120. vb.AddVert(p1 - widthVector * lw * 0.5f, c1, new Vector2(u, uvMax.y));
  121. vb.AddVert(p1 + widthVector * lw * 0.5f, c1, new Vector2(u, uvMin.y));
  122. vb.AddTriangle(k, k + 1, k + 3);
  123. vb.AddTriangle(k, k + 3, k + 2);
  124. }
  125. if (roundEdge && si == segCount - 1 && t1 == 1)
  126. DrawRoundEdge(vb, points[cnt - 1], points[cnt - 2], lw, c1, uvMax);
  127. t += ratio;
  128. }
  129. }
  130. void DrawRoundEdge(VertexBuffer vb, Vector2 p0, Vector2 p1, float lw, Color32 color, Vector2 uv)
  131. {
  132. Vector2 widthVector = Vector3.Cross(p0 - p1, new Vector3(0, 0, 1));
  133. widthVector.Normalize();
  134. widthVector = widthVector * lw / 2f;
  135. Vector2 lineVector = (p0 - p1).normalized * lw / 2f;
  136. int sides = Mathf.CeilToInt(Mathf.PI * lw / 2);
  137. if (sides < 6)
  138. sides = 6;
  139. int current = vb.currentVertCount;
  140. float angleUnit = Mathf.PI / (sides - 1);
  141. vb.AddVert(p0, color, uv);
  142. vb.AddVert(p0 + widthVector, color, uv);
  143. for (int n = 0; n < sides; n++)
  144. {
  145. vb.AddVert(p0 + Mathf.Cos(angleUnit * n) * widthVector + Mathf.Sin(angleUnit * n) * lineVector, color, uv);
  146. vb.AddTriangle(current, current + 1 + n, current + 2 + n);
  147. }
  148. }
  149. }
  150. }