# Tutorial 6: Drawing with Randomness

# Randomness

To produce variations on a design we need some way to change the values of variables used in the drawing process. One way to do this is to use a "random number generator", which typically uses a chaotic mathematical function to generate a sequence of pseudo-random numbers that follow an unpredicatable sequence (unless you have detailed knowledge of the algorithm that it uses and know the precise starting conditions). In Processing, the `random()`

function is used to create unpredictable values within a range:

```
// Assign f a random float value from 0 to 5.2
float f = random(5.2);
// Try to assign a float to an int
int i = random(5.2); // ERROR!
// Assign j an int value from 0 to 5
int j = int(random(5.2));
```

## Random Drawings

We can use the `random()`

function to very quickly write a simple sketch that is drawn differently each time it is run. The following sketch draws 5 lines, each of them is drawn from the left to the right-hand side of the display window, i.e., from `0`

to `width`

on the x-axis, and from a randomly chosen vertical position on the left to another randomly chosen vertical position on the right.

- Show Sketch

```
/** @peep sketchcode */
size(200, 200);
smooth();
strokeWeight(20);
stroke(0, 130);
line(0, random(height), width, random(height));
line(0, random(height), width, random(height));
line(0, random(height), width, random(height));
line(0, random(height), width, random(height));
line(0, random(height), width, random(height));
```

Alter the above program to draw bezier curves using the

`random()`

function to determine the y-coordinate of the four control points in much the same way that the sketch above uses the`random()`

function to determine the y-coordinates of the end points of each line. The end result should look something like this:

# Random Loops

Using `random()`

within a for structure is an easy way to generate lots of random numbers for drawing complex forms. The following example demonstrates how we can draw many, almost parallel, lines using `random()`

to produce an interesting texture where the lines cross.

- Show Sketch

```
/** @peep sketchcode */
size(200, 200);
background(0);
stroke(255,60);
for (int i = 0; i < width; i++) {
float r = random(width/10);
strokeWeight(r);
float offset = r * 5.0;
line(i - width/5, height, i+offset, 0);
}
```

Modify the above example to draw ellipses with random radii like the following:

The next example uses one `for`

loop embedded within another to draw a grid of randomly sized squares. The size of each square is determined using the call to `random(10, 40)`

, meaning that each square will be between 10 and 40 pixels in size.

- Show Sketch

```
/** @peep sketchcode */
size(200, 200);
background(0);
fill(255,60);
noStroke();
rectMode(CENTER);
for (int x = 20; x < width; x += 20) {
for (int y = 20; y < height; y += 20) {
float r = random(20, 40);
rect(x, y, r, r);
}
}
```

Change the above code to experiment with the range of values that

`random()`

produces by changing the values for the`low`

and`high`

parameters. Observe the changes to the appearance of the sketch with relatively small changes in the parameter settings.

# Random Tests

To use random values to determine the flow of the program, you can place the result of running the `random()`

function in a relational expression used as a test in an `for`

statement.

- Show Sketch

```
/** @peep sketchcode */
size(200, 200);
for (int y = 0; y < height; y += 20) {
int w = int(random(width)) + 1;
for (int x = 0; x < w; x += 4) {
line(x, y, x, y + 20);
}
}
```

We can also use the result of calling `random()`

in conditional tests, i.e., `if`

statements. For example, the following sketch builds on the examples of drawing repeating patterns using loops and conditionals from the previous tutorial. It uses `random()`

instead of a calculation based on the `%`

operator to determine which way to draw a diagonal line. This results in a non-repeating pattern:

- Show Sketch

```
/** @peep sketchcode */
size(200, 200);
smooth();
for (int y = 20; y <= height - 20; y += 10) {
for (int x = 20; x <= width - 20; x += 10) {
if (random(1) < 0.5) {
line(x-5, y+5, x+5, y-5);
} else {
line(x-5, y-5, x+5, y+5);
}
}
}
```

The type of conditional test using `random()`

illustrated above can be thought of a simulating a coin toss, with "heads" being a value less than `0.5`

and "tails" being a value greater than or equal to `0.5`

.

Using the tests based on

`random()`

