Fixed unity terrain generation bug.

This commit is contained in:
Tiberiu Chibici 2015-03-19 12:34:58 +02:00
parent 8f9f935796
commit 68140b11a7
40 changed files with 326 additions and 245 deletions

6
.gitignore vendored
View File

@ -1,5 +1,7 @@
## Ignore Visual Studio temporary files, build results, and # Logs
## files generated by popular Visual Studio add-ons. Game/Logs/
Game/[Oo]bj/
Game/[Tt]emp/
# User-specific files # User-specific files
*.suo *.suo

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<biome> <biome>
<name>Grassland</name> <name>Grassland</name>
<heightRange min="0" max="10" /> <height>100</height>
<moisture min=".1" max=".5"/> <moisture min=".1" max=".5"/>
<vegetationDensity min=".2" max=".5" /> <vegetationDensity min=".2" max=".5" />
</biome> </biome>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<biome> <biome>
<name>Mountain</name> <name>Mountain</name>
<heightRange min="0" max="500" /> <height>500</height>
<moisture min=".1" max=".3"/> <moisture min=".1" max=".3"/>
<vegetationDensity min=".5" max=".9" /> <vegetationDensity min=".5" max=".9" />
</biome> </biome>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<terrgenConfig> <terrgenConfig>
<noiseOctaves>8</noiseOctaves> <noiseOctaves>9</noiseOctaves>
<noiseNonLinearPower>2</noiseNonLinearPower> <noiseNonLinearPower>2.4</noiseNonLinearPower>
<waterNonLinearPower>1.3</waterNonLinearPower> <waterNonLinearPower>1.9</waterNonLinearPower>
<elevationScale>0.01</elevationScale> <elevationScale>0.0005</elevationScale>
</terrgenConfig> </terrgenConfig>

Binary file not shown.

View File

@ -45,10 +45,14 @@ namespace TransportGame.Generator
// Generate water level // Generate water level
float waterAmount = random.NextSingle(map.Biome.Moisture.Minimum, map.Biome.Moisture.Maximum); float waterAmount = random.NextSingle(map.Biome.Moisture.Minimum, map.Biome.Moisture.Maximum);
map.WaterLevel = Mathf.Pow(waterAmount, ConfigurationManager.TerrGenConfig.WaterNonLinearPower) map.WaterLevel = Mathf.Pow(waterAmount, ConfigurationManager.TerrGenConfig.WaterNonLinearPower) * map.Biome.Height;
* (map.Biome.HeightRange.Maximum - map.Biome.HeightRange.Minimum) + map.Biome.HeightRange.Minimum;
DumpData(map, "1generated.map");
// Simulate water erosion
//Erode(map);
//DumpData(map, "2eroded.map");
DumpData(map);
return map; return map;
} }
@ -64,14 +68,21 @@ 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, map.Biome.HeightRange.Minimum, map.Biome.HeightRange.Maximum); map[x, y] = Noise.Generate(x, y, 0, 1);
} }
private void DumpData(Map map) //private void Erode(Map map)
//{
// float[,] water = new float[map.Width, map.Height];
//}
private void DumpData(Map map, string filename)
{ {
XmlSerializer serializer = new XmlSerializer(typeof(Map)); XmlSerializer serializer = new XmlSerializer(typeof(Map));
using (StreamWriter writer = new StreamWriter(Path.Combine(Logger.LogsDirectory, "mapdump.map"))) using (StreamWriter writer = new StreamWriter(Path.Combine(Logger.LogsDirectory, filename)))
{ {
serializer.Serialize(writer, map); serializer.Serialize(writer, map);
writer.Close(); writer.Close();

View File

@ -17,13 +17,13 @@ namespace TransportGame.Model
public string Name { get; set; } public string Name { get; set; }
/// <summary> /// <summary>
/// Gets or sets the height range of the biome. /// Gets or sets the maximum height of the biome.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// 1 unit = 100 meters. /// 1 unit = 100 meters.
/// </remarks> /// </remarks>
[XmlElement("heightRange")] [XmlElement("height")]
public Range HeightRange { get; set; } public float Height { get; set; }
/// <summary> /// <summary>
/// Gets or sets the moisture range. /// Gets or sets the moisture range.

View File

@ -140,7 +140,7 @@ 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] <= WaterLevel; return grid[x, y] * Biome.Height <= WaterLevel;
} }
} }
} }

View File

