You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hopefully, you'll be able to apply this in your own projects!
48
51
Along the way, we'll learn a little bit about p5.js, rendering, and simulating physics. </p>
49
52
50
-
<divid="BoidContainer"></div>
51
-
52
-
<em> (This is not an actual boids sketch btw - this is a random stepper) </em>
53
+
<divid="DetailedDesertIslands"></div>
54
+
<em> Click to generate a new map </em>
53
55
54
56
55
57
<p> We will be coding in JavaScript but don't worry about knowing the ins and outs of the language; you should be able to pick it up as we go! </p>
56
58
57
-
<h2>Introduction to p5.js </h2>
59
+
<h2>Using p5.js </h2>
58
60
59
61
We will be using JavaScript and a library called <strong> p5.js</strong>, made by the lovely <ahref="https://processingfoundation.org/"> Processing Foundation</a>.
60
62
@@ -99,7 +101,7 @@ <h3> What is a sketch? </h3>
99
101
100
102
<p><strong>Mini-Task:</strong> Try running the above simulation! Maybe change the variables to display your own favourite colour. </p>
101
103
102
-
<h3> Creating Random Noise </h3>
104
+
<h2> Creating Random Noise </h2>
103
105
104
106
<divid="RandomHeightMap"></div>
105
107
<em>Click to generate new random noise</em>
@@ -114,7 +116,7 @@ <h3> Creating Random Noise </h3>
114
116
115
117
<p>Let's tackle (1) first!</p>
116
118
117
-
<h4>Pixels</h4>
119
+
<h3>Pixels</h3>
118
120
119
121
<pre>
120
122
<codeclass="language-js">
@@ -187,7 +189,7 @@ <h4>Pixels</h4>
187
189
188
190
<p><strong>Mini-Task:</strong> Run the above simulation, and see if you guessed what it does correctly! </p>
189
191
190
-
<h4>Random Values</h4>
192
+
<h3>Random Values</h3>
191
193
192
194
<p>A key thing to remember about p5.js is that ultimately, it is still JavaScript. Therefore, we can use JavaScript functions and libraries with p5.js. </p>
193
195
<br>
@@ -232,7 +234,7 @@ <h3>Task: Random Noise</h3>
232
234
</pre>
233
235
<em>Generally, taking this out into its own function for this is a good idea; especially since this function's sole purpose is drawing random noise </em>
234
236
235
-
<h3>Perlin Noise</h3>
237
+
<h2>Perlin Noise</h2>
236
238
237
239
<p>Okay so we've programmed <em>random noise</em> which is "incoherent" noise - you can have sharp constrasts between neighbouring pixels.
238
240
If we want nice smooth gradients, then we can use perlin noise! </p>
<p>From the above, we can see that the values sampled are <em>a lot closer</em>; you can think of this as sampling the 10 points at $x=0.2, 0.4, 0.6 \dots$</p>
259
+
260
+
<p> So the general takeaway is that we can generate smoother noise, by sampling more frequently. How do we do that? We can just divide x,y before feeding it into the noise function!</p>
261
+
262
+
<divid="SmoothNoiseHeightMap"></div>
263
+
264
+
<h2>Task: Smooth Noise </h2>
265
+
266
+
<p>Use the tools above to generate some smooth perlin noise! Have a variable called the smoothing factor, and change its value to see how the noise varies. </p>
267
+
268
+
<h2>Creating Islands</h2>
269
+
270
+
<p>We now have the tools to create islands! By designating pixel with noise values past a certain threshold as "land" and the rest as "ocean", we can generate islands.
271
+
Since the <strong>noise()</strong> function returns a value between 0 and 1, we should have a threshold value between 0 and 1. </p>
<p> Note that the above function returns a "colour" object; if you want to work with large p5.js programs, then you should really be using classes and objects.
289
+
Now we can use the returned colour object like so:
290
+
</p>
291
+
292
+
<pre>
293
+
<codeclass="language-js">
294
+
let colour = getColour(noise(x/sf, y/sf)); // colour object
295
+
stroke(colour); // stroke accepts the colour object directly (instead of number values representing a colour)
296
+
</code>
297
+
</pre>
257
298
299
+
<h2> Task: Desert Islands </h2>
300
+
301
+
<p>Create desert island generation by modifying your smooth noise task, with the above tools. It should look something like below: </p>
302
+
303
+
<divid="DesertIslands"></div>
258
304
305
+
<h3>More Detailed Islands </h3>
306
+
307
+
<p>Sometimes, you want more detailed islands; you want the overall shape of the islands to be the same so you have the same smoothness factor,
308
+
but you want there to be some more granular detail. You might want your beaches to have some roughness to its terrain.
309
+
310
+
After all, terrain isn't perfectly smooth in nature!
311
+
</p>
312
+
313
+
<br>
314
+
315
+
<p>You can add this granular detail by adding layers of perlin noise together; each of these layers being called "octaves".
316
+
Typically, you'll have a large amplitude perlin noise wave which describes the general overall shape,
317
+
and then you'll have a smaller amplitude perlin noise waves to describe the finer details.
318
+
These smaller waves usually have higher frequency, which will give the islands a distinct roughness.
319
+
</p>
320
+
321
+
<br>
322
+
323
+
<p> You can increase the number of octaves and how much the smaller waves contribute to the noise by using p5's <strong>noiseDetail()</strong> function.
324
+
Read up on the details <ahref="https://p5js.org/reference/p5/noiseDetail/">here</a>.</p>
325
+
326
+
<br>
327
+
328
+
<p>You can also add more "detail" to the islands by creating multiple threshold levels, like in the example at the top of this webpage! An example of a more complicated threshold colour function: </p>
329
+
330
+
<pre>
331
+
<codeclass="language-js">
332
+
const snowcapThreshold = 0.75;
333
+
const mountainThreshold = 0.6;
334
+
const grassThreshold = 0.4;
335
+
const shallowWaterThreshold = 0.35;
336
+
337
+
function getColour(noiseVal){
338
+
if(noiseVal > snowcapThreshold){
339
+
return color(219, 219, 219); // snowcap white
340
+
}else if(noiseVal > mountainThreshold){
341
+
return color(112, 112, 112); // mountain gray
342
+
}else if (noiseVal > grassThreshold){
343
+
return color(75, 139, 59); // grass green
344
+
}else if (noiseVal > shallowWaterThreshold){
345
+
return color(0, 157, 196); // light blue
346
+
}else{
347
+
return color(0, 147, 186); // slightly darker blue
348
+
}
349
+
}
350
+
</code>
351
+
</pre>
352
+
353
+
<h2> Final Task: Create your own islands! </h2>
354
+
355
+
<p>You have everything you need to create your own amazing terrain generation!
356
+
You can take my generator(s) (displayed at the top of the page) as inspiration, but I'm sure you'll be able to create a better looking generator than mine.
357
+
</p>
358
+
359
+
<br>
360
+
361
+
<p>You can view the code for my two generators here:</p>
362
+
<ul>
363
+
<li><ahref="https://editor.p5js.org/RexMortem/sketches/sk3iSZ_ly">Desert Island Generator</a></li>
<p><strong>Tip: </strong> Getting good terrain with perlin noise is often a case of just tweaking your parameters (octaves, amplitude/frequency, smooth factor etc) until they're <em>just</em> right. </p>
368
+
369
+
<h2> Going Further </h2>
370
+
371
+
<p> If you want to make your generator even cooler, then you can explore more procedural generation techniques. Natural next steps include: </p>
372
+
373
+
<ul>
374
+
<li>Adding rivers (perhaps using perlin worms) </li>
375
+
<li>Adding trees e.g. with poisson-disc sampling </li>
0 commit comments