这些 x 与 y(或亮度)之间一对一的关系称作**线性插值**(linear interpolation)。(译者注:插值是离散函数逼近的重要方法,利用它可通过函数在有限个点处的取值状况,估算出函数在其他点处的近似值。因为对机器运算来说,屏幕像素注定是离散的而不是连续的,计算机图形学常用插值来填充图像变换时像素之间的空隙。)现在起我们可以用一些数学函数来改造这些代码行。比如说我们可以把 x 升到 5 来做一个曲线。
这些 x 与 y(或亮度)之间一对一的关系称作**线性插值**(linear interpolation)。(译者注:插值是离散函数逼近的重要方法,利用它可通过函数在有限个点处的取值状况,估算出函数在其他点处的近似值。因为对机器运算来说,屏幕像素注定是离散的而不是连续的,计算机图形学常用插值来填充图像变换时像素之间的空隙。)现在起我们可以用一些数学函数来改造这些代码行。比如说我们可以做一个求 x 的 5 次幂的曲线。
It's time for a break! We've been playing with random functions that look like TV white noise, our head is still spinning thinking about shaders, and our eyes are tired. Time to go out for a walk!
是时候来点突破了!我们已经玩过了看起来像电视白噪音的 random 函数,我们脑袋还在想着 shader,但是眼睛已经花了。是时候出去走走了!
We feel the air on our skin, the sun in our face. The world is such a vivid and rich place. Colors, textures, sounds. While we walk we can't avoid noticing the surface of the roads, rocks, trees and clouds.
是时候来点突破了!我们已经玩过了看起来像电视白噪音的 random 函数,我们脑袋还在想着 shader,但是眼睛已经晕了。是时候出去走走了!
@ -19,18 +15,12 @@ We feel the air on our skin, the sun in our face. The world is such a vivid and
![](texture-05.jpg)
![](texture-06.jpg)
The unpredictability of these textures could be called "random," but they don't look like the random we were playing with before. The “real world” is such a rich and complex place! How can we approximate this variety computationally?
This was the question [Ken Perlin](https://mrl.nyu.edu/~perlin/) was trying to solve in the eary 1980s when he was commissioned to generate more realistic textures for the movie "Tron." In response to that, he came up with an elegant *Oscar winning* noise algorithm. (No biggie.)
In these lines we are doing something similar to what we did in the previous chapter. We are subdividing a continuous floating number (```x```) into its integer (```i```) and fractional (```f```) components. We use [```floor()```](.../glossary/?search=floor) to obtain ```i``` and [```fract()```](.../glossary/?search=fract) to obtain ```f```. Then we apply ```rand()``` to the integer part of ```x```, which gives a unique random value for each integer.
After that you see two commented lines. The first one interpolates each random value linearly.
```glsl
y = mix(rand(i), rand(i + 1.0), f);
```
Go ahead and uncomment this line to see how this looks. We use the [```fract()```](.../glossary/?search=fract) value store in `f` to [```mix()```](.../glossary/?search=mix) the two random values.
At this point in the book, we've learned that we can do better than a linear interpolation, right?
Now try uncommenting the following line, which uses a [```smoothstep()```](.../glossary/?search=smoothstep) interpolation instead of a linear one.
@ -66,33 +47,17 @@ Now try uncommenting the following line, which uses a [```smoothstep()```](.../g
y = mix(rand(i), rand(i + 1.0), smoothstep(0.,1.,f));
```
After uncommenting it, notice how the transition between the peaks gets smooth. In some noise implementations you will find that programmers prefer to code their own cubic curves (like the following formula) instead of using the [```smoothstep()```](.../glossary/?search=smoothstep).
float u = f * f * (3.0 - 2.0 * f ); // custom cubic curve
y = mix(rand(i), rand(i + 1.0), u); // using it in the interpolation
```
This *smooth randomness* is a game changer for graphical engineers or artists - it provides the ability to generate images and geometries with an organic feeling. Perlin's Noise Algorithm has been implemented over and over in different languages and dimensions to make mesmerizing pieces for all sorts of creative uses.
![Robert Hodgin - Written Images (2010)](robert_hodgin.jpg)
Now it's your turn:
* Make your own ```float noise(float x)``` function.
* Use your noise function to animate a shape by moving it, rotating it or scaling it.
* Make an animated composition of several shapes 'dancing' together using noise.
* Construct "organic-looking" shapes using the noise function.
* Once you have your "creature," try to develop it further into a character by assigning it a particular movement.
现在轮到你了:
* 写你自己的 ```float noise(float x)``` 函数。
@ -109,47 +74,23 @@ Now it's your turn:
![](02.png)
Now that we know how to do noise in 1D, it's time to move on to 2D. In 2D, instead of interpolating between two points of a line (```fract(x)``` and ```fract(x)+1.0```), we are going to interpolate between the four corners of the square area of a plane (```fract(st)```, ```fract(st)+vec2(1.,0.)```, ```fract(st)+vec2(0.,1.)``` and ```fract(st)+vec2(1.,1.)```).
Similarly, if we want to obtain 3D noise we need to interpolate between the eight corners of a cube. This technique is all about interpolating random values, which is why it's called **value noise**.
We start by scaling the space by 5 (line 45) in order to see the interpolation between the squares of the grid. Then inside the noise function we subdivide the space into cells. We store the integer position of the cell along with the fractional positions inside the cell. We use the integer position to calculate the four corners' coordinates and obtain a random value for each one (lines 23-26). Finally, in line 35 we interpolate between the 4 random values of the corners using the fractional positions we stored before.
* Change the multiplier of line 45. Try to animate it.
* At what level of zoom does the noise start looking like random again?
* At what zoom level is the noise is imperceptible?
* Try to hook up this noise function to the mouse coordinates.
* What if we treat the gradient of the noise as a distance field? Make something interesting with it.
* Now that you've achieved some control over order and chaos, it's time to use that knowledge. Make a composition of rectangles, colors and noise that resembles some of the complexity of a [Mark Rothko](http://en.wikipedia.org/wiki/Mark_Rothko) painting.
## Using Noise in Generative Designs 生成式设计中的 noise 应用
## 生成式设计中的 noise 应用
Noise algorithms were originally designed to give a natural *je ne sais quoi* to digital textures. The 1D and 2D implementations we've seen so far were interpolations between random *values*, which is why they're called **Value Noise**, but there are more ways to obtain noise...
[ ![Inigo Quilez - Value Noise](value-noise.png) ](../edit.html#11/2d-vnoise.frag)
As you discovered in the previous exercises, value noise tends to look "blocky." To diminish this blocky effect, in 1985 [Ken Perlin](https://mrl.nyu.edu/~perlin/) developed another implementation of the algorithm called **Gradient Noise**. Ken figured out how to interpolate random *gradients* instead of values. These gradients were the result of a 2D random function that returns directions (represented by a ```vec2```) instead of single values (```float```). Click on the following image to see the code and how it works.
Take a minute to look at these two examples by [Inigo Quilez](http://www.iquilezles.org/) and pay attention to the differences between [value noise](https://www.shadertoy.com/view/lsf3WH) and [gradient noise](https://www.shadertoy.com/view/XdXGW8).
Like a painter who understands how the pigments of their paints work, the more we know about noise implementations the better we will be able to use them. For example, if we use a two dimensional noise implementation to rotate the space where straight lines are rendered, we can produce the following swirly effect that looks like wood. Again you can click on the image to see what the code looks like.
@ -196,9 +129,7 @@ Like a painter who understands how the pigments of their paints work, the more w
pattern = lines(pos,.5); // 画直线
```
Another way to get interesting patterns from noise is to treat it like a distance field and apply some of the tricks described in the [Shapes chapter](../07/).
@ -207,80 +138,52 @@ Another way to get interesting patterns from noise is to treat it like a distanc
color -= smoothstep(.35,.4,noise(st*10.)); // 泼溅点上的洞
```
A third way of using the noise function is to modulate a shape. This also requires some of the techniques we learned in the [chapter about shapes](../07/).
* What other generative pattern can you make? What about granite? marble? magma? water? Find three pictures of textures you are interested in and implement them algorithmically using noise.
* Use noise to modulate a shape.
* What about using noise for motion? Go back to the [Matrix chapter](../08/). Use the translation example that moves the "+" around, and apply some *random* and *noise* movements to it.
* 把 noise 加到动作中会如何?回顾[第八章](../08/)。用移动 “+” 四处跑的那个例子,加一些 random 和 noise 进去。
* 用代码生成波洛克(Jackson Pollock)的画。
![Jackson Pollock - Number 14 gray (1948)](pollock.jpg)
## Simplex Noise
For Ken Perlin the success of his algorithm wasn't enough. He thought it could perform better. At Siggraph 2001 he presented the "simplex noise" in which he achieved the following improvements over the previous algorithm:
* An algorithm with lower computational complexity and fewer multiplications.
* A noise that scales to higher dimensions with less computational cost.
* A noise without directional artifacts.
* A noise with well-defined and continuous gradients that can be computed quite cheaply.
* An algorithm that is easy to implement in hardware.
对于 Ken Perlin 来说他的算法所取得的成功是远远不够的。他觉得可以更好。在 2001 年的 Siggraph(Siggraph是由美国计算机协会「计算机图形专业组」组织的计算机图形学顶级年度会议)上,他展示了“simplex noise”(simplex 噪声),“simplex noise”比之前的算法有如下优化:
I know what you are thinking... "Who is this man?" Yes, his work is fantastic! But seriously, how did he improve the algorithm? Well, we saw how for two dimensions he was interpolating 4 points (corners of a square); so we can correctly guess that for [three (see an implementation here)](../edit.html#11/3d-noise.frag) and four dimensions we need to interpolate 8 and 16 points. Right? In other words for N dimensions you need to smoothly interpolate 2 to the N points (2^N). But Ken smartly noticed that although the obvious choice for a space-filling shape is a square, the simplest shape in 2D is the equilateral triangle. So he started by replacing the squared grid (we just learned how to use) for a simplex grid of equilateral triangles.
我知道你一定在想:“这人是谁?”是的,他的工作非常杰出!但是说真的,他是如何优化算法的呢?我们已经知道在二维中他是如何在四个点(正方形的四个角)之间插值的;所以没错你已经猜到了,对于三维[(这里有个示例)](../edit.html#11/3d-noise.frag)和四维我们需要插入 8 个和 16 个点。对吧?也就是说对于 N 维你需要插入 2 的 n 次方个点(2^N)。但是 Ken 很聪明地意识到尽管很显然填充屏幕的形状应该是方形,在二维中最简单的形状却是等边三角形。所以他把正方形网格(我们才刚学了怎么用)替换成了单纯形等边三角形的网格。
![](simplex-grid-00.png)
The simplex shape for N dimensions is a shape with N + 1 corners. In other words one fewer corner to compute in 2D, 4 fewer corners in 3D and 11 fewer corners in 4D! That's a huge improvement!
In two dimensions the interpolation happens similarly to regular noise, by interpolating the values of the corners of a section. But in this case, by using a simplex grid, we only need to interpolate the sum of 3 corners.
这时 N 维的形状就只需要 N + 1 个点了。也就是说在二维中少了 1 个点,三维中少了 4 个,四维中则少了 11 个!巨大的提升!
How is the simplex grid made? In another brilliant and elegant move, the simplex grid can be obtained by subdividing the cells of a regular 4 cornered grid into two isosceles triangles and then skewing it until each triangle is equilateral.
Then, as [Stefan Gustavson describes in this paper](http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf): _"...by looking at the integer parts of the transformed coordinates (x,y) for the point we want to evaluate, we can quickly determine which cell of two simplices that contains the point. By also comparing the magnitudes of x and y, we can determine whether the point is in the upper or the lower simplex, and traverse the correct three corner points."_
In the following code you can uncomment line 44 to see how the grid is skewed, and then uncomment line 47 to see how a simplex grid can be constructed. Note how on line 22 we are subdividing the skewed square into two equilateral triangles just by detecting if ```x > y``` ("lower" triangle) or ```y > x``` ("upper" triangle).
然后,就像 [Stefan Gustavson 在这篇文献中说的](http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf): _“……通过观察转换后坐标的整数部分,我们就可以快速地判断哪个包含着两个单纯形的单元含有我们所需的点。并且通过比较 x 和 y 的大小,我们就可以判断这个点是在上三角还是下三角中,并且遍历这个正确的三角形。”_
然后,就像 [Stefan Gustavson 在这篇文献中说的](http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf):**“……通过观察转换后坐标的整数部分,我们就可以快速地判断哪个包含着两个单纯形的单元含有我们所需的点。并且通过比较 x 和 y 的大小,我们就可以判断这个点是在上三角还是下三角中,并且遍历这个正确的三角形。”**
Another improvement introduced by Perlin with **Simplex Noise**, is the replacement of the Cubic Hermite Curve ( _f(x) = 3x^2-2x^3_ , which is identical to the [```smoothstep()```](.../glossary/?search=smoothstep) function) for a Quintic Hermite Curve ( _f(x) = 6x^5-15x^4+10x^3_ ). This makes both ends of the curve more "flat" so each border gracefully stiches with the next one. In other words you get a more continuous transition between the cells. You can see this by uncommenting the second formula in the following graph example (or see the [two equations side by side here](https://www.desmos.com/calculator/2xvlk5xp8b)).
Note how the ends of the curve change. You can read more about this in [Ken's own words](http://mrl.nyu.edu/~perlin/paper445.pdf).
All these improvements result in an algorithmic masterpiece known as **Simplex Noise**. The following is a GLSL implementation of this algorithm made by Ian McEwan (and presented in [this paper](http://webstaff.itn.liu.se/~stegu/jgt2012/article.pdf)) which is overcomplicated for educational purposes, but you will be happy to click on it and see that it is less cryptic than you might expect.
所有这些进步汇聚成了算法中的杰作 **Simplex Noise**。下面是这个算法在 GLSL 中的应用,作者是 Ian McEwan,以[这篇论文](http://webstaff.itn.liu.se/~stegu/jgt2012/article.pdf)发表,对于我们的教学而言太复杂了,但你可以点开看看,也许没有你想象得那么晦涩难懂。
[ ![Ian McEwan of Ashima Arts - Simplex Noise](simplex-noise.png) ](../edit.html#11/2d-snoise-clear.frag)
Well... enough technicalities, it's time for you to use this resource in your own expressive way:
* Contemplate how each noise implementation looks**【??】**. Imagine them as a raw material, like a marble rock for a sculptor. What can you say about about the "feeling" that each one has? Squinch your eyes to trigger your imagination, like when you want to find shapes in a cloud. What do you see? What are you reminded of? What do you imagine each noise implementation could be made into? Following your guts and try to make it happen in code.
* Make a shader that projects the illusion of flow. Like a lava lamp, ink drops, water, etc.
In this chapter we have introduced some control over the chaos. It was not an easy job! Becoming a noise-bender-master takes time and effort.
In the following chapters we will see some well known techniques to perfect your skills and get more out of your noise to design quality generative content with shaders. Until then enjoy some time outside contemplating nature and its intricate patterns. Your ability to observe needs equal (or probably more) dedication than your making skills. Go outside and enjoy the rest of the day!