/// <summary> /// Checks if a chunk is nearby to or has a road. /// </summary> /// <param name="startProgress">Start progress.</param> public void CheckForRoad(float startProgress) { _hasCheckedForRoad = true; Road road = WorldManager.Instance.Road; DynamicTerrain terrain = DynamicTerrain.Instance; Vector3 chunkPos = transform.position; float chunkSize = WorldManager.Instance.ChunkSize; float checkResolution = (1f - startProgress) * WorldManager.Instance.RoadPathCheckResolution; // Set boundaries for "near road" consideration Vector2 nearMin = new Vector2(chunkPos.x - chunkSize, chunkPos.z - chunkSize); Vector2 nearMax = new Vector2(chunkPos.x + chunkSize * 2f, chunkPos.z + chunkSize * 2f); // Set boundaries for "has road" consideration Vector2 hasMin = new Vector2(chunkPos.x, chunkPos.z); Vector2 hasMax = new Vector2(chunkPos.x + chunkSize, chunkPos.z + chunkSize); float progress = startProgress; while (progress <= 1f) { // Sample road and check distance to chunk Vector3 sample = road.GetPoint(progress); if (sample.x >= nearMin.x && sample.x <= nearMax.x && sample.z >= nearMin.y && sample.z <= nearMax.y) { if (!_nearRoad) { gameObject.name += "|nearRoad"; terrain.AddCloseToRoadChunk(this); } _nearRoad = true; // If near road, check if has road if (sample.x >= hasMin.x && sample.x <= hasMax.x && sample.z >= hasMin.y && sample.z <= hasMax.y) { terrain.AddRoadChunk(this); gameObject.name += "|hasRoad"; _grassEmitter.SetActive(false); _hasRoad = true; return; } } progress += 1f / checkResolution; } }
/// <summary> /// Resets necessary variables after de-pooling a chunk. /// </summary> public void Reuse(int x, int y) { DynamicTerrain terrain = DynamicTerrain.Instance; VertexMap vmap = terrain.VertexMap; float chunkSize = WorldManager.Instance.ChunkSize; // Update vars _x = x; _y = y; // Move chunk to appropriate position transform.position = new Vector3(x * chunkSize - chunkSize / 2f, 0f, y * chunkSize - chunkSize / 2f); // Update chunk name gameObject.name = "Chunk (" + x + "," + y + ") Position:" + transform.position.ToString(); _priority = 0f; // Clear decoration list _decorations.Clear(); // Register all vertices with vertex map // Move vertices, generate normals/colors for (int i = 0; i < _numVerts; i++) { // Get VMap coords IntVector2 coord = IntToV2(i); _coords[i] = coord; // Get corresponding vertex _mapVerts[i] = vmap.VertexAt(coord, true); // Get height from vertex UpdateVertex(i, _mapVerts[i].Height); } _hasCheckedForRoad = false; UpdateCollider(); }
public void SetHeight(float h) { // Skip locked vertices if (_locked || h == _height) { return; } _loaded = true; // Set height _height = h; _color.a = 0f; /*Vertex l = map.VertexAt(x-1,y); * color.a += (l != null ? Mathf.Abs (h - l.height) : 0f); * * Vertex r = map.VertexAt(x+1,y); * color.a += (r != null ? Mathf.Abs (h - r.height) : 0f); * * Vertex u = map.VertexAt(x,y+1); * color.a += (u != null ? Mathf.Abs (h - u.height) : 0f); * * Vertex d = map.VertexAt(x,y-1); * color.a += (d != null ? Mathf.Abs (h - d.height) : 0f); * * color.a /= (WorldManager.Instance.heightScale/10f); * color.a = Mathf.Clamp01(color.a);*/ CalculateBlend2(); int index; DynamicTerrain terrain = DynamicTerrain.Instance; if (IsEdge(_x)) { // Corner if (IsEdge(_y)) { Chunk ul = terrain.ChunkAt(ChunkMin(_x), ChunkMax(_y)); if (ul != null) { index = CoordToIndex(ul.X, ul.Y); ul.UpdateVertex(index, _height, true); ul.UpdateColor(index, _color); } Chunk ur = terrain.ChunkAt(ChunkMax(_x), ChunkMax(_y)); if (ur != null) { index = CoordToIndex(ur.X, ur.Y); ur.UpdateVertex(index, _height, true); ur.UpdateColor(index, _color); } Chunk dl = terrain.ChunkAt(ChunkMin(_x), ChunkMin(_y)); if (dl != null) { index = CoordToIndex(dl.X, dl.Y); dl.UpdateVertex(index, _height, true); dl.UpdateColor(index, _color); } Chunk dr = terrain.ChunkAt(ChunkMax(_x), ChunkMin(_y)); if (dr != null) { index = CoordToIndex(dr.X, dr.Y); dr.UpdateVertex(index, _height, true); dr.UpdateColor(index, _color); } // X edge } else { Chunk left = terrain.ChunkAt(ChunkMin(_x), ChunkAt(_y)); if (left != null) { index = CoordToIndex(left.X, left.Y); left.UpdateVertex(index, _height, true); left.UpdateColor(index, _color); } Chunk right = terrain.ChunkAt(ChunkMax(_x), ChunkAt(_y)); if (right != null) { index = CoordToIndex(right.X, right.Y); right.UpdateVertex(index, _height, true); right.UpdateColor(index, _color); } } // Y edge } else if (IsEdge(_y)) { Chunk bottom = terrain.ChunkAt(ChunkAt(_x), ChunkMin(_y)); if (bottom != null) { index = CoordToIndex(bottom.X, bottom.Y); bottom.UpdateVertex(index, _height, true); bottom.UpdateColor(index, _color); } Chunk top = terrain.ChunkAt(ChunkAt(_x), ChunkMax(_y)); if (top != null) { index = CoordToIndex(top.X, top.Y); top.UpdateVertex(index, _height, true); top.UpdateColor(index, _color); } // No edge } else { Chunk chunk = terrain.ChunkAt(ChunkAt(_x), ChunkAt(_y)); if (chunk != null) { index = CoordToIndex(chunk.X, chunk.Y); chunk.UpdateVertex(index, _height, false); chunk.UpdateColor(index, _color); } } }
/// <summary> /// Coroutine to update the vertices of a chunk. /// </summary> /// <returns>The verts.</returns> private IEnumerator UpdateVerts() { if (!GameManager.Instance.IsLoaded) { yield break; } _isUpdatingVerts = true; float margin = WorldManager.Instance.ChunkSize / 2; float startTime = Time.realtimeSinceStartup; Vector3 playerPos = PlayerMovement.Instance.transform.position; Vector3 chunkPos = transform.position; DynamicTerrain terrain = DynamicTerrain.Instance; VertexMap vmap = terrain.VertexMap; int v = 0; for (; v < _numVerts; v++) { // Get VMap coordinates IntVector2 coord = _coords[v]; // Get coresponding vertex Vertex vert = _mapVerts[v]; // Update vertex height UpdateVertex(v, vert.Height); if (terrain.FreqData == null) { yield break; } // If vertex is not locked and there is frequency data to use if (!vert.Locked) { // Distance between player and vertex Vector3 vertPos = chunkPos + _verts[v]; float distance = Vector3.Distance(vertPos, playerPos); // If vertex is close enough if (CheckDist(distance, WorldManager.Instance.VertexUpdateDistance, margin)) { // Calculate new height Vector3 angleVector = vertPos - playerPos; float angle = Vector3.Angle(Vector3.right, angleVector); float linIntInput = angle / 360f; float newY = terrain.FreqData.GetDataPoint(linIntInput) * WorldManager.Instance.HeightScale; // If new height, set it //if (newY != vmap.VertexAt(coord, false).height) vmap.SetHeight (coord, newY); if (newY != 0f) { vmap.AddHeight(coord, newY); } } } if (v == _numVerts - 1) { _isUpdatingVerts = false; yield break; } else if (Time.realtimeSinceStartup - startTime > GameManager.TargetDeltaTime) { yield return(null); startTime = Time.realtimeSinceStartup; } } }
/// <summary> /// Initializes a brand new chunk at x and y. /// </summary> public void Initialize(int x, int y) { DynamicTerrain terrain = DynamicTerrain.Instance; // Init vars _x = x; _y = y; VertexMap vmap = terrain.VertexMap; int chunkRes = WorldManager.Instance.ChunkResolution; float chunkSize = WorldManager.Instance.ChunkSize; // Generate vertices _verts = CreateUniformVertexArray(chunkRes); _numVerts = _verts.Length; // Generate triangles _triangles = CreateSquareArrayTriangles(chunkRes); // Init normals _normals = new Vector3[_numVerts]; // Generate UVs _uvs = CreateUniformUVArray(chunkRes); // Init colors _colors = new Color[_numVerts]; // Init coords and mapVerts _coords = new IntVector2[_numVerts]; _mapVerts = new Vertex[_numVerts]; // Build initial chunk mesh _mesh = CreateChunkMesh(); // Assign mesh GetComponent <MeshFilter>().mesh = _mesh; // Move GameObject to appropriate position transform.position = new Vector3(x * chunkSize - chunkSize / 2f, 0f, y * chunkSize - chunkSize / 2f); // Initialize name gameObject.name = "Chunk (" + x + "," + y + ") Position:" + transform.position.ToString(); // Init decorations list _decorations = new List <GameObject>(); // Register all vertices with vertex map // Move vertices, generate normals/colors for (int i = 0; i < _numVerts; i++) { // Init normal/color _normals[i] = Vector3.up; _colors[i] = Color.white; // Get VMap coords IntVector2 coord = IntToV2(i); _coords[i] = coord; // Get corresponding vertex _mapVerts[i] = vmap.VertexAt(coord, true); // If vertex exists, get height UpdateVertex(i, _mapVerts[i].Height); UpdateColor(i, _mapVerts[i].Color); } // Assign material MeshRenderer renderer = GetComponent <MeshRenderer>(); renderer.sharedMaterial = WorldManager.Instance.TerrainMaterial; renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.On; renderer.reflectionProbeUsage = UnityEngine.Rendering.ReflectionProbeUsage.Off; // Assign collision mesh MeshCollider collider = GetComponent <MeshCollider>(); collider.sharedMesh = _mesh; collider.convex = false; // Init rigidbody Rigidbody rigidbody = GetComponent <Rigidbody>(); rigidbody.freezeRotation = true; rigidbody.isKinematic = true; rigidbody.useGravity = false; rigidbody.constraints = RigidbodyConstraints.FreezeAll; // Add grass system _grassEmitter = GameObject.Instantiate(WorldManager.Instance.GrassEmitterPrefab); _grassEmitter.transform.parent = transform; _grassEmitter.transform.localPosition = Vector3.zero; // Randomize grass density ParticleSystem sys = _grassEmitter.GetComponent <ParticleSystem>(); sys.maxParticles = UnityEngine.Random.Range(0, WorldManager.Instance.GrassPerChunk); sys.playOnAwake = true; // Assign particle system emission shape ParticleSystem.ShapeModule shape = sys.shape; shape.mesh = _mesh; // Assign particle system emission rate ParticleSystem.EmissionModule emit = sys.emission; emit.rate = new ParticleSystem.MinMaxCurve(WorldManager.Instance.DecorationsPerStep); UpdateCollider(); }