public Site(TerraMesh _host, int _index) { m_Host = _host; Index = _index; CornerIdxs = m_Host.SiteCorners[Index]; NeighborIdxs = m_Host.SiteNeighbors[Index]; }
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(); }
//TODO update for new terramesh public static TerraMesh Deserialize(byte[] _serializedData) { var sb = new SerializedBundle(_serializedData); var tm = new TerraMesh(sb.Vertices, sb.Triangles); tm.HullSites = sb.HullSites; tm.SiteCorners = sb.SiteCorners; tm.SiteNeighbors = sb.SiteNeighbors; tm.SitesHavingCorner = sb.SitesHavingCorner; return(tm); }
public static void SetSiteHeight(TerraMesh _terraMesh, int _siteIdx, float _newZ) { var curSitePos = _terraMesh.GetSitePosition(_siteIdx); var heightDiff = _newZ - curSitePos.z; var cornerIndexes = _terraMesh.SiteCorners[_siteIdx]; foreach (var cornerIdx in cornerIndexes) { var curCornerPos = _terraMesh.Vertices[cornerIdx]; var newCornerPos = new Vector3(curCornerPos.x, curCornerPos.y, curCornerPos.z + heightDiff); _terraMesh.Vertices[cornerIdx] = newCornerPos; _terraMesh.m_Bounds.Encapsulate(newCornerPos); } }
public static void Erode(TerraMesh _tMesh, float _maxErosionRate, float[] _waterFlux) { var sitePositions = _tMesh.GetAllSitePositions(); //TODO SLOW //Get all site slope vectors and slope values var slopeVecs = new Vector3[sitePositions.Length]; var slopeVals = new float[sitePositions.Length]; for (var pIdx = 0; pIdx < sitePositions.Length; ++pIdx) { var p = sitePositions[pIdx]; var aveSlp = Vector3.zero; var nbrCnt = 0; foreach (var nIdx in _tMesh.SiteNeighbors[pIdx]) { if (nIdx == SiteIdxNull) { continue; } nbrCnt++; var n = sitePositions[nIdx]; var slpVec = n - p; if (slpVec.z > 0) { slpVec = -slpVec; } aveSlp += slpVec; } var slpVecCell = aveSlp / nbrCnt; slopeVecs[pIdx] = slpVecCell; slopeVals[pIdx] = slpVecCell.z / new Vector2(slpVecCell.x, slpVecCell.y).magnitude; } //Apply erosion to terra mesh surface for (var pIdx = 0; pIdx < _waterFlux.Length; ++pIdx) { var sitePos = sitePositions[pIdx]; var fx = (float)Math.Sqrt(_waterFlux[pIdx]); var slp = slopeVals[pIdx]; var erosionShift = Math.Min(-slp * fx, _maxErosionRate); //var newPos = new Vector3(sitePos.x, sitePos.y, sitePos.z - erosionShift); SetSiteHeight(_tMesh, pIdx, sitePos.z - erosionShift); } _tMesh.RecalculateBounds(); }
public static void Blob(TerraMesh _tMesh, float _strength, float _radius, Vector2 _loc) { for (var sIdx = 0; sIdx < _tMesh.Vertices.Length; ++sIdx) { var sPos = _tMesh.Vertices[sIdx]; var vert2d = sPos.ToVec2(); var dist = (vert2d - _loc).magnitude; if (dist > _radius) { continue; } var cosVal = dist / _radius * (float)Math.PI / 2f; var zShift = _strength * (float)Math.Cos(cosVal); var newZ = sPos.z + zShift; var newPos = new Vector3(vert2d.x, vert2d.y, sPos.z + zShift); _tMesh.Vertices[sIdx] = newPos; } _tMesh.RecalculateBounds(); }
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 void SetHeightSpan(TerraMesh _terraMesh, float _min, float _max) { float minZ = float.PositiveInfinity, maxZ = float.NegativeInfinity; for (var sIdx = 0; sIdx < _terraMesh.Vertices.Length; ++sIdx) { var z = _terraMesh.Vertices[sIdx].z; if (z < minZ) { minZ = z; } if (z > maxZ) { maxZ = z; } } var zSpan = maxZ - minZ; var newSpan = _max - _min; for (var sIdx = 0; sIdx < _terraMesh.Vertices.Length; ++sIdx) { var sPos = _terraMesh.Vertices[sIdx]; var zPct = (sPos.z - minZ) / zSpan; _terraMesh.Vertices[sIdx].Set(sPos.x, sPos.y, zPct * newSpan + _min); } var bounds = _terraMesh.bounds; bounds.min = new Vector3(bounds.min.x, bounds.min.y, _min); bounds.max = new Vector3(bounds.max.x, bounds.max.y, _max); _terraMesh.m_Bounds = bounds; }
public SerializedBundle(TerraMesh _tm) { Version = CUR_VERSION; //Vector3 -- 12 bytes Vertices = _tm.Vertices; //TODO Broken //int - 4 bytes Triangles = _tm.Triangles; //int - 4 bytes HullSites = _tm.HullSites; //3 ints - 12 bytes SiteCorners = _tm.SiteCorners; //3 ints - 12 bytes SiteNeighbors = _tm.SiteNeighbors; //Vector3 -- 12 bytes //SitePositions = _tm.SitePositions; //TODO BROKEN //Variable -- need to track length for each set SitesHavingCorner = _tm.SitesHavingCorner; var totalSetCount = 0; for (var cornerIdx = 0; cornerIdx < SitesHavingCorner.Length; ++cornerIdx) { totalSetCount += _tm.SitesHavingCorner[cornerIdx].Count; } var dataLen = sizeof(int); //Total size header dataLen += sizeof(int); // Version dataLen += sizeof(int); // Vertex count header dataLen += Vertices.Length * sizeof(float) * 2; // Vector2 dataLen += sizeof(int); // Triangle count header dataLen += Triangles.Length * sizeof(int); //int dataLen += sizeof(int); // HullSites count header dataLen += HullSites.Length * sizeof(int); //int dataLen += sizeof(int); // SiteCorners count header dataLen += SiteCorners.Length * sizeof(int) * 3; //int * 3 dataLen += sizeof(int); // SiteNeighbors count header dataLen += SiteNeighbors.Length * sizeof(int) * 3; // int * 3 dataLen += sizeof(int); // SitePositions count header dataLen += SitePositions.Length * sizeof(float) * 3; // Vector3 dataLen += sizeof(int); // Site having corner set count dataLen += SitesHavingCorner.Length * sizeof(int); //Site Having corner count headers dataLen += totalSetCount * sizeof(int); //Sites having corner set indexes SerializedData = new byte[dataLen]; BufIdx = 0; byte32 = new Byte32(); bytesVec2 = new ByteVector2(); bytesVec3 = new ByteVector3(); byte32.Write(SerializedData, ref BufIdx, dataLen); byte32.Write(SerializedData, ref BufIdx, Version); SerializeVertices(ref BufIdx, SerializedData); SerializeTris(ref BufIdx, SerializedData); SerializeHullSites(ref BufIdx, SerializedData); SerializeSiteCorners(ref BufIdx, SerializedData); SerializeSiteNeighbors(ref BufIdx, SerializedData); SerializeSitePositions(ref BufIdx, SerializedData); SerializeSitesHavingCorner(ref BufIdx, SerializedData); }
public static byte[] Serialize(TerraMesh _terraMesh) { var sb = new SerializedBundle(_terraMesh); return(sb.SerializedData); }
public static void NormalizeHeight(TerraMesh _terraMesh) { SetHeightSpan(_terraMesh, 0, 1); }
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); }
public static void Slice(TerraMesh _tMesh, int _maxVertCount, out int[][] _triIdxs) { //Check if already meet max vert count if (_tMesh.Vertices.Length <= _maxVertCount) { _triIdxs = new int[1][]; _triIdxs[0] = _tMesh.Triangles; return; } var bndRect = new Rect(_tMesh.m_Bounds.min.x, _tMesh.m_Bounds.min.y, _tMesh.m_Bounds.size.x, _tMesh.m_Bounds.size.y); //Find correct slice count (2x2, 3x3, 4x4, etc.) var rowCnt = 2; int boxCnt; float sliceWidth; float sliceHeight; Dictionary <int, int> vIdxToMIdx; while (true) { var nextRowCnt = false; boxCnt = rowCnt * rowCnt; sliceWidth = bndRect.width / rowCnt; sliceHeight = bndRect.height / rowCnt; var vertsPerBox = new int[boxCnt]; vIdxToMIdx = new Dictionary <int, int>(); for (var vIdx = 0; vIdx < _tMesh.Vertices.Length; ++vIdx) { var curVert = _tMesh.Vertices[vIdx]; //Find Col for (var xScanIdx = 1; xScanIdx <= rowCnt; ++xScanIdx) { var pointBoxed = false; var xMax = xScanIdx * sliceWidth; if (curVert.x > xMax) { continue; } //Find Row for (var yScanIdx = 1; yScanIdx <= rowCnt; ++yScanIdx) { var yMax = yScanIdx * sliceHeight; if (curVert.y > yMax) { continue; } var meshIdx = (yScanIdx - 1) * rowCnt + (xScanIdx - 1); vertsPerBox[meshIdx]++; if (vertsPerBox[meshIdx] >= _maxVertCount) { nextRowCnt = true; break; } vIdxToMIdx.Add(vIdx, meshIdx); pointBoxed = true; break; } if (nextRowCnt || pointBoxed) { break; } } if (nextRowCnt) { break; } } if (!nextRowCnt) { break; } rowCnt++; } boxCnt = rowCnt * rowCnt; var triIdx = new List <int> [boxCnt]; var tris = _tMesh.Triangles; for (var boxIdx = 0; boxIdx < boxCnt; ++boxIdx) { triIdx[boxIdx] = new List <int>(); } for (var tIdx = 0; tIdx < tris.Length; tIdx += 3) { var idxa = tris[tIdx]; var idxb = tris[tIdx + 1]; var idxc = tris[tIdx + 2]; var meshBoxIdx = vIdxToMIdx[idxa]; triIdx[meshBoxIdx].Add(idxa); triIdx[meshBoxIdx].Add(idxb); triIdx[meshBoxIdx].Add(idxc); } _triIdxs = new int[boxCnt][]; for (var boxIdx = 0; boxIdx < boxCnt; ++boxIdx) { _triIdxs[boxIdx] = triIdx[boxIdx].ToArray(); } }