Quantcast
Channel: MSDN Blogs
Viewing all articles
Browse latest Browse all 29128

Generating Noise for applications

$
0
0

Abstract

This article goes into depth around four different types of noise generation algorithms. We cover the implementation as well as performance information for Perlin, Simplex, Wavelet, and Worley noise. This is an analysis of the implementation and the pro’s and cons for each.

Keywords: Noise, Simplex, Wavelet, Value, Worley, Perlin, texturing

Introduction

Noise is a random disturbance in a sample which is not part of an expected result. Think of audio signals on images that you take with your Digital SLR. The noise is the pieces of information that are not desirable such as hiss or speckled spots on low light photos. In these instances this extra information is usually undesirable but in some application this noise makes things more natural and realistic when using random information.

There are many different applications of noise in game development from terrain generation, procedural textures, to artificial intelligence and many more. Noise is surprisingly interesting and is not necessarily just random numbers. Its about how are those numbers distributed how to they relate to previous information. This can be quite a complex topic and in this blog post I will be going through the following types of noise and providing source code and libraries you can leverage to create applications. The types I am going to cover are:

  • Value
  • Perlin
  • Simplex   
  • Worley

Research Method

The process I am going to take here is focused around implementing and comparing results of each of the noise generation functions. We will compare the following qualitative values:

  • Implementation Difficulty
  • Resulting graphical noise

The quantitative values we will leverage are:

  • Processing time for various image sizes
  • Aggregate variance from white

Results

Noise can be a fairly complex topic with a large amount of information on the topic that varies from article to article. We aim to resolve a number of the difficulties with this article as well as provide a complete set of code and framework that can be reused or inspected. Noise functions do not necessarily generate those beautiful pictures you are used to seeing, it’s the layering and adding those layers together which has those various effects.

In order for us to understand these various noise functions we need to compare it to a purely random function. For this we will be leveraging each of the languages random function to generate a number between 0.0f and 1.0f. We will attempt to stick to floating points as much as the language will allows us to. This is in an effort to ensure consistency between the results. Simply put:

   1: function RandomNoise(){
   2:return random(0.0f,1.0f);
   3: }

1. Random Noise

We take the result of the RandomNoise Function and convert it to an RGB value between 0 and 255. For this article we will stick to shades of grey so the RGB values will all be the same.

   1:int r = g = b = randomvalue * 255

The results of the RandomNoise function look as follows: 

Untitled-1

Figure 1.0 Noise Pattern


For an image 300px x 200px the average generation time sits in the 1600ms time range in JavaScript. As you can see there is no uniformity to the noise generated. The performance per language is broken down as follows:

Language300x2001024x7681600x9001280x1080
Javascript7.644.870.665.6
C#3.123589.3752520.3074720.31865
C++    

Table 1.0 Random Noise Average Time per resolution

As you can see the performance is purely based on the number of pixels you are trying to generate as well as the language you are using.

Before we go into Perlin Noise there is a bit of understanding of the different types of interpolation that we need to have. Interpolation calculates a projected value between a set of points based on various functions or techniques. 

Linear interpolation performs curve fitting using linear polynomials. It takes in 3 inputs Point1, Point2 and t which is a range between 0.0 and 1.0. The function for linear interpolation we will leverage is:

   1: function lerp(v0, v1, t) 
   2: { 
   3:return v0+(v1-v0)*t; 
   4: }

Cosine interpolation is a form of trigonometric interpolation which will provide us with smoother interpolations than linear. The function we will leverage is:

   1: function cosinerp(v0, v1, t) 
   2: { 
   3:      ft = t * 3.1415927 
   4:      f = (1 - cos(ft)) * .5 
   5:return v0*(1-f) + v1*f 
   6: }

Cubic interpolation is a more complex form of interpolation but results in much higher amounts of smoothing between points. Its also one of the simpler options to implement although it does require 4 points and t a range which works similar to the other two versions of interpolation. CatmullRom is a variation of this with weighted multiples applied to the calculation (See source code). The implementation is as follows:

   1: function cuberp(y0, y1,  y2, y3,  mu) 
   2: { 
   3:      a0,a1,a2,a3,mu2; 
   4:      mu2 = mu*mu; 
   5:      a0 = y3 - y2 - y0 + y1; 
   6:      a1 = y0 - y1 - a0; 
   7:      a2 = y2 - y0; 
   8:      a3 = y1; 
   9:return(a0*mu*mu2+a1*mu2+a2*mu+a3); 
  10: } 