to choose between two drawing options, develop a sketch that draws differently at every point on a grid.Experiment with using different values in the random test, for example, how does the drawing of the grid change when you change the test from 50/50 to 80/20?

Based on the first of the sketches drawing non-repeating patterns above, can you draw the following pattern by varying the probablility of choosing to draw in one direction rather than the other:

Experiment with using the values of

`x`

and/or`y`

to vary the random test. For example, can you reproduce the following designs that vary the choice of line orientation horizontally and vertically by testing`random(200)`

against the current`x`

or`y`

position:Notice how the majority of the lines at one side of each of the above images is in the opposite direction from those at the other side.

## Using Multiple Tests to Draw Shapes

The following sketch uses two tests, and calls `random()`

twice for each point in the regular grid to determine where to draw two diagonal lines at 90 degrees to each other.

- Show Sketch

```
/** @peep sketchcode */
size(200, 200);
for (int y = 20; y <= height-20; y += 10) {
for (int x = 20; x <= width-20; x += 10) {
if (random(1) < 0.5) {
line(x, y, x+5, y-5);
} else {
line(x, y, x+5, y+5);
}
if (random(1) < 0.5) {
line(x, y, x-5, y-5);
} else {
line(x, y, x-5, y+5);
}
}
}
```

Experiment with different shapes that can be drawn at different grid points. For example, can you produce interesting grid-like patterns using dots or Bezier curves:

# Seeding Random Numbers

It's sometimes desirable to include unpredictable numbers in your programs but to force the same sequence of numbers each time the program is run. The `randomSeed(value)`

function is the key to producing such numbers. The `value`

parameter must be an `int`

. Use the same `value`

parameter in a program each time it is run to force the same random numbers to be produced in the same order. Using `randomSeed()`

allows use to produce the same picture each time the program is run. The following sketch will create the same drawing every time it is run because the random seed has been fixed.

- Show Sketch

```
/** @peep sketchcode */
int s = 6; // Change this seed value to change the drawing
randomSeed(s);
size(200, 200);
background(0);
stroke(255,60);
for (int i = 0; i < width; i++) {
float r = random(width/10);
strokeWeight(r);
float offset = r * 5.0;
line(i - width/5, height, i+offset, 0);
}
```

Experiment with the above sketch by copying it to the editor and changing the value of

`s`

. Notice that when you don't change`s`

between runs you get the same drawing.

# Noise

Values produced using the `random()`

function can be hard to control because each number is generated is independent from the previous. The `noise()`

function is a more controllable way to create unexpected values. The `noise()`

function uses the Perlin Noise technique, developed by Ken Perlin. Originally used for simulating natural textures through subtle irregularities, Perlin Noise is also used for generating shapes and realistic motion. The `noise()`

function works by interpolating between random values to create smoother transitions than the numbers returned from `random()`

. The noise function has between one and three parameters:

Different versions of the `noise()`

function sample a space of noise values with 1, 2 or 3 dimensions:

`noise(x)`

creates random numbers based on a 1-dimensional space (i.e., an imaginary line) that can be mapped to drawing lines on the screen, etc.

`noise(x, y)`

creates random number based on sampling a 2-dimensional space (i.e., an imaginary plane) that can be used for generating 2D textures.

`noise(x, y, z)`

creates random number number based on sampling a 2-dimensional space that can be used for generating 3D shapes, textures or animated 2D textures.

The following sketch is an example of using the 1-dimensional `noise()`

function:

- Show Sketch

```
/** @peep sketchcode */
size(400, 100);
float inc = 0.1;
noStroke();
fill(0);
noiseSeed(0);
for (int x = 0; x < width; x += 4) {
float n = noise(x * inc) * 70.0;
rect(x, 10 + n, 3, 20);
}
```

Experiment with the above sketch in the editor by changing the value for

`inc`

and observing how this changes the smoothness of the line of rectangles being drawn.

The next example illustrates how to generate a 2D texture using the `noise()`

function to ensure that it varies smoothly over small distances.

- Show Sketch

```
/** @peep sketchcode */
float inc = 0.04;
size(200, 200);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
float gray = noise(x*inc, y*inc) * 255;
stroke(gray);
point(x, y);
}
}
```

