using System; using System.Collections.Generic; using UnityEngine; using Random = UnityEngine.Random; public class PlaneGenerator : MonoBehaviour { public Material material; public float noiseLevel = 0.1f; public float noiseScale = 0.1f; private const int pqsResolution = 64; private const int sphereRadius = 2; private List quads; // Start is called once before the first execution of Update after the MonoBehaviour is created void Start() { BuildRootQuads(); UpdateMeshes(); } // Update is called once per frame void Update() { } private void BuildRootQuads() { var quadY = new Quad(); var quadY1 = new Quad(); var quadZ = new Quad(); var quadZ1 = new Quad(); var quadX = new Quad(); var quadX1 = new Quad(); quadY = BuildRootQuad( id: 1, eulerAngles: new Vector3(0, 0, 0), upperQuad: null, getUpperSideNumber: null, rightQuad: null, getRightSideNumber: null, lowerQuad: null, getLowerSideNumber: null, leftQuad: null, getLeftSideNumber: null); quadY1 = BuildRootQuad( id: 2, eulerAngles: new Vector3(180, 0, 0), upperQuad: null, getUpperSideNumber: null, rightQuad: null, getRightSideNumber: null, lowerQuad: null, getLowerSideNumber: null, leftQuad: null, getLeftSideNumber: null); quadX = BuildRootQuad( id: 5, eulerAngles: new Vector3(0, 0, 90), upperQuad: quadY, getUpperSideNumber: GetFirstRowNumber, rightQuad: null, getRightSideNumber: null, lowerQuad: quadY1, getLowerSideNumber: GetFirstRowInverseNumber, leftQuad: null, getLeftSideNumber: null); quadX1 = BuildRootQuad( id: 6, eulerAngles: new Vector3(0, 0, -90), upperQuad: quadY1, getUpperSideNumber: GetLastRowInverseNumber, rightQuad: null, getRightSideNumber: null, lowerQuad: quadY, getLowerSideNumber: GetLastRowNumber, leftQuad: null, getLeftSideNumber: null); quadZ = BuildRootQuad( id: 3, eulerAngles: new Vector3(90, 0, 0), upperQuad: quadX1, getUpperSideNumber: GetLastColumnNumber, rightQuad: quadY, getRightSideNumber: GetLastColumnNumber, lowerQuad: quadX, getLowerSideNumber: GetLastColumnInverseNumber, leftQuad: quadY1, getLeftSideNumber: GetLastColumnNumber); quadZ1 = BuildRootQuad( id: 4, eulerAngles: new Vector3(-90, 0, 0), upperQuad: quadX1, getUpperSideNumber: GetFirstColumnInverseNumber, rightQuad: quadY1, getRightSideNumber: GetFirstColumnNumber, lowerQuad: quadX, getLowerSideNumber: GetFirstColumnNumber, leftQuad: quadY, getLeftSideNumber: GetFirstColumnNumber); quads = new List { quadY, quadY1, quadZ, quadZ1, quadX, quadX1 }; } private Quad BuildRootQuad( int id, Vector3 eulerAngles, Quad? upperQuad, Func getUpperSideNumber, Quad? rightQuad, Func getRightSideNumber, Quad? lowerQuad, Func getLowerSideNumber, Quad? leftQuad, Func getLeftSideNumber) { var (vertices, uv) = CreateVertices(); Rotate(vertices, eulerAngles); AddHeights( vertices, upperQuad, getUpperSideNumber, rightQuad, getRightSideNumber, lowerQuad, getLowerSideNumber, leftQuad, getLeftSideNumber); var triangles = CreateTriangles(); return new Quad { Id = id, Vertices = vertices, Triangles = triangles, Uv = uv }; } private void UpdateMeshes() { foreach (var quad in quads) { CreateMesh($"quad_{quad.Id}", quad.Vertices, quad.Uv, quad.Triangles); } } private (Vector3[] vertices, Vector2[] uv) CreateVertices() { var half = sphereRadius / 2f; var vertices = new Vector3[(pqsResolution + 1) * (pqsResolution + 1)]; Vector2[] uv = new Vector2[(pqsResolution + 1) * (pqsResolution + 1)]; for (int x = 0, vertex = 0; x <= pqsResolution; x++) { for (int z = 0; z <= pqsResolution; z++, vertex++) { vertices[vertex] = new Vector3((float)x / pqsResolution * sphereRadius - half, half, (float)z / pqsResolution * sphereRadius - half); uv[vertex] = new Vector2((float)x / pqsResolution, (float)z / pqsResolution); } } return (vertices, uv); } private int[] CreateTriangles() { var triangles = new int[(pqsResolution) * (pqsResolution) * 6]; int triangle = 0; for (int x = 1, vertex = 0; x(); meshFilter.mesh.vertices = vertices; meshFilter.mesh.triangles = triangles; meshFilter.mesh.uv = uv; mesh.GetComponent().sharedMesh = meshFilter.mesh; meshFilter.mesh.RecalculateBounds(); meshFilter.mesh.RecalculateNormals(); mesh.GetComponent().material = material; } private void Rotate(Vector3[] vertices, Vector3 eulerAngles) { for (int x = 0, vertex = 0; x <= pqsResolution; x++) { for (int z = 0; z <= pqsResolution; z++, vertex++) { vertices[vertex] = Rotate(vertices[vertex], eulerAngles); vertices[vertex] = Vector3.Normalize(vertices[vertex]); } } } private Vector3 Rotate(Vector3 vertex, Vector3 eulerAngles) { var result = vertex; if (eulerAngles.x != 0) result = RotateX(result, eulerAngles.x); if (eulerAngles.y != 0) result = RotateY(result, eulerAngles.y); if (eulerAngles.z != 0) result = RotateZ(result, eulerAngles.z); return result; } private Vector3 RotateX(Vector3 vertex, float angle) { var angleDeg = Mathf.Deg2Rad * angle; return new Vector3( x: vertex.x, y: vertex.y * Mathf.Cos(angleDeg) - vertex.z * Mathf.Sin(angleDeg), z: vertex.y * Mathf.Sin(angleDeg) + vertex.z * Mathf.Cos(angleDeg)); } private Vector3 RotateY(Vector3 vertex, float angle) { var angleDeg = Mathf.Deg2Rad * angle; return new Vector3( x: vertex.x * Mathf.Cos(angleDeg) + vertex.z * Mathf.Sin(angleDeg), y: vertex.y, z: -vertex.x * Mathf.Sin(angleDeg) + vertex.z * Mathf.Cos(angleDeg)); } private Vector3 RotateZ(Vector3 vertex, float angle) { var angleDeg = Mathf.Deg2Rad * angle; return new Vector3( x: vertex.x * Mathf.Cos(angleDeg) - vertex.y * Mathf.Sin(angleDeg), y: vertex.x * Mathf.Sin(angleDeg) + vertex.y * Mathf.Cos(angleDeg), z: vertex.z); } private float GetNoise(float x, float y) { return Mathf.PerlinNoise(x * noiseScale, y * noiseScale) * noiseLevel; } private void AddHeights( Vector3[] vertices, Quad? upperQuad, Func getUpperSideNumber, Quad? rightQuad, Func getRightSideNumber, Quad? lowerQuad, Func getLowerSideNumber, Quad? leftQuad, Func getLeftSideNumber) { for (int x = 0, vertex = 0; x <= pqsResolution; x++) { for (int z = 0; z <= pqsResolution; z++, vertex++) { if (x == 0 && lowerQuad?.Vertices != null && getLowerSideNumber != null) { vertices[vertex] = lowerQuad.Value.Vertices[getLowerSideNumber(z)]; //+ } else if (x == pqsResolution && upperQuad?.Vertices != null && getUpperSideNumber != null) { vertices[vertex] = upperQuad.Value.Vertices[getUpperSideNumber(z)]; //[z]; } else if (z == 0 && rightQuad?.Vertices != null && getRightSideNumber != null) { vertices[vertex] = rightQuad.Value.Vertices[(pqsResolution + 1) * (x + 1) - 1]; //+ } else if (z == pqsResolution && leftQuad?.Vertices != null && getLeftSideNumber != null) { vertices[vertex] = leftQuad.Value.Vertices[x * (pqsResolution + 1)]; //+ } else { var noise = 1 + GetNoise(Random.value, Random.value); vertices[vertex] = noise * sphereRadius * vertices[vertex]; } } } } private int GetFirstColumnNumber(int x) { return x * (pqsResolution + 1); } private int GetFirstColumnInverseNumber(int x) { return (pqsResolution - x) * (pqsResolution + 1); } private int GetLastColumnNumber(int x) { return (pqsResolution + 1) * (x + 1) - 1; } private int GetLastColumnInverseNumber(int x) { return (pqsResolution + 1) * (pqsResolution - x + 1) - 1; } private int GetFirstRowNumber(int x) { return x; } private int GetFirstRowInverseNumber(int x) { return pqsResolution - x; } private int GetLastRowNumber(int x) { return (pqsResolution + 1) * pqsResolution + x; } private int GetLastRowInverseNumber(int x) { return (pqsResolution + 1) * (pqsResolution + 1) - 1 - x; } ////private void OnDrawGizmos() ////{ //// var gizmoSize = 0.05f; //// if (quads != null) //// { //// foreach (var quad in quads) //// { //// if (quad.Vertices == null) //// continue; //// for (int x = 0, vertex = 0; x <= pqsResolution; x++) //// { //// for (int z = 0; z <= pqsResolution; z++, vertex++) //// { //// if (x == 0) //// { //// Gizmos.DrawSphere(quad.Vertices[vertex], gizmoSize); //// } //// else if (x == pqsResolution) //// { //// Gizmos.DrawWireSphere(quad.Vertices[vertex], gizmoSize); //// } //// else if (z == 0) //// { //// Gizmos.DrawCube(quad.Vertices[vertex], new Vector3(gizmoSize, gizmoSize, gizmoSize)); //// } //// else if (z == pqsResolution) //// { //// Gizmos.DrawWireCube(quad.Vertices[vertex], new Vector3(gizmoSize, gizmoSize, gizmoSize)); //// } //// else //// { //// var noise = 1; // 1 + GetNoise(Random.value, Random.value); //// //vertices[vertex] = noise * sphereRadius * vertices[vertex]; //// } //// } //// } //// } //// } ////} }