Hermite interpolation is similar to Cubic except with the addition of two parameters Tension and Bias. Tension tightens up the curvature of the points and bias twists the curve around specific points. The formula for Hermite interpolation is:

   1: function hermiterp(v0, v1, v2, v3, t, tension, bias){
   2:     var m0,m1,t2,t3;
   3:     var a0, a1, a2, a3;
   4:     t2 = t * t;
   5:     t3 = t2 * t;
   6:     m0  = (v1-v0)*(1+bias)*(1-tension)/2;
   7:     m0 += (v2-v1)*(1-bias)*(1-tension)/2;
   8:     m1  = (v2-v1)*(1+bias)*(1-tension)/2;|
   9:     m1 += (v3-v2)*(1-bias)*(1-tension)/2;
  10:  
  11:     a0 =  2*t3 - 3*t2 + 1;
  12:     a1 =    t3 - 2*t2 + t;
  13:     a2 =    t3 -   t2;
  14:     a3 = -2*t3 + 3*t2;
  15:
  16:return(a0*y1+a1*m0+a2*m1+a3*y2);
  17: }

We also need to understand some terminology before proceeding as I found that without a decent understanding of these terms the following explanations become somewhat difficult to understand first time round. These concepts are focused on how layers are added together and the various properties of the layers.

Octaves: this first term is how many layers of noise are we going to blend together. The more octaves or layers the more detail the noise has

Frequency: this is the number of segments that we are going to put into the space we are using. This is the same as frequency when it comes to sound waves or signal process. The lower the frequency the bigger the features and the higher the frequency the smaller the features.

Amplitude: this is the height of the details. The bigger the amplitude the bigger the height of the features. Generally one will decrease the amplitude for each octave to have a more general smoothing effect.

Persistence: This is the rate at which the amplitude will decrease with each octave that is added. The smaller the persistence the lower the amount of change

With these concepts we can multiply and add various layers of noise together to generate wood like textures, clouds and many other types of procedural textures.

2. Value Noise

The next one we will look at is Value noise which is one of the simplest. Value noise is a simple algorithm that leverages a grid of random values between 0 and 1 to work out what a pixel should be. Below is a picture of what Value Noise Looks like:

ValueNoise

Figure 2.0 Value Noise

The way value noise works is by using a set of points which are randomized and then for each sample between points are interpolated between that set of randomized values. The general flow of this is as follows:

  1. Generate a set of random values for points
  2. For the given point calculate the points surrounding
  3. Get the random value using the surrounding points
  4. Calculate the difference between the points and use that for your interpolation value
  5. Interpolate the values
  6. Return the result

Lets have a look at each of the steps and understand them further. The first stage we generate an array of the appropriate dimension and we assign random values to this. The size of the array can vary quite widely and its worth having a look how the array size affects the out come. For a 2D noise function it will simply be:

   1:for(int x = 0; x < size; x++){ 
   2:for(int y = 0; y < size; y++){ 
   3:           RandomArray[x][y] = Random(); 
   4:      } 
   5: }

Now we have an array populated with random values this is our noise information that we are going to use to interpolate to have smooth transitions. Lets have a look at how this works. Given a point we map that point to the RandomArray and interpolate the value from the surrounding values points. We also need to know the position of the point given relative to the surrounding points we use this relative information to determine the interpolation value between two points. Now we interpolate and return the value for the noise. Once we populate our grid it should be something similar to this:

Populate-Grid

Figure 2.1 Populated Random Grid

Say we have a point 2,3 that we want noise for on an image that is 300x200 pixels wide we will pass in the x and y values multiplied by the inverse of the width and height of the area you wish to fill with noise. eg.

tx = 0,0033333 = 1/300
ty = 0,005 = 1/200

So we pass into the noise function 2.003333 and 3.005 (the red dot on the diagram). We now break down the point passed in into two components, its whole number and the remainder (tx and ty). With the remainder we use a smoothing function to get a new value that is used during interpolation. We then figure out which are the neighbouring points in the generated grid (the green dots on the diagram). We then interpolate the values with each other.