Experiment with the value of

`inc`

in this example to see how it affects the smoothness of the texture generated.

# Turbulence

Diverse textures can be created using `noise()`

in collaboration with `sin()`

. The following example deforms a regular sequence of bars created with `sin()`

into a texture reminiscent of those found in nature. The `power`

variable sets the amount the texture deforms from the lines and the density parameter `d`

sets the granularity of the texture.

- Show Sketch

```
/** @peep sketchcode */
float power = 6; // Turbulence power
float d = 16; // Turbulence density
size(200, 200);
noiseSeed(0);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
float turbulence = 0.0;
for (float i = d; i >= 1; i = i/2) {
turbulence += power * noise(x/d, y/d) * i/d;
}
float gray = abs(sin(x*0.05 + y*0.03 + turbulence)) * 255;
stroke(gray);
point(x, y);
}
}
```

Experiment with the values for

`power`

and`d`

in the above sketch to explore the space of possible textures that can be created.

# Using Randomness and Noise

The ability to generate, constrain and control random and noisy values can be powerful tools for any designer exploring the space of possible designs using code. However, too many random values, or too much noise, can detract from the design itself. Compare the following examples.

The first sketch shows how a regular grid can be distorted to add visual interest using the subtle application of `noise()`

. The result suggests that the design may be for a regular grid but drawn by an unsteady hand.

- Show Code

```
/** @peep sketch */
size(200, 200);
smooth();
float s = 4;
noFill();
for (int y = 20; y <= height-20; y += 10) {
float ny = y * 0.04;
beginShape();
for (int x = 20; x <= width-20; x++) {
float nx = x * 0.04;
vertex(x + s*(noise(nx,ny)-0.5), y + s*(noise(ny,nx)-0.5));
}
endShape();
}
for (int x = 20; x <= width-20; x += 10) {
float nx = x * 0.04;
beginShape();
for (int y = 20; y <= height-20; y++) {
float ny = y * 0.04;
vertex(x + s*(noise(nx,ny)-0.5), y + s*(noise(ny,nx)-0.5));
}
endShape();
}
```

The second sketch uses much the same code except that the visual effect is that the second grid is dominated by the noisy distortion field and loses much of the sense of the underlying grid design.

- Show Code

```
/** @peep sketch */
size(200, 200);
smooth();
float s = 40;
noFill();
for (int y = 20; y <= height-20; y += 10) {
float ny = y * 0.04;
beginShape();
for (int x = 20; x <= width-20; x++) {
float nx = x * 0.04;
vertex(x + s*(noise(nx,ny)-0.5), y + s*(noise(ny,nx)-0.5));
}
endShape();
}
for (int x = 20; x <= width-20; x += 10) {
float nx = x * 0.04;
beginShape();
for (int y = 20; y <= height-20; y++) {
float ny = y * 0.04;
vertex(x + s*(noise(nx,ny)-0.5), y + s*(noise(ny,nx)-0.5));
}
endShape();
}
```

The only difference between these two sketches is that the scale factor for the noise used to offset the grid in the second is `30`

while in the first it is `3`

. From the perspective of design, less (noise) can be much more.

# Exercises

- Use three variables assigned to random values to create a composition that is different every time the program is run.
- Create a composition using a for structure and
`random()`

to make a different dense composition every time the program is run. - Use
`noise()`

and`noiseSeed()`

to create the same irregular shape every time a program is run.

## Comments

size(200, 200); for (int y = 20; y <= height-20 ; y += 10) { for (int x = 20; x <= width-20; x += 10) { if ((x % 20) == 0|| (y % 20) == 0 ) { line(x-5, y+5, x+5, y-5); } else { line(x-5, y-5, x+5, y+5); } } }

/** @peep sketchcode **/

/** @peep sketchcode */ size(400, 400); background(0,255,0); fill(255,0,0); stroke(255,255,0); strokeWeight(8); ellipseMode(CENTER); for (int x = 50; x < width; x += 50) { for (int y = 50; y < height; y += 50) { float r = random(20, 40); ellipse(x, y, r, r); } }