terrain-map
ARCHIVED - repo for blog post http://www.vogt.world/writing/procedural-terrain-generation/
git clone https://git.vogt.world/terrain-map.git
Log | Files | README.md
← Commit log
commit
message
finally got complex erosion working!
author
Ben Vogt <[email protected]>
date
2016-05-14 03:01:46
stats
2 file(s) changed, 156 insertions(+), 12 deletions(-)
files
index.html
main.js
  1diff --git a/index.html b/index.html
  2index 7ec84cf..a12c080 100644
  3--- a/index.html
  4+++ b/index.html
  5@@ -6,6 +6,7 @@
  6     <script type="text/javascript" src="main.js"></script>
  7   </head>
  8   <body>
  9+    <!-- header -->
 10     <div class="container">
 11       <div class="row">
 12         <h1>Terrain Maps</h1>
 13@@ -13,6 +14,7 @@
 14         <p>I've been messing around with different terrain smoothing algorithms to run on Diamond-Square-generated maps. I'm putting them here to so I remember them and write them out a little more clearly.</p>
 15       </div>
 16     </div>
 17+    <!-- container-1 -->
 18     <div class="container">
 19       <hr>
 20       <div class="row">
 21@@ -25,6 +27,7 @@
 22       <div class="set-of" id="container-1"></div>
 23       <hr>
 24     </div>
 25+    <!-- container-2 -->
 26     <div class="container">
 27       <div class="row">
 28         <h2>Combining Diamond-Square maps</h2>
 29@@ -43,6 +46,7 @@
 30       <div class="set-of" id="container-2"></div>
 31       <hr>
 32     </div>
 33+    <!-- container-3 -->
 34     <div class="container">
 35       <div class="row">
 36         <h2>Greedy Raindrop Erosion Algorithm</h2>
 37@@ -54,17 +58,31 @@
 38       <div class="set-of" id="container-3"></div>
 39       <hr>
 40     </div>
 41+    <!-- container-4 -->
 42     <div class="container">
 43       <div class="row">
 44-        <h2>Soil Erosion Algorithm</h2>
 45+        <h2>Simple Erosion Algorithm</h2>
 46         <p>
 47           Randomly place a "droplet" of water on the map. For a number of iterations, let the droplet roll to it's nearest neighbor, eroding it's current point on the map if the droplet has not reached it carrying-capacity of sediment. If it has reached
 48           it's carrying capacity, deposit sediment on that point. Repeat this process with many more droplets.
 49-          <button class="run button-primary" id="erosion">RUN</button>
 50+          <button class="run button-primary" id="simpleErosion">RUN</button>
 51         </p>
 52       </div>
 53       <div class="set-of" id="container-4"></div>
 54+      <hr>
 55+    </div>
 56+    <!-- container-5 -->
 57+    <div class="container">
 58+      <div class="row">
 59+        <h2>Complex Erosion Algorithm</h2>
 60+        <p>
 61+          <button class="run button-primary" id="complexErosion">RUN</button>
 62+        </p>
 63+      </div>
 64+      <div class="set-of" id="container-5"></div>
 65+      <hr>
 66     </div>
 67+    <!-- hidden canvas for rendering-->
 68     <canvas class="hidden" id="tmp" width="256" height="256"></canvas>
 69   </body>
 70 </html>
 71diff --git a/main.js b/main.js
 72index e8f0a94..113bdbe 100644
 73--- a/main.js
 74+++ b/main.js
 75@@ -262,14 +262,13 @@ $(document).ready(function() {
 76     }
 77   };
 78 
 79-  LandMap.prototype.erosion = function(options) {
 80+  LandMap.prototype.simpleErosion = function(options) {
 81     var Kq = options.carryingCapacity;
 82     var Kd = options.depositionSpeed;
 83     var iterations = options.iterations;
 84     var drops = options.drops;
 85     var one = options.one;
 86     var two = options.two;
 87-    var ds = 0;
 88 
 89     var HeightMap = new Array(this.size * this.size);
 90     for (var y = 0; y < this.size; y++) {
 91@@ -289,18 +288,14 @@ $(document).ready(function() {
 92       return HeightMap[(x + HMAP_SIZE * y)];
 93     }
 94 
 95-
 96-    var MAX_PATH_LEN = this.size * 4;
 97-
 98     function DEPOSIT_AT(X, Y) {
 99       var c = 0.0;
100       var v = 1.05;
101-      var g = 1.4;
102-      var mv = 10.0;
103+      var maxVelocity = 10.0;
104 
105       // For the number of iterations
106       for (var iter = 0; iter < iterations; iter++) {
107-        var v = Math.min(v, mv); // limiting velocity
108+        v = Math.min(v, maxVelocity); // limiting velocity
109         var val = HMAP_VALUE(X, Y);
110         var nv = [
111           HMAP_VALUE(X, Y - 1), //NORTH
112@@ -371,8 +366,115 @@ $(document).ready(function() {
113       DEPOSIT_AT(Math.floor(Math.random() * this.size), Math.floor(Math.random() * this.size));
114       this.maps[two] = HeightMap;
115     }
116-  }
117+  };
118+
119+  LandMap.prototype.complexErosion = function(options) {
120+    var Kq = options.carryingCapacity;
121+    var Kd = options.depositionSpeed;
122+    var iterations = options.iterations;
123+    var drops = options.drops;
124+    var one = options.one;
125+    var two = options.two;
126+
127+    var HeightMap = new Array(this.size * this.size);
128+    for (var y = 0; y < this.size; y++) {
129+      for (var x = 0; x < this.size; x++) {
130+        HeightMap[(x + this.size * y)] = this.get(one, x, y);
131+      }
132+    }
133+
134+    var HMAP_SIZE = this.size;
135+
136+    function HMAP_INDEX(x, y) {
137+      var val = (x + HMAP_SIZE * y)
138+      return val;
139+    }
140+
141+    function HMAP_VALUE(x, y) {
142+      return HeightMap[(x + HMAP_SIZE * y)];
143+    }
144+
145+    function DEPOSIT_AT(X, Y) {
146+      var c = 0.0;
147+      var v = 1.05;
148+      var minSlope = 1.15;
149+      var maxVelocity = 10.0;
150+
151+      // For the number of iterations
152+      for (var iter = 0; iter < iterations; iter++) {
153+        v = Math.min(v, maxVelocity); // limiting velocity
154+        var val = HMAP_VALUE(X, Y);
155+        var nv = [
156+          HMAP_VALUE(X, Y - 1), //NORTH
157+          HMAP_VALUE(X, Y + 1), //SOUTH
158+          HMAP_VALUE(X + 1, Y), //EAST
159+          HMAP_VALUE(X - 1, Y) //WEST
160+        ];
161+
162+        var minInd = indexOfMin(nv);
163+        // if the lowest neighbor is NOT greater than the current value
164+        if (nv[minInd] < val) {
165+          //deposit or erode
166+          var slope = Math.min(minSlope, val - nv[minInd])
167+          var vtc = Kd * v * slope; // value to steal is depositionSpeed * velocity * abs(slope);
168+          // if carrying amount is greater than Kq
169+          if (c > Kq) {
170+            //DEPOSIT
171+            c -= vtc;
172+            HeightMap[HMAP_INDEX(X, Y)] += vtc;
173+          } else {
174+            //ERODE
175+            // if carrying + value to steal > carrying cap
176+            if (c + vtc > Kq) {
177+              var delta = c + vtc - Kq;
178+              c += delta;
179+              HeightMap[HMAP_INDEX(X, Y)] -= delta;
180+            } else {
181+              c += vtc;
182+              HeightMap[HMAP_INDEX(X, Y)] -= vtc;
183+            }
184+          }
185+
186+          // move to next value
187+          if (minInd == 0) {
188+            //NORTH
189+            Y -= 1
190+          }
191+          if (minInd == 1) {
192+            //SOUTH
193+            Y += 1
194+          }
195+          if (minInd == 2) {
196+            //EAST
197+            X += 1
198+          }
199+          if (minInd == 3) {
200+            //WEST
201+            X -= 1
202+          }
203 
204+          // limiting to edge of map
205+          if (X > this.size - 1) {
206+            X = this.size;
207+          }
208+          if (Y > this.size - 1) {
209+            Y = this.size;
210+          }
211+          if (Y < 0) {
212+            Y = 0;
213+          }
214+          if (X < 0) {
215+            X = 0;
216+          }
217+        }
218+      }
219+    }
220+
221+    for (var drop = 0; drop < drops; drop++) {
222+      DEPOSIT_AT(Math.floor(Math.random() * this.size), Math.floor(Math.random() * this.size));
223+      this.maps[two] = HeightMap;
224+    }
225+  };
226 
227   LandMap.prototype.draw = function() {
228     var html = '<div class="row">';
229@@ -467,20 +569,34 @@ $(document).ready(function() {
230   });
231 
232 
233-  $("#erosion").click(function() {
234+  $("#simpleErosion").click(function() {
235     var terrain = new LandMap({
236       containerId: "container-4"
237     });
238     terrain.generate(0.75, "standard");
239-    terrain.erosion({
240+    terrain.simpleErosion({
241       carryingCapacity: 1.5,
242       depositionSpeed: 0.03,
243       iterations: 10,
244       drops: 1000000,
245       one: "standard",
246-      two: "erosion"
247+      two: "simpleErosion"
248     });
249     terrain.draw();
250   });
251 
252+  var terrain = new LandMap({
253+    containerId: "container-5"
254+  });
255+  terrain.generate(0.75, "standard");
256+  terrain.complexErosion({
257+    carryingCapacity: 1.5,
258+    depositionSpeed: 0.03,
259+    iterations: 10,
260+    drops: 1000000,
261+    one: "standard",
262+    two: "complexErosion"
263+  });
264+  terrain.draw();
265+
266 })