public static void Conify(TerraMesh _tMesh, float _strength, Progress.OnUpdate _onUpdate = null) { if (_onUpdate == null) { _onUpdate = (_prog, _str) => { } } ; var prog = new Progress(); prog.SetOnUpdate(_onUpdate); var cent = _tMesh.m_Bounds.center.ToVec2(); var min = _tMesh.m_Bounds.min.ToVec2(); var maxMag = (min - cent).magnitude; prog.Update(0, "Conifying"); for (var sIdx = 0; sIdx < _tMesh.Vertices.Length; ++sIdx) { var sitePos = _tMesh.Vertices[sIdx]; var magScal = (new Vector2(sitePos.x, sitePos.y) - cent).magnitude / maxMag - 0.5f; var zShift = magScal * _strength / 2f; var newPos = new Vector3(sitePos.x, sitePos.y, zShift + sitePos.z); _tMesh.Vertices[sIdx] = newPos; prog.Update((float)sIdx / _tMesh.Vertices.Length); } _tMesh.RecalculateBounds(); }
public void TestGenerate() { var sets = TerraMap.Settings.Default; var width = sets.Bounds.width; var height = sets.Bounds.height; var density = sets.Resolution; var seed = sets.Seed; var vertices = TerraMap.TerraMesh.Generator.GenerateRandomVertices(width, height, density, seed); var generator = TerraMap.TerraMesh.Generator.StageMeshGeneration(vertices); TerraMap.TerraMesh tMesh; Progress.OnUpdate onUpdate = (_pct, _str) => Trace.WriteLine(_str + " : " + _pct); TerraMap.TerraMesh.Generator.OnComplete onComplete = _tm => tMesh = _tm; var genThread = new Thread(() => generator.Generate(onUpdate, onComplete)); genThread.Start(); var secondCounter = 0; while (genThread.IsAlive) { Trace.WriteLine("Waiting for thread: " + secondCounter++); System.Threading.Thread.Sleep(1000); } }
private void GenerateTMesh(Progress.OnUpdate _onUpdate = null) { var onUpdate = _onUpdate ?? ((_progPct, _progStr) => { }); m_Prog.SetOnUpdate(onUpdate); void TMeshOnComplete(TerraMesh _tMesh) { m_TerraMap.TMesh = _tMesh; } var settings = m_TerraMap.settings; var width = settings.Bounds.height; var height = settings.Bounds.height; var pointDensity = settings.Resolution; var seed = settings.Seed; if (Vertices == null) { Vertices = TerraMesh.Generator.GenerateRandomVertices(width, height, pointDensity, seed); } var terraMeshGen = TerraMesh.Generator.StageMeshGeneration(Vertices); terraMeshGen.Generate(_onUpdate, TMeshOnComplete); //TerraMesh.Generator.Generate(_gen.m_TerraMap.settings, onUpdate, TMeshOnComplete); }
public void Generate(OnComplete _onComplete, Progress.OnUpdate _onUpdate) { GenerateTMesh(_onUpdate); //Temp TODO m_Prog.Update(0, "Creating Map Texture", true); m_TerraMap.TTex = new TerraTexture(m_TerraMap, _onUpdate); m_Prog.Update(1, "Creating Map Texture", true); m_Prog.Update(0, "Creating Biomes", true); m_TerraMap.TBiome = new BiomeStuff(m_TerraMap); m_Prog.Update(1, "Creating Biomes", true); _onComplete(m_TerraMap); }
public void TestSerializationTerraMesh() { var fullFileName = FilePath + "\\TerraMesh" + FileName; var resolution = 1f; var sets = new TerraMap.Settings(); sets.Resolution = 1; sets.Bounds = new Rect(Vector2.one, 256 * Vector2.one); sets.GlobalSlopeDir = Vector2.left; Progress.OnUpdate progOnUpdate = (_pct, _str) => { Trace.WriteLine(_str); Trace.WriteLine(_pct * 100 + "%"); }; var isDone = false; TerraMap finishedMap = null; TerraMap.Generator.OnComplete onComplete = _tMap => { finishedMap = _tMap; isDone = true; }; var gen = TerraMap.Generator.StageMapCreation(sets); var genThread = new Thread(() => gen.Generate(onComplete, progOnUpdate)); genThread.Start(); while (isDone == false) { Thread.Sleep(100); } var mapExists = finishedMap != null; var tMeshOrig = finishedMap.TMesh; var serializedTMesh = TerraMap.TerraMesh.Serialize(tMeshOrig); File.WriteAllBytes(fullFileName, serializedTMesh); var dataFromFile = File.ReadAllBytes(fullFileName); var tMeshFromFile = TerraMap.TerraMesh.Deserialize(dataFromFile); Assert.True(true); }
public TerraTexture(TerraMap _host, Progress.OnUpdate _onUpdate = null) { Host = _host; canvas = new Canvas((int)Math.Ceiling(Host.settings.TextureResolution * Host.settings.Bounds.width), (int)Math.Ceiling(Host.settings.TextureResolution * Host.settings.Bounds.height)); m_Progress = new Progress("TerraTexture"); var actProg = _onUpdate ?? ((_progPct, _progStr) => { }); m_Progress.SetOnUpdate(actProg); m_PixSize = new Vector2(Host.TMesh.bounds.size.x / canvas.Width, Host.TMesh.bounds.size.y / canvas.Height); m_ZeroOffset = Host.TMesh.bounds.min.ToVec2(); Trace.WriteLine("Init Texture W: " + canvas.Width + " H: " + canvas.Height); //Paint Waterways //PaintRivers(); }
public void Test1() { var resolution = 1f; var sets = new TerraMap.Settings(); sets.Resolution = 1; sets.Bounds = new Rect(Vector2.one, 256 * Vector2.one); sets.GlobalSlopeDir = Vector2.left; Progress.OnUpdate progOnUpdate = (_pct, _str) => { Trace.WriteLine(_str); Trace.WriteLine(_pct * 100 + "%"); }; var isDone = false; TerraMap finishedMap = null; TerraMap.Generator.OnComplete onComplete = _tMap => { finishedMap = _tMap; isDone = true; }; var gen = TerraMap.Generator.StageMapCreation(sets); var genThread = new Thread(() => gen.Generate(onComplete, progOnUpdate)); genThread.Start(); while (isDone == false) { Thread.Sleep(100); } var mapExists = finishedMap != null; Assert.True(mapExists); }
public void Generate(Progress.OnUpdate _onUpdate, OnComplete _onComplete) { ProgOnUpdate = _onUpdate; ProgressGenerator.SetOnUpdate(_onUpdate); //Create and triangluate Delaunay DoDelaunayTriangulation(); //Create Voronoi and Lloyd Relax DoVoronoiAndRelax(); //Build TerraMesh Object var mesh = Delaunay.Mesh; TMesh = new TerraMesh(mesh.Vertices, mesh.Triangles); IndexSites(); ComputeSiteData(); PopulateHullSites(); _onComplete(TMesh); }
public static void SlopeGlobal(TerraMesh _tMesh, Vector2 _dir, float _strength, Progress.OnUpdate _onUpdate = null) { if (_onUpdate == null) { _onUpdate = (_prog, _str) => { } } ; var prog = new Progress(); prog.SetOnUpdate(_onUpdate); var dir = _dir.normalized; var bnds = _tMesh.bounds; Func <Vector3, float> strf = _pos => { var xPct = (_pos.x - bnds.min.x) / bnds.size.x - 0.5f; var yPct = (_pos.y - bnds.min.y) / bnds.size.y - 0.5f; var xStr = xPct * dir.x; var yStr = yPct * dir.y; return((xStr + yStr) * _strength / 4f); }; prog.Update(0, "Global Slope"); for (var sIdx = 0; sIdx < _tMesh.Vertices.Length; ++sIdx) { //if (_tMesh.HullSites.Contains(sIdx)) // Trace.WriteLine("Debug Hullsites"); //TODO DEbug var sitePos = _tMesh.Vertices[sIdx]; var zShift = strf(sitePos); var newZ = sitePos.z + zShift; var newPos = new Vector3(sitePos.x, sitePos.y, newZ); _tMesh.Vertices[sIdx] = newPos; prog.Update((float)sIdx / _tMesh.Vertices.Length); } _tMesh.RecalculateBounds(); }
public static Vector3[] PlanchonDarboux(TerraMesh _tMesh, float _minSlope, Progress.OnUpdate _onUpdate) { var prog = new Progress("PlanchonDarboux"); prog.SetOnUpdate(_onUpdate); var sitePosArr = _tMesh.GetAllSitePositions(); //TODO slow? var hullSites = new HashSet <int>(_tMesh.HullSites); //var hullSites = _tMesh.HullSites; //Generate waterflow surface points var newSurf = new Vector3[sitePosArr.Length]; for (var pIdx = 0; pIdx < sitePosArr.Length; ++pIdx) { var sPos = sitePosArr[pIdx]; var z = float.PositiveInfinity; if (hullSites.Contains(pIdx)) { z = sPos.z; } newSurf[pIdx] = new Vector3(sPos.x, sPos.y, z); } Func <int, float> Z = _idx => sitePosArr[_idx].z; Func <int, float> W = _idx => newSurf[_idx].z; Func <int, int, float> E = (_cIdx, _nIdx) => { var cVert = sitePosArr[_cIdx]; var nVert = sitePosArr[_nIdx]; var subX = nVert.x - cVert.x; var subY = nVert.y - cVert.y; return((float)Math.Sqrt(subX * subX + subY * subY) * _minSlope); }; var opDone = false; var wCnt = 0; //DEBUG todo do { opDone = false; var sitePosArrLen = sitePosArr.Length; //TODO Debug for (var pIdx = 0; pIdx < sitePosArrLen; ++pIdx) { var progPct = (float)pIdx / sitePosArrLen; prog.Update(progPct, pIdx + " of " + sitePosArrLen); if (hullSites.Contains(pIdx)) { continue; } var sitePos = sitePosArr[pIdx]; var c = pIdx; if (!(W(c) > Z(c))) { continue; } var cVertZ = sitePos; foreach (var n in _tMesh.SiteNeighbors[pIdx]) { var e = E(c, n); var wpn = W(n) + e; if (cVertZ.z >= wpn) { newSurf[c].Set(cVertZ.x, cVertZ.y, cVertZ.z); opDone = true; break; } if (W(c) > wpn) { newSurf[c].Set(cVertZ.x, cVertZ.y, wpn); opDone = true; } } } if (++wCnt > 2) { break; // TODO DEBUG } } while (opDone); return(newSurf); }
//TODO split old settings add new settings for just this. public static void ApplyRandomLandFeatures(TerraMap _tMap, Action _onComplete, Progress.OnUpdate _onUpdate) { var prog = new Progress(); prog.SetOnUpdate(_onUpdate); var tMesh = _tMap.TMesh; var settings = _tMap.settings; //Land morphing prog.Update(0, "Conifying", true); TerraMesh.Modify.Conify(tMesh, settings.ConifyStrength, _onUpdate); prog.Update(1, "Conifying", true); prog.Update(0, "Applying Global Slope", true); var gSlpDir = settings.GlobalSlopeDir == Vector2.zero ? new Vector2((float)(settings.m_Rnd.NextDouble() - 0.5f), (float)(settings.m_Rnd.NextDouble() - 0.5f)) : settings.GlobalSlopeDir; TerraMesh.Modify.SlopeGlobal(tMesh, gSlpDir, settings.GlobalSlopeMag); prog.Update(1, "Applying Global Slope", true); prog.Update(0, "Adding Hills / Blobs", true); var meshBnd = tMesh.bounds; var rectXY = new Rect(meshBnd.min.x, meshBnd.min.y, meshBnd.size.x, meshBnd.size.y); for (var hIdx = 0; hIdx < settings.HillRndCnt.Count; ++hIdx) { prog.Update((float)hIdx / settings.HillRndCnt.Count, "Adding hills / blobs"); for (var hCnt = 0; hCnt < settings.HillRndCnt[hIdx]; ++hCnt) { TerraMesh.Modify.Blob(tMesh, settings.HillRndStr[hIdx], settings.HillRndRad[hIdx], Settings.RndVec2(rectXY, settings.m_Rnd)); } } prog.Update(1, "Adding Hills / Blobs", true); //Calculate water flux prog.Update(0, "Making Rivers", true); ApplyWaterFlux(_tMap, _onUpdate); prog.Update(1, "Making Rivers", true); //Erosion prog.Update(0, "Eroding", true); TerraMesh.Modify.Erode(tMesh, settings.MaxErosionRate, _tMap.WaterFlux.Select(_node => _node.Flux).ToArray()); prog.Update(1, "Eroding", true); //Calculate Water Level prog.Update(0, "Setting Sea Level", true); SetSeaLevelByLandRatio(_tMap, settings.LandWaterRatio); prog.Update(1, "Setting Sea Level", true); PlaceRivers(_tMap, settings.m_WaterwayThresh); }
//TODO - consider wind effect on rain? ie less rain on downward slopes? public static void ApplyWaterFlux(TerraMap _tMap, Progress.OnUpdate _onUpdate) { var pdSurface = TerraMesh.Generator.PlanchonDarboux(_tMap.TMesh, _tMap.settings.MinPDSlope, _onUpdate); //Calc water flux var sitePos = _tMap.TMesh.GetAllSitePositions(); _tMap.WaterFlux = new WaterNode[sitePos.Length]; //Init waterflux and heightmap - TODO sort not needed? var pIdxByHt = new int[sitePos.Length]; for (var pIdx = 0; pIdx < sitePos.Length; ++pIdx) { pIdxByHt[pIdx] = pIdx; _tMap.WaterFlux[pIdx] = new WaterNode { Flux = _tMap.settings.RainfallGlobal, SiteIdx = pIdx }; } Array.Sort(pIdxByHt, (_a, _b) => pdSurface[_b].z.CompareTo(pdSurface[_a].z)); var dbgHtArr = new float[pIdxByHt.Length]; for (var idx = 0; idx < pIdxByHt.Length; idx++) { dbgHtArr[idx] = pdSurface[pIdxByHt[idx]].z; } for (var hIdx = 0; hIdx < sitePos.Length; ++hIdx) { var pIdx = pIdxByHt[hIdx]; var w = pdSurface[pIdx]; //Find biggest slope neighbor var minNIdx = -1; //var maxNSlp = 0f; float maxZdiff = 0; var siteNbrs = _tMap.TMesh.SiteNeighbors; foreach (var nIdx in siteNbrs[pIdx]) { if (nIdx == TerraMesh.SiteIdxNull) { continue; } var n = pdSurface[nIdx]; if (n.z <= w.z) { var diff = w.z - n.z; if (diff > maxZdiff) { maxZdiff = diff; minNIdx = nIdx; } /* Use slope - (Not working?) * var vec = n - w; * var run = (float) Math.Sqrt(vec.x * vec.x + vec.y * vec.y); * var rise = w.z - n.z; * var slp = rise / run; * if (slp > maxNSlp) * { * minNIdx = nIdx; * maxNSlp = slp; * } */ } } if (minNIdx == -1) //TODO DEBUG should never happen? { continue; } if (minNIdx == pIdx) //TODO DEBUG { continue; } //Add this nodes flux to downhill neighbor _tMap.WaterFlux[minNIdx].Flux += _tMap.WaterFlux[pIdx].Flux; //Set waterway direction _tMap.WaterFlux[pIdx].NodeTo = _tMap.WaterFlux[minNIdx]; //Check min / max var chkFlx = _tMap.WaterFlux[minNIdx].Flux; if (chkFlx > _tMap.WaterFluxMax) { _tMap.WaterFluxMax = chkFlx; } } }