Populate-Grid---Value

Figure 2.2 The Points used for interpolation to ensure smooth noise.

To view the source code for this please see the source code links in the references section. Below are the performance metrics for the different languages and resolutions.

Language300x2001024x7681600x9001280x1080
Javascript8.294174173
C#2.1005758.1606996.2774794.56971
C++1.64.73.10

Table 2.0 Value Noise Average Time per resolution

3. Perlin Noise

Perlin Noise is the award winning technique developed by Ken Perlin in 1982 and was leveraged in the motion Picture Tron. It is a gradient noise which is a pseudo random technique. Instead of storing random numbers in the grid as in Value noise and interpolating, Perlin noise stores a gradient vector. To get the values we calculate the dot products of each gradient vector. The dot product is then interpolated to get our result which looks like:

PerlinNoise

Figure 3.0 Perlin Noise

From the above image you can see Perlin noise is less uniform than Value. There are a number of great articles covering the theory behind Perlin noise which are found in the references section but I will do my best to sum up the jist of what is going on at each step. Looking at Ken Perlin’s improved Perlin noise first step is initializing the array p[]. What is array p?  The P array allows us to have a predefined pseudo random allocation of number we can use to generate gradients. We could generate this array using the original method defined by Ken Perlins C code but for performance sake we use a predefined list. This p array is populated to fill 512 items.

Perlin-Noise---Permutation-population

Figure 3.1 Populating the P array

Now we have an array that can be used for random numbers we will take our input values and begin processing. It is important to note that the input expected is a floating point (eg 0.0333 or 1.0333). This is why we divide the x and y values by the width and height. This gives us a percentage which is the distance across the width or height. Using this adjusted x and y value as input we then find the cube that surrounds the inputs.

Perlin-Noise---Cube-Finding

Figure 3.2 Components used for the Perlin Noise calculation

Once we have the required components we now calculate the value that we will be using for the interpolation between the various gradients. This is done using a smoothing function which given a value will return the corresponding value that is on a smoothed curve.

Perlin-Noise---Smoothing-curve

Figure 3.3 Smooth curve values for the Lerp

Using this information we use the values in the p[] array to get hash values that we can leverage to generate the gradients for each point. For example given that our x and y values are (0.0333, 0.0333) for x = 0 and y = 0 the hashes would look as follows:

   1: A = p[0] + 0 = 151 
   2: AA = p[A] + 0 = p[151] = 17 
   3:

Using those points we now calculate the various gradients for AA,AB,BA,BB and AA+1, AB+1, BA+1, BB +1.

   1: x = 0.0333 
   2: y = 0.0333 
   3:  AA = 17 
   4:  h = 17 & 15 = 1 
   5:  u = 1 < 8 ? 0.0333 : 0.0333 = 0.0333 
   6:  v = 1 < 4 ? 1 == 12 || h == 14 ? 0.0333 : 0 = 0 
   7:  a = h & 1 == 0 ? u : -u = 0.0333 
   8:  b = h & 2 == 0 ? v : -v = 0;
   9:
  10:return a + b = 0.0333

With each of those gradients we now perform a Linear Interpolation between those using the smoothed values and that’s about it.

Language300x2001024x7681600x9001280x1080
Javascript22.1259.6447.7440.5
C#10.91993178.67824329.77866318.2969
C++4.640.770.378.2

Table 3.0 Perlin Noise Average Time per resolution

4. Simplex

Simplex Noise developed by Ken Perlin in 2001 has similar results to Perlin Noise with less computational requirements than Perlin. The idea of Simplex is to divide the N dimensional space into triangles that reduces the number of data  points. In Perlin noise we would find the cube that the point we are given in resides and find the points related. Visually the result is not much different from Perlin noise.

SimplexNoise

Figure 4.0 Simplex Noise

With simplex we are finding the shape that is based on a equilateral triangle and returning fewer points. The major difference Basically it takes the previous grid and skews it and forms triangles for the simplex representation. The gradients for each of the points are then generated and then the rest of the implementation is pretty much the same.

[TODO – Diagram showing the difference between Perlin and Simplex]

The results are good and the performance is much better than Perlin with higher dimensions but it is quite complex to understand