@ -56,8 +56,8 @@ public class TerrainGeneratorScript : MonoBehaviour
// Generate terrain data // Generate terrain data
TerrainData terrainData = new TerrainData(); TerrainData terrainData = new TerrainData();
terrainData.heightmapResolution = Mathf.Max(map.Height, map.Width); terrainData.heightmapResolution = Mathf.Max(map.Height, map.Width) + 1;
terrainData.size = new Vector3(map.Width, map.Biome.HeightRange.Maximum, map.Height); terrainData.size = new Vector3(map.Width, map.Biome.Height, map.Height);
terrainData.SetDetailResolution(1024, 8); terrainData.SetDetailResolution(1024, 8);
terrainData.SetHeights(0, 0, map.Heights); terrainData.SetHeights(0, 0, map.Heights);
terrainData.name = "Generated Terrain Data"; terrainData.name = "Generated Terrain Data";

Binary file not shown.

Binary file not shown.

View File

@ -1,9 +1,3 @@
Base path: E:/SDKs/Unity/Editor/Data Base path: E:/SDKs/Unity/Editor/Data
Pipe name: \\.\pipe\UnityShaderCompiler-32bit-1-3856 Pipe name: \\.\pipe\UnityShaderCompiler-32bit-1-4308
Cmd: getPlatforms Cmd: getPlatforms
Unhandled exception: Readfile from pipe failed. GLE=The pipe has been ended.
Quitting shader compiler process
Crashed!

View File

@ -1,3 +1,7 @@
Base path: E:/SDKs/Unity/Editor/Data Base path: E:/SDKs/Unity/Editor/Data
Pipe name: \\.\pipe\UnityShaderCompiler-64bit-1-3856 Pipe name: \\.\pipe\UnityShaderCompiler-64bit-1-4308
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

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using TransportGame.MapViewer.Model;
namespace TransportGame.MapViewer.Business
{
public static class BitmapExtensions
{
/// <summary>
/// Gets a wpf bitmap source from a bitmap.
/// </summary>
/// <param name="this">The bitmap</param>
/// <returns>The bitmap source</returns>
public static BitmapSource ToBitmapSource(this Bitmap24 @this)
{
return BitmapSource.Create(@this.Width, @this.Height,
96, 96, PixelFormats.Rgb24, null, @this.Raw, @this.Width * 3);
}
}
}

View File

@ -1,11 +1,6 @@
using System; using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using TransportGame.MapViewer.Model;
using TransportGame.Model; using TransportGame.Model;
namespace TransportGame.MapViewer namespace TransportGame.MapViewer
@ -23,8 +18,8 @@ namespace TransportGame.MapViewer
/// <summary> /// <summary>
/// Gets or sets the scale /// Gets or sets the scale
/// </summary> /// </summary>
private int _scale; private float _scale;
public int Scale public float Scale
{ {
get get
{ {
@ -45,7 +40,7 @@ namespace TransportGame.MapViewer
public MapRenderer() public MapRenderer()
{ {
Scale = 4; Scale = 1;
} }
///<summary> ///<summary>
@ -54,72 +49,46 @@ namespace TransportGame.MapViewer
///<param name="file"></param> ///<param name="file"></param>
///<param name="map"></param> ///<param name="map"></param>
///<param name="layers"></param> ///<param name="layers"></param>
public Color[,] Render(Map map, Layers layers = Layers.All) public Bitmap24 Render(Map map, Layers layers = Layers.All)
{ {
lock (this) lock (this)
{ {
// Create texture on which to draw // Create texture on which to draw
Color[,] pixels = new Color[map.Width * Scale, map.Height * Scale]; Bitmap24 bitmap = new Bitmap24(Convert.ToInt32(map.Width * Scale), Convert.ToInt32(map.Height * Scale));
// First layer - cells // First layer - cells
DrawCells(pixels, map, (layers & Layers.Elevation) > 0); DrawCells(bitmap, map, (layers & Layers.Elevation) > 0);
// Done // Done
return pixels; return bitmap;
} }
} }
private void DrawCells(Color[,] pixels, Map map, bool elevation) private void DrawCells(Bitmap24 bitmap, Map map, bool elevation)
{ {
for (int x = 0; x < pixels.GetLength(0); x++) for (int x = 0; x < bitmap.Width; x++)
for (int y = 0; y < pixels.GetLength(1); y++) for (int y = 0; y < bitmap.Height; y++)
{ {
int mapX = x / Scale; int mapX = Convert.ToInt32(x / Scale);
int mapY = y / Scale; int mapY = Convert.ToInt32(y / Scale);
// Draw water // Draw water
if (map.IsWater(mapX, mapY)) if (map.IsWater(mapX, mapY))
pixels[x, y] = WaterColor; bitmap[x, y] = WaterColor;
// Draw elevation // Draw elevation
else if (elevation) else if (elevation)
{ {
float alpha = (map[mapX, mapY] - map.Biome.HeightRange.Minimum) / (map.Biome.HeightRange.Maximum - map.Biome.HeightRange.Minimum); float alpha = map[mapX, mapY]; // map height range is [0,1]
pixels[x, y] = Color.Multiply(ElevationTerrainColor, alpha); bitmap[x, y] = Color.Multiply(ElevationTerrainColor, alpha);
} }
// Draw terrain // Draw terrain
else else
{ {
pixels[x, y] = TerrainColor; bitmap[x, y] = TerrainColor;
} }
} }
} }
public async Task<BitmapSource> RenderToImageSource(Map map, Layers layers = Layers.All)
{
var colors = await Task.Run(() => Render(map, layers));
colors[0, 0] = Colors.Red;
colors[colors.GetLength(0) - 1, 0] = Colors.Red;
// Convert to raw pixels
byte[] raw = new byte[colors.GetLength(0) * colors.GetLength(1) * 3];
for (int x = 0; x < colors.GetLength(0); x++)
for (int y = 0; y < colors.GetLength(1); y++)
{
int pixelIndex = x + y * colors.GetLength(0);
raw[3 * pixelIndex] = colors[x, y].R;
raw[3 * pixelIndex + 1] = colors[x, y].G;
raw[3 * pixelIndex + 2] = colors[x, y].B;
}
// Create bitmap source
BitmapSource bmp = BitmapSource.Create(colors.GetLength(0), colors.GetLength(1),
96, 96, PixelFormats.Rgb24, null, raw, colors.GetLength(0) * 3);
return bmp;
}
} }
} }

