Implemented road & road mesh generator.
This commit is contained in:
		@@ -66,6 +66,7 @@
 | 
			
		||||
     <Compile Include="Assets\Scripts\Noise\NoiseGenerator.cs" />
 | 
			
		||||
     <Compile Include="Assets\Scripts\Noise\PerlinNoiseGenerator.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\Utils\Algorithms.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\PerlinNoiseGenerator.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\Utils\Algorithms.cs" />
 | 
			
		||||
     <Compile Include="Assets\Scripts\Utils\Algorithms\GridTraverseAlgorithm.cs" />
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8" ?> 
 | 
			
		||||
<biome>
 | 
			
		||||
	<name>Mountain</name>
 | 
			
		||||
	<height>500</height>
 | 
			
		||||
	<height>400</height>
 | 
			
		||||
	<moisture min=".1" max=".3"/>
 | 
			
		||||
	<vegetationDensity min=".5" max=".9" />
 | 
			
		||||
  <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 DefaultSegmentLength = 24;
 | 
			
		||||
        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 RoadSnapDistance = 19;
 | 
			
		||||
        const float MinNodeDistance = 12;
 | 
			
		||||
@@ -154,7 +154,7 @@ namespace TransportGame.Generator
 | 
			
		||||
        private IEnumerable<RoadGeneratorSegment> GlobalGoals(RoadSegment segment)
 | 
			
		||||
        {
 | 
			
		||||
            Vector2 prevPos = segment.Terminal2.Position;
 | 
			
		||||
            Vector2 dir = (segment.Terminal2.Position - segment.Terminal1.Position).Normalized;
 | 
			
		||||
            Vector2 dir = segment.Direction;
 | 
			
		||||
            bool highway = (segment.LanesTo1 >= 3);
 | 
			
		||||
            bool highwayBranched = false;
 | 
			
		||||
 | 
			
		||||
@@ -258,18 +258,14 @@ namespace TransportGame.Generator
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Filter & sort the segments by distance
 | 
			
		||||
            segmentIds = segmentIds.Distinct().OrderBy(id =>
 | 
			
		||||
            {
 | 
			
		||||
                var seg = map.RoadNetwork.ArticulationSegments[id];
 | 
			
		||||
                var line = new LineSegment(seg.Terminal1.Position, seg.Terminal2.Position);
 | 
			
		||||
                return LineSegment.Distance(line, segment.Terminal2Pos);
 | 
			
		||||
            });
 | 
			
		||||
            segmentIds = segmentIds.Distinct().OrderBy(id => 
 | 
			
		||||
                LineSegment.Distance(map.RoadNetwork.ArticulationSegments[id].AsLineSegment(), segment.Terminal2Pos));
 | 
			
		||||
 | 
			
		||||
            foreach (var segmentId in segmentIds)
 | 
			
		||||
            {
 | 
			
		||||
                var other = map.RoadNetwork.ArticulationSegments[segmentId];
 | 
			
		||||
                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);
 | 
			
		||||
 | 
			
		||||
@@ -294,7 +290,7 @@ namespace TransportGame.Generator
 | 
			
		||||
                    // Check angle between intersecting segments
 | 
			
		||||
                    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)
 | 
			
		||||
                            return false;
 | 
			
		||||
                    }
 | 
			
		||||
 
 | 
			
		||||
