I’ve been working on a set of Processing sketches that start from an oscillating sine wave. This is created by making a bezier whose anchor points are at either sides of your window, and setting two control points that oscillate up and down in opposite directions. When you stack multiple iterations of the same function, you can create a nice wave effect:
Things start to get even more interesting when you set the window not to refresh with every frame, and turn the alpha (opacity) of your line to a very low percentage. As the frames accumulate without being erased, they generate interference patterns that are most visible where the lines move and intersect most frequently. The wave that is actually telling the pixels to change color is constantly moving, but an apparently static image slowly emerges like a developing photograph, producing some very lovely shapes, which almost feel three dimensional because of the shading effects that result. It reminds me of the famous Chladni plates, which when bowed, vibrate in ways that almost magically concentrate randomly scattered particles on their surfaces into coherent patterns.
The following image shows the interference pattern that results from the waves seen in the animation above. For this one I reversed the colors so that the lines are black and the background is white, which seemed to produce a more interesting effect.
You can also place multiple sine waves in motion at the same time. For example, instead of having one set of waves span the entire window, you can add two sets of waves, each of which spans half of the widow, or divide it even further.
You can also add vertical waves. This animation shows the motion of a 5×5 set of perpendicular sine waves.
When you use a similar trick of not refreshing the screen after every frame, you can generate some very satisfying patterns, like this one here.
The following code illustrates how this final sketch is produced. Playing with the parameters should offer options for producing a variety of patterns.
float x1, y1, x2, y2, x3, y3, x4, y4;
float xx1, yy1, xx2, yy2, xx3, yy3, xx4, yy4;
int subdivisions;
void setup() {
size(800, 800);
background(0);
smooth();
hint(ENABLE_STROKE_PURE);
subdivisions = 4; // Sets how many waves you want to draw on each axis
}
void draw(){
stroke(255, 2); // tells it to create a white line, with very low opacity.
noFill();
// This is the oscillation function that tells the control points to move back and forth.
float t1 = millis()/200.0f;
int oscillation = int(map(sin(t1), -TWO_PI, TWO_PI, -3000, 3000));
// Determines the number of times you want to partition the horizontal and vertical axes
for (int divisions = 0; divisions < 2; divisions++) {
for (int numBeziers = -(int(subdivisions/3)); numBeziers < subdivisions+(int(subdivisions/3)); numBeziers++) {
// Controls the movement of the horizontal beziers
x1 = divisions * width/2;
x2 = width/8 + (divisions*width/2);
x3 = 3*width/8 + (divisions*width/2);
x4 = (width/2)+(divisions*width/2);
y1 = numBeziers*height/subdivisions;
y2 = y1+oscillation;
y3 = y1-oscillation;
y4 = numBeziers*height/subdivisions;
bezier(x1, y1, x2, y2, x3, y3, x4, y4);
// Controls the movement of the vertical beziers
xx1 = numBeziers*width/subdivisions;
xx2 = xx1+oscillation;
xx3 = xx1-oscillation;
xx4 = numBeziers*width/subdivisions;
yy1 = divisions * height/2;
yy2 = height/8 + (divisions*height/2);
yy3 = 3*height/8 + (divisions*height/2);
yy4 = (height/2) + (divisions*height/2);
bezier(xx1, yy1, xx2, yy2, xx3, yy3, xx4, yy4);
}
}
}