PlaneGenerator.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using Random = UnityEngine.Random;
  5. public class PlaneGenerator : MonoBehaviour
  6. {
  7. public Material material;
  8. public float noiseLevel = 0.1f;
  9. public float noiseScale = 0.1f;
  10. private const int pqsResolution = 64;
  11. private const int sphereRadius = 2;
  12. private List<Quad> quads;
  13. // Start is called once before the first execution of Update after the MonoBehaviour is created
  14. void Start()
  15. {
  16. BuildRootQuads();
  17. UpdateMeshes();
  18. }
  19. // Update is called once per frame
  20. void Update()
  21. {
  22. }
  23. private void BuildRootQuads()
  24. {
  25. var quadY = new Quad();
  26. var quadY1 = new Quad();
  27. var quadZ = new Quad();
  28. var quadZ1 = new Quad();
  29. var quadX = new Quad();
  30. var quadX1 = new Quad();
  31. quadY = BuildRootQuad(
  32. id: 1,
  33. eulerAngles: new Vector3(0, 0, 0),
  34. upperQuad: null,
  35. getUpperSideNumber: null,
  36. rightQuad: null,
  37. getRightSideNumber: null,
  38. lowerQuad: null,
  39. getLowerSideNumber: null,
  40. leftQuad: null,
  41. getLeftSideNumber: null);
  42. quadY1 = BuildRootQuad(
  43. id: 2,
  44. eulerAngles: new Vector3(180, 0, 0),
  45. upperQuad: null,
  46. getUpperSideNumber: null,
  47. rightQuad: null,
  48. getRightSideNumber: null,
  49. lowerQuad: null,
  50. getLowerSideNumber: null,
  51. leftQuad: null,
  52. getLeftSideNumber: null);
  53. quadX = BuildRootQuad(
  54. id: 5,
  55. eulerAngles: new Vector3(0, 0, 90),
  56. upperQuad: quadY,
  57. getUpperSideNumber: GetFirstRowNumber,
  58. rightQuad: null,
  59. getRightSideNumber: null,
  60. lowerQuad: quadY1,
  61. getLowerSideNumber: GetFirstRowInverseNumber,
  62. leftQuad: null,
  63. getLeftSideNumber: null);
  64. quadX1 = BuildRootQuad(
  65. id: 6,
  66. eulerAngles: new Vector3(0, 0, -90),
  67. upperQuad: quadY1,
  68. getUpperSideNumber: GetLastRowInverseNumber,
  69. rightQuad: null,
  70. getRightSideNumber: null,
  71. lowerQuad: quadY,
  72. getLowerSideNumber: GetLastRowNumber,
  73. leftQuad: null,
  74. getLeftSideNumber: null);
  75. quadZ = BuildRootQuad(
  76. id: 3,
  77. eulerAngles: new Vector3(90, 0, 0),
  78. upperQuad: quadX1,
  79. getUpperSideNumber: GetLastColumnNumber,
  80. rightQuad: quadY,
  81. getRightSideNumber: GetLastColumnNumber,
  82. lowerQuad: quadX,
  83. getLowerSideNumber: GetLastColumnInverseNumber,
  84. leftQuad: quadY1,
  85. getLeftSideNumber: GetLastColumnNumber);
  86. quadZ1 = BuildRootQuad(
  87. id: 4,
  88. eulerAngles: new Vector3(-90, 0, 0),
  89. upperQuad: quadX1,
  90. getUpperSideNumber: GetFirstColumnInverseNumber,
  91. rightQuad: quadY1,
  92. getRightSideNumber: GetFirstColumnNumber,
  93. lowerQuad: quadX,
  94. getLowerSideNumber: GetFirstColumnNumber,
  95. leftQuad: quadY,
  96. getLeftSideNumber: GetFirstColumnNumber);
  97. quads = new List<Quad> { quadY, quadY1, quadZ, quadZ1, quadX, quadX1 };
  98. }
  99. private Quad BuildRootQuad(
  100. int id,
  101. Vector3 eulerAngles,
  102. Quad? upperQuad,
  103. Func<int, int> getUpperSideNumber,
  104. Quad? rightQuad,
  105. Func<int, int> getRightSideNumber,
  106. Quad? lowerQuad,
  107. Func<int, int> getLowerSideNumber,
  108. Quad? leftQuad,
  109. Func<int, int> getLeftSideNumber)
  110. {
  111. var (vertices, uv) = CreateVertices();
  112. Rotate(vertices, eulerAngles);
  113. AddHeights(
  114. vertices,
  115. upperQuad,
  116. getUpperSideNumber,
  117. rightQuad,
  118. getRightSideNumber,
  119. lowerQuad,
  120. getLowerSideNumber,
  121. leftQuad,
  122. getLeftSideNumber);
  123. var triangles = CreateTriangles();
  124. return new Quad
  125. {
  126. Id = id,
  127. Vertices = vertices,
  128. Triangles = triangles,
  129. Uv = uv
  130. };
  131. }
  132. private void UpdateMeshes()
  133. {
  134. foreach (var quad in quads)
  135. {
  136. CreateMesh($"quad_{quad.Id}", quad.Vertices, quad.Uv, quad.Triangles);
  137. }
  138. }
  139. private (Vector3[] vertices, Vector2[] uv) CreateVertices()
  140. {
  141. var half = sphereRadius / 2f;
  142. var vertices = new Vector3[(pqsResolution + 1) * (pqsResolution + 1)];
  143. Vector2[] uv = new Vector2[(pqsResolution + 1) * (pqsResolution + 1)];
  144. for (int x = 0, vertex = 0; x <= pqsResolution; x++)
  145. {
  146. for (int z = 0; z <= pqsResolution; z++, vertex++)
  147. {
  148. vertices[vertex] = new Vector3((float)x / pqsResolution * sphereRadius - half, half, (float)z / pqsResolution * sphereRadius - half);
  149. uv[vertex] = new Vector2((float)x / pqsResolution, (float)z / pqsResolution);
  150. }
  151. }
  152. return (vertices, uv);
  153. }
  154. private int[] CreateTriangles()
  155. {
  156. var triangles = new int[(pqsResolution) * (pqsResolution) * 6];
  157. int triangle = 0;
  158. for (int x = 1, vertex = 0; x<pqsResolution + 1; x++, vertex++)
  159. {
  160. for (int z = 1; z<pqsResolution + 1; z++, vertex++)
  161. {
  162. triangles[triangle] = vertex;
  163. triangles[triangle + 1] = vertex + pqsResolution + 2;
  164. triangles[triangle + 2] = vertex + pqsResolution + 1;
  165. triangles[triangle + 3] = vertex;
  166. triangles[triangle + 4] = vertex + 1;
  167. triangles[triangle + 5] = vertex + pqsResolution + 2;
  168. triangle += 6;
  169. }
  170. }
  171. return triangles;
  172. }
  173. private void CreateMesh(string name, Vector3[] vertices, Vector2[] uv, int[] triangles)
  174. {
  175. var mesh = new GameObject(name, typeof(MeshFilter), typeof(MeshRenderer), typeof(MeshCollider));
  176. mesh.transform.localScale = new Vector3(1, 1, 1);
  177. var meshFilter = mesh.GetComponent<MeshFilter>();
  178. meshFilter.mesh.vertices = vertices;
  179. meshFilter.mesh.triangles = triangles;
  180. meshFilter.mesh.uv = uv;
  181. mesh.GetComponent<MeshCollider>().sharedMesh = meshFilter.mesh;
  182. meshFilter.mesh.RecalculateBounds();
  183. meshFilter.mesh.RecalculateNormals();
  184. mesh.GetComponent<MeshRenderer>().material = material;
  185. }
  186. private void Rotate(Vector3[] vertices, Vector3 eulerAngles)
  187. {
  188. for (int x = 0, vertex = 0; x <= pqsResolution; x++)
  189. {
  190. for (int z = 0; z <= pqsResolution; z++, vertex++)
  191. {
  192. vertices[vertex] = Rotate(vertices[vertex], eulerAngles);
  193. vertices[vertex] = Vector3.Normalize(vertices[vertex]);
  194. }
  195. }
  196. }
  197. private Vector3 Rotate(Vector3 vertex, Vector3 eulerAngles)
  198. {
  199. var result = vertex;
  200. if (eulerAngles.x != 0)
  201. result = RotateX(result, eulerAngles.x);
  202. if (eulerAngles.y != 0)
  203. result = RotateY(result, eulerAngles.y);
  204. if (eulerAngles.z != 0)
  205. result = RotateZ(result, eulerAngles.z);
  206. return result;
  207. }
  208. private Vector3 RotateX(Vector3 vertex, float angle)
  209. {
  210. var angleDeg = Mathf.Deg2Rad * angle;
  211. return new Vector3(
  212. x: vertex.x,
  213. y: vertex.y * Mathf.Cos(angleDeg) - vertex.z * Mathf.Sin(angleDeg),
  214. z: vertex.y * Mathf.Sin(angleDeg) + vertex.z * Mathf.Cos(angleDeg));
  215. }
  216. private Vector3 RotateY(Vector3 vertex, float angle)
  217. {
  218. var angleDeg = Mathf.Deg2Rad * angle;
  219. return new Vector3(
  220. x: vertex.x * Mathf.Cos(angleDeg) + vertex.z * Mathf.Sin(angleDeg),
  221. y: vertex.y,
  222. z: -vertex.x * Mathf.Sin(angleDeg) + vertex.z * Mathf.Cos(angleDeg));
  223. }
  224. private Vector3 RotateZ(Vector3 vertex, float angle)
  225. {
  226. var angleDeg = Mathf.Deg2Rad * angle;
  227. return new Vector3(
  228. x: vertex.x * Mathf.Cos(angleDeg) - vertex.y * Mathf.Sin(angleDeg),
  229. y: vertex.x * Mathf.Sin(angleDeg) + vertex.y * Mathf.Cos(angleDeg),
  230. z: vertex.z);
  231. }
  232. private float GetNoise(float x, float y)
  233. {
  234. return Mathf.PerlinNoise(x * noiseScale, y * noiseScale) * noiseLevel;
  235. }
  236. private void AddHeights(
  237. Vector3[] vertices,
  238. Quad? upperQuad,
  239. Func<int, int> getUpperSideNumber,
  240. Quad? rightQuad,
  241. Func<int, int> getRightSideNumber,
  242. Quad? lowerQuad,
  243. Func<int, int> getLowerSideNumber,
  244. Quad? leftQuad,
  245. Func<int, int> getLeftSideNumber)
  246. {
  247. for (int x = 0, vertex = 0; x <= pqsResolution; x++)
  248. {
  249. for (int z = 0; z <= pqsResolution; z++, vertex++)
  250. {
  251. if (x == 0 && lowerQuad?.Vertices != null && getLowerSideNumber != null)
  252. {
  253. vertices[vertex] = lowerQuad.Value.Vertices[getLowerSideNumber(z)]; //+
  254. }
  255. else if (x == pqsResolution && upperQuad?.Vertices != null && getUpperSideNumber != null)
  256. {
  257. vertices[vertex] = upperQuad.Value.Vertices[getUpperSideNumber(z)]; //[z];
  258. }
  259. else if (z == 0 && rightQuad?.Vertices != null && getRightSideNumber != null)
  260. {
  261. vertices[vertex] = rightQuad.Value.Vertices[(pqsResolution + 1) * (x + 1) - 1]; //+
  262. }
  263. else if (z == pqsResolution && leftQuad?.Vertices != null && getLeftSideNumber != null)
  264. {
  265. vertices[vertex] = leftQuad.Value.Vertices[x * (pqsResolution + 1)]; //+
  266. }
  267. else
  268. {
  269. var noise = 1 + GetNoise(Random.value, Random.value);
  270. vertices[vertex] = noise * sphereRadius * vertices[vertex];
  271. }
  272. }
  273. }
  274. }
  275. private int GetFirstColumnNumber(int x)
  276. {
  277. return x * (pqsResolution + 1);
  278. }
  279. private int GetFirstColumnInverseNumber(int x)
  280. {
  281. return (pqsResolution - x) * (pqsResolution + 1);
  282. }
  283. private int GetLastColumnNumber(int x)
  284. {
  285. return (pqsResolution + 1) * (x + 1) - 1;
  286. }
  287. private int GetLastColumnInverseNumber(int x)
  288. {
  289. return (pqsResolution + 1) * (pqsResolution - x + 1) - 1;
  290. }
  291. private int GetFirstRowNumber(int x)
  292. {
  293. return x;
  294. }
  295. private int GetFirstRowInverseNumber(int x)
  296. {
  297. return pqsResolution - x;
  298. }
  299. private int GetLastRowNumber(int x)
  300. {
  301. return (pqsResolution + 1) * pqsResolution + x;
  302. }
  303. private int GetLastRowInverseNumber(int x)
  304. {
  305. return (pqsResolution + 1) * (pqsResolution + 1) - 1 - x;
  306. }
  307. ////private void OnDrawGizmos()
  308. ////{
  309. //// var gizmoSize = 0.05f;
  310. //// if (quads != null)
  311. //// {
  312. //// foreach (var quad in quads)
  313. //// {
  314. //// if (quad.Vertices == null)
  315. //// continue;
  316. //// for (int x = 0, vertex = 0; x <= pqsResolution; x++)
  317. //// {
  318. //// for (int z = 0; z <= pqsResolution; z++, vertex++)
  319. //// {
  320. //// if (x == 0)
  321. //// {
  322. //// Gizmos.DrawSphere(quad.Vertices[vertex], gizmoSize);
  323. //// }
  324. //// else if (x == pqsResolution)
  325. //// {
  326. //// Gizmos.DrawWireSphere(quad.Vertices[vertex], gizmoSize);
  327. //// }
  328. //// else if (z == 0)
  329. //// {
  330. //// Gizmos.DrawCube(quad.Vertices[vertex], new Vector3(gizmoSize, gizmoSize, gizmoSize));
  331. //// }
  332. //// else if (z == pqsResolution)
  333. //// {
  334. //// Gizmos.DrawWireCube(quad.Vertices[vertex], new Vector3(gizmoSize, gizmoSize, gizmoSize));
  335. //// }
  336. //// else
  337. //// {
  338. //// var noise = 1; // 1 + GetNoise(Random.value, Random.value);
  339. //// //vertices[vertex] = noise * sphereRadius * vertices[vertex];
  340. //// }
  341. //// }
  342. //// }
  343. //// }
  344. //// }
  345. ////}
  346. }