Implemented eroder.
This commit is contained in:
parent
68140b11a7
commit
76527c2619
@ -48,6 +48,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Assets\Scripts\Business\BiomeManager.cs" />
|
<Compile Include="Assets\Scripts\Business\BiomeManager.cs" />
|
||||||
<Compile Include="Assets\Scripts\Business\ConfigurationManager.cs" />
|
<Compile Include="Assets\Scripts\Business\ConfigurationManager.cs" />
|
||||||
|
<Compile Include="Assets\Scripts\Generator\TerrainEroder.cs" />
|
||||||
<Compile Include="Assets\Scripts\Generator\TerrainGenerator.cs" />
|
<Compile Include="Assets\Scripts\Generator\TerrainGenerator.cs" />
|
||||||
<Compile Include="Assets\Scripts\InitializeScript.cs" />
|
<Compile Include="Assets\Scripts\InitializeScript.cs" />
|
||||||
<Compile Include="Assets\Scripts\Model\Biome.cs" />
|
<Compile Include="Assets\Scripts\Model\Biome.cs" />
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Assets\Scripts\Business\BiomeManager.cs" />
|
<Compile Include="Assets\Scripts\Business\BiomeManager.cs" />
|
||||||
<Compile Include="Assets\Scripts\Business\ConfigurationManager.cs" />
|
<Compile Include="Assets\Scripts\Business\ConfigurationManager.cs" />
|
||||||
|
<Compile Include="Assets\Scripts\Generator\TerrainEroder.cs" />
|
||||||
<Compile Include="Assets\Scripts\Generator\TerrainGenerator.cs" />
|
<Compile Include="Assets\Scripts\Generator\TerrainGenerator.cs" />
|
||||||
<Compile Include="Assets\Scripts\InitializeScript.cs" />
|
<Compile Include="Assets\Scripts\InitializeScript.cs" />
|
||||||
<Compile Include="Assets\Scripts\Model\Biome.cs" />
|
<Compile Include="Assets\Scripts\Model\Biome.cs" />
|
||||||
|
@ -3,5 +3,8 @@
|
|||||||
<noiseOctaves>9</noiseOctaves>
|
<noiseOctaves>9</noiseOctaves>
|
||||||
<noiseNonLinearPower>2.4</noiseNonLinearPower>
|
<noiseNonLinearPower>2.4</noiseNonLinearPower>
|
||||||
<waterNonLinearPower>1.9</waterNonLinearPower>
|
<waterNonLinearPower>1.9</waterNonLinearPower>
|
||||||
<elevationScale>0.0005</elevationScale>
|
<elevationScale>0.001</elevationScale>
|
||||||
|
<erodePoints>100</erodePoints>
|
||||||
|
<erodeIterations>60</erodeIterations>
|
||||||
|
<erodeAmountPercent>0.1</erodeAmountPercent>
|
||||||
</terrgenConfig>
|
</terrgenConfig>
|
Binary file not shown.
234
Game/Assets/Scripts/Generator/TerrainEroder.cs
Normal file
234
Game/Assets/Scripts/Generator/TerrainEroder.cs
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using TransportGame.Business;
|
||||||
|
using TransportGame.Model;
|
||||||
|
|
||||||
|
namespace TransportGame.Generator
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Simulates water erosion
|
||||||
|
/// </summary>
|
||||||
|
public class TerrainEroder
|
||||||
|
{
|
||||||
|
#region Constants
|
||||||
|
|
||||||
|
/// <summary> Direction vector (X)</summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// In order: Center, North, North-East, East, South-East, South, South-West, West, North-West
|
||||||
|
/// </remarks>
|
||||||
|
readonly static private int[] DirectionsX = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };
|
||||||
|
|
||||||
|
/// <summary> Direction vector (Y)</summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// In order: Center, North, North-East, East, South-East, South, South-West, West, North-West
|
||||||
|
/// </remarks>
|
||||||
|
readonly static private int[] DirectionsY = { 0, -1, -1, 0, 1, 1, 1, 0, -1 };
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Public properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the terrain to erode
|
||||||
|
/// </summary>
|
||||||
|
public Map Terrain { get; private set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
protected int SpringCount { get { return ConfigurationManager.TerrGenConfig.ErodePoints; } }
|
||||||
|
protected int IterationCount { get { return ConfigurationManager.TerrGenConfig.ErodeIterations; } }
|
||||||
|
protected float ErosionAmount { get { return ConfigurationManager.TerrGenConfig.ErodeAmountPercent; } }
|
||||||
|
|
||||||
|
#region Private variables
|
||||||
|
|
||||||
|
private Random random = new Random();
|
||||||
|
private float[,] water;
|
||||||
|
private int[] springsX;
|
||||||
|
private int[] springsY;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public TerrainEroder(Map terrain)
|
||||||
|
{
|
||||||
|
this.Terrain = terrain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Erode()
|
||||||
|
{
|
||||||
|
Initialize();
|
||||||
|
GenerateSprings();
|
||||||
|
|
||||||
|
for (int i = 0; i < IterationCount; i++)
|
||||||
|
NextIteration();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Initialize()
|
||||||
|
{
|
||||||
|
// Initialize matrices
|
||||||
|
water = new float[Terrain.Width, Terrain.Height];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateSprings()
|
||||||
|
{
|
||||||
|
// Step 1: Generate random points, which will be the water springs
|
||||||
|
springsX = new int[SpringCount];
|
||||||
|
springsY = new int[SpringCount];
|
||||||
|
|
||||||
|
for (int i = 0; i < SpringCount; i++)
|
||||||
|
{
|
||||||
|
springsX[i] = random.Next(0, Terrain.Width);
|
||||||
|
springsY[i] = random.Next(0, Terrain.Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Find local maximums, where the springs are placed
|
||||||
|
bool changed;
|
||||||
|
int iterations = 100;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
changed = false;
|
||||||
|
for (int i = 0; i < SpringCount; i++)
|
||||||
|
{
|
||||||
|
// Find best neighbour
|
||||||
|
float maxHeight = Terrain[springsX[i], springsY[i]];
|
||||||
|
int maxDir = 0;
|
||||||
|
|
||||||
|
ForEachDirection(springsX[i], springsY[i], (dx, dy, dir) =>
|
||||||
|
{
|
||||||
|
if (Terrain[dx, dy] >= maxHeight)
|
||||||
|
{
|
||||||
|
maxHeight = Terrain[dx, dy];
|
||||||
|
maxDir = dir;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (maxDir > 0)
|
||||||
|
{
|
||||||
|
springsX[i] += DirectionsX[maxDir];
|
||||||
|
springsY[i] += DirectionsY[maxDir];
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
--iterations;
|
||||||
|
} while (changed && iterations > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NextIteration()
|
||||||
|
{
|
||||||
|
Step1_RainAndErode();
|
||||||
|
Step2_MoveWater();
|
||||||
|
Step3_Evaporate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Step1_RainAndErode()
|
||||||
|
{
|
||||||
|
// Springs generate a lot of water
|
||||||
|
for (int i = 0; i < SpringCount; i++)
|
||||||
|
water[springsX[i], springsY[i]] += 100f;
|
||||||
|
|
||||||
|
// Rain in the rest of the terrain
|
||||||
|
for (int x = 0; x < Terrain.Width; x++)
|
||||||
|
for (int y = 0; y < Terrain.Height; y++)
|
||||||
|
{
|
||||||
|
water[x, y] += 1f;
|
||||||
|
|
||||||
|
// Erode some terrain
|
||||||
|
Terrain[x, y] -= ErosionAmount * water[x, y];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Step2_MoveWater()
|
||||||
|
{
|
||||||
|
for (int x = 0; x < Terrain.Width; x++)
|
||||||
|
for (int y = 0; y < Terrain.Height; y++)
|
||||||
|
{
|
||||||
|
List<int> directions = new List<int>();
|
||||||
|
|
||||||
|
// Find relevant directions
|
||||||
|
ForEachDirection(x, y, (dx, dy, dir) =>
|
||||||
|
{
|
||||||
|
if (Level(x, y) > Level(dx, dy))
|
||||||
|
directions.Add(dir);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Order directions by level
|
||||||
|
directions.Sort((dir1, dir2) =>
|
||||||
|
{
|
||||||
|
float level1 = Level(x + DirectionsX[dir1], y + DirectionsY[dir1]);
|
||||||
|
float level2 = Level(x + DirectionsX[dir2], y + DirectionsY[dir2]);
|
||||||
|
|
||||||
|
return Convert.ToInt32(100 * (level1 - level2));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Distribute water
|
||||||
|
for (int dirIndex = 0; dirIndex < directions.Count; dirIndex++)
|
||||||
|
{
|
||||||
|
int dir = directions[dirIndex];
|
||||||
|
|
||||||
|
// We distribute all the water equally to cells from
|
||||||
|
// directions 0..dir.
|
||||||
|
float distributeAmount = water[x, y] / (dirIndex + 1);
|
||||||
|
|
||||||
|
// If the resulting level is higher than the level of the next direction,
|
||||||
|
// we only add the level difference
|
||||||
|
if (dirIndex < directions.Count - 1)
|
||||||
|
{
|
||||||
|
int dx = x + DirectionsX[dir], dy = y + DirectionsY[dir];
|
||||||
|
int dx1 = x + DirectionsX[directions[dirIndex + 1]], dy1 = y + DirectionsY[directions[dirIndex + 1]];
|
||||||
|
|
||||||
|
distributeAmount = Math.Min(distributeAmount, Level(dx1, dy1) - Level(dx, dy));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Distribute water & sediment
|
||||||
|
for (int dirDistribIndex = 0; dirDistribIndex < dirIndex; dirDistribIndex++)
|
||||||
|
{
|
||||||
|
int dirDistrib = directions[dirDistribIndex];
|
||||||
|
water[x + DirectionsX[dirDistrib], y + DirectionsY[dirDistrib]] += distributeAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subtract from current cell
|
||||||
|
water[x, y] -= distributeAmount * (dirIndex + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Step3_Evaporate()
|
||||||
|
{
|
||||||
|
for (int x = 0; x < Terrain.Width; x++)
|
||||||
|
for (int y = 0; y < Terrain.Height; y++)
|
||||||
|
{
|
||||||
|
// Some sediment deposits
|
||||||
|
Terrain[x, y] += water[x, y] * ErosionAmount;
|
||||||
|
|
||||||
|
// Water evaporates
|
||||||
|
water[x, y] *= .5f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ForEachDirection(int x, int y, Action<int, int, int> action)
|
||||||
|
{
|
||||||
|
for (int dir = 1; dir < DirectionsX.Length; dir++)
|
||||||
|
{
|
||||||
|
int dx = x + DirectionsX[dir];
|
||||||
|
int dy = y + DirectionsY[dir];
|
||||||
|
|
||||||
|
if (Terrain.IsInside(dx, dy))
|
||||||
|
action(dx, dy, dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the soil + water level
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">x coordinate</param>
|
||||||
|
/// <param name="y">y coordinate</param>
|
||||||
|
/// <returns>level</returns>
|
||||||
|
private float Level(int x, int y)
|
||||||
|
{
|
||||||
|
return Terrain[x, y] + water[x, y];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,9 @@ namespace TransportGame.Generator
|
|||||||
{
|
{
|
||||||
public class TerrainGenerator
|
public class TerrainGenerator
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the underlying noise generator
|
||||||
|
/// </summary>
|
||||||
public NoiseGenerator Noise { get; set; }
|
public NoiseGenerator Noise { get; set; }
|
||||||
|
|
||||||
private System.Random random = new System.Random();
|
private System.Random random = new System.Random();
|
||||||
@ -50,8 +53,8 @@ namespace TransportGame.Generator
|
|||||||
DumpData(map, "1generated.map");
|
DumpData(map, "1generated.map");
|
||||||
|
|
||||||
// Simulate water erosion
|
// Simulate water erosion
|
||||||
//Erode(map);
|
new TerrainEroder(map).Erode();
|
||||||
//DumpData(map, "2eroded.map");
|
DumpData(map, "2eroded.map");
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
@ -68,16 +71,9 @@ namespace TransportGame.Generator
|
|||||||
{
|
{
|
||||||
for (int x = 0; x < map.Width; ++x)
|
for (int x = 0; x < map.Width; ++x)
|
||||||
for (int y = 0; y < map.Height; ++y)
|
for (int y = 0; y < map.Height; ++y)
|
||||||
map[x, y] = Noise.Generate(x, y, 0, 1);
|
map.Heights[x, y] = Noise.Generate(x, y, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//private void Erode(Map map)
|
|
||||||
//{
|
|
||||||
// float[,] water = new float[map.Width, map.Height];
|
|
||||||
|
|
||||||
|
|
||||||
//}
|
|
||||||
|
|
||||||
private void DumpData(Map map, string filename)
|
private void DumpData(Map map, string filename)
|
||||||
{
|
{
|
||||||
XmlSerializer serializer = new XmlSerializer(typeof(Map));
|
XmlSerializer serializer = new XmlSerializer(typeof(Map));
|
||||||
|
@ -20,5 +20,14 @@ namespace Assets.Scripts.Model.Config
|
|||||||
|
|
||||||
[XmlElement("waterNonLinearPower")]
|
[XmlElement("waterNonLinearPower")]
|
||||||
public float WaterNonLinearPower { get; set; }
|
public float WaterNonLinearPower { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("erodePoints")]
|
||||||
|
public int ErodePoints { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("erodeIterations")]
|
||||||
|
public int ErodeIterations { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("erodeAmountPercent")]
|
||||||
|
public float ErodeAmountPercent { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ namespace TransportGame.Model
|
|||||||
public Biome Biome { get; set; }
|
public Biome Biome { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the heights array
|
/// Gets the heights array in range [0,1]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[XmlIgnore()]
|
[XmlIgnore()]
|
||||||
public float[,] Heights
|
public float[,] Heights
|
||||||
@ -102,7 +102,7 @@ namespace TransportGame.Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the cell at specified position
|
/// Gets or sets the cell at specified position in range [0, Biome.Height]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="x">X</param>
|
/// <param name="x">X</param>
|
||||||
/// <param name="y">Y</param>
|
/// <param name="y">Y</param>
|
||||||
@ -112,11 +112,11 @@ namespace TransportGame.Model
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return grid[x, y];
|
return grid[x, y] * Biome.Height;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
grid[x, y] = value;
|
grid[x, y] = value / Biome.Height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,7 +140,18 @@ namespace TransportGame.Model
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public bool IsWater(int x, int y)
|
public bool IsWater(int x, int y)
|
||||||
{
|
{
|
||||||
return grid[x, y] * Biome.Height <= WaterLevel;
|
return this[x, y] <= WaterLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if given coordinates is inside the map
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="x">X</param>
|
||||||
|
/// <param name="y">Y</param>
|
||||||
|
/// <returns>True if coordinates are inside the map</returns>
|
||||||
|
public bool IsInside(int x, int y)
|
||||||
|
{
|
||||||
|
return x >= 0 && y >= 0 && x < Width && y < Height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ Global
|
|||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(MonoDevelopProperties) = preSolution
|
GlobalSection(MonoDevelopProperties) = preSolution
|
||||||
StartupItem = Assembly-CSharp.csproj
|
StartupItem = Assembly-CSharp.csproj
|
||||||
Policies = $0
|
Policies = $0
|
||||||
$0.TextStylePolicy = $1
|
$0.TextStylePolicy = $1
|
||||||
|
@ -29,7 +29,7 @@ Global
|
|||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(MonoDevelopProperties) = preSolution
|
GlobalSection(MonoDevelopProperties) = preSolution
|
||||||
StartupItem = Assembly-CSharp.csproj
|
StartupItem = Assembly-CSharp.csproj
|
||||||
Policies = $0
|
Policies = $0
|
||||||
$0.TextStylePolicy = $1
|
$0.TextStylePolicy = $1
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Game/Library/metadata/67/672be213b87b4064b8c12fe4e4ec29aa
Normal file
BIN
Game/Library/metadata/67/672be213b87b4064b8c12fe4e4ec29aa
Normal file
Binary file not shown.
BIN
Game/Library/metadata/67/672be213b87b4064b8c12fe4e4ec29aa.info
Normal file
BIN
Game/Library/metadata/67/672be213b87b4064b8c12fe4e4ec29aa.info
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,3 +1,9 @@
|
|||||||
Base path: E:/SDKs/Unity/Editor/Data
|
Base path: E:/SDKs/Unity/Editor/Data
|
||||||
Pipe name: \\.\pipe\UnityShaderCompiler-32bit-1-4308
|
Pipe name: \\.\pipe\UnityShaderCompiler-32bit-1-5636
|
||||||
Cmd: getPlatforms
|
Cmd: getPlatforms
|
||||||
|
Unhandled exception: Readfile from pipe failed. GLE=The pipe has been ended.
|
||||||
|
|
||||||
|
|
||||||
|
Quitting shader compiler process
|
||||||
|
|
||||||
|
Crashed!
|
||||||
|
@ -1,7 +1,3 @@
|
|||||||
Base path: E:/SDKs/Unity/Editor/Data
|
Base path: E:/SDKs/Unity/Editor/Data
|
||||||
Pipe name: \\.\pipe\UnityShaderCompiler-64bit-1-4308
|
Pipe name: \\.\pipe\UnityShaderCompiler-64bit-1-5636
|
||||||
Cmd: getPlatforms
|
Cmd: getPlatforms
|
||||||
Cmd: compileSnippet
|
|
||||||
api=4 type=0 insize=14871 outsize=3492 kw=DIRECTIONAL SHADOWS_OFF LIGHTMAP_OFF DIRLIGHTMAP_OFF DYNAMICLIGHTMAP_OFF ok=1
|
|
||||||
Cmd: compileSnippet
|
|
||||||
api=4 type=1 insize=14871 outsize=10090 kw=DIRECTIONAL SHADOWS_OFF LIGHTMAP_OFF DIRLIGHTMAP_OFF DYNAMICLIGHTMAP_OFF ok=1
|
|
||||||
|
@ -67,6 +67,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Assets\Scripts\Business\BiomeManager.cs" />
|
<Compile Include="Assets\Scripts\Business\BiomeManager.cs" />
|
||||||
<Compile Include="Assets\Scripts\Business\ConfigurationManager.cs" />
|
<Compile Include="Assets\Scripts\Business\ConfigurationManager.cs" />
|
||||||
|
<Compile Include="Assets\Scripts\Generator\TerrainEroder.cs" />
|
||||||
<Compile Include="Assets\Scripts\Generator\TerrainGenerator.cs" />
|
<Compile Include="Assets\Scripts\Generator\TerrainGenerator.cs" />
|
||||||
<Compile Include="Assets\Scripts\InitializeScript.cs" />
|
<Compile Include="Assets\Scripts\InitializeScript.cs" />
|
||||||
<Compile Include="Assets\Scripts\Model\Biome.cs" />
|
<Compile Include="Assets\Scripts\Model\Biome.cs" />
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -79,7 +79,7 @@ namespace TransportGame.MapViewer
|
|||||||
// Draw elevation
|
// Draw elevation
|
||||||
else if (elevation)
|
else if (elevation)
|
||||||
{
|
{
|
||||||
float alpha = map[mapX, mapY]; // map height range is [0,1]
|
float alpha = map.Heights[mapX, mapY]; // map.Heights range is [0,1]
|
||||||
bitmap[x, y] = Color.Multiply(ElevationTerrainColor, alpha);
|
bitmap[x, y] = Color.Multiply(ElevationTerrainColor, alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user