/// <summary> /// Resize the grid while maintain old Colors data /// </summary> /// <param name="oldDimensions"></param> /// <param name="newDimensions"></param> internal void ResizeGrid(Index2D oldDimensions, Index2D newDimensions) { if (colors == null || colors.Length == 0) { colors = new Color[newDimensions.X * newDimensions.Z]; Utilities.Fill(colors, Color.clear); } else { Color[] tmp = new Color[newDimensions.X * newDimensions.Z]; Utilities.Fill(tmp, Color.clear); int xLimit = Mathf.Min(oldDimensions.X, newDimensions.X); int zLimit = Mathf.Min(oldDimensions.Z, newDimensions.Z); Color value; for (int z = 0; z < zLimit; ++z) { for (int x = 0; x < xLimit; ++x) { value = colors[Utilities.To1DIndex(x, z, oldDimensions.X)]; tmp[Utilities.To1DIndex(x, z, newDimensions.X)] = value; } } colors = tmp; } }
public void EnsureDimensionsUpToDate(Index2D dimensions) { if (surfaceDimensions != dimensions) { UpdateDimension(dimensions); } }
/// <summary> /// Resize the grid while maintain old elevations data /// </summary> /// <param name="oldDimensions"></param> /// <param name="newDimensions"></param> internal void ResizeGrid(Index2D oldDimensions, Index2D newDimensions) { if (elevations == null || elevations.Length == 0) { elevations = new float[newDimensions.X * newDimensions.Z]; Utilities.Fill(elevations, 0); } else { float[] tmp = new float[newDimensions.X * newDimensions.Z]; Utilities.Fill(tmp, 0); int xLimit = Mathf.Min(oldDimensions.X, newDimensions.X); int zLimit = Mathf.Min(oldDimensions.Z, newDimensions.Z); float value; for (int z = 0; z < zLimit; ++z) { for (int x = 0; x < xLimit; ++x) { value = elevations[Utilities.To1DIndex(x, z, oldDimensions.X)]; tmp[Utilities.To1DIndex(x, z, newDimensions.X)] = value; } } elevations = tmp; } }
/// <summary> /// Update grid dimension /// </summary> /// <param name="newSurfaceDimensions"></param> internal void UpdateDimension(Index2D newSurfaceDimensions) { if (surfaceDimensions != newSurfaceDimensions || colors == null || colors.Length != newSurfaceDimensions.X * newSurfaceDimensions.Z) { ResizeGrid(surfaceDimensions, newSurfaceDimensions); surfaceDimensions = newSurfaceDimensions; } }
/// <summary> /// Perform a paint action at a specific location /// </summary> /// <param name="hit"></param> /// <param name="currentEvent"></param> private void Paint(RaycastHit hit, Event currentEvent) { if (!GuiEventUtilities.IsLeftMouse) { return; } Vector3[] vertices = Terrain.MeshData.vertices; float sqrRadius = Settings.brushSettings.brushRadius * Settings.brushSettings.brushRadius; float sqrMagnitude = 0; List <int> modifiedVertexIndices = new List <int>(); List <Color> deltas = new List <Color>(); List <float> f = new List <float>(); //how much a vertex be affected by the brush //determine the vertices are being modified and how much they are affected (f) for (int i = 0; i < vertices.Length; ++i) { Index2D i2d = Utilities.To2DIndex(i, Terrain.VerticesGridLength.X); //only modify surface vertex if (!Terrain.IsSurfaceVertex(i2d)) { continue; } Vector3 worldPos = Terrain.transform.TransformPoint(vertices[i]); sqrMagnitude = Vector3.SqrMagnitude(hit.point - worldPos); if (sqrMagnitude >= sqrRadius) { continue; } f.Add(1 - sqrMagnitude / sqrRadius); modifiedVertexIndices.Add(i); } float sign = GuiEventUtilities.IsCtrl ? -1 : 1; for (int i = 0; i < modifiedVertexIndices.Count; ++i) { int index = modifiedVertexIndices[i]; if (sign > 0) { AddColor(index, settings.brushSettings.color, f[i] * settings.brushSettings.strength); } else { EraseColor(index, f[i] * settings.brushSettings.strength); } } //send data to the terrain to modify itself if (Painting != null) { Painting(modifiedVertexIndices, deltas); } }
public static Index2D[] GetIndicesArray2D(int row, int column) { Index2D[] indices = new Index2D[row * column]; for (int i = 0; i < row; ++i) { for (int j = 0; j < column; ++j) { indices[i * column + j] = new Index2D(j, i); } } return(indices); }
public static Index2D[] GetShuffleIndicesArray2D(int row, int column) { Index2D[] indices = GetIndicesArray2D(row, column); for (int i = 0; i < indices.Length - 1; ++i) { int j = UnityEngine.Random.Range(0, indices.Length); Index2D tmp = indices[i]; indices[i] = indices[j]; indices[j] = tmp; } return(indices); }
/// <summary> /// Add elevation value for a vertex /// </summary> /// <param name="vertexIndex"></param> /// <param name="value"></param> public void AddElevation(int vertexIndex, float value) { Settings.EnsureDimensionsUpToDate(new Index2D(Terrain.SurfaceTileCountX + 1, Terrain.SurfaceTileCountZ + 1)); Index2D i2d = Utilities.To2DIndex(vertexIndex, Terrain.VerticesGridLength.X); if (!Terrain.IsSurfaceVertex(i2d)) { return; } Index2D surfaceIndex = Terrain.GetSurfaceVertexIndex(i2d); Settings.AddElevation(surfaceIndex, value); }
/// <summary> /// Add Color value for a vertex /// </summary> /// <param name="surfaceIndex"></param> /// <param name="value"></param> public void EraseColor(Index2D surfaceIndex, float f) { if (colors == null || colors.Length != surfaceDimensions.X * surfaceDimensions.Z) { colors = new Color[surfaceDimensions.X * surfaceDimensions.Z]; } int index = Utilities.To1DIndex(surfaceIndex.X, surfaceIndex.Z, surfaceDimensions.X); if (index < colors.Length) { colors[index] = Color.Lerp(colors[index], Color.clear, f); } }
/// <summary> /// Add elevation value for a vertex /// </summary> /// <param name="surfaceIndex"></param> /// <param name="value"></param> public void AddElevation(Index2D surfaceIndex, float value) { if (elevations == null || elevations.Length != surfaceDimensions.X * surfaceDimensions.Z) { elevations = new float[surfaceDimensions.X * surfaceDimensions.Z]; } int index = Utilities.To1DIndex(surfaceIndex.X, surfaceIndex.Z, surfaceDimensions.X); if (index < elevations.Length) { elevations[index] += value; } }
/// <summary> /// Add Color value for a vertex /// </summary> /// <param name="surfaceIndex"></param> /// <param name="value"></param> public void AddColor(Index2D surfaceIndex, Color value, float f) { if (colors == null || colors.Length != surfaceDimensions.X * surfaceDimensions.Z) { colors = new Color[surfaceDimensions.X * surfaceDimensions.Z]; } int index = Utilities.To1DIndex(surfaceIndex.X, surfaceIndex.Z, surfaceDimensions.X); if (index < colors.Length) { //colors[index] = ColorLibrary.Blend(colors[index], 1 - Mathf.Clamp01(f), value, Mathf.Clamp01(f)); colors[index] = Color.Lerp(colors[index], value, f); } }
/// <summary> /// Get Color value for a vertex /// </summary> /// <param name="i"></param> /// <returns></returns> public Color GetColor(Index2D i) { if (colors == null) { return(Color.clear); } int index = Utilities.To1DIndex(i.X, i.Z, surfaceDimensions.X); if (index >= colors.Length) { return(Color.clear); } else { return(colors[index]); } }
/// <summary> /// Get elevation value for a vertex /// </summary> /// <param name="i"></param> /// <returns></returns> public float GetElevation(Index2D i) { if (elevations == null) { return(0); } int index = Utilities.To1DIndex(i.X, i.Z, surfaceDimensions.X); if (index >= elevations.Length) { return(0); } else { return(elevations[index]); } }
public Texture2D ExportTextureData() { Texture2D tex = new Texture2D(textureSize, textureSize); Color[] textureData = new Color[textureSize * textureSize]; MeshData data = terrain.MeshData; int trisCount = data.triangles.Length / 3; for (int i = 0; i < trisCount; ++i) { int i0 = data.triangles[i * 3 + 0]; int i1 = data.triangles[i * 3 + 1]; int i2 = data.triangles[i * 3 + 2]; Index2D i2d0 = Utilities.To2DIndex(i0, terrain.VerticesGridLength.X); Index2D i2d1 = Utilities.To2DIndex(i1, terrain.VerticesGridLength.X); Index2D i2d2 = Utilities.To2DIndex(i2, terrain.VerticesGridLength.X); if (!terrain.IsSurfaceVertex(i2d0) || !terrain.IsSurfaceVertex(i2d1) || !terrain.IsSurfaceVertex(i2d2)) { continue; } Vector2 uv0 = terrain.GetVertexUVOnHeightMap(i2d0); Vector2 uv1 = terrain.GetVertexUVOnHeightMap(i2d1); Vector2 uv2 = terrain.GetVertexUVOnHeightMap(i2d2); float minHeight = terrain.BaseHeight; float maxHeight = terrain.BaseHeight + terrain.SurfaceMaxHeight; Color c0 = Color.white * Mathf.InverseLerp(minHeight, maxHeight, data.vertices[i0].y); Color c1 = Color.white * Mathf.InverseLerp(minHeight, maxHeight, data.vertices[i1].y); Color c2 = Color.white * Mathf.InverseLerp(minHeight, maxHeight, data.vertices[i2].y); TextureExporter.DrawTriangleOnTexture( tex, new Vector2[] { uv0, uv1, uv2 }, new Color[] { c0, c1, c2 }, textureData); } tex.SetPixels(textureData); tex.Apply(); return(tex); }
/// <summary> /// Get elevation value for a vertex /// </summary> /// <param name="i"></param> /// <returns></returns> public float GetElevation(Index2D i) { return(Settings.GetElevation(i)); }
/// <summary> /// Get color value for a vertex /// </summary> /// <param name="i"></param> /// <returns></returns> public Color GetColor(Index2D i) { return(Settings.GetColor(i)); }
/// <summary> /// Perform a paint action at a specific location /// </summary> /// <param name="hit"></param> /// <param name="currentEvent"></param> private void Paint(RaycastHit hit, Event currentEvent) { if (!GuiEventUtilities.IsLeftMouse) { return; } Vector3[] vertices = Terrain.MeshData.vertices; float sqrRadius = Settings.brushRadius * Settings.brushRadius; float sqrMagnitude = 0; List <int> modifiedVertexIndices = new List <int>(); List <float> deltas = new List <float>(); List <float> f = new List <float>(); //how much a vertex be affected by the brush //determine the vertices are being modified and how much they are affected (f) for (int i = 0; i < vertices.Length; ++i) { Index2D i2d = Utilities.To2DIndex(i, Terrain.VerticesGridLength.X); //only modify surface vertex if (!Terrain.IsSurfaceVertex(i2d)) { continue; } //project brush and vertex position to XZ-plane if using Cylindrical mode Vector3 hitPoint = Settings.brushMode == BrushMode.Spherical ? hit.point : new Vector3(hit.point.x, 0, hit.point.z); Vector3 worldPos = Terrain.transform.TransformPoint(vertices[i]); Vector3 projWorldPos = Settings.brushMode == BrushMode.Spherical ? worldPos : new Vector3(worldPos.x, 0, worldPos.z); sqrMagnitude = Vector3.SqrMagnitude(hitPoint - projWorldPos); if (sqrMagnitude >= sqrRadius) { continue; } f.Add(1 - sqrMagnitude / sqrRadius); modifiedVertexIndices.Add(i); } if (GuiEventUtilities.IsShift) { //apply a Laplacian smooth function to the vertices List <Vector3> verts = new List <Vector3>(); for (int i = 0; i < modifiedVertexIndices.Count; ++i) { Vector3 v = vertices[modifiedVertexIndices[i]]; verts.Add(v); } for (int i = 0; i < modifiedVertexIndices.Count; ++i) { Vector3 v = vertices[modifiedVertexIndices[i]]; List <Vector3> adjacents = FindAdjacents(v, verts); float expectedY = CalculateExpectedY(adjacents); float newY = Mathf.MoveTowards(v.y, expectedY, Settings.strength * f[i]); deltas.Add(newY - v.y); } } else { //raise or lower vertices float sign = GuiEventUtilities.IsCtrl ? -1 : 1; for (int i = 0; i < modifiedVertexIndices.Count; ++i) { deltas.Add(sign * f[i] * Settings.strength); } } //send data to the terrain to modify itself if (Painting != null) { Painting(modifiedVertexIndices, deltas); } }