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