PlaneGenerator.cs 9.9 KB

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