Brak opisu
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

GridEditorUtility.cs 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEditor;
  4. using UnityEngine;
  5. using UnityEngine.Tilemaps;
  6. using Event = UnityEngine.Event;
  7. namespace UnityEditor.Tilemaps
  8. {
  9. internal static class GridEditorUtility
  10. {
  11. private const int k_GridGizmoVertexCount = 32000;
  12. private const float k_GridGizmoDistanceFalloff = 50f;
  13. public static Vector3Int ClampToGrid(Vector3Int p, Vector2Int origin, Vector2Int gridSize)
  14. {
  15. return new Vector3Int(
  16. Math.Max(Math.Min(p.x, origin.x + gridSize.x - 1), origin.x),
  17. Math.Max(Math.Min(p.y, origin.y + gridSize.y - 1), origin.y),
  18. p.z
  19. );
  20. }
  21. public static Vector3 ScreenToLocal(Transform transform, Vector2 screenPosition)
  22. {
  23. return ScreenToLocal(transform, screenPosition, new Plane(transform.forward * -1f, transform.position));
  24. }
  25. public static Vector3 ScreenToLocal(Transform transform, Vector2 screenPosition, Plane plane)
  26. {
  27. Ray ray;
  28. if (Camera.current.orthographic)
  29. {
  30. Vector2 screen = EditorGUIUtility.PointsToPixels(GUIClip.Unclip(screenPosition));
  31. screen.y = Camera.current.pixelHeight - screen.y;
  32. Vector3 cameraWorldPoint = Camera.current.ScreenToWorldPoint(screen);
  33. ray = new Ray(cameraWorldPoint, Camera.current.transform.forward);
  34. }
  35. else
  36. {
  37. ray = HandleUtility.GUIPointToWorldRay(screenPosition);
  38. }
  39. float result;
  40. plane.Raycast(ray, out result);
  41. Vector3 world = ray.GetPoint(result);
  42. return transform.InverseTransformPoint(world);
  43. }
  44. public static RectInt GetMarqueeRect(Vector2Int p1, Vector2Int p2)
  45. {
  46. return new RectInt(
  47. Math.Min(p1.x, p2.x),
  48. Math.Min(p1.y, p2.y),
  49. Math.Abs(p2.x - p1.x) + 1,
  50. Math.Abs(p2.y - p1.y) + 1
  51. );
  52. }
  53. public static BoundsInt GetMarqueeBounds(Vector3Int p1, Vector3Int p2)
  54. {
  55. return new BoundsInt(
  56. Math.Min(p1.x, p2.x),
  57. Math.Min(p1.y, p2.y),
  58. Math.Min(p1.z, p2.z),
  59. Math.Abs(p2.x - p1.x) + 1,
  60. Math.Abs(p2.y - p1.y) + 1,
  61. Math.Abs(p2.z - p1.z) + 1
  62. );
  63. }
  64. // http://ericw.ca/notes/bresenhams-line-algorithm-in-csharp.html
  65. public static IEnumerable<Vector2Int> GetPointsOnLine(Vector2Int p1, Vector2Int p2)
  66. {
  67. int x0 = p1.x;
  68. int y0 = p1.y;
  69. int x1 = p2.x;
  70. int y1 = p2.y;
  71. bool steep = Math.Abs(y1 - y0) > Math.Abs(x1 - x0);
  72. if (steep)
  73. {
  74. int t;
  75. t = x0; // swap x0 and y0
  76. x0 = y0;
  77. y0 = t;
  78. t = x1; // swap x1 and y1
  79. x1 = y1;
  80. y1 = t;
  81. }
  82. if (x0 > x1)
  83. {
  84. int t;
  85. t = x0; // swap x0 and x1
  86. x0 = x1;
  87. x1 = t;
  88. t = y0; // swap y0 and y1
  89. y0 = y1;
  90. y1 = t;
  91. }
  92. int dx = x1 - x0;
  93. int dy = Math.Abs(y1 - y0);
  94. int error = dx / 2;
  95. int ystep = (y0 < y1) ? 1 : -1;
  96. int y = y0;
  97. for (int x = x0; x <= x1; x++)
  98. {
  99. yield return new Vector2Int((steep ? y : x), (steep ? x : y));
  100. error = error - dy;
  101. if (error < 0)
  102. {
  103. y += ystep;
  104. error += dx;
  105. }
  106. }
  107. }
  108. public static void DrawBatchedHorizontalLine(float x1, float x2, float y)
  109. {
  110. GL.Vertex3(x1, y, 0f);
  111. GL.Vertex3(x2, y, 0f);
  112. GL.Vertex3(x2, y + 1, 0f);
  113. GL.Vertex3(x1, y + 1, 0f);
  114. }
  115. public static void DrawBatchedVerticalLine(float y1, float y2, float x)
  116. {
  117. GL.Vertex3(x, y1, 0f);
  118. GL.Vertex3(x, y2, 0f);
  119. GL.Vertex3(x + 1, y2, 0f);
  120. GL.Vertex3(x + 1, y1, 0f);
  121. }
  122. public static void DrawBatchedLine(Vector3 p1, Vector3 p2)
  123. {
  124. GL.Vertex3(p1.x, p1.y, p1.z);
  125. GL.Vertex3(p2.x, p2.y, p2.z);
  126. }
  127. public static void DrawLine(Vector2 p1, Vector2 p2, Color color)
  128. {
  129. if (Event.current.type != EventType.Repaint)
  130. return;
  131. HandleUtility.ApplyWireMaterial();
  132. GL.PushMatrix();
  133. GL.MultMatrix(GUI.matrix);
  134. GL.Begin(GL.LINES);
  135. GL.Color(color);
  136. DrawBatchedLine(p1, p2);
  137. GL.End();
  138. GL.PopMatrix();
  139. }
  140. public static void DrawBox(Rect r, Color color)
  141. {
  142. if (Event.current.type != EventType.Repaint)
  143. return;
  144. HandleUtility.ApplyWireMaterial();
  145. GL.PushMatrix();
  146. GL.MultMatrix(GUI.matrix);
  147. GL.Begin(GL.LINES);
  148. GL.Color(color);
  149. DrawBatchedLine(new Vector3(r.xMin, r.yMin, 0f), new Vector3(r.xMax, r.yMin, 0f));
  150. DrawBatchedLine(new Vector3(r.xMax, r.yMin, 0f), new Vector3(r.xMax, r.yMax, 0f));
  151. DrawBatchedLine(new Vector3(r.xMax, r.yMax, 0f), new Vector3(r.xMin, r.yMax, 0f));
  152. DrawBatchedLine(new Vector3(r.xMin, r.yMax, 0f), new Vector3(r.xMin, r.yMin, 0f));
  153. GL.End();
  154. GL.PopMatrix();
  155. }
  156. public static void DrawFilledBox(Rect r, Color color)
  157. {
  158. if (Event.current.type != EventType.Repaint)
  159. return;
  160. HandleUtility.ApplyWireMaterial();
  161. GL.PushMatrix();
  162. GL.MultMatrix(GUI.matrix);
  163. GL.Begin(GL.QUADS);
  164. GL.Color(color);
  165. GL.Vertex3(r.xMin, r.yMin, 0f);
  166. GL.Vertex3(r.xMax, r.yMin, 0f);
  167. GL.Vertex3(r.xMax, r.yMax, 0f);
  168. GL.Vertex3(r.xMin, r.yMax, 0f);
  169. GL.End();
  170. GL.PopMatrix();
  171. }
  172. public static void DrawGridMarquee(GridLayout gridLayout, BoundsInt area, Color color)
  173. {
  174. if (gridLayout == null)
  175. return;
  176. switch (gridLayout.cellLayout)
  177. {
  178. case GridLayout.CellLayout.Hexagon:
  179. DrawSelectedHexGridArea(gridLayout, area, color);
  180. break;
  181. case GridLayout.CellLayout.Isometric:
  182. case GridLayout.CellLayout.IsometricZAsY:
  183. case GridLayout.CellLayout.Rectangle:
  184. var cellStride = gridLayout.cellSize + gridLayout.cellGap;
  185. var cellGap = Vector3.one;
  186. if (!Mathf.Approximately(cellStride.x, 0f))
  187. {
  188. cellGap.x = gridLayout.cellSize.x / cellStride.x;
  189. }
  190. if (!Mathf.Approximately(cellStride.y, 0f))
  191. {
  192. cellGap.y = gridLayout.cellSize.y / cellStride.y;
  193. }
  194. Vector3[] cellLocals =
  195. {
  196. gridLayout.CellToLocal(new Vector3Int(area.xMin, area.yMin, area.zMin)),
  197. gridLayout.CellToLocalInterpolated(new Vector3(area.xMax - 1 + cellGap.x, area.yMin, area.zMin)),
  198. gridLayout.CellToLocalInterpolated(new Vector3(area.xMax - 1 + cellGap.x, area.yMax - 1 + cellGap.y, area.zMin)),
  199. gridLayout.CellToLocalInterpolated(new Vector3(area.xMin, area.yMax - 1 + cellGap.y, area.zMin))
  200. };
  201. HandleUtility.ApplyWireMaterial();
  202. GL.PushMatrix();
  203. GL.MultMatrix(gridLayout.transform.localToWorldMatrix);
  204. GL.Begin(GL.LINES);
  205. GL.Color(color);
  206. int i = 0;
  207. for (int j = cellLocals.Length - 1; i < cellLocals.Length; j = i++)
  208. DrawBatchedLine(cellLocals[j], cellLocals[i]);
  209. GL.End();
  210. GL.PopMatrix();
  211. break;
  212. }
  213. }
  214. public static void DrawSelectedHexGridArea(GridLayout gridLayout, BoundsInt area, Color color)
  215. {
  216. int requiredVertices = 4 * (area.size.x + area.size.y) - 2;
  217. if (requiredVertices < 0)
  218. return;
  219. Vector3[] cellLocals = new Vector3[requiredVertices];
  220. int horizontalCount = area.size.x * 2;
  221. int verticalCount = area.size.y * 2 - 1;
  222. int bottom = 0;
  223. int top = horizontalCount + verticalCount + horizontalCount - 1;
  224. int left = requiredVertices - 1;
  225. int right = horizontalCount;
  226. Vector3[] cellOffset =
  227. {
  228. Grid.Swizzle(gridLayout.cellSwizzle, new Vector3(0, gridLayout.cellSize.y / 2, 0)),
  229. Grid.Swizzle(gridLayout.cellSwizzle, new Vector3(gridLayout.cellSize.x / 2, gridLayout.cellSize.y / 4, 0)),
  230. Grid.Swizzle(gridLayout.cellSwizzle, new Vector3(gridLayout.cellSize.x / 2, -gridLayout.cellSize.y / 4, 0)),
  231. Grid.Swizzle(gridLayout.cellSwizzle, new Vector3(0, -gridLayout.cellSize.y / 2, 0)),
  232. Grid.Swizzle(gridLayout.cellSwizzle, new Vector3(-gridLayout.cellSize.x / 2, -gridLayout.cellSize.y / 4, 0)),
  233. Grid.Swizzle(gridLayout.cellSwizzle, new Vector3(-gridLayout.cellSize.x / 2, gridLayout.cellSize.y / 4, 0))
  234. };
  235. // Fill Top and Bottom Vertices
  236. for (int x = area.min.x; x < area.max.x; x++)
  237. {
  238. cellLocals[bottom++] = gridLayout.CellToLocal(new Vector3Int(x, area.min.y, area.zMin)) + cellOffset[4];
  239. cellLocals[bottom++] = gridLayout.CellToLocal(new Vector3Int(x, area.min.y, area.zMin)) + cellOffset[3];
  240. cellLocals[top--] = gridLayout.CellToLocal(new Vector3Int(x, area.max.y - 1, area.zMin)) + cellOffset[0];
  241. cellLocals[top--] = gridLayout.CellToLocal(new Vector3Int(x, area.max.y - 1, area.zMin)) + cellOffset[1];
  242. }
  243. // Fill first Left and Right Vertices
  244. cellLocals[left--] = gridLayout.CellToLocal(new Vector3Int(area.min.x, area.min.y, area.zMin)) + cellOffset[5];
  245. cellLocals[top--] = gridLayout.CellToLocal(new Vector3Int(area.max.x - 1, area.max.y - 1, area.zMin)) + cellOffset[2];
  246. // Fill Left and Right Vertices
  247. for (int y = area.min.y + 1; y < area.max.y; y++)
  248. {
  249. cellLocals[left--] = gridLayout.CellToLocal(new Vector3Int(area.min.x, y, area.zMin)) + cellOffset[4];
  250. cellLocals[left--] = gridLayout.CellToLocal(new Vector3Int(area.min.x, y, area.zMin)) + cellOffset[5];
  251. }
  252. for (int y = area.min.y; y < (area.max.y - 1); y++)
  253. {
  254. cellLocals[right++] = gridLayout.CellToLocal(new Vector3Int(area.max.x - 1, y, area.zMin)) + cellOffset[2];
  255. cellLocals[right++] = gridLayout.CellToLocal(new Vector3Int(area.max.x - 1, y, area.zMin)) + cellOffset[1];
  256. }
  257. HandleUtility.ApplyWireMaterial();
  258. GL.PushMatrix();
  259. GL.MultMatrix(gridLayout.transform.localToWorldMatrix);
  260. GL.Begin(GL.LINES);
  261. GL.Color(color);
  262. int i = 0;
  263. for (int j = cellLocals.Length - 1; i < cellLocals.Length; j = i++)
  264. {
  265. DrawBatchedLine(cellLocals[j], cellLocals[i]);
  266. }
  267. GL.End();
  268. GL.PopMatrix();
  269. }
  270. public static void DrawGridGizmo(GridLayout gridLayout, Transform transform, Color color, ref Mesh gridMesh, ref Material gridMaterial)
  271. {
  272. // TODO: Hook this up with DrawGrid
  273. if (Event.current.type != EventType.Repaint)
  274. return;
  275. if (gridMesh == null)
  276. gridMesh = GenerateCachedGridMesh(gridLayout, color);
  277. if (gridMaterial == null)
  278. {
  279. gridMaterial = (Material)EditorGUIUtility.LoadRequired("SceneView/GridGap.mat");
  280. }
  281. if (gridLayout.cellLayout == GridLayout.CellLayout.Hexagon)
  282. {
  283. gridMaterial.SetVector("_Gap", new Vector4(1f, 1f / 3f, 1f, 1f));
  284. gridMaterial.SetVector("_Stride", new Vector4(1f, 1f, 1f, 1f));
  285. }
  286. else
  287. {
  288. gridMaterial.SetVector("_Gap", gridLayout.cellSize);
  289. gridMaterial.SetVector("_Stride", gridLayout.cellGap + gridLayout.cellSize);
  290. }
  291. gridMaterial.SetPass(0);
  292. GL.PushMatrix();
  293. if (gridMesh.GetTopology(0) == MeshTopology.Lines)
  294. GL.Begin(GL.LINES);
  295. else
  296. GL.Begin(GL.QUADS);
  297. Graphics.DrawMeshNow(gridMesh, transform.localToWorldMatrix);
  298. GL.End();
  299. GL.PopMatrix();
  300. }
  301. public static Vector3 GetSpriteWorldSize(Sprite sprite)
  302. {
  303. if (sprite != null && sprite.rect.size.magnitude > 0f)
  304. {
  305. return new Vector3(
  306. sprite.rect.size.x / sprite.pixelsPerUnit,
  307. sprite.rect.size.y / sprite.pixelsPerUnit,
  308. 1f
  309. );
  310. }
  311. return Vector3.one;
  312. }
  313. private static Mesh GenerateCachedGridMesh(GridLayout gridLayout, Color color)
  314. {
  315. switch (gridLayout.cellLayout)
  316. {
  317. case GridLayout.CellLayout.Hexagon:
  318. return GenerateCachedHexagonalGridMesh(gridLayout, color);
  319. case GridLayout.CellLayout.Isometric:
  320. case GridLayout.CellLayout.IsometricZAsY:
  321. case GridLayout.CellLayout.Rectangle:
  322. var min = k_GridGizmoVertexCount / -32;
  323. var max = min * -1;
  324. var numCells = max - min;
  325. var bounds = new RectInt(min, min, numCells, numCells);
  326. return GenerateCachedGridMesh(gridLayout, color, 0f, bounds, MeshTopology.Lines);
  327. }
  328. return null;
  329. }
  330. public static Mesh GenerateCachedGridMesh(GridLayout gridLayout, Color color, float screenPixelSize, RectInt bounds, MeshTopology topology)
  331. {
  332. Mesh mesh = new Mesh();
  333. mesh.hideFlags = HideFlags.HideAndDontSave;
  334. int vertex = 0;
  335. int totalVertices = topology == MeshTopology.Quads ?
  336. 8 * (bounds.size.x + bounds.size.y) :
  337. 4 * (bounds.size.x + bounds.size.y);
  338. Vector3 horizontalPixelOffset = new Vector3(screenPixelSize, 0f, 0f);
  339. Vector3 verticalPixelOffset = new Vector3(0f, screenPixelSize, 0f);
  340. Vector3[] vertices = new Vector3[totalVertices];
  341. Vector2[] uvs2 = new Vector2[totalVertices];
  342. Vector3 cellStride = gridLayout.cellSize + gridLayout.cellGap;
  343. Vector3Int minPosition = new Vector3Int(0, bounds.min.y, 0);
  344. Vector3Int maxPosition = new Vector3Int(0, bounds.max.y, 0);
  345. Vector3 cellGap = Vector3.zero;
  346. if (!Mathf.Approximately(cellStride.x, 0f))
  347. {
  348. cellGap.x = gridLayout.cellSize.x / cellStride.x;
  349. }
  350. for (int x = bounds.min.x; x < bounds.max.x; x++)
  351. {
  352. minPosition.x = x;
  353. maxPosition.x = x;
  354. vertices[vertex + 0] = gridLayout.CellToLocal(minPosition);
  355. vertices[vertex + 1] = gridLayout.CellToLocal(maxPosition);
  356. uvs2[vertex + 0] = Vector2.zero;
  357. uvs2[vertex + 1] = new Vector2(0f, cellStride.y * bounds.size.y);
  358. if (topology == MeshTopology.Quads)
  359. {
  360. vertices[vertex + 2] = gridLayout.CellToLocal(maxPosition) + horizontalPixelOffset;
  361. vertices[vertex + 3] = gridLayout.CellToLocal(minPosition) + horizontalPixelOffset;
  362. uvs2[vertex + 2] = new Vector2(0f, cellStride.y * bounds.size.y);
  363. uvs2[vertex + 3] = Vector2.zero;
  364. }
  365. vertex += topology == MeshTopology.Quads ? 4 : 2;
  366. vertices[vertex + 0] = gridLayout.CellToLocalInterpolated(minPosition + cellGap);
  367. vertices[vertex + 1] = gridLayout.CellToLocalInterpolated(maxPosition + cellGap);
  368. uvs2[vertex + 0] = Vector2.zero;
  369. uvs2[vertex + 1] = new Vector2(0f, cellStride.y * bounds.size.y);
  370. if (topology == MeshTopology.Quads)
  371. {
  372. vertices[vertex + 2] = gridLayout.CellToLocalInterpolated(maxPosition + cellGap) + horizontalPixelOffset;
  373. vertices[vertex + 3] = gridLayout.CellToLocalInterpolated(minPosition + cellGap) + horizontalPixelOffset;
  374. uvs2[vertex + 2] = new Vector2(0f, cellStride.y * bounds.size.y);
  375. uvs2[vertex + 3] = Vector2.zero;
  376. }
  377. vertex += topology == MeshTopology.Quads ? 4 : 2;
  378. }
  379. minPosition = new Vector3Int(bounds.min.x, 0, 0);
  380. maxPosition = new Vector3Int(bounds.max.x, 0, 0);
  381. cellGap = Vector3.zero;
  382. if (!Mathf.Approximately(cellStride.y, 0f))
  383. {
  384. cellGap.y = gridLayout.cellSize.y / cellStride.y;
  385. }
  386. for (int y = bounds.min.y; y < bounds.max.y; y++)
  387. {
  388. minPosition.y = y;
  389. maxPosition.y = y;
  390. vertices[vertex + 0] = gridLayout.CellToLocal(minPosition);
  391. vertices[vertex + 1] = gridLayout.CellToLocal(maxPosition);
  392. uvs2[vertex + 0] = Vector2.zero;
  393. uvs2[vertex + 1] = new Vector2(cellStride.x * bounds.size.x, 0f);
  394. if (topology == MeshTopology.Quads)
  395. {
  396. vertices[vertex + 2] = gridLayout.CellToLocal(maxPosition) + verticalPixelOffset;
  397. vertices[vertex + 3] = gridLayout.CellToLocal(minPosition) + verticalPixelOffset;
  398. uvs2[vertex + 2] = new Vector2(cellStride.x * bounds.size.x, 0f);
  399. uvs2[vertex + 3] = Vector2.zero;
  400. }
  401. vertex += topology == MeshTopology.Quads ? 4 : 2;
  402. vertices[vertex + 0] = gridLayout.CellToLocalInterpolated(minPosition + cellGap);
  403. vertices[vertex + 1] = gridLayout.CellToLocalInterpolated(maxPosition + cellGap);
  404. uvs2[vertex + 0] = Vector2.zero;
  405. uvs2[vertex + 1] = new Vector2(cellStride.x * bounds.size.x, 0f);
  406. if (topology == MeshTopology.Quads)
  407. {
  408. vertices[vertex + 2] = gridLayout.CellToLocalInterpolated(maxPosition + cellGap) + verticalPixelOffset;
  409. vertices[vertex + 3] = gridLayout.CellToLocalInterpolated(minPosition + cellGap) + verticalPixelOffset;
  410. uvs2[vertex + 2] = new Vector2(cellStride.x * bounds.size.x, 0f);
  411. uvs2[vertex + 3] = Vector2.zero;
  412. }
  413. vertex += topology == MeshTopology.Quads ? 4 : 2;
  414. }
  415. var uv0 = new Vector2(k_GridGizmoDistanceFalloff, 0f);
  416. var uvs = new Vector2[vertex];
  417. var indices = new int[vertex];
  418. var colors = new Color[vertex];
  419. var normals = new Vector3[totalVertices]; // Normal channel stores the position of the other end point of the line.
  420. var uvs3 = new Vector2[totalVertices]; // UV3 channel stores the UV2 value of the other end point of the line.
  421. for (int i = 0; i < vertex; i++)
  422. {
  423. uvs[i] = uv0;
  424. indices[i] = i;
  425. colors[i] = color;
  426. var alternate = i + ((i % 2) == 0 ? 1 : -1);
  427. normals[i] = vertices[alternate];
  428. uvs3[i] = uvs2[alternate];
  429. }
  430. mesh.vertices = vertices;
  431. mesh.uv = uvs;
  432. mesh.uv2 = uvs2;
  433. mesh.uv3 = uvs3;
  434. mesh.colors = colors;
  435. mesh.normals = normals;
  436. mesh.SetIndices(indices, topology, 0);
  437. return mesh;
  438. }
  439. private static Mesh GenerateCachedHexagonalGridMesh(GridLayout gridLayout, Color color)
  440. {
  441. Mesh mesh = new Mesh();
  442. mesh.hideFlags = HideFlags.HideAndDontSave;
  443. int vertex = 0;
  444. int max = k_GridGizmoVertexCount / (2 * (6 * 2));
  445. max = (max / 4) * 4;
  446. int min = -max;
  447. float numVerticalCells = 6 * (max / 4);
  448. int totalVertices = max * 2 * 6 * 2;
  449. var cellStrideY = gridLayout.cellGap.y + gridLayout.cellSize.y;
  450. var cellOffsetY = gridLayout.cellSize.y / 2;
  451. var hexOffset = (1.0f / 3.0f);
  452. var drawTotal = numVerticalCells * 2.0f * hexOffset;
  453. var drawDiagTotal = 2 * drawTotal;
  454. Vector3[] vertices = new Vector3[totalVertices];
  455. Vector2[] uvs2 = new Vector2[totalVertices];
  456. // Draw Vertical Lines
  457. for (int x = min; x < max; x++)
  458. {
  459. vertices[vertex] = gridLayout.CellToLocal(new Vector3Int(x, min, 0));
  460. vertices[vertex + 1] = gridLayout.CellToLocal(new Vector3Int(x, max, 0));
  461. uvs2[vertex] = new Vector2(0f, 2 * hexOffset);
  462. uvs2[vertex + 1] = new Vector2(0f, 2 * hexOffset + drawTotal);
  463. vertex += 2;
  464. // Alternate Row Offset
  465. vertices[vertex] = gridLayout.CellToLocal(new Vector3Int(x, min - 1, 0));
  466. vertices[vertex + 1] = gridLayout.CellToLocal(new Vector3Int(x, max - 1, 0));
  467. uvs2[vertex] = new Vector2(0f, 2 * hexOffset);
  468. uvs2[vertex + 1] = new Vector2(0f, 2 * hexOffset + drawTotal);
  469. vertex += 2;
  470. }
  471. // Draw Diagonals
  472. for (int y = min; y < max; y++)
  473. {
  474. float drawDiagOffset = ((y + 1) % 3) * hexOffset;
  475. var cellOffSet = Grid.Swizzle(gridLayout.cellSwizzle, new Vector3(0f, y * cellStrideY + cellOffsetY, 0.0f));
  476. // Slope Up
  477. vertices[vertex] = gridLayout.CellToLocal(new Vector3Int(Mathf.RoundToInt(1.5f * min), min, 0)) + cellOffSet;
  478. vertices[vertex + 1] = gridLayout.CellToLocal(new Vector3Int(Mathf.RoundToInt(1.5f * max), max, 0)) + cellOffSet;
  479. uvs2[vertex] = new Vector2(0f, drawDiagOffset);
  480. uvs2[vertex + 1] = new Vector2(0f, drawDiagOffset + drawDiagTotal);
  481. vertex += 2;
  482. // Slope Down
  483. vertices[vertex] = gridLayout.CellToLocal(new Vector3Int(Mathf.RoundToInt(1.5f * max), min, 0)) + cellOffSet;
  484. vertices[vertex + 1] = gridLayout.CellToLocal(new Vector3Int(Mathf.RoundToInt(1.5f * min), max, 0)) + cellOffSet;
  485. uvs2[vertex] = new Vector2(0f, drawDiagOffset);
  486. uvs2[vertex + 1] = new Vector2(0f, drawDiagOffset + drawDiagTotal);
  487. vertex += 2;
  488. // Alternate Row Offset
  489. vertices[vertex] = gridLayout.CellToLocal(new Vector3Int(Mathf.RoundToInt(1.5f * min) + 1, min, 0)) + cellOffSet;
  490. vertices[vertex + 1] = gridLayout.CellToLocal(new Vector3Int(Mathf.RoundToInt(1.5f * max) + 1, max, 0)) + cellOffSet;
  491. uvs2[vertex] = new Vector2(0f, drawDiagOffset);
  492. uvs2[vertex + 1] = new Vector2(0f, drawDiagOffset + drawDiagTotal);
  493. vertex += 2;
  494. vertices[vertex] = gridLayout.CellToLocal(new Vector3Int(Mathf.RoundToInt(1.5f * max) + 1, min, 0)) + cellOffSet;
  495. vertices[vertex + 1] = gridLayout.CellToLocal(new Vector3Int(Mathf.RoundToInt(1.5f * min) + 1, max, 0)) + cellOffSet;
  496. uvs2[vertex] = new Vector2(0f, drawDiagOffset);
  497. uvs2[vertex + 1] = new Vector2(0f, drawDiagOffset + drawDiagTotal);
  498. vertex += 2;
  499. }
  500. var uv0 = new Vector2(k_GridGizmoDistanceFalloff, 0f);
  501. var indices = new int[totalVertices];
  502. var uvs = new Vector2[totalVertices];
  503. var colors = new Color[totalVertices];
  504. var normals = new Vector3[totalVertices]; // Normal channel stores the position of the other end point of the line.
  505. var uvs3 = new Vector2[totalVertices]; // UV3 channel stores the UV2 value of the other end point of the line.
  506. for (int i = 0; i < totalVertices; i++)
  507. {
  508. uvs[i] = uv0;
  509. indices[i] = i;
  510. colors[i] = color;
  511. var alternate = i + ((i % 2) == 0 ? 1 : -1);
  512. normals[i] = vertices[alternate];
  513. uvs3[i] = uvs2[alternate];
  514. }
  515. mesh.vertices = vertices;
  516. mesh.uv = uvs;
  517. mesh.uv2 = uvs2;
  518. mesh.uv3 = uvs3;
  519. mesh.colors = colors;
  520. mesh.normals = normals;
  521. mesh.SetIndices(indices, MeshTopology.Lines, 0);
  522. return mesh;
  523. }
  524. }
  525. }