static public void ErosionIteration(Matrix heights, Matrix erosion, Matrix sedimentSum, CoordRect area = new CoordRect(), float erosionDurability = 0.9f, float erosionAmount = 1f, float sedimentAmount = 0.5f, int erosionFluidityIterations = 3, float ruffle = 0.1f, Matrix torrents = null, Matrix sediments = null, int[] stepsArray = null, int[] heightsInt = null, int[] order = null) { if (area.isZero) { area = heights.rect; } int count = heights.count; #region Creating order array int steps = 1000000; //creating int-type copy of heights if (heightsInt == null) { heightsInt = new int[count]; } for (int i = 0; i < heights.count; i++) { heightsInt[i] = (int)(Mathf.Clamp01(heights.array[i]) * steps); //TODO replace fn call } //order array if (order == null) { order = new int[count]; } order = ArrayTools.Order(heightsInt, order: order, max: heights.count, stepsArray: stepsArray); /*if (order==null) order = new int[count]; * for (int i=0; i<order.Length; i++) order[i] = i; * float[] refHeights = new float[heights.array.Length]; * Array.Copy(heights.array, refHeights, heights.array.Length); * Array.Sort(refHeights, order);*/ //setting out-of-area order num to negative for (int j = 0; j < heights.count; j++) { int pos = order[j]; Coord coord = heights.rect.CoordByNum(pos); if (!area.CheckInRangeAndBounds(coord)) { order[j] = -1; } } #endregion #region Creating torrents if (torrents == null) { torrents = new Matrix(heights.rect); } torrents.ChangeRect(heights.rect); torrents.Fill(1f); //casting initial rain for (int j = count - 1; j >= 0; j--) { //finding column ordered by height int pos = order[j]; if (pos < 0) { continue; } /* * MooreCross height = new MooreCross(heights, pos); //moore * MooreCross torrent = new MooreCross(torrents, pos); //moore * if (torrent.c > 2000000000) torrent.c = 2000000000; * * //creating torrents * MooreCross delta = new MooreCross(height); //moore * delta.SubtractInverse(height.c); * delta.ClampPositive(); * * delta.Percent(); //every side now determines a percent - how many water should go to it * delta.Multiply(torrent.c); * torrent.Add(delta); */ //getting height values float[] m = heights.array; int i = pos; int sizeX = heights.rect.size.x; float h = m[i]; float hx = m[i - 1]; float hX = m[i + 1]; float hz = m[i - sizeX]; float hZ = m[i + sizeX]; float hxz = m[i - 1 - sizeX]; float hXz = m[i + 1 - sizeX]; float hxZ = m[i - 1 + sizeX]; float hXZ = m[i + 1 + sizeX]; //creating delta float d = h - h; float dx = h - hx; float dX = h - hX; float dz = h - hz; float dZ = h - hZ; float dxz = h - hxz; float dXz = h - hXz; float dxZ = h - hxZ; float dXZ = h - hXZ; //ignoring negative delta values d = d > 0? d : 0; dx = dx > 0? dx : 0; dX = dX > 0? dX : 0; dz = dz > 0? dz : 0; dZ = dZ > 0? dZ : 0; dxz = dxz > 0? dxz : 0; dXz = dXz > 0? dXz : 0; dxZ = dxZ > 0? dxZ : 0; dXZ = dXZ > 0? dXZ : 0; //finding percents float p = 0, px = 0, pX = 0, pz = 0, pZ = 0, pxz = 0, pXz = 0, pxZ = 0, pXZ = 0; float s = d + dx + dX + dz + dZ + dxz + dXz + dxZ + dXZ; if (s > 0.00001f) { p = d / s; px = dx / s; pX = dX / s; pz = dz / s; pZ = dZ / s; pxz = dxz / s; pXz = dXz / s; pxZ = dxZ / s; pXZ = dXZ / s; } //getting central torrent (and clamping it) float t = torrents.array[i]; if (t > 2000000000) { t = 2000000000; } //spreading central torrent according percents delta. And adding to torrents array m = torrents.array; m[i] += t * p; m[i - 1] += t * px; m[i + 1] += t * pX; m[i - sizeX] += t * pz; m[i + sizeX] += t * pZ; m[i - 1 - sizeX] += t * pxz; m[i + 1 - sizeX] += t * pXz; m[i - 1 + sizeX] += t * pxZ; m[i + 1 + sizeX] += t * pXZ; } #endregion #region Erosion if (sediments == null) { sediments = new Matrix(heights.rect); } else { sediments.ChangeRect(heights.rect); } sediments.Clear(); for (int j = count - 1; j >= 0; j--) { //finding column ordered by height int pos = order[j]; if (pos < 0) { continue; } /* * Cross height = new Cross(heights, pos); * Cross torrent = new Cross(torrents, pos); * Cross sediment = new Cross(sediments, pos); * * //erosion * float erodeLine = (height.c + height.min)/2f; //halfway between current and maximum height * * if (height.c > erodeLine) //raising soil if column is higher than eroded column * { * float raised = height.c - erodeLine; * raised = Mathf.Min(raised, raised*(torrent.c-1) * (1-erosionDurability)); //could not raise more soil than height-minHeight. //torrents always have 1 or more * raised *= erosionAmount; * * heights.array[pos] -= raised; //raising soil * height.c -= raised; * sediments.array[pos] += raised * sedimentAmount; //and saving raised to sediment * sediment.c += raised * sedimentAmount; * * if (paintErosion != null) paintErosion.array[pos] += raised * mapsFactor; //and writing to ref * } */ //getting height values float[] m = heights.array; int i = pos; int sizeX = heights.rect.size.x; float h = m[i]; float hx = m[i - 1]; float hX = m[i + 1]; float hz = m[i - sizeX]; float hZ = m[i + sizeX]; //height minimum float h_min = h; if (hx < h_min) { h_min = hx; } if (hX < h_min) { h_min = hX; } if (hz < h_min) { h_min = hz; } if (hZ < h_min) { h_min = hZ; } //erosion line float erodeLine = (h + h_min) / 2f; //halfway between current and maximum height if (h < erodeLine) { continue; } //raising soil float raised = h - erodeLine; float maxRaised = raised * (torrents.array[pos] - 1) * (1 - erosionDurability); if (raised > maxRaised) { raised = maxRaised; } raised *= erosionAmount; //saving arrays heights.array[pos] -= raised; sediments.array[pos] += raised * sedimentAmount; //sedimentSum.array[pos] += sediments.array[pos] * 10; if (erosion != null) { erosion.array[pos] += raised; //and writing to ref } } #endregion #region Settling sediment for (int l = 0; l < erosionFluidityIterations; l++) { for (int j = count - 1; j >= 0; j--) { //finding column ordered by height int pos = order[j]; if (pos < 0) { continue; } //getting height values float[] m = heights.array; int sizeX = heights.rect.size.x; float h = m[pos]; float hx = m[pos - 1]; float hX = m[pos + 1]; float hz = m[pos - sizeX]; float hZ = m[pos + sizeX]; //getting sediment values m = sediments.array; float s = m[pos]; float sx = m[pos - 1]; float sX = m[pos + 1]; float sz = m[pos - sizeX]; float sZ = m[pos + sizeX]; //sediment sum float sum = s + sx + sX + sz + sZ; if (sum < 0.00001f) { continue; } //pouring sum to all cells float sedimentFifth = sum / 5; s = sedimentFifth; sx = sedimentFifth; sX = sedimentFifth; sz = sedimentFifth; sZ = sedimentFifth; //levelling //for (int i=0; i<2; i++) //{ //x line float avg = (h + s + sx + hx) / 2; if (h + s > hx + sx) { float transfer = s + h - avg; if (transfer > s) { transfer = s; } s -= transfer; sx += transfer; } else { float transfer = sx + hx - avg; if (transfer > sx) { transfer = sx; } sx -= transfer; s += transfer; } avg = (hx + sx + sX + hX) / 2; if (hx + sx > hX + sX) { float transfer = sx + hx - avg; if (transfer > sx) { transfer = sx; } sx -= transfer; sX += transfer; } else { float transfer = sX + hX - avg; if (transfer > sX) { transfer = sX; } sX -= transfer; sx += transfer; } avg = (h + s + sX + hX) / 2; if (h + s > hX + sX) { float transfer = s + h - avg; if (transfer > s) { transfer = s; } s -= transfer; sX += transfer; } else { float transfer = sX + hX - avg; if (transfer > sX) { transfer = sX; } sX -= transfer; s += transfer; } //z line avg = (h + s + sz + hz) / 2; if (h + s > hz + sz) { float transfer = s + h - avg; if (transfer > s) { transfer = s; } s -= transfer; sz += transfer; } else { float transfer = sz + hz - avg; if (transfer > sz) { transfer = sz; } sz -= transfer; s += transfer; } avg = (hZ + sZ + sz + hz) / 2; if (hZ + sZ > hz + sz) { float transfer = sZ + hZ - avg; if (transfer > sZ) { transfer = sZ; } sZ -= transfer; sz += transfer; } else { float transfer = sz + hz - avg; if (transfer > sz) { transfer = sz; } sz -= transfer; sZ += transfer; } avg = (h + s + sz + hz) / 2; if (h + s > hz + sz) { float transfer = s + h - avg; if (transfer > s) { transfer = s; } s -= transfer; sz += transfer; } else { float transfer = sz + hz - avg; if (transfer > sz) { transfer = sz; } sz -= transfer; s += transfer; } //side pairs avg = (hx + sx + sz + hz) / 2; if (hx + sx > hz + sz) { float transfer = sx + hx - avg; if (transfer > sx) { transfer = sx; } sx -= transfer; sz += transfer; } else { float transfer = sz + hz - avg; if (transfer > sz) { transfer = sz; } sz -= transfer; sx += transfer; } avg = (hX + sX + sZ + hZ) / 2; if (hX + sX > hZ + sZ) { float transfer = sX + hX - avg; if (transfer > sX) { transfer = sX; } sX -= transfer; sZ += transfer; } else { float transfer = sZ + hZ - avg; if (transfer > sZ) { transfer = sZ; } sZ -= transfer; sX += transfer; } avg = (hx + sx + sZ + hZ) / 2; if (hx + sx > hZ + sZ) { float transfer = sx + hx - avg; if (transfer > sx) { transfer = sx; } sx -= transfer; sZ += transfer; } else { float transfer = sZ + hZ - avg; if (transfer > sZ) { transfer = sZ; } sZ -= transfer; sx += transfer; } avg = (hX + sX + sz + hz) / 2; if (hX + sX > hz + sz) { float transfer = sX + hX - avg; if (transfer > sX) { transfer = sX; } sX -= transfer; sz += transfer; } else { float transfer = sz + hz - avg; if (transfer > sz) { transfer = sz; } sz -= transfer; sX += transfer; } //} //to matrix m = sediments.array; m[pos] = s; m[pos - 1] = sx; m[pos + 1] = sX; m[pos - sizeX] = sz; m[pos + sizeX] = sZ; if (sedimentSum != null) { m = sedimentSum.array; m[pos] += s; m[pos - 1] += sx; m[pos + 1] += sX; m[pos - sizeX] += sz; m[pos + sizeX] += sZ; } } } #endregion #region Writing sediments back to height, adding smooth and ruffle int seed = 12345; for (int j = heights.array.Length - 1; j >= 0; j--) { //writing heights heights.array[j] += sediments.array[j]; seed = 214013 * seed + 2531011; float random = ((seed >> 16) & 0x7FFF) / 32768f; int pos = order[j]; if (pos < 0) { continue; } float[] m = heights.array; int sizeX = heights.rect.size.x; float h = m[pos]; float hx = m[pos - 1]; float hX = m[pos + 1]; float hz = m[pos - sizeX]; float hZ = m[pos + sizeX]; //smoothing sediments a bit float s = sediments.array[pos]; if (s > 0.0001f) { float smooth = s / 2f; if (smooth > 0.75f) { smooth = 0.75f; } heights.array[pos] = h * (1 - smooth) + (hx + hX + hz + hZ) / 4f * smooth; } else { float maxHeight = hx; if (hX > maxHeight) { maxHeight = hX; } if (hz > maxHeight) { maxHeight = hz; } if (hZ > maxHeight) { maxHeight = hZ; } float minHeight = hx; if (hX < minHeight) { minHeight = hX; } if (hz < minHeight) { minHeight = hz; } if (hZ < minHeight) { minHeight = hZ; } float randomHeight = random * (maxHeight - minHeight) + minHeight; heights.array[pos] = heights.array[pos] * (1 - ruffle) + randomHeight * ruffle; } //Cross height = new Cross(heights, pos); //float maxAround = Mathf.Max(heights.array[pos-1], heights.array[pos+1], heights.array[pos-heights.rect.size.x], heights.array[pos+heights.rect.size.x]); //heights.array[pos] = Mathf.Min(heights.array[pos], maxAround); //heights.array[pos] = Mathf.Min(height.c, height.maxAround); //heights.array[pos] = Mathf.Min(height.c, height.avgAround)*0.5f + height.c*0.5f; //float maxHeight = height.maxAround; //float minHeight = height.minAround; //float randomHeight = random*(maxHeight-minHeight) + minHeight; //heights.array[pos] = heights.array[pos]*(1-ruffle) + randomHeight*ruffle; } #endregion } //erosion iteration