AerobicErosion.cs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSim Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. *
  27. */
  28. using System;
  29. namespace libTerrain
  30. {
  31. partial class Channel
  32. {
  33. // Ideas for Aerobic erosion
  34. //
  35. // Unlike thermal (gravity) and hydraulic (water suspension)
  36. // aerobic erosion should displace mass by moving sediment
  37. // in "hops". The length of the hop being dictated by the
  38. // presence of sharp cliffs and wind speed.
  39. // The ability to pickup sediment is defined by the total
  40. // surface area, such that:
  41. // 0 0 0
  42. // 0 1 0
  43. // 0 0 0
  44. // Would be the best possible value for sediment to be
  45. // picked up (total difference = 8) and flatter land
  46. // will erode less quickly.
  47. // Suspended particles assist the erosion process by hitting
  48. // the surface and chiselling additional particles off faster
  49. // than alone.
  50. // Particles are deposited when one of two conditions is met
  51. // First:
  52. // When particles hit a wall - such that the
  53. // wind direction points at a difference >= the
  54. // deposition mininum talus.
  55. // Second:
  56. // When wind speed is lowered to below the minimum
  57. // required for transit. An idea for this is to
  58. // use the navier-stokes algorithms for simulating
  59. // pressure across the terrain.
  60. /// <summary>
  61. /// An experimental erosion algorithm developed by Adam. Moves sediment by factoring the surface area of each height point.
  62. /// </summary>
  63. /// <param name="windspeed">0..1 The speed of the wind</param>
  64. /// <param name="pickup_talus_minimum">The minimum angle at which rock is eroded 0..1 (recommended: <= 0.30)</param>
  65. /// <param name="drop_talus_minimum">The minimum angle at which rock is dropped 0..1 (recommended: >= 0.00)</param>
  66. /// <param name="carry">The percentage of rock which can be picked up to pickup 0..1</param>
  67. /// <param name="rounds">The number of erosion rounds (recommended: 25+)</param>
  68. /// <param name="lowest">Drop sediment at the lowest point?</param>
  69. public void AerobicErosion(double windspeed, double pickupTalusMinimum, double dropTalusMinimum, double carry,
  70. int rounds, bool lowest, bool usingFluidDynamics)
  71. {
  72. bool debugImages = false;
  73. Channel wind = new Channel(w, h);
  74. Channel sediment = new Channel(w, h);
  75. int x, y, i, j;
  76. Normalise();
  77. wind = Copy();
  78. wind.Noise();
  79. if (debugImages)
  80. wind.SaveImage("testimg/wind_start.png");
  81. if (usingFluidDynamics)
  82. {
  83. wind.navierStokes(20, 0.1, 0.0, 0.0);
  84. }
  85. else
  86. {
  87. wind.Pertubation(30);
  88. }
  89. if (debugImages)
  90. wind.SaveImage("testimg/wind_begin.png");
  91. for (i = 0; i < rounds; i++)
  92. {
  93. // Convert some rocks to sand
  94. for (x = 1; x < w - 1; x++)
  95. {
  96. for (y = 1; y < h - 1; y++)
  97. {
  98. double me = Get(x, y);
  99. double surfacearea = 0.3; // Everything will erode even if it's flat. Just slower.
  100. for (j = 0; j < 9; j++)
  101. {
  102. int[] coords = Neighbours(NeighbourSystem.Moore, j);
  103. double target = Get(x + coords[0], y + coords[1]);
  104. surfacearea += Math.Abs(target - me);
  105. }
  106. double amount = surfacearea*wind.map[x, y]*carry;
  107. if (amount < 0)
  108. amount = 0;
  109. if (surfacearea > pickupTalusMinimum)
  110. {
  111. Set(x, y, map[x, y] - amount);
  112. sediment.map[x, y] += amount;
  113. }
  114. }
  115. }
  116. if (usingFluidDynamics)
  117. {
  118. sediment.navierStokes(7, 0.1, 0.0, 0.1);
  119. Channel noiseChan = new Channel(w, h);
  120. noiseChan.Noise();
  121. wind.Blend(noiseChan, 0.01);
  122. wind.navierStokes(10, 0.1, 0.01, 0.01);
  123. sediment.Distort(wind, windspeed);
  124. }
  125. else
  126. {
  127. wind.Pertubation(15); // Can do better later
  128. wind.seed++;
  129. sediment.Pertubation(10); // Sediment is blown around a bit
  130. sediment.seed++;
  131. }
  132. if (debugImages)
  133. wind.SaveImage("testimg/wind_" + i.ToString() + ".png");
  134. // Convert some sand to rock
  135. for (x = 1; x < w - 1; x++)
  136. {
  137. for (y = 1; y < h - 1; y++)
  138. {
  139. double me = Get(x, y);
  140. double surfacearea = 0.01; // Flat land does not get deposition
  141. double min = double.MaxValue;
  142. int[] minside = new int[2];
  143. for (j = 0; j < 9; j++)
  144. {
  145. int[] coords = Neighbours(NeighbourSystem.Moore, j);
  146. double target = Get(x + coords[0], y + coords[1]);
  147. surfacearea += Math.Abs(target - me);
  148. if (target < min && lowest)
  149. {
  150. minside = (int[]) coords.Clone();
  151. min = target;
  152. }
  153. }
  154. double amount = surfacearea*(1.0 - wind.map[x, y])*carry;
  155. if (amount < 0)
  156. amount = 0;
  157. if (surfacearea > dropTalusMinimum)
  158. {
  159. Set(x + minside[0], y + minside[1], map[x + minside[0], y + minside[1]] + amount);
  160. sediment.map[x, y] -= amount;
  161. }
  162. }
  163. }
  164. if (debugImages)
  165. sediment.SaveImage("testimg/sediment_" + i.ToString() + ".png");
  166. wind.Normalise();
  167. wind *= windspeed;
  168. Normalise();
  169. }
  170. Channel myself = this;
  171. myself += sediment;
  172. myself.Normalise();
  173. if (debugImages)
  174. SaveImage("testimg/output.png");
  175. }
  176. }
  177. }