@@ -43,6 +43,14 @@ namespace TransportGame.Model
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Vector2 Direction
 | 
			
		||||
        {
 | 
			
		||||
            get
 | 
			
		||||
            {
 | 
			
		||||
                return (P1 - P0).Normalized;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public LineSegment(Vector2 p0, Vector2 p1)
 | 
			
		||||
            : this()
 | 
			
		||||
        {
 | 
			
		||||
 
 | 
			
		||||
@@ -80,6 +80,33 @@ namespace TransportGame.Model.Road
 | 
			
		||||
        [XmlAttribute("lanesTo1")]
 | 
			
		||||
        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>
 | 
			
		||||
        /// Initializes road segment
 | 
			
		||||
        /// </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>
 | 
			
		||||
        /// Rotates vector by given number of radians
 | 
			
		||||
        /// </summary>
 | 
			
		||||
@@ -123,6 +139,16 @@ namespace TransportGame.Model
 | 
			
		||||
            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>
 | 
			
		||||
        /// Multiply by constant
 | 
			
		||||
        /// </summary>
 | 
			
		||||
@@ -188,6 +214,28 @@ namespace TransportGame.Model
 | 
			
		||||
            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>
 | 
			
		||||
        /// Gets the vector corresponding with specified angle (in radians)
 | 
			
		||||
        /// </summary>
 | 
			
		||||
 
 | 
			
		||||
@@ -13,12 +13,10 @@ public class InitializeScript : MonoBehaviour
 | 
			
		||||
        // Load configuration
 | 
			
		||||
        Logger.Info("Loading configuration...");
 | 
			
		||||
        ConfigurationManager.LoadConfiguration();
 | 
			
		||||
        Logger.Info("Finished loading configuration.");
 | 
			
		||||
 | 
			
		||||
        // Load biomes
 | 
			
		||||
        Logger.Info("Loading biomes...");
 | 
			
		||||
        BiomeManager.LoadBiomes();
 | 
			
		||||
        Logger.Info("Finished loading biomes.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 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 TransportGame.Generator;
 | 
			
		||||
using TransportGame.Model;
 | 
			
		||||
using TransportGame.Unity;
 | 
			
		||||
using TransportGame.Utils;
 | 
			
		||||
using UnityEngine;
 | 
			
		||||
 | 
			
		||||
@@ -14,6 +15,7 @@ public class TerrainGeneratorScript : MonoBehaviour
 | 
			
		||||
	public int TerrainHeight = 1024;
 | 
			
		||||
	public GameObject WaterObject;
 | 
			
		||||
    public Texture2D[] Textures;
 | 
			
		||||
    public Material RoadMaterial;
 | 
			
		||||
 | 
			
		||||
	// Use this for initialization
 | 
			
		||||
	void Start()
 | 
			
		||||
@@ -101,55 +103,49 @@ public class TerrainGeneratorScript : MonoBehaviour
 | 
			
		||||
		}
 | 
			
		||||
        yield return null;
 | 
			
		||||
 | 
			
		||||
		// Set up textures
 | 
			
		||||
        //SetupSplatmaps(terrainData);
 | 
			
		||||
        // Set up textures
 | 
			
		||||
        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 --
 | 
			
		||||
 | 
			
		||||
        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 - 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];
 | 
			
		||||
        Expression[] expressions = new Expression[terrainData.alphamapLayers];
 | 
			
		||||
        float[, ,] splatData = new float[alphaWidth, alphaHeight, alphaLayers];
 | 
			
		||||
        Expression[] expressions = new Expression[alphaLayers];
 | 
			
		||||
 | 
			
		||||
        for (int y = 0; y < terrainData.alphamapHeight; y++)
 | 
			
		||||
            for (int x = 0; x < terrainData.alphamapWidth; x++)
 | 
			
		||||
        for (int y = 0; y < alphaHeight; y++)
 | 
			
		||||
            for (int x = 0; x < alphaWidth; x++)
 | 
			
		||||
            {
 | 
			
		||||
                float y_01 = (float)y / (float)terrainData.alphamapHeight;
 | 
			
		||||
                float x_01 = (float)x / (float)terrainData.alphamapWidth;
 | 
			
		||||
                float y_01 = (float)y / (float)alphaHeight;
 | 
			
		||||
                float x_01 = (float)x / (float)alphaWidth;
 | 
			
		||||
 | 
			
		||||
                int ix = Mathf.RoundToInt(x_01 * TerrainWidth);
 | 
			
		||||
                int iy = Mathf.RoundToInt(y_01 * TerrainHeight);
 | 
			
		||||
 | 
			
		||||
                // Get height
 | 
			
		||||
                float height = map.GetHeight(ix, iy);
 | 
			
		||||
                
 | 
			
		||||
 | 
			
		||||
                // Get steepness
 | 
			
		||||
                float steepness = map.GetSteepness(ix, iy);
 | 
			
		||||
                
 | 
			
		||||
 | 
			
		||||
                // Go through each texture layer
 | 
			
		||||
                float[] weights = new float[terrainData.alphamapLayers];
 | 
			
		||||
                float[] weights = new float[alphaLayers];
 | 
			
		||||
                float sum = 0;
 | 
			
		||||
 | 
			
		||||
                for (int t = 0; t < terrainData.alphamapLayers; t++)
 | 
			
		||||
                for (int t = 0; t < alphaLayers; t++)
 | 
			
		||||
                {
 | 
			
		||||
                    // Set up expression
 | 
			
		||||
                    if (expressions[t] == null)
 | 
			
		||||
@@ -160,7 +156,7 @@ public class TerrainGeneratorScript : MonoBehaviour
 | 
			
		||||
 | 
			
		||||
                    expressions[t].Variables["height"] = height;
 | 
			
		||||
                    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;
 | 
			
		||||
 | 
			
		||||
                    // Obtain weight
 | 
			
		||||
@@ -169,12 +165,25 @@ public class TerrainGeneratorScript : MonoBehaviour
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // 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;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -61,6 +61,10 @@ namespace TransportGame.Utils
 | 
			
		||||
                    case Level.Critical:
 | 
			
		||||
                        UnityEngine.Debug.LogError(String.Format(format, args));
 | 
			
		||||
                        break;
 | 
			
		||||
 | 
			
		||||
                    case Level.Info:
 | 
			
		||||
                        UnityEngine.Debug.Log(String.Format(format, args));
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,7 @@ Global
 | 
			
		||||
	GlobalSection(SolutionProperties) = preSolution
 | 
			
		||||
		HideSolutionNode = FALSE
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
																																																																																																																					GlobalSection(MonoDevelopProperties) = preSolution
 | 
			
		||||
																																																																																																																									GlobalSection(MonoDevelopProperties) = preSolution
 | 
			
		||||
		StartupItem = Assembly-CSharp.csproj
 | 
			
		||||
		Policies = $0
 | 
			
		||||
		$0.TextStylePolicy = $1
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@ Global
 | 
			
		||||
	GlobalSection(SolutionProperties) = preSolution
 | 
			
		||||
		HideSolutionNode = FALSE
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
																																																																																																																				GlobalSection(MonoDevelopProperties) = preSolution
 | 
			
		||||
																																																																																																																								GlobalSection(MonoDevelopProperties) = preSolution
 | 
			
		||||
		StartupItem = Assembly-CSharp.csproj
 | 
			
		||||
		Policies = $0
 | 
			
		||||
		$0.TextStylePolicy = $1
 | 
			
		||||
 
 | 
			
		||||
@@ -7,16 +7,14 @@
 | 
			
		||||
    <SchemaVersion>2.0</SchemaVersion>
 | 
			
		||||
    <ProjectGuid>{02576F1D-BE9C-CFA7-763D-1EBF63B36977}</ProjectGuid>
 | 
			
		||||
    <OutputType>Library</OutputType>
 | 
			
		||||
    <RootNamespace>
 | 
			
		||||
    </RootNamespace>
 | 
			
		||||
    <RootNamespace></RootNamespace>
 | 
			
		||||
    <AssemblyName>Assembly-CSharp</AssemblyName>
 | 
			
		||||
    <FileAlignment>512</FileAlignment>
 | 
			
		||||
    <ProjectTypeGuids>{E097FAD1-6243-4DAD-9C02-E9B9EFC3FFC1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
 | 
			
		||||
    <TargetFrameworkIdentifier>.NETFramework</TargetFrameworkIdentifier>
 | 
			
		||||
    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
 | 
			
		||||
    <TargetFrameworkProfile>Unity Subset v3.5</TargetFrameworkProfile>
 | 
			
		||||
    <CompilerResponseFile>
 | 
			
		||||
    </CompilerResponseFile>
 | 
			
		||||
    <CompilerResponseFile></CompilerResponseFile>
 | 
			
		||||
    <UnityProjectType>Game:1</UnityProjectType>
 | 
			
		||||
    <UnityBuildTarget>StandaloneWindows64:19</UnityBuildTarget>
 | 
			
		||||
    <UnityVersion>5.0.1f1</UnityVersion>
 | 
			
		||||
@@ -90,6 +88,7 @@
 | 
			
		||||
    <Compile Include="Assets\Scripts\Noise\NoiseGenerator.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\Noise\PerlinNoiseGenerator.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\Utils\Algorithms.cs" />
 | 
			
		||||
    <Compile Include="Assets\Scripts\Utils\Algorithms\GridTraverseAlgorithm.cs" />
 | 
			
		||||
@@ -109,8 +108,5 @@
 | 
			
		||||
    <None Include="Assets\Data\Config\tergen.xml" />
 | 
			
		||||
    <None Include="Assets\Standard Assets\Environment\Water (Basic)\Shaders\FXWaterBasic.shader" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Folder Include="Assets\Scripts\Storage\" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <Import Project="$(MSBuildExtensionsPath)\SyntaxTree\UnityVS\2013\UnityVS.CSharp.targets" />
 | 
			
		||||
</Project>
 | 
			
		||||
</Project>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user