View File

@ -21,6 +21,7 @@
<Button Name="buttonSave" ToolTip="Saves as image" Click="buttonSave_Click"> <Button Name="buttonSave" ToolTip="Saves as image" Click="buttonSave_Click">
<Image Source="pack://application:,,,/Resources/picture_save.png" /> <Image Source="pack://application:,,,/Resources/picture_save.png" />
</Button> </Button>
<Separator /> <Separator />
<Button Name="buttonZoomIn" ToolTip="Zoom in" Click="buttonZoomIn_Click"> <Button Name="buttonZoomIn" ToolTip="Zoom in" Click="buttonZoomIn_Click">
@ -31,7 +32,7 @@
</Button> </Button>
<TextBlock VerticalAlignment="Center"> <TextBlock VerticalAlignment="Center">
<Run Text="{Binding ZoomLevel}" /><Run>00%</Run> <Run Text="{Binding ZoomLevel}" /><Run>%</Run>
</TextBlock> </TextBlock>
</ToolBar> </ToolBar>
@ -114,8 +115,8 @@
<TextBlock Grid.Row="0" Grid.Column="0" >Name:</TextBlock> <TextBlock Grid.Row="0" Grid.Column="0" >Name:</TextBlock>
<TextBox Grid.Row="0" Grid.Column="1" IsReadOnly="True" Text="{Binding Map.Biome.Name,Mode=OneWay}" /> <TextBox Grid.Row="0" Grid.Column="1" IsReadOnly="True" Text="{Binding Map.Biome.Name,Mode=OneWay}" />
<TextBlock Grid.Row="1" Grid.Column="0" >Height range:</TextBlock> <TextBlock Grid.Row="1" Grid.Column="0" >Height:</TextBlock>
<TextBox Grid.Row="1" Grid.Column="1" IsReadOnly="True" Text="{Binding Map.Biome.HeightRange,Mode=OneWay}" /> <TextBox Grid.Row="1" Grid.Column="1" IsReadOnly="True" Text="{Binding Map.Biome.Height,Mode=OneWay}" />
<TextBlock Grid.Row="2" Grid.Column="0" >Moisture:</TextBlock> <TextBlock Grid.Row="2" Grid.Column="0" >Moisture:</TextBlock>
<TextBox Grid.Row="2" Grid.Column="1" IsReadOnly="True" Text="{Binding Map.Biome.Moisture,Mode=OneWay}" /> <TextBox Grid.Row="2" Grid.Column="1" IsReadOnly="True" Text="{Binding Map.Biome.Moisture,Mode=OneWay}" />

View File

