Permalink
Browse files

Write terrain article, add pygments style

  • Loading branch information...
1 parent 0807831 commit 697e13d1b932ecb82669e8991ad76392221988fb Merwan Achibet committed May 11, 2012
View
@@ -1,2 +1,4 @@
auto: true
+
markdown: maruku
+pygments: true
@@ -1,9 +1,9 @@
---
layout: post
-title: "[DRAFT] Generating Random Terrain: Value Noise"
+title: "Generating Random Terrain: Value Noise"
published: true
js: [three, terrain/base]
-css: [terrain]
+css: [terrain, pygments]
---
### Motivation
@@ -18,10 +18,10 @@ terraformer.
For the following examples, I am using the [HTML5
canvas](https://developer.mozilla.org/en/Canvas_tutorial) to draw
-height maps and [Three.js](https://github.com/mrdoob/three.js/) with a
-WebGL renderer to display the resulting terrains. If your browser
-doesn't support WebGL, a canvas is displayed instead. But be advised,
-you're missing on some fancy animating here!
+height maps and [Three.js](https://github.com/mrdoob/three.js/) to
+display the resulting 3D terrains. Everything should work fine if your
+browser doesn't support WebGL as Three provides a canvas renderer for
+fallback; things may get little bit slower tough.
### The stuff
@@ -81,27 +81,27 @@ noise](http://www.noisemachine.com/talk1/)) comes into play. The steps
described below let us create a more natural-looking terrain from
the random one we just generated:
-1. Sample *n* regular subsets of pixels (where subset *n* contains
-every *2<sup>n</sup>*-th pixel)
+1. Sample *n* regular subsets of pixels where subset *n* contains
+every *2<sup>n</sup>*-th pixel
2. Fill the gaps between the selected pixels with some kind of
interpolation
-3. Sum up each of these layers with an appropriate weight to obtain
-the final height map
+3. Sum up each of these layers with appropriate weights to obtain the
+final height map
### Sampling
Sampling the original random noise at different levels provides us the
several layers of precision needed. Each of these sampled maps is
called an octave and is associated with a number starting from *0*
where octave *i* is the layer containing every *2<sup>i</sup>* pixels
-of the original height map. You will note that octave *0* actually is
-the random terrain generated earlier because this sampling contains
-every pixel. This is the reason why your height map dimensions must be
-powers of two like 256\*256 or 1024\*512.
+from the original height map. You will note that octave *0* actually
+is the random terrain generated earlier because this sampling contains
+every pixel. This is also the reason why your height map dimensions
+must be powers of two like 256\*256 or 1024\*512.
-Let's take the following 64\*64 randomly-generated height map as an
+Let's take the following 64\*64 randomly generated height map as an
example.
![](/images/octave_base.png)
@@ -125,25 +125,46 @@ For octave 3, only the *8n*-th pixels are kept, and so on...
### Filling the gaps
For the moment, octave are mainly empty, apart from the sampled
-points. We now need to determine the values of absent pixels. Let's
-say we want to compute the value of pixel *P* of a given octave. To do
-that, we simply find in which square *P* is and interpolate the values
-of its corners with respect to the distance from *P* to each
-corner. in the following illustration, *P* is the blue pixel whereas
-the corners of its squares are red.
+points. These points will serve as guides and we want the slopes
+between each pair of sampled points to be continuous (remember the
+cloth metaphor).
+
+So we need to determine the values of absent pixels. Let's say we want
+to compute the height of pixel *P* of a given octave. To do so, we
+simply find in which square *P* is and interpolate the heights of its
+corners with respect to the distance from *P* to each corner. in the
+following illustration, *P* is the blue pixel and the corners of its
+square are red.
![](/images/octave_square.png)
-We can use several kind of interpolation. The simplest is linear
+Several kinds of interpolation are available. The simplest is linear
interpolation; efficient in terms of speed but the result can be a bit
-rough.
+rough (check [this
+page](http://local.wasp.uwa.edu.au/~pbourke/miscellaneous/interpolation/)
+for more interpolation methods).
+{% highlight javascript %}
function linear(a, b, x) {
return a + (b - a) * x;
}
+{% endhighlight %}
+
+*a* is the starting value, *b* the ending value and *x* a ratio. If
+ *x* is *0* then the result is *a*. If *x* is 1 then the result is
+ *b*. More generally, the higher *x* is, the closer the result is to
+ *b*.
+
+{% highlight javascript %}
+> linear(0, 10, 0.5)
+5
-*a* is the starting value, *b* the end value and *x* a real number
- within \[0,1\].
+> linear(1, 2, 0.1)
+1.1
+
+> linear(0, 100, 0.8)
+80
+{% endhighlight %}
You will note that the given functions only work in 1D. To obtain the
value of *P* from the four corner of the square (*C1*, *C2*, *C3*,
@@ -153,14 +174,23 @@ values of points respectively at the top and bottom lines of the
square. Then we interpolate these two intermediate points. This
process is known as bilinear interpolation.
+![](/images/octave_bilinear.png)
+
+The following demo shows the third and fifth octaves. The results
+appear rather smooth because I used cosine interpolation instead of
+the linear one which would have produced more pointy hills but the
+principle is identical.
+
<div class="try" id="try2">
</div>
+<div class="try" id="try3">
+</div>
+
### Summing up
Let's summarize. From a unique random noise, we created octaves by
-regularly sampling pixels and we filled the voids using linear
-interpolation.
+regularly sampling pixels and we filled the voids using interpolation.
Now that we dispose of *n* octaves, we just need to assemble them into
a unique image. In order to make good use of our different layers of
@@ -170,7 +200,7 @@ the largest frequency is going to help define the global relief
whereas the one with the smallest frequency will only influe on small
local details.
-persistence
+WIP
-<div class="try" id="try3">
+<div class="try" id="try4">
</div>
View
@@ -0,0 +1,61 @@
+.hll { background-color: #ffffcc }
+.c { color: #0099FF; font-style: italic } /* Comment */
+.err { color: #AA0000; background-color: #FFAAAA } /* Error */
+.k { color: #006699; font-weight: bold } /* Keyword */
+.o { color: #555555 } /* Operator */
+.cm { color: #0099FF; font-style: italic } /* Comment.Multiline */
+.cp { color: #009999 } /* Comment.Preproc */
+.c1 { color: #0099FF; font-style: italic } /* Comment.Single */
+.cs { color: #0099FF; font-weight: bold; font-style: italic } /* Comment.Special */
+.gd { background-color: #FFCCCC; border: 1px solid #CC0000 } /* Generic.Deleted */
+.ge { font-style: italic } /* Generic.Emph */
+.gr { color: #FF0000 } /* Generic.Error */
+.gh { color: #003300; font-weight: bold } /* Generic.Heading */
+.gi { background-color: #CCFFCC; border: 1px solid #00CC00 } /* Generic.Inserted */
+.go { color: #AAAAAA } /* Generic.Output */
+.gp { color: #000099; font-weight: bold } /* Generic.Prompt */
+.gs { font-weight: bold } /* Generic.Strong */
+.gu { color: #003300; font-weight: bold } /* Generic.Subheading */
+.gt { color: #99CC66 } /* Generic.Traceback */
+.kc { color: #006699; font-weight: bold } /* Keyword.Constant */
+.kd { color: #006699; font-weight: bold } /* Keyword.Declaration */
+.kn { color: #006699; font-weight: bold } /* Keyword.Namespace */
+.kp { color: #006699 } /* Keyword.Pseudo */
+.kr { color: #006699; font-weight: bold } /* Keyword.Reserved */
+.kt { color: #007788; font-weight: bold } /* Keyword.Type */
+.m { color: #FF6600 } /* Literal.Number */
+.s { color: #CC3300 } /* Literal.String */
+.na { color: #330099 } /* Name.Attribute */
+.nb { color: #336666 } /* Name.Builtin */
+.nc { color: #00AA88; font-weight: bold } /* Name.Class */
+.no { color: #336600 } /* Name.Constant */
+.nd { color: #9999FF } /* Name.Decorator */
+.ni { color: #999999; font-weight: bold } /* Name.Entity */
+.ne { color: #CC0000; font-weight: bold } /* Name.Exception */
+.nf { color: #CC00FF } /* Name.Function */
+.nl { color: #9999FF } /* Name.Label */
+.nn { color: #00CCFF; font-weight: bold } /* Name.Namespace */
+.nt { color: #330099; font-weight: bold } /* Name.Tag */
+.nv { color: #003333 } /* Name.Variable */
+.ow { color: #000000; font-weight: bold } /* Operator.Word */
+.w { color: #bbbbbb } /* Text.Whitespace */
+.mf { color: #FF6600 } /* Literal.Number.Float */
+.mh { color: #FF6600 } /* Literal.Number.Hex */
+.mi { color: #FF6600 } /* Literal.Number.Integer */
+.mo { color: #FF6600 } /* Literal.Number.Oct */
+.sb { color: #CC3300 } /* Literal.String.Backtick */
+.sc { color: #CC3300 } /* Literal.String.Char */
+.sd { color: #CC3300; font-style: italic } /* Literal.String.Doc */
+.s2 { color: #CC3300 } /* Literal.String.Double */
+.se { color: #CC3300; font-weight: bold } /* Literal.String.Escape */
+.sh { color: #CC3300 } /* Literal.String.Heredoc */
+.si { color: #AA0000 } /* Literal.String.Interpol */
+.sx { color: #CC3300 } /* Literal.String.Other */
+.sr { color: #33AAAA } /* Literal.String.Regex */
+.s1 { color: #CC3300 } /* Literal.String.Single */
+.ss { color: #FFCC33 } /* Literal.String.Symbol */
+.bp { color: #336666 } /* Name.Builtin.Pseudo */
+.vc { color: #003333 } /* Name.Variable.Class */
+.vg { color: #003333 } /* Name.Variable.Global */
+.vi { color: #003333 } /* Name.Variable.Instance */
+.il { color: #FF6600 } /* Literal.Number.Integer.Long */
View
@@ -27,9 +27,7 @@ h3 {
font-weight: normal;
}
-ul {
- list-style-type: none;
-}
+
.soft {
color: grey;
@@ -124,8 +122,8 @@ article > div > p {
text-align: justify;
}
-article ol li {
- list-style-type: decimal !important;
+article ol {
+ margin-left: 3em;
}
article a {
@@ -141,6 +139,12 @@ article em {
font-style: italic;
}
+article pre {
+ padding: 1em;
+ margin-bottom: 1em;
+ border: 1px solid lightgrey;
+}
+
#articles, #projects {
margin-top: 1em;
margin-bottom: 2em;
View
@@ -34,3 +34,6 @@ img {
img + img {
margin-left: 4em;
}
+ol li {
+ list-style: decimal;
+}
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
@@ -190,6 +190,7 @@ $(function() {
// Add the demos to the page.
insertDemo($('#try1'), {type: 'r'});
- insertDemo($('#try2'), {type: 'o', k: 4});
- insertDemo($('#try3'), {type: 'v', k: 7});
+ insertDemo($('#try2'), {type: 'o', k: 3});
+ insertDemo($('#try3'), {type: 'o', k: 5});
+ insertDemo($('#try4'), {type: 'v', k: 8});
});

0 comments on commit 697e13d

Please sign in to comment.