Some people have asked for an implementation of the noise blending technique in my previous post. Here’s the Processing code for the core idea. Keep in mind that this is just about making a smoothly changing noise field; what you do with that noise is up to you!
The best way to implement this (and the way I did it!) is to use my AU library. Then you can save 2D arrays of floats in AUField
objects, which are easy to make and manipulate. But that library hasn’t been released yet (I just added another function this morning!), so this listing is just pure out-of-the-box Processing.
The only weirdness is the variable ListOfNoiseArrays
, which is of type float[][][]
. If you haven’t seen this kind of thing before, don’t worry: it’s just a 3D array. Think of it as a stack of slices. The first index tells you which slice to use, and the second and third indices tell you the row and column of the pixel you want on that slice.
Conveniently, the value of ListOfNoiseArrays.length
returns the length of the first index. That is, it’s the number of slices that the array holds. So this gives us an easy way to find out how many noise fields we’re blending through without needing to keep a separate global variable. This image shows the output as an animated gif; if it’s not animating, click it to see it in motion.
// A little sketch to demonstrate the multiple noise field interpolation technique. // No guarantee or warranty of any kind. You may use and distribute this freely. // Andrew Glassner, August 28, 2014 float[][][] ListOfNoiseArrays; // global to hold list of noise fields void setup() { size(500, 500); int numFields = 4; // how many fields you want to use. Must be > 0 ListOfNoiseArrays = new float[numFields][height][width]; // create the array for (int n=0; n<ListOfNoiseArrays.length; n++) { // for each field n, for (int y=0; y<height; y++) { // look at all the pixels for (int x=0; x<width; x++) { float noiseX = (x*.02) + (n*width); // .02 was chosen by eye; it's float noiseY = (y*.02) + (n*height); // not too simple or busy ListOfNoiseArrays[n][y][x] = noise(noiseY, noiseX); // save this value } } } } void draw() { int cycleLength = 25; // number of frames to get from one field to another // Find n, the index of the first field in the set of 4 we're going to blend int n = (int)((frameCount*1./cycleLength) % ListOfNoiseArrays.length); // Find alfa, a value from 0 to 1 telling us where we are in this blend float alfa = ((frameCount - (n*cycleLength))/(1.*cycleLength)) % 1.0; // Now build up the noise field for every pixel. I'll draw it, but typically // we'd save this in an array and use it to generate our graphics. loadPixels(); for (int y=0; y<height; y++) { for (int x=0; x<width; x++) { // Find the four values of n that are the fields we're going to interpolate int n0 = n; int n1 = (n0+1)%ListOfNoiseArrays.length; int n2 = (n1+1)%ListOfNoiseArrays.length; int n3 = (n2+1)%ListOfNoiseArrays.length; // Evaulate a Catmull-Rom curve through the values for this pixel float v = curvePoint(ListOfNoiseArrays[n0][y][x], ListOfNoiseArrays[n1][y][x], ListOfNoiseArrays[n2][y][x], ListOfNoiseArrays[n3][y][x], alfa); pixels[(y*width)+x] = color(255 * v); // save noise value as a shade of gray } } updatePixels(); }
Pingback: Noise Blending with the AU Library | Imaginary Institute Blog