Learning From Matt Pearson 1

Page 1

LFMP1 Learning From Matt Pearson

Based on Matt Pearson’s book Generative Art
A practical guide using Processing
2023 Henk Lamers

A programming language isn’t a barrier, it’s a shortcut.

Let me begin with a bit of history. In 2009 I started learning how to program with Processing. I gave myself ten years for accomplishing it. In retrospect, I thought they were chaotic years. With many ups and downs. Much of incomprehensible new stuff. And a lot of code that worked differently than I suspected. Probably my learning period had not been structured enough. On top of that, I had to do it alone. I had no help from friends or acquaintances. I did courses, workshops and learnt a lot from books and the internet.

As I write this, it is 2022. The time has come to take a new step. For me, it is now about the essentials. What are we talking about when we think about programming? What exactly does programming mean? I felt it had become time to find out step by step through research by observing, analysing, asking myself why and also possibly some rethinking.

It seemed like a good idea to take a publication that could serve as a guide for my research. Frederik Vanhoutte pointed me to Matt Pearson’s publication: ‘generative art, a practical guide using processing’. In 2011, I had bought a copy of this publication. I decided to purchase the pdf version. Because electronic publications are more convenient to look something up and taking notes is also easier.

What I’m going to do is try to fillet all the programmes that Matt Pearson describes. So that you can find out in an analytical way exactly what a program or a program line does. What happens if you change it a little bit. And what happens if you change a lot? That seems instructive for myself. But maybe a little less for others.

What I would like to show is how I have experienced using the programs. That includes describing mistakes I have made. Or that I misinterpreted or named things wrong. But I consider making mistakes to be part of programming. Coincidence is also one of those. But I am not consciously looking for it.

What I describe in these publications is not an easy-to-read and exciting story. Essential is the code written by Matt Pearson. So in order to understand my work it is also essential to buy his publication. Otherwise, my story cannot be followed easily. It is lines from Matt Pearson’s code that I have interpreted and changed to finally arrive at a different result. Form is ultimately what you see. Programming is, for me, equal of that. Both are important. You can’t have one without the other. The bottom line is that you also need a lot of visual insight to make variations.

Every program has an analysis phase to begin with. In which I try to find out what the essence of the programme is and how it works. This is followed by a number of variation phases in which I change the program step by step. I especially look for variations that produce a different image than the images generated by the original program. And don‘t get me wrong. It is certainly not my intention to improve or correct Matt Pearson‘s programmes (if I could do that at all).

Henk Lamers

Introduction 3
4

generative system in 24 lines of code.

A

The programme is divided into two blocks: setup and the drawPoint function

LFMP_01_01_00

All this code does is iterate through a grid using two loops. Then, a function call draws a circle at each grid point and displaces it in 3D space using a mathematical variance.

Matt Pearson, page xxii

float xstart = random (10); The variable xstart is an arbitrary floating point number between 0 and 10. xstart is an arbitrary starting point on the x-axis. But whether I enter 0 or 1000 here. I see no change in the output. This might be the initialisation of xstart.

float ynoise = random (10); The variable ynoise is also an arbitrary floating point number between 0 and 10. ynoise is an arbitrary amount of noise in the y-direction. Whether I enter 0 or 1000 I see no change in the output. I just assume it’s the initialisation of ynoise.

translate (width / 2, height / 2, 0); The translate function positions everything in the centre of the display window. ‘Everything’ are the ellipses at the x, y and z directions.

