Implemented road & road mesh generator.
This commit is contained in:
parent
61a05289d3
commit
f9b20b0226
@ -66,6 +66,7 @@
|
|||||||
<Compile Include="Assets\Scripts\Noise\NoiseGenerator.cs" />
|
<Compile Include="Assets\Scripts\Noise\NoiseGenerator.cs" />
|
||||||
<Compile Include="Assets\Scripts\Noise\PerlinNoiseGenerator.cs" />
|
<Compile Include="Assets\Scripts\Noise\PerlinNoiseGenerator.cs" />
|
||||||
<Compile Include="Assets\Scripts\Unity\InitializeScript.cs" />
|
<Compile Include="Assets\Scripts\Unity\InitializeScript.cs" />
|
||||||
|
<Compile Include="Assets\Scripts\Unity\RoadMeshGenerator.cs" />
|
||||||
<Compile Include="Assets\Scripts\Unity\TerrainGeneratorScript.cs" />
|
<Compile Include="Assets\Scripts\Unity\TerrainGeneratorScript.cs" />
|
||||||
<Compile Include="Assets\Scripts\Utils\Algorithms.cs" />
|
<Compile Include="Assets\Scripts\Utils\Algorithms.cs" />
|
||||||
<Compile Include="Assets\Scripts\Utils\Algorithms\GridTraverseAlgorithm.cs" />
|
<Compile Include="Assets\Scripts\Utils\Algorithms\GridTraverseAlgorithm.cs" />
|
||||||
|
@ -66,6 +66,7 @@
|
|||||||
<Compile Include="Assets\Scripts\Noise\NoiseGenerator.cs" />
|
<Compile Include="Assets\Scripts\Noise\NoiseGenerator.cs" />
|
||||||
<Compile Include="Assets\Scripts\Noise\PerlinNoiseGenerator.cs" />
|
<Compile Include="Assets\Scripts\Noise\PerlinNoiseGenerator.cs" />
|
||||||
<Compile Include="Assets\Scripts\Unity\InitializeScript.cs" />
|
<Compile Include="Assets\Scripts\Unity\InitializeScript.cs" />
|
||||||
|
<Compile Include="Assets\Scripts\Unity\RoadMeshGenerator.cs" />
|
||||||
<Compile Include="Assets\Scripts\Unity\TerrainGeneratorScript.cs" />
|
<Compile Include="Assets\Scripts\Unity\TerrainGeneratorScript.cs" />
|
||||||
<Compile Include="Assets\Scripts\Utils\Algorithms.cs" />
|
<Compile Include="Assets\Scripts\Utils\Algorithms.cs" />
|
||||||
<Compile Include="Assets\Scripts\Utils\Algorithms\GridTraverseAlgorithm.cs" />
|
<Compile Include="Assets\Scripts\Utils\Algorithms\GridTraverseAlgorithm.cs" />
|
||||||
|
@ -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>
|
||||||
<height>500</height>
|
<height>400</height>
|
||||||
<moisture min=".1" max=".3"/>
|
<moisture min=".1" max=".3"/>
|
||||||
<vegetationDensity min=".5" max=".9" />
|
<vegetationDensity min=".5" max=".9" />
|
||||||
<textures>
|
<textures>
|
||||||
|
9
Game/Assets/Data/Materials.meta
Normal file
9
Game/Assets/Data/Materials.meta
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6fed1937e656c34458559bd2469f5455
|
||||||
|
folderAsset: yes
|
||||||
|
timeCreated: 1433236765
|
||||||
|
licenseType: Free
|
||||||
|
DefaultImporter:
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
BIN
Game/Assets/Data/Materials/sidewalk.mat
Normal file
BIN
Game/Assets/Data/Materials/sidewalk.mat
Normal file
Binary file not shown.
8
Game/Assets/Data/Materials/sidewalk.mat.meta
Normal file
8
Game/Assets/Data/Materials/sidewalk.mat.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ddd2e09300d67f041977284f4d24a0c9
|
||||||
|
timeCreated: 1433236871
|
||||||
|
licenseType: Free
|
||||||
|
NativeFormatImporter:
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
BIN
Game/Assets/Data/Materials/skybox.mat
Normal file
BIN
Game/Assets/Data/Materials/skybox.mat
Normal file
Binary file not shown.
8
Game/Assets/Data/Materials/skybox.mat.meta
Normal file
8
Game/Assets/Data/Materials/skybox.mat.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bf5942f32f0096844add5527185930f0
|
||||||
|
timeCreated: 1433257206
|
||||||
|
licenseType: Free
|
||||||
|
NativeFormatImporter:
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
BIN
Game/Assets/Data/Materials/street.mat
Normal file
BIN
Game/Assets/Data/Materials/street.mat
Normal file
Binary file not shown.
8
Game/Assets/Data/Materials/street.mat.meta
Normal file
8
Game/Assets/Data/Materials/street.mat.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c62816e268432f840b564c961363e771
|
||||||
|
timeCreated: 1433236770
|
||||||
|
licenseType: Free
|
||||||
|
NativeFormatImporter:
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
BIN
Game/Assets/Data/Textures/sidewalk.jpg
Normal file
BIN
Game/Assets/Data/Textures/sidewalk.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 455 KiB |
55
Game/Assets/Data/Textures/sidewalk.jpg.meta
Normal file
55
Game/Assets/Data/Textures/sidewalk.jpg.meta
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ea607de0299a0a54a8650b9ca86fa298
|
||||||
|
timeCreated: 1433235814
|
||||||
|
licenseType: Free
|
||||||
|
TextureImporter:
|
||||||
|
fileIDToRecycleName: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
mipmaps:
|
||||||
|
mipMapMode: 0
|
||||||
|
enableMipMap: 1
|
||||||
|
linearTexture: 0
|
||||||
|
correctGamma: 0
|
||||||
|
fadeOut: 0
|
||||||
|
borderMipMap: 0
|
||||||
|
mipMapFadeDistanceStart: 1
|
||||||
|
mipMapFadeDistanceEnd: 3
|
||||||
|
bumpmap:
|
||||||
|
convertToNormalMap: 0
|
||||||
|
externalNormalMap: 0
|
||||||
|
heightScale: .25
|
||||||
|
normalMapFilter: 0
|
||||||
|
isReadable: 0
|
||||||
|
grayScaleToAlpha: 0
|
||||||
|
generateCubemap: 0
|
||||||
|
cubemapConvolution: 0
|
||||||
|
cubemapConvolutionSteps: 8
|
||||||
|
cubemapConvolutionExponent: 1.5
|
||||||
|
seamlessCubemap: 0
|
||||||
|
textureFormat: -1
|
||||||
|
maxTextureSize: 2048
|
||||||
|
textureSettings:
|
||||||
|
filterMode: -1
|
||||||
|
aniso: -1
|
||||||
|
mipBias: -1
|
||||||
|
wrapMode: -1
|
||||||
|
nPOTScale: 1
|
||||||
|
lightmap: 0
|
||||||
|
rGBM: 0
|
||||||
|
compressionQuality: 50
|
||||||
|
spriteMode: 0
|
||||||
|
spriteExtrude: 1
|
||||||
|
spriteMeshType: 1
|
||||||
|
alignment: 0
|
||||||
|
spritePivot: {x: .5, y: .5}
|
||||||
|
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
spritePixelsToUnits: 100
|
||||||
|
alphaIsTransparency: 0
|
||||||
|
textureType: -1
|
||||||
|
buildTargetSettings: []
|
||||||
|
spriteSheet:
|
||||||
|
sprites: []
|
||||||
|
spritePackingTag:
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
BIN
Game/Assets/Data/Textures/street.gif
Normal file
BIN
Game/Assets/Data/Textures/street.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 356 KiB |
55
Game/Assets/Data/Textures/street.gif.meta
Normal file
55
Game/Assets/Data/Textures/street.gif.meta
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5db8f6cba4795374c8d741df2458d00e
|
||||||
|
timeCreated: 1433235809
|
||||||
|
licenseType: Free
|
||||||
|
TextureImporter:
|
||||||
|
fileIDToRecycleName: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
mipmaps:
|
||||||
|
mipMapMode: 0
|
||||||
|
enableMipMap: 1
|
||||||
|
linearTexture: 0
|
||||||
|
correctGamma: 0
|
||||||
|
fadeOut: 0
|
||||||
|
borderMipMap: 0
|
||||||
|
mipMapFadeDistanceStart: 1
|
||||||
|
mipMapFadeDistanceEnd: 3
|
||||||
|
bumpmap:
|
||||||
|
convertToNormalMap: 0
|
||||||
|
externalNormalMap: 0
|
||||||
|
heightScale: .25
|
||||||
|
normalMapFilter: 0
|
||||||
|
isReadable: 0
|
||||||
|
grayScaleToAlpha: 0
|
||||||
|
generateCubemap: 0
|
||||||
|
cubemapConvolution: 0
|
||||||
|
cubemapConvolutionSteps: 8
|
||||||
|
cubemapConvolutionExponent: 1.5
|
||||||
|
seamlessCubemap: 0
|
||||||
|
textureFormat: -1
|
||||||
|
maxTextureSize: 2048
|
||||||
|
textureSettings:
|
||||||
|
filterMode: -1
|
||||||
|
aniso: -1
|
||||||
|
mipBias: -1
|
||||||
|
wrapMode: -1
|
||||||
|
nPOTScale: 1
|
||||||
|
lightmap: 0
|
||||||
|
rGBM: 0
|
||||||
|
compressionQuality: 50
|
||||||
|
spriteMode: 0
|
||||||
|
spriteExtrude: 1
|
||||||
|
spriteMeshType: 1
|
||||||
|
alignment: 0
|
||||||
|
spritePivot: {x: .5, y: .5}
|
||||||
|
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
spritePixelsToUnits: 100
|
||||||
|
alphaIsTransparency: 0
|
||||||
|
textureType: -1
|
||||||
|
buildTargetSettings: []
|
||||||
|
spriteSheet:
|
||||||
|
sprites: []
|
||||||
|
spritePackingTag:
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
Binary file not shown.
@ -55,7 +55,7 @@ namespace TransportGame.Generator
|
|||||||
const float DefaultBranchProbability = 0.2f;
|
const float DefaultBranchProbability = 0.2f;
|
||||||
const float DefaultSegmentLength = 24;
|
const float DefaultSegmentLength = 24;
|
||||||
const float SteepnessLimit = 10;
|
const float SteepnessLimit = 10;
|
||||||
const float SlopeLimit = (float)Math.PI / 6;
|
const float SlopeLimit = (float)Math.PI / 7;
|
||||||
const float RoadSegmentAngleLimit = (float)Math.PI / 4;
|
const float RoadSegmentAngleLimit = (float)Math.PI / 4;
|
||||||
const float RoadSnapDistance = 19;
|
const float RoadSnapDistance = 19;
|
||||||
const float MinNodeDistance = 12;
|
const float MinNodeDistance = 12;
|
||||||
@ -154,7 +154,7 @@ namespace TransportGame.Generator
|
|||||||
private IEnumerable<RoadGeneratorSegment> GlobalGoals(RoadSegment segment)
|
private IEnumerable<RoadGeneratorSegment> GlobalGoals(RoadSegment segment)
|
||||||
{
|
{
|
||||||
Vector2 prevPos = segment.Terminal2.Position;
|
Vector2 prevPos = segment.Terminal2.Position;
|
||||||
Vector2 dir = (segment.Terminal2.Position - segment.Terminal1.Position).Normalized;
|
Vector2 dir = segment.Direction;
|
||||||
bool highway = (segment.LanesTo1 >= 3);
|
bool highway = (segment.LanesTo1 >= 3);
|
||||||
bool highwayBranched = false;
|
bool highwayBranched = false;
|
||||||
|
|
||||||
@ -258,18 +258,14 @@ namespace TransportGame.Generator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Filter & sort the segments by distance
|
// Filter & sort the segments by distance
|
||||||
segmentIds = segmentIds.Distinct().OrderBy(id =>
|
segmentIds = segmentIds.Distinct().OrderBy(id =>
|
||||||
{
|
LineSegment.Distance(map.RoadNetwork.ArticulationSegments[id].AsLineSegment(), segment.Terminal2Pos));
|
||||||
var seg = map.RoadNetwork.ArticulationSegments[id];
|
|
||||||
var line = new LineSegment(seg.Terminal1.Position, seg.Terminal2.Position);
|
|
||||||
return LineSegment.Distance(line, segment.Terminal2Pos);
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var segmentId in segmentIds)
|
foreach (var segmentId in segmentIds)
|
||||||
{
|
{
|
||||||
var other = map.RoadNetwork.ArticulationSegments[segmentId];
|
var other = map.RoadNetwork.ArticulationSegments[segmentId];
|
||||||
var line1 = new LineSegment(segment.Terminal1.Position, segment.Terminal2Pos);
|
var line1 = new LineSegment(segment.Terminal1.Position, segment.Terminal2Pos);
|
||||||
var line2 = new LineSegment(other.Terminal1.Position, other.Terminal2.Position);
|
var line2 = other.AsLineSegment();
|
||||||
|
|
||||||
Vector2? inters = LineSegment.Intersect(line1, line2);
|
Vector2? inters = LineSegment.Intersect(line1, line2);
|
||||||
|
|
||||||
@ -294,7 +290,7 @@ namespace TransportGame.Generator
|
|||||||
// Check angle between intersecting segments
|
// Check angle between intersecting segments
|
||||||
foreach (var intersSeg in other.Terminal2.ArticulationSegments)
|
foreach (var intersSeg in other.Terminal2.ArticulationSegments)
|
||||||
{
|
{
|
||||||
float cos = Vector2.Dot((line1.P1 - line1.P0).Normalized, (intersSeg.Terminal2.Position - intersSeg.Terminal1.Position).Normalized);
|
float cos = Vector2.Dot(line1.Direction, intersSeg.Direction);
|
||||||
if (Math.Abs(Math.Acos(cos)) < RoadSegmentAngleLimit)
|
if (Math.Abs(Math.Acos(cos)) < RoadSegmentAngleLimit)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,14 @@ namespace TransportGame.Model
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Vector2 Direction
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (P1 - P0).Normalized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public LineSegment(Vector2 p0, Vector2 p1)
|
public LineSegment(Vector2 p0, Vector2 p1)
|
||||||
: this()
|
: this()
|
||||||
{
|
{
|
||||||
|
@ -80,6 +80,33 @@ namespace TransportGame.Model.Road
|
|||||||
[XmlAttribute("lanesTo1")]
|
[XmlAttribute("lanesTo1")]
|
||||||
public int LanesTo1 { get; set; }
|
public int LanesTo1 { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the direction vector of this road segment
|
||||||
|
/// </summary>
|
||||||
|
[XmlIgnore]
|
||||||
|
public Vector2 Direction
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Terminal1Id == -1 || Terminal2Id == -1 || ParentNetwork == null)
|
||||||
|
return Vector2.Zero;
|
||||||
|
|
||||||
|
return (Terminal2.Position - Terminal1.Position).Normalized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the road segment as a line segment
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public LineSegment AsLineSegment()
|
||||||
|
{
|
||||||
|
if (Terminal1Id == -1 || Terminal2Id == -1 || ParentNetwork == null)
|
||||||
|
throw new InvalidOperationException("Terminals are not initialized.");
|
||||||
|
|
||||||
|
return new LineSegment(Terminal1.Position, Terminal2.Position);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes road segment
|
/// Initializes road segment
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -78,6 +78,22 @@ namespace TransportGame.Model
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the normalized vector raised to second power
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This is less computationally expensive (no need to calculate square root).
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns>Normalized vector</returns>
|
||||||
|
public Vector2 NormalizedSq
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
float len2 = LengthSq;
|
||||||
|
return new Vector2(X * X / len2, Y * Y / len2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Rotates vector by given number of radians
|
/// Rotates vector by given number of radians
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -123,6 +139,16 @@ namespace TransportGame.Model
|
|||||||
return new Vector2(a.X - b.X, a.Y - b.Y);
|
return new Vector2(a.X - b.X, a.Y - b.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Negation operator
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">Vector</param>
|
||||||
|
/// <returns>Negated vector</returns>
|
||||||
|
public static Vector2 operator -(Vector2 a)
|
||||||
|
{
|
||||||
|
return new Vector2(-a.X, -a.Y);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Multiply by constant
|
/// Multiply by constant
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -188,6 +214,28 @@ namespace TransportGame.Model
|
|||||||
return a.X * b.X + a.Y * b.Y;
|
return a.X * b.X + a.Y * b.Y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the magnitude of the cross product between the two vectors (z considered 0)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">First vector</param>
|
||||||
|
/// <param name="b">Second vector</param>
|
||||||
|
/// <returns>Magnitude of cross product</returns>
|
||||||
|
public static float Cross(Vector2 a, Vector2 b)
|
||||||
|
{
|
||||||
|
return (a.X * b.Y) - (a.Y * b.X);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tests if two vectors are colliniar
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">a</param>
|
||||||
|
/// <param name="b">b</param>
|
||||||
|
/// <returns>True if vectors are colliniar</returns>
|
||||||
|
public static bool AreColliniar(Vector2 a, Vector2 b)
|
||||||
|
{
|
||||||
|
return Math.Abs(Cross(a, b)) < 1e-12;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the vector corresponding with specified angle (in radians)
|
/// Gets the vector corresponding with specified angle (in radians)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -13,12 +13,10 @@ public class InitializeScript : MonoBehaviour
|
|||||||
// Load configuration
|
// Load configuration
|
||||||
Logger.Info("Loading configuration...");
|
Logger.Info("Loading configuration...");
|
||||||
ConfigurationManager.LoadConfiguration();
|
ConfigurationManager.LoadConfiguration();
|
||||||
Logger.Info("Finished loading configuration.");
|
|
||||||
|
|
||||||
// Load biomes
|
// Load biomes
|
||||||
Logger.Info("Loading biomes...");
|
Logger.Info("Loading biomes...");
|
||||||
BiomeManager.LoadBiomes();
|
BiomeManager.LoadBiomes();
|
||||||
Logger.Info("Finished loading biomes.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update is called once per frame
|
// Update is called once per frame
|
||||||
|
434
Game/Assets/Scripts/Unity/RoadMeshGenerator.cs
Normal file
434
Game/Assets/Scripts/Unity/RoadMeshGenerator.cs
Normal file
@ -0,0 +1,434 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using TransportGame.Model;
|
||||||
|
using TransportGame.Model.Road;
|
||||||
|
using TransportGame.Utils;
|
||||||
|
using UnityEngine;
|
||||||
|
using Vector2 = TransportGame.Model.Vector2;
|
||||||
|
|
||||||
|
//#define DEBUG_ROAD_MESH_GENERATOR
|
||||||
|
|
||||||
|
namespace TransportGame.Unity
|
||||||
|
{
|
||||||
|
class RoadMeshGenerator
|
||||||
|
{
|
||||||
|
#region Constants
|
||||||
|
|
||||||
|
private const float SidewalkWidth = .8f;
|
||||||
|
private const float LaneWidth = 1f;
|
||||||
|
|
||||||
|
private const float RaiseOffset = 0.8f; // Raises road above actual height of terrain
|
||||||
|
private const float SidewalkHeight = 0.1f; // Height of sidewalk
|
||||||
|
private const float SideCoverHeight = 0.1f; // On the sides of the roads, so that we can't see the road from the underside
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Private fields
|
||||||
|
|
||||||
|
private Map map;
|
||||||
|
|
||||||
|
private Dictionary<int, Vector2[]> segmentTerminal1Limit = new Dictionary<int, Vector2[]>();
|
||||||
|
private Dictionary<int, Vector2[]> segmentTerminal2Limit = new Dictionary<int, Vector2[]>();
|
||||||
|
|
||||||
|
private GameObject parent = new GameObject("roadNetwork");
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public Material RoadMaterial { get; set; }
|
||||||
|
public Material SidewalkMaterial { get; set; }
|
||||||
|
|
||||||
|
public IEnumerable Generate(Map map)
|
||||||
|
{
|
||||||
|
this.map = map;
|
||||||
|
|
||||||
|
List<int> visitedNodes = new List<int>();
|
||||||
|
List<int> visitedSegments = new List<int>();
|
||||||
|
Queue<RoadNode> queue = new Queue<RoadNode>();
|
||||||
|
queue.Enqueue(map.RoadNetwork.Nodes.First().Value);
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (queue.Count > 0)
|
||||||
|
{
|
||||||
|
// Pop a node
|
||||||
|
RoadNode node = queue.Dequeue();
|
||||||
|
visitedNodes.Add(node.Id);
|
||||||
|
|
||||||
|
// Generate intersection
|
||||||
|
GenerateIntersection(node);
|
||||||
|
|
||||||
|
// Enqueue
|
||||||
|
foreach (var segment in node.ArticulationSegments)
|
||||||
|
{
|
||||||
|
// Generate segments linked to node that have been visited
|
||||||
|
if (visitedNodes.Contains(segment.Terminal1Id) && visitedNodes.Contains(segment.Terminal2Id))
|
||||||
|
{
|
||||||
|
if (!visitedSegments.Contains(segment.Id))
|
||||||
|
{
|
||||||
|
GenerateSegment(segment);
|
||||||
|
visitedSegments.Add(segment.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (node == segment.Terminal1)
|
||||||
|
queue.Enqueue(segment.Terminal2);
|
||||||
|
else queue.Enqueue(segment.Terminal1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take a break
|
||||||
|
++i;
|
||||||
|
if (i % 20 == 0)
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Info("Finished generating road mesh.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private int LanesTo(RoadSegment segment, RoadNode terminal)
|
||||||
|
{
|
||||||
|
if (segment.Terminal1 == terminal)
|
||||||
|
return segment.LanesTo1;
|
||||||
|
|
||||||
|
if (segment.Terminal2 == terminal)
|
||||||
|
return segment.LanesTo2;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int LanesFrom(RoadSegment segment, RoadNode terminal)
|
||||||
|
{
|
||||||
|
if (segment.Terminal1 == terminal)
|
||||||
|
return segment.LanesTo2;
|
||||||
|
|
||||||
|
if (segment.Terminal2 == terminal)
|
||||||
|
return segment.LanesTo1;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector2 DirectionFrom(RoadSegment segment, RoadNode terminal)
|
||||||
|
{
|
||||||
|
return (segment.Terminal1 == terminal) ? segment.Direction : -segment.Direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GenerateIntersection(RoadNode node)
|
||||||
|
{
|
||||||
|
List<Vector3> vertices = new List<Vector3>();
|
||||||
|
List<UnityEngine.Vector2> uv = new List<UnityEngine.Vector2>();
|
||||||
|
List<int> triangles = new List<int>();
|
||||||
|
int vindex = 0;
|
||||||
|
|
||||||
|
// Helper function
|
||||||
|
Action<Vector2, float> addV = (v, h) =>
|
||||||
|
{
|
||||||
|
Vector3 v3 = new Vector3(v.Y, map.GetHeight((int)node.X, (int)node.Y) + RaiseOffset + h, v.X);
|
||||||
|
UnityEngine.Vector2 v2 = new UnityEngine.Vector2(v.Y / 3 - v3.y, v.X / 3 - v3.y);
|
||||||
|
|
||||||
|
vertices.Add(v3);
|
||||||
|
uv.Add(v2);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add current node
|
||||||
|
addV(node.Position, 0);
|
||||||
|
vindex += 1;
|
||||||
|
|
||||||
|
// Sort adjacent segments in trigonometric order
|
||||||
|
var segs = node.ArticulationSegments.OrderBy(segment =>
|
||||||
|
{
|
||||||
|
Vector2 dir = DirectionFrom(segment, node);
|
||||||
|
|
||||||
|
if (dir.X >= 0 && dir.Y >= 0) // First quadrant:
|
||||||
|
return dir.Y; // Y coordinate grows from 0 to 1
|
||||||
|
|
||||||
|
else if (dir.X <= 0 && dir.Y >= 0) // Second quadrant:
|
||||||
|
return 1 + Math.Abs(dir.X); // X goes from 0 to -1
|
||||||
|
|
||||||
|
else if (dir.X <= 0 && dir.Y <= 0) // Third quadrant:
|
||||||
|
return 2 + Math.Abs(dir.Y); // Y goes from 0 to -1
|
||||||
|
|
||||||
|
else return 3 + dir.X; // Fourth quadrant: X grows from 0 to 1
|
||||||
|
}).ToArray();
|
||||||
|
|
||||||
|
Vector2[] sideCrns = new Vector2[segs.Length];
|
||||||
|
Vector2[] strCrns = new Vector2[segs.Length];
|
||||||
|
|
||||||
|
// Holds intersection points for perpendicular on segment that goes through sidewalk corners
|
||||||
|
// 0, 1, 2, 3 - 0 sidewalk, 1 street, 2 street, 3 sidewalk (in trigonometric order). (when first segment)
|
||||||
|
// 4, 5, 6, 7 - the same (when second segment)
|
||||||
|
Vector2[,] p = new Vector2[8, segs.Length];
|
||||||
|
|
||||||
|
// Process each pair of segments
|
||||||
|
for (int i = 0; i < segs.Length; ++i)
|
||||||
|
{
|
||||||
|
// Wrap around
|
||||||
|
int j = i + 1;
|
||||||
|
if (j >= segs.Length)
|
||||||
|
j = 0;
|
||||||
|
|
||||||
|
// Get direction vectors
|
||||||
|
var dir0 = DirectionFrom(segs[i], node);
|
||||||
|
var dir1 = DirectionFrom(segs[j], node);
|
||||||
|
float cross = Vector2.Cross(dir0, dir1);
|
||||||
|
|
||||||
|
// Colliniar vectors
|
||||||
|
if (Math.Abs(cross) < 1e-2)
|
||||||
|
{
|
||||||
|
var dirP = dir0.RotateDeg(90);
|
||||||
|
|
||||||
|
strCrns[i] = node.Position + dirP * LanesTo(segs[i], node) * LaneWidth;
|
||||||
|
sideCrns[i] = strCrns[i] + dirP * SidewalkWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vectors not colliniar
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Vector2 off0 = dir0 * ((LanesFrom(segs[j], node) * LaneWidth) / cross);
|
||||||
|
Vector2 off1 = dir1 * ((LanesTo(segs[i], node) * LaneWidth) / cross);
|
||||||
|
strCrns[i] = node.Position + off0 + off1;
|
||||||
|
sideCrns[i] = strCrns[i] + dir0 * (SidewalkWidth / cross) + dir1 * (SidewalkWidth / cross);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate perpendicular vectors from sidewalk corner on first segment
|
||||||
|
Vector2 perp0 = dir0.RotateDeg(-90);
|
||||||
|
p[3, i] = sideCrns[i];
|
||||||
|
p[2, i] = p[3, i] + perp0 * SidewalkWidth;
|
||||||
|
p[1, i] = p[2, i] + perp0 * (segs[i].LanesTo1 + segs[i].LanesTo2) * LaneWidth;
|
||||||
|
p[0, i] = p[1, i] + perp0 * SidewalkWidth;
|
||||||
|
|
||||||
|
// Calculate perpendicular vectors from sidewalk corner on second segment
|
||||||
|
Vector2 perp1 = dir1.RotateDeg(90);
|
||||||
|
p[4, j] = sideCrns[i];
|
||||||
|
p[5, j] = p[4, j] + perp1 * SidewalkWidth;
|
||||||
|
p[6, j] = p[5, j] + perp1 * (segs[j].LanesTo1 + segs[j].LanesTo2) * LaneWidth;
|
||||||
|
p[7, j] = p[6, j] + perp1 * SidewalkWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (segs.Length == 1)
|
||||||
|
{
|
||||||
|
var dir = DirectionFrom(segs[0], node);
|
||||||
|
Vector2 perp = dir.RotateDeg(-90);
|
||||||
|
Vector2[] end = new[] {
|
||||||
|
node.Position + perp * (LanesFrom(segs[0], node) * LaneWidth + SidewalkWidth),
|
||||||
|
node.Position + perp * (LanesFrom(segs[0], node) * LaneWidth),
|
||||||
|
node.Position - perp * (LanesTo(segs[0], node) * LaneWidth),
|
||||||
|
node.Position - perp * (LanesTo(segs[0], node) * LaneWidth + SidewalkWidth)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (segs[0].Terminal1 == node)
|
||||||
|
{
|
||||||
|
segmentTerminal1Limit[segs[0].Id] = end;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
segmentTerminal2Limit[segs[0].Id] = end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
// Now we generate for each segment
|
||||||
|
for (int i = 0; i < segs.Length; i++)
|
||||||
|
{
|
||||||
|
// Find furthest perpendicular
|
||||||
|
float dist0 = (p[0, i] - node.Position).LengthSq;
|
||||||
|
float dist1 = (p[4, i] - node.Position).LengthSq;
|
||||||
|
|
||||||
|
int furth = (dist0 > dist1) ? 0 : 4;
|
||||||
|
int cornerLeft = i;
|
||||||
|
int cornerRight = (i - 1 >= 0) ? i - 1 : segs.Length - 1;
|
||||||
|
|
||||||
|
// Add to limit dictionaries
|
||||||
|
if (segs[i].Terminal1 == node)
|
||||||
|
{
|
||||||
|
segmentTerminal1Limit[segs[i].Id] = new[] { p[furth, i], p[furth + 1, i], p[furth + 2, i], p[furth + 3, i] };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
segmentTerminal2Limit[segs[i].Id] = new[] { p[furth, i], p[furth + 1, i], p[furth + 2, i], p[furth + 3, i] };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build road
|
||||||
|
// Right side
|
||||||
|
addV(p[furth, i], SidewalkHeight); // 0 - p0 raised
|
||||||
|
addV(sideCrns[cornerRight], SidewalkHeight); // 1 - side corner raised
|
||||||
|
addV(sideCrns[cornerRight], SidewalkHeight - SideCoverHeight); // 2 - side corner cover
|
||||||
|
addV(p[furth, i], SidewalkHeight - SideCoverHeight); // 3 - p0 cover
|
||||||
|
addV(p[furth + 1, i], SidewalkHeight); // 4 - p1 raised
|
||||||
|
addV(strCrns[cornerRight], SidewalkHeight); // 5 - street corner raised
|
||||||
|
addV(strCrns[cornerRight], 0); // 6 - street corner
|
||||||
|
addV(p[furth + 1, i], 0); // 7 - p1
|
||||||
|
|
||||||
|
// Left side
|
||||||
|
addV(p[furth + 2, i], 0); // 8 - p2
|
||||||
|
addV(strCrns[cornerLeft], 0); // 9 - street corner
|
||||||
|
addV(strCrns[cornerLeft], SidewalkHeight); //10 - street corner raised
|
||||||
|
addV(p[furth + 2, i], SidewalkHeight); //11 - p2 raised
|
||||||
|
addV(p[furth + 3, i], SidewalkHeight - SideCoverHeight); //12 - p3 cover
|
||||||
|
addV(sideCrns[cornerLeft], SidewalkHeight - SideCoverHeight); //13 - side corner cover
|
||||||
|
addV(sideCrns[cornerLeft], SidewalkHeight); //14 - side corner raised
|
||||||
|
addV(p[furth + 3, i], SidewalkHeight); //15 - p3 raised
|
||||||
|
|
||||||
|
// Right sidewalk
|
||||||
|
triangles.AddRange(new[] { vindex, vindex + 1, vindex + 2 }); // sidewalk side cover 0
|
||||||
|
triangles.AddRange(new[] { vindex, vindex + 2, vindex + 3 }); // sidewalk side cover 1
|
||||||
|
triangles.AddRange(new[] { vindex, vindex + 4, vindex + 1 }); // sidewalk surface 0
|
||||||
|
triangles.AddRange(new[] { vindex + 4, vindex + 5, vindex + 1 }); // sidewalk surface 1
|
||||||
|
triangles.AddRange(new[] { vindex + 4, vindex + 7, vindex + 6 }); // sidewalk road raise 0
|
||||||
|
triangles.AddRange(new[] { vindex + 4, vindex + 6, vindex + 5 }); // sidewalk road raise 1
|
||||||
|
|
||||||
|
// Road surface
|
||||||
|
triangles.AddRange(new[] { vindex + 8, vindex + 6, vindex + 7 }); // road surface 0
|
||||||
|
triangles.AddRange(new[] { vindex + 8, vindex + 9, vindex + 6 }); // road surface 0
|
||||||
|
triangles.AddRange(new[] { vindex + 6, vindex + 9, 0 }); // road surface 0
|
||||||
|
|
||||||
|
// Left sidewalk
|
||||||
|
triangles.AddRange(new[] { vindex + 11, vindex + 10, vindex + 9 }); // sidewalk road raise 0
|
||||||
|
triangles.AddRange(new[] { vindex + 11, vindex + 9, vindex + 8 }); // sidewalk road raise 1
|
||||||
|
triangles.AddRange(new[] { vindex + 11, vindex + 14, vindex + 10 });// sidewalk surface 0
|
||||||
|
triangles.AddRange(new[] { vindex + 11, vindex + 15, vindex + 14 });// sidewalk surface 1
|
||||||
|
triangles.AddRange(new[] { vindex + 15, vindex + 12, vindex + 13 });// sidewalk side cover 0
|
||||||
|
triangles.AddRange(new[] { vindex + 15, vindex + 13, vindex + 14 });// sidewalk side cover 1
|
||||||
|
|
||||||
|
// update vindex
|
||||||
|
vindex = vertices.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct mesh
|
||||||
|
Mesh mesh = new Mesh();
|
||||||
|
mesh.vertices = vertices.ToArray();
|
||||||
|
mesh.triangles = triangles.ToArray();
|
||||||
|
mesh.uv = uv.ToArray();
|
||||||
|
mesh.RecalculateNormals();
|
||||||
|
|
||||||
|
// Construct game object
|
||||||
|
GameObject inters = new GameObject("intersection" + node.Id);
|
||||||
|
inters.transform.parent = parent.transform;
|
||||||
|
|
||||||
|
MeshFilter meshFilter = inters.AddComponent<MeshFilter>();
|
||||||
|
meshFilter.mesh = mesh;
|
||||||
|
|
||||||
|
MeshRenderer meshRenderer = inters.AddComponent<MeshRenderer>();
|
||||||
|
meshRenderer.materials = new[] { RoadMaterial };
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEBUG_ROAD_MESH_GENERATOR
|
||||||
|
// Debug draw
|
||||||
|
Debug.DrawLine(
|
||||||
|
new Vector3(node.Y, map.GetHeight((int)node.X, (int)node.Y) + 0.5f, node.X),
|
||||||
|
new Vector3(node.Y, map.GetHeight((int)node.X, (int)node.Y) + 1.2f, node.X),
|
||||||
|
Color.white, 10000);
|
||||||
|
|
||||||
|
foreach (var sidewalkCorner in sideCrns)
|
||||||
|
Debug.DrawLine(
|
||||||
|
new Vector3(sidewalkCorner.Y, map.GetHeight((int)sidewalkCorner.X, (int)sidewalkCorner.Y) + 0.5f, sidewalkCorner.X),
|
||||||
|
new Vector3(sidewalkCorner.Y, map.GetHeight((int)sidewalkCorner.X, (int)sidewalkCorner.Y) + 1.1f, sidewalkCorner.X),
|
||||||
|
Color.cyan, 10000);
|
||||||
|
|
||||||
|
foreach (var strCorner in strCrns)
|
||||||
|
Debug.DrawLine(
|
||||||
|
new Vector3(strCorner.Y, map.GetHeight((int)strCorner.X, (int)strCorner.Y) + 0.5f, strCorner.X),
|
||||||
|
new Vector3(strCorner.Y, map.GetHeight((int)strCorner.X, (int)strCorner.Y) + 1.1f, strCorner.X),
|
||||||
|
Color.blue, 10000);
|
||||||
|
|
||||||
|
for (int i = 0; i < segs.Length; i++)
|
||||||
|
for (int j = 0; j < 8; j++)
|
||||||
|
Debug.DrawLine(
|
||||||
|
new Vector3(p[j, i].Y, map.GetHeight((int)p[j, i].X, (int)p[j, i].Y) + 0.5f, p[j, i].X),
|
||||||
|
new Vector3(p[j, i].Y, map.GetHeight((int)p[j, i].X, (int)p[j, i].Y) + 1.0f, p[j, i].X),
|
||||||
|
Color.green, 10000);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GenerateSegment(RoadSegment s)
|
||||||
|
{
|
||||||
|
List<Vector3> vertices = new List<Vector3>();
|
||||||
|
List<UnityEngine.Vector2> uv = new List<UnityEngine.Vector2>();
|
||||||
|
List<int> triangles = new List<int>();
|
||||||
|
|
||||||
|
// Helper function
|
||||||
|
Action<Vector2, float, int> addV = (v, h, term) =>
|
||||||
|
{
|
||||||
|
if (term == 1)
|
||||||
|
h += map.GetHeight((int)s.Terminal1.X, (int)s.Terminal1.Y);
|
||||||
|
else
|
||||||
|
h += map.GetHeight((int)s.Terminal2.X, (int)s.Terminal2.Y);
|
||||||
|
|
||||||
|
Vector3 v3 = new Vector3(v.Y, RaiseOffset + h, v.X);
|
||||||
|
UnityEngine.Vector2 v2 = new UnityEngine.Vector2(v.Y / 3 - v3.y, v.X / 3 - v3.y);
|
||||||
|
|
||||||
|
vertices.Add(v3);
|
||||||
|
uv.Add(v2);
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector2[] pT1 = segmentTerminal1Limit[s.Id];
|
||||||
|
Vector2[] pT2 = segmentTerminal2Limit[s.Id];
|
||||||
|
|
||||||
|
addV(pT1[0], SidewalkHeight - SideCoverHeight, 1);
|
||||||
|
addV(pT1[0], SidewalkHeight, 1);
|
||||||
|
addV(pT1[1], SidewalkHeight, 1);
|
||||||
|
addV(pT1[1], 0, 1);
|
||||||
|
addV(pT1[2], 0, 1);
|
||||||
|
addV(pT1[2], SidewalkHeight, 1);
|
||||||
|
addV(pT1[3], SidewalkHeight, 1);
|
||||||
|
addV(pT1[3], SidewalkHeight - SideCoverHeight, 1);
|
||||||
|
|
||||||
|
addV(pT2[0], SidewalkHeight - SideCoverHeight, 2);
|
||||||
|
addV(pT2[0], SidewalkHeight, 2);
|
||||||
|
addV(pT2[1], SidewalkHeight, 2);
|
||||||
|
addV(pT2[1], 0, 2);
|
||||||
|
addV(pT2[2], 0, 2);
|
||||||
|
addV(pT2[2], SidewalkHeight, 2);
|
||||||
|
addV(pT2[3], SidewalkHeight, 2);
|
||||||
|
addV(pT2[3], SidewalkHeight - SideCoverHeight, 2);
|
||||||
|
|
||||||
|
triangles.AddRange(new[] { 0, 15, 14 }); // sidewalk side cover 0
|
||||||
|
triangles.AddRange(new[] { 0, 14, 1 }); // sidewalk side cover 1
|
||||||
|
triangles.AddRange(new[] { 1, 14, 13 }); // sidewalk surface 0
|
||||||
|
triangles.AddRange(new[] { 1, 13, 2 }); // sidewalk surface 1
|
||||||
|
triangles.AddRange(new[] { 2, 12, 3 }); // sidewalk road raise 0
|
||||||
|
triangles.AddRange(new[] { 2, 13, 12 }); // sidewalk road raise 1
|
||||||
|
|
||||||
|
// Road surface
|
||||||
|
triangles.AddRange(new[] { 3, 12, 11 }); // road surface 0
|
||||||
|
triangles.AddRange(new[] { 3, 11, 4 }); // road surface 0
|
||||||
|
|
||||||
|
// Left sidewalk
|
||||||
|
triangles.AddRange(new[] { 4, 11, 10 }); // sidewalk road raise 0
|
||||||
|
triangles.AddRange(new[] { 4, 10, 5 }); // sidewalk road raise 1
|
||||||
|
triangles.AddRange(new[] { 5, 10, 9 }); // sidewalk surface 0
|
||||||
|
triangles.AddRange(new[] { 5, 9, 6 }); // sidewalk surface 1
|
||||||
|
triangles.AddRange(new[] { 6, 9, 8 }); // sidewalk side cover 0
|
||||||
|
triangles.AddRange(new[] { 6, 8, 7 }); // sidewalk side cover 1
|
||||||
|
|
||||||
|
// Construct mesh
|
||||||
|
Mesh mesh = new Mesh();
|
||||||
|
mesh.vertices = vertices.ToArray();
|
||||||
|
mesh.triangles = triangles.ToArray();
|
||||||
|
mesh.uv = uv.ToArray();
|
||||||
|
mesh.RecalculateNormals();
|
||||||
|
|
||||||
|
// Construct game object
|
||||||
|
GameObject inters = new GameObject("road" + s.Id);
|
||||||
|
inters.transform.parent = parent.transform;
|
||||||
|
|
||||||
|
MeshFilter meshFilter = inters.AddComponent<MeshFilter>();
|
||||||
|
meshFilter.mesh = mesh;
|
||||||
|
|
||||||
|
MeshRenderer meshRenderer = inters.AddComponent<MeshRenderer>();
|
||||||
|
meshRenderer.materials = new[] { RoadMaterial };
|
||||||
|
|
||||||
|
#if DEBUG_ROAD_MESH_GENERATOR
|
||||||
|
// Debug draw
|
||||||
|
Color color = (s.LanesTo1 >= 3) ? Color.magenta : Color.red;
|
||||||
|
Debug.DrawLine(
|
||||||
|
new Vector3(s.Terminal1.Y, map.GetHeight((int)s.Terminal1.X, (int)s.Terminal1.Y) + 1f, s.Terminal1.X),
|
||||||
|
new Vector3(s.Terminal2.Y, map.GetHeight((int)s.Terminal2.X, (int)s.Terminal2.Y) + 1f, s.Terminal2.X),
|
||||||
|
color, 10000);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
12
Game/Assets/Scripts/Unity/RoadMeshGenerator.cs.meta
Normal file
12
Game/Assets/Scripts/Unity/RoadMeshGenerator.cs.meta
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6515820b5324dbf4baa10c3a1a480eaa
|
||||||
|
timeCreated: 1432970903
|
||||||
|
licenseType: Free
|
||||||
|
MonoImporter:
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -3,6 +3,7 @@ using System.Collections;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using TransportGame.Generator;
|
using TransportGame.Generator;
|
||||||
using TransportGame.Model;
|
using TransportGame.Model;
|
||||||
|
using TransportGame.Unity;
|
||||||
using TransportGame.Utils;
|
using TransportGame.Utils;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
@ -14,6 +15,7 @@ public class TerrainGeneratorScript : MonoBehaviour
|
|||||||
public int TerrainHeight = 1024;
|
public int TerrainHeight = 1024;
|
||||||
public GameObject WaterObject;
|
public GameObject WaterObject;
|
||||||
public Texture2D[] Textures;
|
public Texture2D[] Textures;
|
||||||
|
public Material RoadMaterial;
|
||||||
|
|
||||||
// Use this for initialization
|
// Use this for initialization
|
||||||
void Start()
|
void Start()
|
||||||
@ -101,55 +103,49 @@ public class TerrainGeneratorScript : MonoBehaviour
|
|||||||
}
|
}
|
||||||
yield return null;
|
yield return null;
|
||||||
|
|
||||||
// Set up textures
|
// Set up textures
|
||||||
//SetupSplatmaps(terrainData);
|
Logger.Info("Setting up textures...");
|
||||||
|
foreach (var i in SetupSplatmaps(terrainData))
|
||||||
|
yield return i;
|
||||||
|
|
||||||
|
// Generate road mesh
|
||||||
|
Logger.Info("Generating roads...");
|
||||||
|
RoadMeshGenerator meshGenerator = new RoadMeshGenerator();
|
||||||
|
meshGenerator.RoadMaterial = RoadMaterial;
|
||||||
|
foreach (object i in meshGenerator.Generate(map))
|
||||||
|
yield return i;
|
||||||
|
|
||||||
// -- DEBUG --
|
// -- DEBUG --
|
||||||
|
|
||||||
foreach (var center in map.PopulationCenters)
|
foreach (var center in map.PopulationCenters)
|
||||||
Debug.DrawLine(new Vector3(center.Y, 0, center.X), new Vector3(center.Y, map.Biome.Height, center.X), Color.yellow, 100000);
|
Debug.DrawLine(new Vector3(center.Y, 0, center.X), new Vector3(center.Y, map.Biome.Height, center.X), Color.yellow, 100000);
|
||||||
|
|
||||||
// Debug - draw lines
|
|
||||||
if (map != null && map.RoadNetwork != null)
|
|
||||||
{
|
|
||||||
foreach (var segment in map.RoadNetwork.ArticulationSegments)
|
|
||||||
{
|
|
||||||
Color color = (segment.Value.LanesTo1 >= 3) ? Color.magenta : Color.red;
|
|
||||||
Debug.DrawLine(new Vector3(segment.Value.Terminal1.Y, map.Biome.Height / 2, segment.Value.Terminal1.X), new Vector3(segment.Value.Terminal2.Y, map.Biome.Height / 2, segment.Value.Terminal2.X), color, 10000);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var node in map.RoadNetwork.Nodes)
|
|
||||||
{
|
|
||||||
Debug.DrawLine(new Vector3(node.Value.Y, map.Biome.Height / 2, node.Value.X), new Vector3(node.Value.Y, map.Biome.Height / 2 + 5, node.Value.X), Color.blue, 10000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetupSplatmaps(TerrainData terrainData)
|
private float[,,] GenerateSplatData(int alphaWidth, int alphaHeight, int alphaLayers)
|
||||||
{
|
{
|
||||||
float[, ,] splatData = new float[terrainData.alphamapWidth, terrainData.alphamapHeight, terrainData.alphamapLayers];
|
float[, ,] splatData = new float[alphaWidth, alphaHeight, alphaLayers];
|
||||||
Expression[] expressions = new Expression[terrainData.alphamapLayers];
|
Expression[] expressions = new Expression[alphaLayers];
|
||||||
|
|
||||||
for (int y = 0; y < terrainData.alphamapHeight; y++)
|
for (int y = 0; y < alphaHeight; y++)
|
||||||
for (int x = 0; x < terrainData.alphamapWidth; x++)
|
for (int x = 0; x < alphaWidth; x++)
|
||||||
{
|
{
|
||||||
float y_01 = (float)y / (float)terrainData.alphamapHeight;
|
float y_01 = (float)y / (float)alphaHeight;
|
||||||
float x_01 = (float)x / (float)terrainData.alphamapWidth;
|
float x_01 = (float)x / (float)alphaWidth;
|
||||||
|
|
||||||
int ix = Mathf.RoundToInt(x_01 * TerrainWidth);
|
int ix = Mathf.RoundToInt(x_01 * TerrainWidth);
|
||||||
int iy = Mathf.RoundToInt(y_01 * TerrainHeight);
|
int iy = Mathf.RoundToInt(y_01 * TerrainHeight);
|
||||||
|
|
||||||
// Get height
|
// Get height
|
||||||
float height = map.GetHeight(ix, iy);
|
float height = map.GetHeight(ix, iy);
|
||||||
|
|
||||||
// Get steepness
|
// Get steepness
|
||||||
float steepness = map.GetSteepness(ix, iy);
|
float steepness = map.GetSteepness(ix, iy);
|
||||||
|
|
||||||
// Go through each texture layer
|
// Go through each texture layer
|
||||||
float[] weights = new float[terrainData.alphamapLayers];
|
float[] weights = new float[alphaLayers];
|
||||||
float sum = 0;
|
float sum = 0;
|
||||||
|
|
||||||
for (int t = 0; t < terrainData.alphamapLayers; t++)
|
for (int t = 0; t < alphaLayers; t++)
|
||||||
{
|
{
|
||||||
// Set up expression
|
// Set up expression
|
||||||
if (expressions[t] == null)
|
if (expressions[t] == null)
|
||||||
@ -160,7 +156,7 @@ public class TerrainGeneratorScript : MonoBehaviour
|
|||||||
|
|
||||||
expressions[t].Variables["height"] = height;
|
expressions[t].Variables["height"] = height;
|
||||||
expressions[t].Variables["steepness"] = steepness;
|
expressions[t].Variables["steepness"] = steepness;
|
||||||
expressions[t].Variables["maxHeight"] = terrainData.size.y;
|
expressions[t].Variables["maxHeight"] = map.Biome.Height;
|
||||||
expressions[t].Variables["waterLevel"] = map.WaterLevel - 1f;
|
expressions[t].Variables["waterLevel"] = map.WaterLevel - 1f;
|
||||||
|
|
||||||
// Obtain weight
|
// Obtain weight
|
||||||
@ -169,12 +165,25 @@ public class TerrainGeneratorScript : MonoBehaviour
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Normalize and copy weights
|
// Normalize and copy weights
|
||||||
for (int t = 0; t < terrainData.alphamapLayers; t++)
|
for (int t = 0; t < alphaLayers; t++)
|
||||||
{
|
{
|
||||||
splatData[x, y, t] = weights[t] / sum;
|
splatData[x, y, t] = weights[t] / sum;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return splatData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable SetupSplatmaps(TerrainData terrainData)
|
||||||
|
{
|
||||||
|
float[, ,] splatData = null;
|
||||||
|
int alphaW = terrainData.alphamapWidth;
|
||||||
|
int alphaH = terrainData.alphamapHeight;
|
||||||
|
int alphaL = terrainData.alphamapLayers;
|
||||||
|
|
||||||
|
foreach (var i in Task.RunAsync(() => splatData = GenerateSplatData(alphaW, alphaH, alphaL)))
|
||||||
|
yield return i;
|
||||||
|
|
||||||
terrainData.SetAlphamaps(0, 0, splatData);
|
terrainData.SetAlphamaps(0, 0, splatData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +61,10 @@ namespace TransportGame.Utils
|
|||||||
case Level.Critical:
|
case Level.Critical:
|
||||||
UnityEngine.Debug.LogError(String.Format(format, args));
|
UnityEngine.Debug.LogError(String.Format(format, args));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Level.Info:
|
||||||
|
UnityEngine.Debug.Log(String.Format(format, args));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -7,16 +7,14 @@
|
|||||||
<SchemaVersion>2.0</SchemaVersion>
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
<ProjectGuid>{02576F1D-BE9C-CFA7-763D-1EBF63B36977}</ProjectGuid>
|
<ProjectGuid>{02576F1D-BE9C-CFA7-763D-1EBF63B36977}</ProjectGuid>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<RootNamespace>
|
<RootNamespace></RootNamespace>
|
||||||
</RootNamespace>
|
|
||||||
<AssemblyName>Assembly-CSharp</AssemblyName>
|
<AssemblyName>Assembly-CSharp</AssemblyName>
|
||||||
<FileAlignment>512</FileAlignment>
|
<FileAlignment>512</FileAlignment>
|
||||||
<ProjectTypeGuids>{E097FAD1-6243-4DAD-9C02-E9B9EFC3FFC1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
<ProjectTypeGuids>{E097FAD1-6243-4DAD-9C02-E9B9EFC3FFC1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
<TargetFrameworkIdentifier>.NETFramework</TargetFrameworkIdentifier>
|
<TargetFrameworkIdentifier>.NETFramework</TargetFrameworkIdentifier>
|
||||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||||
<TargetFrameworkProfile>Unity Subset v3.5</TargetFrameworkProfile>
|
<TargetFrameworkProfile>Unity Subset v3.5</TargetFrameworkProfile>
|
||||||
<CompilerResponseFile>
|
<CompilerResponseFile></CompilerResponseFile>
|
||||||
</CompilerResponseFile>
|
|
||||||
<UnityProjectType>Game:1</UnityProjectType>
|
<UnityProjectType>Game:1</UnityProjectType>
|
||||||
<UnityBuildTarget>StandaloneWindows64:19</UnityBuildTarget>
|
<UnityBuildTarget>StandaloneWindows64:19</UnityBuildTarget>
|
||||||
<UnityVersion>5.0.1f1</UnityVersion>
|
<UnityVersion>5.0.1f1</UnityVersion>
|
||||||
@ -90,6 +88,7 @@
|
|||||||
<Compile Include="Assets\Scripts\Noise\NoiseGenerator.cs" />
|
<Compile Include="Assets\Scripts\Noise\NoiseGenerator.cs" />
|
||||||
<Compile Include="Assets\Scripts\Noise\PerlinNoiseGenerator.cs" />
|
<Compile Include="Assets\Scripts\Noise\PerlinNoiseGenerator.cs" />
|
||||||
<Compile Include="Assets\Scripts\Unity\InitializeScript.cs" />
|
<Compile Include="Assets\Scripts\Unity\InitializeScript.cs" />
|
||||||
|
<Compile Include="Assets\Scripts\Unity\RoadMeshGenerator.cs" />
|
||||||
<Compile Include="Assets\Scripts\Unity\TerrainGeneratorScript.cs" />
|
<Compile Include="Assets\Scripts\Unity\TerrainGeneratorScript.cs" />
|
||||||
<Compile Include="Assets\Scripts\Utils\Algorithms.cs" />
|
<Compile Include="Assets\Scripts\Utils\Algorithms.cs" />
|
||||||
<Compile Include="Assets\Scripts\Utils\Algorithms\GridTraverseAlgorithm.cs" />
|
<Compile Include="Assets\Scripts\Utils\Algorithms\GridTraverseAlgorithm.cs" />
|
||||||
@ -109,8 +108,5 @@
|
|||||||
<None Include="Assets\Data\Config\tergen.xml" />
|
<None Include="Assets\Data\Config\tergen.xml" />
|
||||||
<None Include="Assets\Standard Assets\Environment\Water (Basic)\Shaders\FXWaterBasic.shader" />
|
<None Include="Assets\Standard Assets\Environment\Water (Basic)\Shaders\FXWaterBasic.shader" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Assets\Scripts\Storage\" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(MSBuildExtensionsPath)\SyntaxTree\UnityVS\2013\UnityVS.CSharp.targets" />
|
<Import Project="$(MSBuildExtensionsPath)\SyntaxTree\UnityVS\2013\UnityVS.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
||||||
|
Loading…
Reference in New Issue
Block a user