Language300x2001024x7681600x9001280x1080
Javascript36.2475.7847.7820.5
C#15.75991230.19422418.06524393.17309
C++3107.6192.4182.6

Table 4.0 Simplex Noise Average Time per resolution

5. Worley

Worley Noise (Aka Cell Noise) was developed by Steven Worley in 1996 which is very useful in generating stone, water or cell noise textures. The  way Worley noise works is that is has a random set of feature points. Given a specific point it calculates the distance of that point to the nearest feature point and uses that for the information. The result is seen below:

Worley

Figure 5.0 Worley Noise

What is needed is a set of random points which we compare against. Then we calculate the distance from to the nearest point from the point supplied. Worley’s algorithm has a more efficient implementation of this concept which performs the following steps:

  1. Calculates which cube a point is in
  2. Create a random number generator for the cube
  3. Calculate how many points are inside the cube
  4. Randomly assign points in the cube
  5. Find the point closest to the point given
  6. Check neighboring cubes
  7. Calculate the distance

Distance-Grid

Figure 5.1 How the noise value is determined

We can change our results by changing the number of feature points, the way distance is computed and the size of the grid used. If you invert the image you can see the points and the distance information clearly.

Language300x2001024x7681600x9001280x1080
Javascript764.810003.21887917875.9
C#906.924511532.65421078.358520539.72
C++290.13866.47078.46615

Table 5.0 Worley Noise Average Time per resolution

Conclusion

The various types of noises all have different visual and performance benefits. Below is a visual comparison of each of the different types of noise covered in this article.
Comparison
Chart 1.0 Comparison of each of the performance factors across the various languages.
By far C++ has the best performance compared to the other languages and C# was typically slower than JavaScript but this can be explained by the direct porting of code instead of using appropriate data structures. The last table summarizes the findings.
TechniqueResulting ImageImplementation DifficultyProcessing timeVarianceProsCons
RandomRandom-NoiseEasyLow amount of processing requiredHi amount of variance with no smoothingRandom informationNo smooth transitions between points
ValueValueNoiseEasyMore expensive than RandomMinimal Smoothing Not a very organic pattern
PerlinPerlinNoiseModerateSlightly slower but not considerablyHi amount of variance Great smoothingA little complex to understand
SImplexSimplexNoiseModerateFastSimilar result to PerlinFast to compute east to implement in hardwareComplex to understand
WorleyWorleyComplexSlowHi varianceNice effects, various different items to changeNot a simple to implement and requires more processing

Table 6.0 Summarized findings

Source Code:

Sharp Noise : https://sharpnoise.codeplex.com/

References:

Bourke, P (1999)Interpolation Methods, [Online]
Available: http://paulbourke.net/miscellaneous/interpolation/ [7 Feb 2014]

(2012) Noise Part 1, [Online],
Available: http://scratchapixel.com/lessons/3d-advanced-lessons/noise-part-1/ [12 Feb 2014]

(2010) Value_Noise – Explanation of Value Noise, [Online],
Available: http://code.google.com/p/fractalterraingeneration/wiki/Value_Noise [12 Feb 2014]

(2013) Perlin Noise, Wikipedia, [Online],
Available: http://en.wikipedia.org/wiki/Perlin_noise [5 Feb 2014]

Zucker, M (2001) The Perlin noise math FAQ, [Online],  
Available: http://webstaff.itn.liu.se/~stegu/TNM022-2005/perlinnoiselinks/perlin-noise-math-faq.html [5 Feb 2014]

Hugo, E (2003) Perlin noise,[Online]
Available: http://freespace.virgin.net/hugo.elias/models/m_perlin.htm [5 Feb 2014]    

Perlin, K () Noise and Turbulance, [Online]
Available: http://www.mrl.nyu.edu/~perlin/doc/oscar.html#noise [24 Feb 2014]  

Perlin, K () Noise Hardware, [Online]
Available: http://www.csee.umbc.edu/~olano/s2002c36/ch02.pdf [26 Mar 2014]

Perlin, K (2002) Improved Noise Reference Implementation,[Online],
Available: http://mrl.nyu.edu/~perlin/noise/ [7 Feb 2014]