for (float y = -(height / 8); y <= (height / 8); y += 3) { I reduced the width and height from 2000 to 1500 pixels because the image didn’t fit on my screen. That then becomes 1500 : 8 = 187.5. Boils down to: for (float y = –187.5; y less than or equal to 187.5); y + 3. So y = –187.5 as long as y is less than or equal to height 187.5. Then y is incremented by 3 pixels.

ynoise += 0.02; ynoise is (a random number out of 10) + 0.02

float xnoise = xstart; The initialisation of the variable xnoise. This is equal to xstart. xstart is a random number out of 10, which in turn is equal to xnoise.

for (float x = -(width / 8); x <= (width / 9); x += 3) { In fact, this x-loop is the same as the y-loop. So: for (float x = –187.5); Just as long as x is less than or equal to width (1500 / 9) Divided by nine? That’s 166.666. No idea why this isn’t 8. And then x is incremented by 3 pixels.

xnoise += 0.02; xnoise (which was equal to xstart) is raised by 0.02.

drawPoint (x, y, noise (xnoise, ynoise)); Here the program goes to the drawPoint function. That has three variables x, y, and noiseFactor. x and y are the coordinates. noiseFactor is the amount of noise (I think, not sure about that (yet)).

pushMatrix ();

The pushMatrix () function saves the current coordinate system to the stack. translate (x * noiseFactor * 4, y * noiseFactor * 4, -y); NoiseFactor is determined by xnoise and ynoise. When I suppose xnoise is 1 and ynoise is also 1. Then they are both 1.02 during the first call of the function. This then implies that: x * 1.02 * 4 = 4.08 and y * 1.02 * 4 = 4.08, – y

float edgeSize = noiseFactor * 26; edgeSize = the noiseFactor 1.02 * 26 = 26.52

ellipse (0, 0, edgeSize, edgeSize); An ellipse is placed at: 0, 0, with a width of 26.52 and a height of 26.52

popMatrix ();

Restores the prior coordinate system. And then we enter the for next loops again until all conditions are met.

Analysis
5
6

Variations

A generative system in 24 lines of code.

You cannot omit xstart and ynoise

LFMP_01_01_01

size (1500, 1500, P3D);

I will use the size 1000 x 1000 pixels for all programmes to come from now on.

background (0);

I often use a dark background when creating graphic images. In this program, it makes the grid stand out better as a shape.

stroke (0, 50);

I commented out the stroke function. Because of the dark background, it is now redundant as you can hardly see it.

noStroke ();

Disables drawing the outline. Because I don‘t want outlines at the moment.

fill (255, 96);

A small adjustment to transparency. You sometimes need transparency to achieve more depth in images.

float xstart = random (10);

The first variable xstart is an arbitrary floating point number between 0 and 10. This is the initialisation of xstart.

float ynoise = random (10);

To be sure, I changed the number 10 to 10000. But this makes no difference in the output. So I think xstart and ynoise are variables that need to be initialised. You cannot omit both variables because then you get the error message: ynoise cannot be resolved to a variable.

translate (width / 2, height / 2, 0);

Specifies an amount to displace objects within the display window. In this case, the translate function positions everything in the centre of the display. Both in the x, y and z direction. It makes little sense to change the width and height because then the image disappears behind the edges of the display window. Perhaps it makes sense to change something in the z direction. 100 Works reasonably well within the display window. Although there must be something somewhere in the program that determines the size of the graph.

for (float y = -(height / 8); y <= (height / 8); y += 3) { A for next loop that will determine the y coordinates. That then becomes 1000 : 8 = 125. That comes down to: for (float y = –125; y less than or equal to 125); y + 3. So y = –125 as long as y is less than or equal to height 125. And during that moment, y is incremented by 3 pixels. When you double 8, the grid field becomes twice as high. If you double += 3 that doubles the distances between the elements in height. The moment you change 3 to 12 you get horizontal lines.

ynoise += 0.02; ynoise is (a random number between 0 and 10) + 0.02. ynoise in my variation is now very low: 0.00002. In this, the grid becomes even more visible. It seems to become a kind of wall or screen.

float xnoise = xstart; The initialisation of the variable xnoise. This is equal to xstart. xstart is a random number out of 10, which in turn is equal to xnoise.

7
8

Variations

A generative system in 24 lines of code.

for (float x = -(width / 8); x <= (width / 9); x += 3) { This is the for next loop that will determine the x-coordinates. In fact, this is the same loop with pretty much the same variables as the y loop. for x = –125 just as long as x is less than or equal to width (1000 / 9)? Divided by nine? That's 111.111. But maybe there is a deeper meaning to it which I don’t get at the moment. I've changed it to (1000 / 8). And then x is incremented by 3 pixels.

xnoise += 0.02; xnoise (which was equal to xstart) is raised by 0.02. But in this version, xnoise is lowered just like ynoise to 0.00002. There is virtually no xnoise or ynoise.

drawPoint (x, y, noise (xnoise, ynoise)); The programme moves to the drawPoint function.

void DrawPoint (float x, float y, float noiseFactor) { This is the function that constructs the image. It has three variables x, y, and noiseFactor. x and y are the coordinates, noiseFactor is the amount of noise.

pushMatrix ();

The pushMatrix () function saves the current coordinate system to the stack.

translate (x * noiseFactor * 4, y * noiseFactor * 4, -y); NoiseFactor is determined by xnoise and ynoise. Suppose xnoise is 1 and ynoise is also 1. Then they are both 1.02 during the first call of the function. This then implies that: x * 1.02 * 4 = 4.08 and y * 1.02 * 4 = 4.08, – y. I replaced 4 with 7, because I suspect this has something to do with the magnification factor. –y is now 0. And then the grid comes into view nicely.

float edgeSize = noiseFactor * 26;

edgeSize = the noiseFactor 1.02 * 26 = 26.52. But I replaced that with: float edgeSize = noiseFactor * 104. In this format, I actually want all noise out of the image because I want to see the basic shape of the image.

popMatrix ();

Restores the prior coordinate system. And then we enter the for next loops of setup again until all conditions are met. Finally, the object is build in the display window. The bottom line is that the grid is now visible and formed by overlapping ellipses. All the chaos is gone. But I will try to bring that back in the upcoming variations.

9
10

A generative system in 24 lines of code. LFMP_01_01_02

Which variables affect the controlled form of chaos? At first glance, that seems to be xnoise and ynoise. Hence their names

ynoise += 0.00002; This produces very little chaos in the y-direction.

xnoise += 0.00002; Also, xnoise produces little else in the form of chaos. When I change both xnoise and ynoise to 0.0002 (just one 0 less) you can see that the square gets smaller. However, the grid does not become more chaotic.

ynoise += 0.002; When I change ynoise to 0.002 the grid deforms. A horizontal dent appears at the top.

ynoise += 0.02; This makes it even more mysterious. Accumulations of grid points are now taking place at various places. I reset ynoise to 0.00002.

xnoise += 0.002; Again, this only results in an enlargement of the grid.

xnoise += 0.02; And you see the same thing happening here as with ynoise at 0.02. Accumulation of pixel grids. A wave pattern.

ynoise += 0.2; But what happens if I also bring ynoise to 0.2? That produces a fairly chaotic image. I'm going to try to get that under control.

xnoise += 0.002; This makes the grid almost disappear. The majority of the grid consists of horizontal lines. Some are wavy.

ynoise += 0.002; This produces a grid with a nice quiet wavy pattern. So xnoise and ynoise are responsible for the amount of chaos within the grid. But what happens inside the drawPoint function?

float edgeSize = noiseFactor * 64; The variable edgeSize has been reduced from 104 to 64. It seems to fill the image a bit better. But what determines the size of the surface?

translate (x * noiseFactor * 8, y * noiseFactor * 8, + y); I suspect that this translate function determines the size of the surface. The edgeSize variable is only responsible for the size of an ellipse. When I return to the original program, I see that in the drawPoint translate function that I replaced –y with 0. It is now clear that xnoise and ynoise are responsible for the chaos. I have now enlarged them to 0.02. As in the original program. I think it's now a matter of fine-tuning.

Variations
11
12

Variations

A generative system in 24 lines of code.

Avoid the chaotic knot

LFMP_01_01_03 for (float y = -(height / 2); y <= (height / 2); y += 2.5) { When you divide everything by 2 in the y version of the for next loop, you get a kind of curtain-like object. A curtain that appears vertically in the display window.

for (float x = -(width / 2); x <= (width / 2); x += 2.5) { The same goes for the horizontal version. But then that looks more like a flag. Although black and white flags do not occur. Apart from the flag of the Islamic Emirate of Afghanistan (Taliban), which was introduced in 1997.

ynoise += 0.016; Meanwhile, I made ynoise smaller.

xnoise += 0.0016; The key is to keep one of the two (xnoise or ynoise) small. Otherwise it becomes a chaotic knot.

ellipse (96, 96, edgeSize, edgeSize); You get an interesting effect when you repeat the ellipse function in drawPoint. In this case, I chose a randomly different starting position of the ellipse.

13
14

Variations

A generative system in 24 lines of code.

Sometimes optical illusions are just fine

LFMP_01_01_04

rect (0, 0, edgeSize, edgeSize); I quite simply replaced the ellipses with rects.

rect (32, 32, edgeSize, edgeSize); And repeated that with another series of rects but they start at another location.

rect (64, 64, edgeSize, edgeSize); Added a third square. They now all have different starting positions. This makes it look like they are all on separate layers. But I think this is an optical illusion caused by the transparency.

15
16

Variations

A generative system in 24 lines of code.

This might be a bit over the top

LFMP_01_01_05 for (int i = 0; i <= 64; i += 16) { After making several versions with two, three and four fictitious layers, I have now introduced a for next loop for the layers.

rotate (radians (225)); Rotation was used here. This is because I felt the image should be able to be at an angle. This makes the image more interesting.

ellipse (i, i, edgeSize * 2, edgeSize * 160); edgeSize * 160 presents exactly the right image I was looking for. There is something unpredictable in it but it is not chaotic. Also, the image deviates completely from what I started with. This is not a necessity but it was the point where I ended with making variations in this first publication.

17
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.