@ -5,6 +5,7 @@ using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using Microsoft.Win32; using Microsoft.Win32;
using TransportGame.MapViewer.Business;
using TransportGame.MapViewer.Storage; using TransportGame.MapViewer.Storage;
using TransportGame.Model; using TransportGame.Model;
@ -152,15 +153,15 @@ namespace TransportGame.MapViewer
/// <summary> /// <summary>
/// Gets or sets the zoom level /// Gets or sets the zoom level
/// </summary> /// </summary>
public int ZoomLevel public float ZoomLevel
{ {
get get
{ {
return Renderer.Scale; return Renderer.Scale * 100f;
} }
set set
{ {
Renderer.Scale = value; Renderer.Scale = value / 100f;
if (PropertyChanged != null) if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("ZoomLevel")); PropertyChanged(this, new PropertyChangedEventArgs("ZoomLevel"));
} }
@ -215,7 +216,8 @@ namespace TransportGame.MapViewer
try try
{ {
RenderedMap = await Renderer.RenderToImageSource(Map, _layers); var renderResult = await Task.Run(() => Renderer.Render(Map, _layers));
RenderedMap = renderResult.ToBitmapSource();
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -260,10 +262,10 @@ namespace TransportGame.MapViewer
private async void buttonZoomIn_Click(object sender, RoutedEventArgs e) private async void buttonZoomIn_Click(object sender, RoutedEventArgs e)
{ {
// Zoom // Zoom
ZoomLevel++; ZoomLevel *= 2;
// Update IsEnabled // Update IsEnabled
if (ZoomLevel >= 10) if (ZoomLevel >= 400)
buttonZoomIn.IsEnabled = false; buttonZoomIn.IsEnabled = false;
buttonZoomOut.IsEnabled = true; buttonZoomOut.IsEnabled = true;
@ -275,10 +277,10 @@ namespace TransportGame.MapViewer
private async void buttonZoomOut_Click(object sender, RoutedEventArgs e) private async void buttonZoomOut_Click(object sender, RoutedEventArgs e)
{ {
// Zoom // Zoom
ZoomLevel--; ZoomLevel /=2;
// Update IsEnabled // Update IsEnabled
if (ZoomLevel <= 1) if (ZoomLevel <= 10)
buttonZoomOut.IsEnabled = false; buttonZoomOut.IsEnabled = false;
buttonZoomIn.IsEnabled = true; buttonZoomIn.IsEnabled = true;
@ -334,6 +336,5 @@ namespace TransportGame.MapViewer
} }
#endregion #endregion
} }
} }

View File

@ -59,6 +59,8 @@
<Compile Include="..\..\..\Game\Assets\Scripts\Model\Map.cs"> <Compile Include="..\..\..\Game\Assets\Scripts\Model\Map.cs">
<Link>Model\Map.cs</Link> <Link>Model\Map.cs</Link>
</Compile> </Compile>
<Compile Include="Business\BitmapExtensions.cs" />
<Compile Include="Model\Bitmap24.cs" />
<Compile Include="Storage\MapStorage.cs" /> <Compile Include="Storage\MapStorage.cs" />
<Page Include="MainWindow.xaml"> <Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>

View File

@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
namespace TransportGame.MapViewer.Model
{
public class Bitmap24
{
/// <summary>
/// Gets the width of the bitmap
/// </summary>
public int Width { get; private set; }
/// <summary>
/// Gets the height of the bitmap
/// </summary>
public int Height { get; private set; }
/// <summary>
/// Gets the raw bytes of the bitmap
/// </summary>
public byte[] Raw { get; private set; }
/// <summary>
/// Initializes a bitmap
/// </summary>
/// <param name="w"></param>
/// <param name="h"></param>
public Bitmap24(int w, int h)
{
Width = w;
Height = h;
Raw = new byte[w * h * 3];
}
/// <summary>
/// Gets or sets a pixel
/// </summary>
/// <param name="x">x coordinate of pixel</param>
/// <param name="y">y coordinate of pixel</param>
public Color this[int x, int y]
{
get
{
int index = RawIndexOf(x, y);
return Color.FromRgb(Raw[index], Raw[index + 1], Raw[index + 2]);
}
set
{
int index = RawIndexOf(x, y);
Raw[index] = value.R;
Raw[index + 1] = value.G;
Raw[index + 2] = value.B;
}
}
private int RawIndexOf(int x, int y)
{
if (x < 0 || x >= Width)
throw new ArgumentOutOfRangeException("x is out of range");
if (y < 0 || y >= Height)
throw new ArgumentOutOfRangeException("x is out of range");
return 3 * (x + y * Width);
}
}
}