Tulleken, H (2009) How to use Perlin Noise in your games, [Online],
Available: http://devmag.org.za/2009/04/25/perlin-noise/ [7 Feb 2014]

Thomas, K (2011) Perlin Noise in JavaScript, [Online]
Available: http://asserttrue.blogspot.co.uk/2011/12/perlin-noise-in-javascript_31.html [26 Mar 2014]

Explanation of Perlin Noise, [Online]
Available: http://code.google.com/p/fractalterraingeneration/wiki/Perlin_Noise [26 Mar 2014]

Simplex Noise, [Online]
Available: http://en.wikipedia.org/wiki/Simplex_noise [26 Mar 2014]

Gustavson, S (2005) Simplex noise demystified, [Online]
Available: http://webstaff.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf [26 Mar 2014]

Explanation of Simplex Noise, [Online]
Available: http://code.google.com/p/fractalterraingeneration/wiki/Simplex_Noise [26 Mar 2014]

Worley Noise, [Online]
Available: http://en.wikipedia.org/wiki/Worley_noise [26 Mar 2014]

FreeTheNation (alias) (2013) Cell Noise, [Online]
Available: http://aftbit.com/cell-noise-2/ [26 Mar 2014]

Worley, S, A Cellular Texture Basis Function, [Online]
Available: http://www.rhythmiccanvas.com/research/papers/worley.pdf [26 Mar 2014]

Endre, S (2012) Worley Noise Cellular Texturing, [Online]
Available: http://esimov.com/2012/05/worley-noise-cellular-texturing#.Ux790v_MOM8 [26 Mar 2014]

Nouanesengsy, B  CSE 782 Lab 4, [Online]
Available: http://www.cse.ohio-state.edu/~nouanese/782/lab4/ [26 Mar 2014]

Rosen, C (2006) Cell Noise and Processing, [Online]
Available: http://www.carljohanrosen.com/share/CellNoiseAndProcessing.pdf [26 Mar 2014]

Appendix A – Data Results

 300x2001024x7681600x9001280x1080
Sample 15113614173
Sample 23386570
Sample 32346261
Sample 42336159
Sample 53336261
Sample 62376259
Sample 74346469
Sample 83366385
Sample 93356361
Sample 103326358
Average7.644.870.665.6

Table A.0.1 Javascript Random Noise in milliseconds

 300x2001024x7681600x9001280x1080
Sample 113105157142
Sample 2687156140
Sample 3781214237
Sample 414112236229
Sample 510115209215
Sample 66104152150
Sample 7684147148
Sample 8788159148
Sample 9783153168
Sample 10681157153
Average8.294174173

Table A.0.2 Javascript Value Noise in milliseconds

 300x2001024x7681600x9001280x1080
Sample 126266414403
Sample 228364449423
Sample 323227432405
Sample 417246430452
Sample 516232436468
Sample 623243442469
Sample 730258448435
Sample 817280468448
Sample 915234482462
Sample 1026246476440
Average22.1259.6447.7440.5

Table A.0.3 Javascript Perlin Noise in milliseconds

 300x2001024x7681600x9001280x1080
Sample 141498869827
Sample 235457863874
Sample 336491893815
Sample 435474861837
Sample 536499872849
Sample 635463822788
Sample 733440813771
Sample 833464849862
Sample 945520823797
Sample 1033451812785
Average36.2475.7847.7820.5

Table A.0.3 Javascript Simplex Noise in milliseconds

 300x2001024x7681600x9001280x1080
Sample 177398001797017342
Sample 2752100661873518308
Sample 3754104321840118257
Sample 4889110352049517651
Sample 576195551850718100
Sample 675399341851818836
Sample 7748100012071817671
Sample 871594651787517159
Sample 9760100471905417786
Sample 1074396971851717649
Average764.810003.21887917875.9

Table A.0.4 Javascript Worley Noise in milliseconds

 300x2001024x7681600x9001280x1080
Sample 115,621915,625915,624331,2802
Sample 20031,250315,6251
Sample 3015,626415,625115,6267
Sample 4015,623915,624715,626
Sample 515,6239015,625931,2503
Sample 60031,25115,6264
Sample 7015,624315,598415,6518
Sample 8015,626415,625915,6243
Sample 9015,625615,59831,2781
Sample 100031,251115,5976
Average3,124589,3752520,3074720,31865

