Linear 2D Noise Code

© 2001 Harriet Fell for COM3370 Computer Graphics

Below is a C++ implementation of Linear Noise and Turbulence. Marble and simple Clouds are built on them.

```// Standard Shell for C++ Courseware

// Copyright 1997; modified June 2000 for CodeWarrior IDE 4.0
// College of Computer Science
// Northeastern University Boston MA 02115

// This software may be used for educational purposes as long as this copyright
// notice is retained at the top of all files

// Should this software be modified, the words "Modified from Original" must be
// included as a comment below this notice

// All publication rights are retained.  This software or its documentation may
// not be published in any media either in whole or in part.

///////////////////////////////////////////////////////////////////////////////

// C++2DNoise
// Harriet Fell 8/9/2001; clouds revised 8/15/2001

///////////////////////////////////////////////////////////////////////////////
using namespace std;

#include "SWindows.h"					// set up for windows
#include "IOTools.h"					// tools for safe I/O
#include "Graphics.h"					// graphics functions & RGB definition
#include "RGBNames.h"					// RGB names
#include "Random.h"						// random numbers
#include "FileTool.h"					// file tools
#include "Text.h"						// fonts and text
#include "Delay.h"						// delay controls

// globals
const size = 39;		// multiple of 3 for splines

typedef double noiseArray[size + 1][size + 1];
noiseArray noiseR, noiseG, noiseB;  // Each is a 40x40 array of randoms from 0 to 1
//double factorR, factorG, factorB, factor; // to set the proportions of Red, Green, Blue
int divisor;	// for spreading out the noise
enum {
Quit		= 0,
Noise		= 1,
Turbulence	= 2,
Marble		= 3,
Clouds		= 4
};

// prototypes
int main();
void setNoises();		// fill the noise arrays with random integers
// Generate linear noise and turbulence from the noise array.
// Return val between 0 and 1
double linearNoise (double u, double v, noiseArray noise);
double Lturbulence(double u,double v, noiseArray noise);
// sinusoidal functions to blend with turbulence
double marble (double x, double y, noiseArray noise, int twist);
double cloud (double x, double y, noiseArray noise, int fluff);
// Scale color to 0 to 255 range
RGB noiseColor(double x, double y);
RGB turbulenceColor(double x, double y, int m);
RGB marbleColor (double x, double y, int twist);
RGB cloudColor(double x, double y, int fluff);

// definitions
int main()
{
// open text and drawing windows
BigSquarePair();
// start random number generator
SetRandomSeed();
//Fill the noise arrays
setNoises();

int h, v;			// pixel coordinates
double x, y;		// x = h/divisor, y= v/divisor are sent to LinearNoise function
int m = 1;			// scaling turbulence color
int twist = 1;		// for twistiness of marble
int fluff = 1;		// for fluffiness of cloud
divisor = 1;
int choice = Noise;

do{
choice = RequestInt("Noise\t\t1\nTurbulence\t2\nMarble\t\t3\nClouds\t\t4\nQuit\t\t0\nChoose an action  ", choice);

divisor = RequestInt("Enter divisor = ", divisor);
if (choice == Turbulence)  m = RequestInt("color scale, 255 for smooth, greater for breaks", 255);
if (choice == Marble) twist = RequestInt("for twistiness of marble, >= 1", twist);
if (choice == Clouds) fluff = RequestInt("for fluffiness of clouds, >= 1", fluff);

for (v = 0; v < 400; v++)
for( h = 0; h < 400; h++){
x = (double)h / divisor;
y = (double)v / divisor;
if      (choice == Noise)	    SetColorPixel(h, v, noiseColor(x,y));
else if (choice == Turbulence)	SetColorPixel(h, v, turbulenceColor(x, y, m));
else if (choice == Marble)	    SetColorPixel(h, v, marbleColor(x, y, twist));
else if (choice == Clouds)      SetColorPixel(h, v, cloudColor(x, y, fluff));
}
} while (choice != Quit);

// done
PressReturn("Select 'quit' from the file menu to terminate.");
return(0);
}

void setNoises(){
// fill the noise arrays with random integers
int i, j;

for (j = 0; j < size; j++)
for (i = 0; i < size; i++){
noiseR[i][j] = RandomDouble(0, 1);
noiseG[i][j] = RandomDouble(0, 1);
noiseB[i][j] = RandomDouble(0, 1);
}
for (j = 0; j < size; j++){
noiseR[size][j] = noiseR[0][j];	// set the last row and column to match the first row and column
noiseR[j][size] = noiseR[j][0];
noiseG[size][j] = noiseG[0][j];
noiseG[j][size] = noiseG[j][0];
noiseB[size][j] = noiseB[0][j];
noiseB[j][size] = noiseB[j][0];
}

noiseR[size][size] = noiseR[0][0];	//set the last corner to complete the wrap
noiseG[size][size] = noiseG[0][0];
noiseB[size][size] = noiseB[0][0];
}

double linearNoise (double u, double v, noiseArray noise){
int iu, iv, ip, iq;
double du, dv, bot, top;

iu = trunc(u);		// integer parts of u and v
iv = trunc(v);
du = u - iu;		// fractional parts uf u and v
dv = v - iv;

iu = iu % size;		// intergral parts of u and v
iv = iv % size;		// mapped to integers 0 to size - 1
ip = (iu + 1);      // (ip, iu) lattice point one up and to right of (iu, iv)
iq = (iv + 1);
//          top gets noise from linear function across the top of the square
//           |
//	(iu, iq)----(ip, iq)
//		|	 |		|
//		|	 *		|
//		|	 |		|
//	(iu, iv)----(ip, iv)
//           |
//          bot gets noise from linear function across the bottom of the square
// go a distance du along the top and bottom of the square
bot = noise[iu][iv] + du * (noise[ip][iv] - noise[iu][iv]);
top = noise[iu][iq] + du * (noise[ip][iq] - noise[iu][iq]);

// use a linear function from bot to top
// go a distance dv from bot to top
return (bot + dv * (top - bot));
}

RGB noiseColor(double x, double y){
// converts linear noise factors to 0 to 255 range for an RGB color.
double factorR, factorG, factorB; // to set the proportions of Red, Green, Blue
RGB myColor;
factorR = linearNoise(x, y, noiseR);
factorG = linearNoise(x, y, noiseG);
factorB = linearNoise(x, y, noiseB);

myColor.Set(round(factorR * 255), round(factorG * 255), round(factorB * 255));
return myColor;
}

double Lturbulence(double u,double v, noiseArray noise){
double t, scale;
// LN(u, v) +LN(2u, 2v)/2 + LN(4u, 4v)/4 + ...
// Value is between between 0 and 2.
t = 0;
for (scale = 1; scale >= (double)1 / divisor; scale /= 2) {
t = t + linearNoise(u / scale, v / scale, noise) * scale;
}
return t/2; // value is between 0 and 1
}

RGB turbulenceColor(double x, double y, int m){
// converts linear turbulence factors to 0 to 255 range for an RGB color.
// m is a scale factor.  m=255 gives smooth color of maximal brightness
// Lower values give darker color.
// Higher values give 'broken' but interesting color - caused by overflow
double factorR, factorG, factorB; // to set the proportions of Red, Green, Blue
RGB myColor;
factorR = Lturbulence(x, y, noiseR);
factorG = Lturbulence(x, y, noiseG);
factorB = Lturbulence(x, y, noiseB);

myColor.Set(round(factorR * m), round(factorG * m), round(factorB * m));
return myColor;
}

double marble (double x, double y, noiseArray noise, int twist){
// take the square root to fatten the green bands, leaving thin blue veins
return sqrt(abs(sin(x + twist*Lturbulence(x, y, noise))));
}

RGB marbleColor (double x, double y, int twist){
RGB myColor;
double factorG = marble(x, y, noiseG, twist);
// When factorG is 1, the color is cyan (0, 255, 255).
// When factorG is 0, the color is blue (0, 0, 255).
// The color changes linearly with factorG.
myColor.Set(0, trunc(factorG*255), 255);
return myColor;
}

double cloud (double x, double y, noiseArray noise, int fluff){
//	return sin(x + Lturbulence(x, y, noise));
double r =  sqrt((x-(double)200/divisor)*(x-(double)200/divisor) + (y-(double)200/divisor)*(y-(double)200/divisor));
return cos(r + fluff*Lturbulence(x, y, noise));
}

RGB cloudColor(double x, double y, int fluff){
double factorB; // to set the proportions of Blue (really, to regulate the saturation)
RGB myColor;
factorB = abs(cloud(x, y, noiseR, fluff));
// When factorB is 1, the color is pale blue (127, 127, 255).
// When factorB is 0, the color is white (255, 255, 255).
// The color changes linearly with factorB.
myColor.Set(127 + 128*(1 - factorB), 127 + 128*(1 - factorB), 255);
return myColor;
}
```

Harriet J. Fell
College of Computer Science, Northeastern University
360 Huntington Avenue #161CN,
Boston, MA 02115
Internet: fell@ccs.neu.edu
Phone: (617) 373-2198 / Fax: (617) 373-5121

Last Updated: August 15, 11:43 a.m.
The URL for this document is: http://www.ccs.neu.edu/home/fell/COM3370/noiseCode2.html