Assignment for RMIT Mixed Reality in 2020
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.

274 lines
9.5 KiB

  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Linq;
  4. using System.Collections.Generic;
  5. namespace Utility.Meshes
  6. {
  7. public static class Subdivion
  8. {
  9. static List<Vector3> vertices;
  10. static List<Vector3> normals;
  11. static List<Color> colors;
  12. static List<Vector2> uv;
  13. static List<Vector2> uv1;
  14. static List<Vector2> uv2;
  15. static List<List<int>> allIndices;
  16. static Dictionary<uint, int> newVectices;
  17. static void InitArrays(Mesh mesh)
  18. {
  19. vertices = new List<Vector3>(mesh.vertices);
  20. normals = new List<Vector3>(mesh.normals);
  21. colors = new List<Color>(mesh.colors);
  22. uv = new List<Vector2>(mesh.uv);
  23. uv1 = new List<Vector2>(mesh.uv2);
  24. uv2 = new List<Vector2>(mesh.uv2);
  25. allIndices = new List<List<int>>();
  26. }
  27. static void CleanUp()
  28. {
  29. vertices = null;
  30. normals = null;
  31. colors = null;
  32. uv = null;
  33. uv1 = null;
  34. uv2 = null;
  35. allIndices = null;
  36. }
  37. #region Subdivide4 (2x2)
  38. static int GetNewVertex4(int i1, int i2)
  39. {
  40. int newIndex = vertices.Count;
  41. uint t1 = ((uint)i1 << 16) | (uint)i2;
  42. uint t2 = ((uint)i2 << 16) | (uint)i1;
  43. if (newVectices.ContainsKey(t2))
  44. return newVectices[t2];
  45. if (newVectices.ContainsKey(t1))
  46. return newVectices[t1];
  47. newVectices.Add(t1, newIndex);
  48. vertices.Add((vertices[i1] + vertices[i2]) * 0.5f);
  49. if (normals.Count > 0)
  50. normals.Add((normals[i1] + normals[i2]).normalized);
  51. if (colors.Count > 0)
  52. colors.Add((colors[i1] + colors[i2]) * 0.5f);
  53. if (uv.Count > 0)
  54. uv.Add((uv[i1] + uv[i2]) * 0.5f);
  55. if (uv1.Count > 0)
  56. uv1.Add((uv1[i1] + uv1[i2]) * 0.5f);
  57. if (uv2.Count > 0)
  58. uv2.Add((uv2[i1] + uv2[i2]) * 0.5f);
  59. return newIndex;
  60. }
  61. /// <summary>
  62. /// Devides each triangles into 4. A quad(2 tris) will be splitted into 2x2 quads( 8 tris )
  63. /// </summary>
  64. /// <param name="mesh"></param>
  65. public static void Subdivide4(Mesh mesh)
  66. {
  67. newVectices = new Dictionary<uint, int>();
  68. InitArrays(mesh);
  69. int[] triangles = mesh.triangles;
  70. Debug.Log(mesh.subMeshCount);
  71. for (int j = 0; j < mesh.subMeshCount; j++)
  72. {
  73. var subMesh = mesh.GetSubMesh(j);
  74. allIndices.Add(new List<int>());
  75. List<int> subIndices = allIndices[j];
  76. for (int i = subMesh.indexStart; i < subMesh.indexStart + subMesh.indexCount; i += 3)
  77. {
  78. int i1 = triangles[i + 0];
  79. int i2 = triangles[i + 1];
  80. int i3 = triangles[i + 2];
  81. int a = GetNewVertex4(i1, i2);
  82. int b = GetNewVertex4(i2, i3);
  83. int c = GetNewVertex4(i3, i1);
  84. subIndices.Add(i1); subIndices.Add(a); subIndices.Add(c);
  85. subIndices.Add(i2); subIndices.Add(b); subIndices.Add(a);
  86. subIndices.Add(i3); subIndices.Add(c); subIndices.Add(b);
  87. subIndices.Add(a); subIndices.Add(b); subIndices.Add(c); // center triangle
  88. }
  89. }
  90. mesh.vertices = vertices.ToArray();
  91. if (normals.Count > 0)
  92. mesh.normals = normals.ToArray();
  93. if (colors.Count > 0)
  94. mesh.colors = colors.ToArray();
  95. if (uv.Count > 0)
  96. mesh.uv = uv.ToArray();
  97. if (uv1.Count > 0)
  98. mesh.uv2 = uv1.ToArray();
  99. if (uv2.Count > 0)
  100. mesh.uv2 = uv2.ToArray();
  101. mesh.triangles = allIndices.SelectMany(x => x).ToArray();
  102. mesh.subMeshCount = allIndices.Count;
  103. for (int i = 0; i < allIndices.Count; i++)
  104. mesh.SetTriangles(allIndices[i], i);
  105. CleanUp();
  106. }
  107. #endregion Subdivide4 (2x2)
  108. #region Subdivide9 (3x3)
  109. static int GetNewVertex9(int i1, int i2, int i3)
  110. {
  111. int newIndex = vertices.Count;
  112. // center points don't go into the edge list
  113. if (i3 == i1 || i3 == i2)
  114. {
  115. uint t1 = ((uint)i1 << 16) | (uint)i2;
  116. if (newVectices.ContainsKey(t1))
  117. return newVectices[t1];
  118. newVectices.Add(t1, newIndex);
  119. }
  120. // calculate new vertex
  121. vertices.Add((vertices[i1] + vertices[i2] + vertices[i3]) / 3.0f);
  122. if (normals.Count > 0)
  123. normals.Add((normals[i1] + normals[i2] + normals[i3]).normalized);
  124. if (colors.Count > 0)
  125. colors.Add((colors[i1] + colors[i2] + colors[i3]) / 3.0f);
  126. if (uv.Count > 0)
  127. uv.Add((uv[i1] + uv[i2] + uv[i3]) / 3.0f);
  128. if (uv1.Count > 0)
  129. uv1.Add((uv1[i1] + uv1[i2] + uv1[i3]) / 3.0f);
  130. if (uv2.Count > 0)
  131. uv2.Add((uv2[i1] + uv2[i2] + uv2[i3]) / 3.0f);
  132. return newIndex;
  133. }
  134. /// <summary>
  135. /// Devides each triangles into 9. A quad(2 tris) will be splitted into 3x3 quads( 18 tris )
  136. /// </summary>
  137. /// <param name="mesh"></param>
  138. public static void Subdivide9(Mesh mesh)
  139. {
  140. newVectices = new Dictionary<uint, int>();
  141. InitArrays(mesh);
  142. int[] triangles = mesh.triangles;
  143. Debug.Log(mesh.subMeshCount);
  144. for (int j = 0; j < mesh.subMeshCount; j++)
  145. {
  146. var subMesh = mesh.GetSubMesh(j);
  147. allIndices.Add(new List<int>());
  148. List<int> subIndices = allIndices[j];
  149. for (int i = subMesh.indexStart; i < subMesh.indexStart + subMesh.indexCount; i += 3)
  150. {
  151. int i1 = triangles[i + 0];
  152. int i2 = triangles[i + 1];
  153. int i3 = triangles[i + 2];
  154. int a1 = GetNewVertex9(i1, i2, i1);
  155. int a2 = GetNewVertex9(i2, i1, i2);
  156. int b1 = GetNewVertex9(i2, i3, i2);
  157. int b2 = GetNewVertex9(i3, i2, i3);
  158. int c1 = GetNewVertex9(i3, i1, i3);
  159. int c2 = GetNewVertex9(i1, i3, i1);
  160. int d = GetNewVertex9(i1, i2, i3);
  161. subIndices.Add(i1); subIndices.Add(a1); subIndices.Add(c2);
  162. subIndices.Add(i2); subIndices.Add(b1); subIndices.Add(a2);
  163. subIndices.Add(i3); subIndices.Add(c1); subIndices.Add(b2);
  164. subIndices.Add(d); subIndices.Add(a1); subIndices.Add(a2);
  165. subIndices.Add(d); subIndices.Add(b1); subIndices.Add(b2);
  166. subIndices.Add(d); subIndices.Add(c1); subIndices.Add(c2);
  167. subIndices.Add(d); subIndices.Add(c2); subIndices.Add(a1);
  168. subIndices.Add(d); subIndices.Add(a2); subIndices.Add(b1);
  169. subIndices.Add(d); subIndices.Add(b2); subIndices.Add(c1);
  170. }
  171. }
  172. mesh.vertices = vertices.ToArray();
  173. if (normals.Count > 0)
  174. mesh.normals = normals.ToArray();
  175. if (colors.Count > 0)
  176. mesh.colors = colors.ToArray();
  177. if (uv.Count > 0)
  178. mesh.uv = uv.ToArray();
  179. if (uv1.Count > 0)
  180. mesh.uv2 = uv1.ToArray();
  181. if (uv2.Count > 0)
  182. mesh.uv2 = uv2.ToArray();
  183. mesh.triangles = allIndices.SelectMany(x => x).ToArray();
  184. mesh.subMeshCount = allIndices.Count;
  185. for (int i = 0; i < allIndices.Count; i++)
  186. mesh.SetTriangles(allIndices[i], i);
  187. CleanUp();
  188. }
  189. #endregion Subdivide9 (3x3)
  190. #region Subdivide
  191. /// <summary>
  192. /// This functions subdivides the mesh based on the level parameter
  193. /// Note that only the 4 and 9 subdivides are supported so only those divides
  194. /// are possible. [2,3,4,6,8,9,12,16,18,24,27,32,36,48,64, ...]
  195. /// The function tried to approximate the desired level
  196. /// </summary>
  197. /// <param name="mesh"></param>
  198. /// <param name="level">Should be a number made up of (2^x * 3^y)
  199. /// [2,3,4,6,8,9,12,16,18,24,27,32,36,48,64, ...]
  200. /// </param>
  201. public static void Subdivide(Mesh mesh, int level)
  202. {
  203. if (level < 2)
  204. return;
  205. while (level > 1)
  206. {
  207. // remove prime factor 3
  208. while (level % 3 == 0)
  209. {
  210. Subdivide9(mesh);
  211. level /= 3;
  212. }
  213. // remove prime factor 2
  214. while (level % 2 == 0)
  215. {
  216. Subdivide4(mesh);
  217. level /= 2;
  218. }
  219. // try to approximate. All other primes are increased by one
  220. // so they can be processed
  221. if (level > 3)
  222. level++;
  223. }
  224. }
  225. #endregion Subdivide
  226. public static Mesh DuplicateMesh(Mesh mesh)
  227. {
  228. Mesh newMesh = (Mesh)UnityEngine.Object.Instantiate(mesh);
  229. newMesh.uv = mesh.uv;
  230. return newMesh;
  231. }
  232. }
  233. }