C# Random Noise

 300x2001024x7681600x9001280x1080
Sample 1062,499393,782793,7233
Sample 2062,529293,751593,7524
Sample 3062,500993,75493,7216
Sample 4062,530993,722893,7819
Sample 5062,501793,751698,6821
Sample 64,000354,003699,978294,0085
Sample 74,000355,033299,00694,0094
Sample 83,999953,0043101,008395,0069
Sample 95,000853,003997,00895,0032
Sample 104,004453,999997,011694,0078
Average2,1005758,1606996,2774794,56971

C# Value Noise

 300x2001024x7681600x9001280x1080
Sample 13,0671187,5339328,1042312,5086
Sample 20187,5314312,4794328,1621
Sample 30187,4756328,1596296,8797
Sample 415,6276187,5044328,1329296,8814
Sample 515,6259171,8792328,105312,5053
Sample 615,6256171,9055328,1324323,6092
Sample 714,001179,0144329,0262328,0242
Sample 814,0022164,5815328,1325312,5077
Sample 915,6252187,4768312,5345312,5077
Sample 1015,6247171,8797374,9799359,3831
Average10,91993179,67824329,77866318,2969

C# Perlin Noise

 300x2001024x7681600x9001280x1080
Sample 115,6272265,6312468,759390,6362
Sample 215,6235218,785399,3286390,6338
Sample 315,6255218,755421,8578400,3869
Sample 416,9734223,7623406,2314453,1643
Sample 515,6255281,228437,5071390,6379
Sample 615,6226218,7575406,2581375,0374
Sample 715,6255218,7275421,9124374,9803
Sample 815,6252218,7841406,2589375,0087
Sample 915,6251218,7562406,2528390,6395
Sample 1015,6256218,7554406,2593390,6059
Average15,75991230,19422418,06254393,17309

C# Simplex Noise

 300x2001024x7681600x9001280x1080
Sample 1875,050711721,828921159,697320796,8689<
Sample 2881,751211395,972821601,966321163,0641<
Sample 3937,518811781,618221021,705220026,9773<
Sample 4875,020411425,82620934,02820934,7304
Sample 5968,790611538,246920978,240720503,3906<
Sample 6875,01511437,830421050,545320282,7218
Sample 7859,362411500,55321201,937120710,8594
Sample 81046,846711692,110621034,710720608,7085
Sample 9874,958511458,680920889,126919987,1211<
Sample 10874,93111373,870320911,627420382,7533<
Average906,9245311532,653821078,3584920539,7195

C# Worley Noise

 300x2001024x7681600x9001280x1080
Sample 10000
Sample 20000
Sample 30000
Sample 40000
Sample 516000
Sample 601500
Sample 701600
Sample 801600
Sample 900150
Sample 1000160
Average1.64.73.10
C++ Random Noise
 300x2001024x7681600x9001280x1080
Sample 10477879
Sample 215317978
Sample 315327878
Sample 40327878
Sample 50466378
Sample 60476278
Sample 70476278
Sample 80476278
Sample 916476279
Sample 100317978
Average4.640.770.378.2
C++ Value Noise
 300x2001024x7681600x9001280x1080
Sample 116109187188
Sample 216109187188
Sample 316109187172
Sample 41693203170
Sample 516109188187
Sample 60109188187
Sample 70109188187
Sample 80109188187
Sample 91693194188
Sample 101694203187
Average11.2104.3191.3184.1
C++ Perlin Noise
 300x2001024x7681600x9001280x1080
Sample 115110187172
Sample 21594203172
Sample 30109188187
Sample 40109188187
Sample 50109188187
Sample 60109188187
Sample 70109188187
Sample 80109203172
Sample 90109188187
Sample 100109203188
Average3107.6192.4182.6
C++ Simplex Noise
 300x2001024x7681600x9001280x1080
Sample 1281377666726992
Sample 2312371970146674
Sample 3281426674536719
Sample 4281415679546922
Sample 5281385973856484
Sample 6297406367976487
Sample 7313389469926435
Sample 8281361969156365
Sample 9277370567286634
Sample 10297360768746438
Average290.13866.47078.46615
C++ Worley Noise

Viewing all articles
Browse latest Browse all 29128

Trending Articles