static public void ApplyNoiseToSphere(SurfaceMap sphereLayer, Vector3Int center) { foreach (int contourPoint in sphereLayer.contour3D) { Vector3Int contourStartPoint = new Vector3Int(contourPoint % sphereLayer.resolution, (contourPoint / sphereLayer.resolution) % sphereLayer.resolution, contourPoint / sphereLayer.resolution2); Vector3 direction = contourStartPoint - center; direction = direction.normalized; Vector3 contourEndPointF = (contourStartPoint + direction * NoiseSettings.noiseMethod(contourStartPoint, NoiseSettings.frequency) * NoiseSettings.gain); Vector3Int contourEndPoint = new Vector3Int(Mathf.RoundToInt(contourEndPointF.x), Mathf.RoundToInt(contourEndPointF.y), Mathf.RoundToInt(contourEndPointF.z)); Cylinder(sphereLayer, contourStartPoint, contourEndPoint, 1, sphereLayer.ReadMaterial(contourStartPoint.x, contourStartPoint.y, contourStartPoint.z)); } Vector3Int point = new Vector3Int(sphereLayer.contour3D[0] % sphereLayer.resolution, (sphereLayer.contour3D[0] / sphereLayer.resolution) % sphereLayer.resolution, sphereLayer.contour3D[0] / sphereLayer.resolution2); Sphere(sphereLayer, center, (int)((point - center).magnitude), (int)((point - center).magnitude + 1), /*sphereLayer.ReadMaterial(point.x, point.y, point.z)*/ 1, false); }
/// <summary> /// <para>Draw a cylinder between p1 & p2</para> /// <para>Mode: 0 - overlay, 1 - add, 2 - inverse</para> /// </summary> static public void Cylinder(SurfaceMap surfaceMap, Vector3Int p1, Vector3Int p2, int radius, int material) { if (p1.x < 0 || p1.x >= surfaceMap.resolution || p1.y < 0 || p1.y >= surfaceMap.resolution || p1.z < 0 || p1.z >= surfaceMap.resolution) { throw new Exception("p1OutOfBounds"); } if (p2.x < 0 || p2.x >= surfaceMap.resolution || p2.y < 0 || p2.y >= surfaceMap.resolution || p2.z < 0 || p2.z >= surfaceMap.resolution) { throw new Exception("p2OutOfBounds"); } float distance = Vector3Int.Distance(p1, p2); Quaternion rotation = Quaternion.FromToRotation(new Vector3Int(1, 0, 0), p2 - p1); for (int x = 0; x < distance; x++) { for (int z = -radius; z <= radius; z++) { for (int y = -radius; y <= radius; y++) { if (Mathf.Pow(y, 2) + Mathf.Pow(z, 2) <= radius * radius) { //dodać mody Vector3Int pointOnCylinder = Vector3Int.RoundToInt(rotation * new Vector3(x, y, z)); surfaceMap.SetMaterial(p1.x + pointOnCylinder.x, p1.y + pointOnCylinder.y, p1.z + pointOnCylinder.z, material); surfaceMap.SetMaterial(p1.x + pointOnCylinder.x + 1, p1.y + pointOnCylinder.y + 1, p1.z + pointOnCylinder.z + 1, material); } } } } }
/// <summary> /// <para>Draw a sphere from center to radius</para> /// </summary> static public void Sphere(SurfaceMap surfaceMap, Vector3Int center, int radius, int material, bool contour) { if (center.x < 0 || center.y < 0 || center.z < 0) { throw new Exception("PointBelowZero"); } if (center.x >= surfaceMap.resolution || center.y >= surfaceMap.resolution || center.z >= surfaceMap.resolution) { throw new Exception("PointAboweResolution"); } int radius2 = radius * radius; for (int z = center.z - radius; z <= center.z + radius && z < surfaceMap.resolution; z++) { if (z < 0) { z = 0; } for (int y = center.y - radius; y <= center.y + radius && y < surfaceMap.resolution; y++) { if (y < 0) { y = 0; } for (int x = center.x - radius; x <= center.x + radius && x < surfaceMap.resolution; x++) { if (x < 0) { x = 0; } int pointOnSphere = (int)(Mathf.Pow(x - center.x, 2) + Mathf.Pow(y - center.y, 2) + Mathf.Pow(z - center.z, 2)); if (pointOnSphere <= radius2) { surfaceMap.SetBiome(x, y, z, 1); surfaceMap.SetMaterial(x, y, z, material); if (contour && ( (int)(Mathf.Pow(x - center.x + 1, 2) + Mathf.Pow(y - center.y, 2) + Mathf.Pow(z - center.z, 2)) > radius2 || (int)(Mathf.Pow(x - center.x, 2) + Mathf.Pow(y - center.y + 1, 2) + Mathf.Pow(z - center.z, 2)) > radius2 || (int)(Mathf.Pow(x - center.x, 2) + Mathf.Pow(y - center.y, 2) + Mathf.Pow(z - center.z + 1, 2)) > radius2 || (int)(Mathf.Pow(x - center.x - 1, 2) + Mathf.Pow(y - center.y, 2) + Mathf.Pow(z - center.z, 2)) > radius2 || (int)(Mathf.Pow(x - center.x, 2) + Mathf.Pow(y - center.y - 1, 2) + Mathf.Pow(z - center.z, 2)) > radius2 || (int)(Mathf.Pow(x - center.x, 2) + Mathf.Pow(y - center.y, 2) + Mathf.Pow(z - center.z - 1, 2)) > radius2 || x == 0 || x == surfaceMap.resolution - 1 || y == 0 || y == surfaceMap.resolution - 1 || z == 0 || y == surfaceMap.resolution - 1) ) { surfaceMap.SetContour(x, y, z); } } //else surfaceMap.SetMaterial(x, y, z, 0); } } } }
/// <summary> /// Calculates the approximate area of a point on a map projection with the given /// characteristics, by transforming the point and its nearest neighbors to latitude and /// longitude, calculating the midpoints between them, and calculating the area of the /// region enclosed within those midpoints. /// </summary> /// <param name="region">The mapped region.</param> /// <param name="planet">The mapped planet.</param> /// <param name="x">The x coordinate of a point on a map projection, with zero as the /// westernmost point.</param> /// <param name="y">The y coordinate of a point on a map projection, with zero as the /// northernmost point.</param> /// <param name="resolution">The vertical resolution of the projection.</param> /// <param name="options"> /// The map projection options used to generate the map used. /// </param> /// <returns>The area of the given point, in m².</returns> public static HugeNumber GetAreaOfLocalPoint( this SurfaceRegion region, Planetoid planet, int x, int y, int resolution, MapProjectionOptions options) => SurfaceMap.GetAreaOfPointFromRadiusSquared( planet.RadiusSquared, x, y, (int)Math.Floor(resolution * options.AspectRatio), resolution, region.GetProjection(planet, options.EqualArea));
public static DunesDescription CreateFromPlacement(Point origin, int width, int height) { Rectangle area = new Rectangle(origin.X - width / 2, origin.Y - height / 2, width, height); return(new DunesDescription { Area = area, IsValid = true, Surface = SurfaceMap.FromArea(area.Left - 20, area.Width + 40), WindDirection = ((WorldGen.genRand.Next(2) != 0) ? WindDirection.Right : WindDirection.Left) }); }
/// <summary> /// <para>Draw a straight line between p1 & p2</para> /// <para>Mode: 0 - overlay, 1 - add, 2 - inverse</para> /// </summary> static public void Line(SurfaceMap surfaceMap, Vector3Int p1, Vector3Int p2, int width, int material, bool contour, int mode) { if (p1.x < 0 || p1.x >= surfaceMap.resolution || p1.y < 0 || p1.y >= surfaceMap.resolution || p1.z < 0 || p1.z >= surfaceMap.resolution) { throw new Exception("p1OutOfBounds"); } if (p2.x < 0 || p2.x >= surfaceMap.resolution || p2.y < 0 || p2.y >= surfaceMap.resolution || p2.z < 0 || p2.z >= surfaceMap.resolution) { throw new Exception("p2OutOfBounds"); } if (mode < 0 || mode > 2) { throw new Exception("InvalidMode"); } if (Vector3Int.Distance(Vector3Int.zero, p1) > Vector3Int.Distance(Vector3Int.zero, p2)) { Vector3Int tmp = p2; p2 = p1; p1 = tmp; } Vector3Int direction = p2 - p1; int x, y, z; for (float t = 0.0f; t <= 1.0f; t = t + (1.0f / (2 * Vector3.Distance(p1, p2)))) { int offset = 0; int widthCopy = width; while (widthCopy > 0) { if (width % 2 == 1) { x = p1.x + offset + (int)(direction.x * t); y = p1.y + offset + (int)(direction.y * t); z = p1.z + offset + (int)(direction.z * t); } else { x = p1.x - offset + (int)(direction.x * t); y = p1.y - offset + (int)(direction.y * t); z = p1.z - offset + (int)(direction.z * t); } offset++; widthCopy--; surfaceMap.SetMaterial(x, y, z, material); if (contour) { surfaceMap.SetContour(x, y, z); } } } }
public static DunesBiome.DunesDescription CreateFromPlacement( Point origin, int width, int height) { Microsoft.Xna.Framework.Rectangle rectangle = new Microsoft.Xna.Framework.Rectangle(origin.X - width / 2, origin.Y - height / 2, width, height); return(new DunesBiome.DunesDescription() { Area = rectangle, IsValid = true, Surface = SurfaceMap.FromArea(rectangle.Left - 20, rectangle.Width + 40), WindDirection = WorldGen.genRand.Next(2) == 0 ? DunesBiome.WindDirection.Left : DunesBiome.WindDirection.Right }); }
/// <summary> /// Determines whether the given proportion of the year falls within the range indicated for /// a <paramref name="position"/> in a <paramref name="region"/>. /// </summary> /// <param name="region">The mapped region.</param> /// <param name="planet">The mapped planet.</param> /// <param name="position">A position relative to the center of <paramref /// name="region"/>.</param> /// <param name="ranges">A set of ranges.</param> /// <param name="proportionOfYear"> /// The proportion of the year, starting and ending with midwinter, at which the calculation /// is to be performed. /// </param> /// <param name="equalArea"> /// If <see langword="true"/> the projection will be a cylindrical equal-area projection. /// Otherwise, an equirectangular projection will be used. /// </param> /// <returns><see langword="true"/> if the given proportion of the year falls within the /// range indicated for a <paramref name="position"/> in a <paramref name="region"/>; /// otherwise <see langword="false"/>.</returns> public static bool GetAnnualRangeIsPositiveAtTimeAndLocalPosition( this SurfaceRegion region, Planetoid planet, Vector3 position, FloatRange[,] ranges, float proportionOfYear, bool equalArea = false) { var(x, y) = region.GetProjectionFromLocalPosition( planet, position, ranges.GetLength(0), ranges.GetLength(1), equalArea); return(SurfaceMap.GetAnnualRangeIsPositiveAtTime(ranges[x, y], proportionOfYear)); }
/// <summary> /// <para>Merge layer top with bottom</para> /// <para>Mode: 0 - overlay, 1 - add, 2 - inverse</para> /// </summary> public static void MergeMaterialLayers(SurfaceMap bottom, SurfaceMap top, int mode) { if (mode < 0 || mode > 2) { throw new Exception("InvalidMode"); } for (int i = 0; i < Mathf.Pow(bottom.resolution, 3); i++) { switch (mode) { case 0: bottom.map3D[i] = (byte)((bottom.map3D[i] & 0xF0) | (top.map3D[i] & 0x0F)); break; case 1: if ((bottom.map3D[i] & 0x0F) == 0) { bottom.map3D[i] = (byte)((bottom.map3D[i] & 0xF0) | (top.map3D[i] & 0x0F)); } break; case 2: if ((bottom.map3D[i] & 0x0F) != 0) { bottom.map3D[i] = (byte)(bottom.map3D[i] & 0xF0); } else { bottom.map3D[i] = (byte)((bottom.map3D[i] & 0xF0) | (top.map3D[i] & 0x0F)); } break; } } bottom.contour3D.Clear(); for (int i = 0; i < top.contour3D.Count; i++) { bottom.contour3D.Add(top.contour3D[i]); } }
private void Awake() { resolution = chunkGridResolution * chunksMultiplier * isoMultiplier; Vector3Int center = new Vector3Int(resolution / 2, resolution / 2, resolution / 2); surfaceMap = new SurfaceMap(resolution); SurfaceMap layer1 = new SurfaceMap(resolution); DrawSurface.Sphere(layer1, center, radius, 3, true); DrawSurface.NoiseSettings.lacunarity = 1; DrawSurface.NoiseSettings.persistance = 0; DrawSurface.NoiseSettings.octaves = 1; DrawSurface.NoiseSettings.frequency = 3; DrawSurface.NoiseSettings.gain = 5; DrawSurface.ApplyNoiseToSphere(layer1, center); SurfaceMap.MergeMaterialLayers(surfaceMap, layer1, 1); //SurfaceMap.MergeMaterialLayers(surfaceMap, layer1, 0); //DrawSurface.Cylinder(surfaceMap, new Vector3Int(7, 7, 7), new Vector3Int(13, 13, 10), 6, 2, 0); /*//DrawSurface.Line(layer1, new Vector3Int(1, 0, 0), new Vector3Int(1, 5, 0), 2, 1, false, 0); * * DrawSurface.NoiseSettings.lacunarity = 1; * DrawSurface.NoiseSettings.persistance = 0; * DrawSurface.NoiseSettings.octaves = 1; * DrawSurface.NoiseSettings.frequency = 1; * DrawSurface.NoiseSettings.gain = 20; * DrawSurface.ApplyNoiseToSphere(layer1, center); * SurfaceMap.MergeMaterialLayers(surfaceMap, layer1, 1);*/ voxelMap.size = size; voxelMap.chunkResolution = chunksMultiplier; voxelMap.voxelResolution = chunkGridResolution; voxelMapObject = Instantiate <VoxelMap>(voxelMap, position, rotation); Refresh(); }
/// <summary> /// Initializes a new instance of <see cref="WeatherMaps"/>. /// </summary> /// <param name="planet">The planet being mapped.</param> /// <param name="elevationMap">An elevation map.</param> /// <param name="winterTemperatureMap">A winter temperature map.</param> /// <param name="summerTemperatureMap">A summer temperature map.</param> /// <param name="precipitationMap">A precipitation map.</param> /// <param name="resolution">The intended vertical resolution of the maps.</param> /// <param name="options"> /// The map projection options to use. All the map images must have been generated using /// these same options, or thew results will not be accurate. /// </param> public WeatherMaps( Planetoid planet, Image <L16> elevationMap, Image <L16> winterTemperatureMap, Image <L16> summerTemperatureMap, Image <L16> precipitationMap, int resolution, MapProjectionOptions?options = null) { var projection = options ?? MapProjectionOptions.Default; XLength = (int)Math.Floor(projection.AspectRatio * resolution); YLength = resolution; BiomeMap = new BiomeType[XLength][]; ClimateMap = new ClimateType[XLength][]; var humidityMap = new HumidityType[XLength][]; SeaIceRangeMap = new FloatRange[XLength][]; for (var x = 0; x < XLength; x++) { BiomeMap[x] = new BiomeType[YLength]; ClimateMap[x] = new ClimateType[YLength]; humidityMap[x] = new HumidityType[YLength]; SeaIceRangeMap[x] = new FloatRange[YLength]; } var scale = SurfaceMap.GetScale(resolution, projection.Range); var stretch = scale / projection.ScaleFactor; var elevationScale = SurfaceMap.GetScale(elevationMap.Height, projection.Range); var winterScale = winterTemperatureMap.Height == elevationMap.Height ? elevationScale : SurfaceMap.GetScale(winterTemperatureMap.Height, projection.Range); var summerScale = summerTemperatureMap.Height == elevationMap.Height ? elevationScale : SurfaceMap.GetScale(summerTemperatureMap.Height, projection.Range); var precipitationScale = precipitationMap.Height == elevationMap.Height ? elevationScale : SurfaceMap.GetScale(precipitationMap.Height, projection.Range); var totalElevation = 0.0; var minTemperature = 5000.0f; var maxTemperature = 0.0f; var totalTemperature = 0.0f; var totalPrecipiation = 0.0; var xToEX = new Dictionary <int, int>(); var xToWX = new Dictionary <int, int>(); var xToSX = new Dictionary <int, int>(); var xToPX = new Dictionary <int, int>(); for (var y = 0; y < YLength; y++) { var latitude = projection.EqualArea ? SurfaceMap.GetLatitudeOfCylindricalEqualAreaProjection(y, resolution, scale, projection) : SurfaceMap.GetLatitudeOfEquirectangularProjection(y, resolution, scale, projection); var elevationY = projection.EqualArea ? SurfaceMap.GetCylindricalEqualAreaYFromLatWithScale(latitude, elevationMap.Height, elevationScale, projection) : SurfaceMap.GetEquirectangularYFromLatWithScale(latitude, elevationMap.Height, elevationScale, projection); var elevationSpan = elevationMap.GetPixelRowSpan(elevationY); int winterY; if (winterTemperatureMap.Height == elevationMap.Height) { winterY = elevationY; } else if (projection.EqualArea) { winterY = SurfaceMap.GetCylindricalEqualAreaYFromLatWithScale(latitude, winterTemperatureMap.Height, winterScale, projection); } else { winterY = SurfaceMap.GetEquirectangularYFromLatWithScale(latitude, winterTemperatureMap.Height, winterScale, projection); } var winterSpan = winterTemperatureMap.GetPixelRowSpan(winterY); int summerY; if (summerTemperatureMap.Height == elevationMap.Height) { summerY = elevationY; } else if (projection.EqualArea) { summerY = SurfaceMap.GetCylindricalEqualAreaYFromLatWithScale(latitude, summerTemperatureMap.Height, summerScale, projection); } else { summerY = SurfaceMap.GetEquirectangularYFromLatWithScale(latitude, summerTemperatureMap.Height, summerScale, projection); } var summerSpan = summerTemperatureMap.GetPixelRowSpan(summerY); int precipitationY; if (precipitationMap.Height == elevationMap.Height) { precipitationY = elevationY; } else if (projection.EqualArea) { precipitationY = SurfaceMap.GetCylindricalEqualAreaYFromLatWithScale(latitude, precipitationMap.Height, precipitationScale, projection); } else { precipitationY = SurfaceMap.GetEquirectangularYFromLatWithScale(latitude, precipitationMap.Height, precipitationScale, projection); } var precipitationSpan = precipitationMap.GetPixelRowSpan(precipitationY); for (var x = 0; x < XLength; x++) { if (!xToEX.TryGetValue(x, out var elevationX)) { var longitude = projection.EqualArea ? SurfaceMap.GetLongitudeOfCylindricalEqualAreaProjection(x, XLength, scale, projection) : SurfaceMap.GetLongitudeOfEquirectangularProjection(x, XLength, stretch, projection); elevationX = projection.EqualArea ? SurfaceMap.GetCylindricalEqualAreaXFromLonWithScale(longitude, elevationMap.Width, elevationScale, projection) : SurfaceMap.GetEquirectangularXFromLonWithScale(longitude, elevationMap.Width, elevationScale, projection); int wX; if (winterTemperatureMap.Width == elevationMap.Width) { wX = elevationX; } else if (projection.EqualArea) { wX = SurfaceMap.GetCylindricalEqualAreaXFromLonWithScale(longitude, winterTemperatureMap.Width, winterScale, projection); } else { wX = SurfaceMap.GetEquirectangularXFromLonWithScale(longitude, winterTemperatureMap.Width, winterScale, projection); } int sX; if (summerTemperatureMap.Width == elevationMap.Width) { sX = elevationX; } else if (projection.EqualArea) { sX = SurfaceMap.GetCylindricalEqualAreaXFromLonWithScale(longitude, summerTemperatureMap.Width, summerScale, projection); } else { sX = SurfaceMap.GetEquirectangularXFromLonWithScale(longitude, summerTemperatureMap.Width, summerScale, projection); } int pX; if (precipitationMap.Width == elevationMap.Width) { pX = elevationX; } else if (projection.EqualArea) { pX = SurfaceMap.GetCylindricalEqualAreaXFromLonWithScale(longitude, precipitationMap.Width, precipitationScale, projection); } else { pX = SurfaceMap.GetEquirectangularXFromLonWithScale(longitude, precipitationMap.Width, precipitationScale, projection); } xToEX.Add(x, elevationX); xToWX.Add(x, wX); xToSX.Add(x, sX); xToPX.Add(x, pX); } var winterX = xToWX[x]; var summerX = xToSX[x]; var precipitationX = xToPX[x]; var normalizedElevation = elevationSpan[elevationX].GetValueFromPixel_PosNeg() - planet.NormalizedSeaLevel; totalElevation += normalizedElevation; var winterTemperature = (float)(winterSpan[winterX].GetValueFromPixel_Pos() * SurfaceMapImage.TemperatureScaleFactor); var summerTemperature = (float)(summerSpan[summerX].GetValueFromPixel_Pos() * SurfaceMapImage.TemperatureScaleFactor); minTemperature = Math.Min(minTemperature, Math.Min(winterTemperature, summerTemperature)); maxTemperature = Math.Max(maxTemperature, Math.Max(winterTemperature, summerTemperature)); totalTemperature += (minTemperature + maxTemperature) / 2; var precipValue = precipitationSpan[precipitationX].GetValueFromPixel_Pos(); var precipitation = precipValue * planet.Atmosphere.MaxPrecipitation; totalPrecipiation += precipValue; ClimateMap[x][y] = Universe.Climate.Climate.GetClimateType(new FloatRange( Math.Min(winterTemperature, summerTemperature), Math.Max(winterTemperature, summerTemperature))); humidityMap[x][y] = Universe.Climate.Climate.GetHumidityType(precipitation); BiomeMap[x][y] = Universe.Climate.Climate.GetBiomeType(ClimateMap[x][y], humidityMap[x][y], normalizedElevation); if (normalizedElevation > 0 || (summerTemperature >= Substances.All.Seawater.MeltingPoint && winterTemperature >= Substances.All.Seawater.MeltingPoint)) { continue; } if (summerTemperature < Substances.All.Seawater.MeltingPoint && winterTemperature < Substances.All.Seawater.MeltingPoint) { SeaIceRangeMap[x][y] = FloatRange.ZeroToOne; continue; } var freezeProportion = ((summerTemperature >= winterTemperature ? winterTemperature.InverseLerp(summerTemperature, (float)(Substances.All.Seawater.MeltingPoint ?? 0)) : summerTemperature.InverseLerp(winterTemperature, (float)(Substances.All.Seawater.MeltingPoint ?? 0))) * 0.8f) - 0.1f; if (freezeProportion <= 0 || float.IsNaN(freezeProportion)) { continue; } var freezeStart = 1 - (freezeProportion / 4); var iceMeltFinish = freezeProportion * 3 / 4; if (latitude < 0) { freezeStart += 0.5f; if (freezeStart > 1) { freezeStart--; } iceMeltFinish += 0.5f; if (iceMeltFinish > 1) { iceMeltFinish--; } } SeaIceRangeMap[x][y] = new FloatRange(freezeStart, iceMeltFinish); } } Climate = Universe.Climate.Climate.GetClimateType(new FloatRange(minTemperature, totalTemperature / (XLength * YLength), maxTemperature)); var humidity = Universe.Climate.Climate.GetHumidityType(totalPrecipiation / (XLength * YLength) * planet.Atmosphere.MaxPrecipitation); Biome = Universe.Climate.Climate.GetBiomeType(Climate, humidity, totalElevation / (XLength * YLength) * planet.MaxElevation); }
/// <summary> /// Determines whether the given <paramref name="moment"/> falls within the range indicated. /// </summary> /// <param name="planet">The mapped planet.</param> /// <param name="range">The range being interpolated.</param> /// <param name="moment">The time at which the determination is to be performed.</param> /// <returns><see langword="true"/> if the range indicates a positive result for the given /// <paramref name="moment"/>; otherwise <see langword="false"/>.</returns> public static bool GetAnnualRangeIsPositiveAtTime( this Planetoid planet, FloatRange range, Instant moment) => SurfaceMap.GetAnnualRangeIsPositiveAtTime(range, (float)planet.GetProportionOfYearAtTime(moment));