Learning From Matt Pearson 5

Page 1

LFMP5

Learning From Matt Pearson

Based on Matt Pearson’s book Generative Art

A practical guide using Processing

2024 Henk Lamers


2 2


Introduction

The TX-2 operating area with Sketchpad in use. Sketchpad was a man-machine graphical communication system. The first Graphical User Interface (GUI). Designed by Ivan Edward Sutherland in 1960 at the California Institute Of Technology. The author is holding a light pen. The push buttons used to control specific drawing functions are on the box in front of the author. Part of the bank of toggle switches can be seen behind the author. The size and position of the part of the total picture seen on the display is obtained through the four black knobs just above the table.

Construction of the light pen. Drawing courtesy of Electronic Systems Laboratory. This drawing was made by conventional methods.

Please note that all code in this publication refers to Matt Pearson's original code in his publication: Generative Art. A practical guide using Processing. 3

The third dimension

In this chapter, Matt Pearson goes deeper into the noise function. So this main publication contains even more Perlin noise than the previous one. We also look at what happens when we start manipulating time and space by introducing the third dimension. The history of 3D modeling began with mathematical ideas underlying 3D visualisation. The basic ideas came from the founders of mathematical sciences. Like Euclid who invented geometry. Descartes who developed analytic geometry. And James Joseph Sylvester who invented matrix mathematics (which is now used to create any computer-generated image). When I worked at Philips Design, there were many product designers. Those were using 3D software. In 1998, I also started working three-dimensionally for the first time. It was a completely different world than in the flat plane. In the 3D environments, all designs are described in three dimensions. Width, height and depth. An example of a three-dimensional object is a pyramid. But in this chapter we are going to deal with 3D noise and cubes. Henk Lamers


4


Analysis

LFMP_05_01_00

A two-dimensional noise grid

The program uses two for next loops in which x and y are incremented by 1. Furthermore, a noise function is used that generates the alpha grayscale. There is something that, to me, was completely new. Matt Pearson used lines two pixels long instead of points. background (255); We start on a white background. float xstart = random (10); float xnoise = xstart; float ynoise = random (10); Interesting. xstart is a random number between 0 and 10 (but not including 10). Then xnoise is given the same value as xstart. And ynoise is again a digit between 0 and 10. for (int y = 0; y <= height; y += 1) { In the beginning y is 0. As long as y is less than or equal to the height (300 pixels) then y is incremented by 1 pixel. ynoise += 0.01; In the previous loop, y is always incremented by 0.01. xnoise = xstart; Resets xnoise at start of each row. for (int x = 0; x <= width; x += 1) { At first, x is 0. As long as x is less than or equal to the width (300 pixels) then x is incremented by 1 pixel. xnoise += 0.01; In the previous loop, x is also incremented by 0.01.

The output of the same code but now with the point function

int alph = int (noise (xnoise, ynoise) * 255); Why is alph multiplied by 255? If you remove multiplication you get a white area. Suppose you take half of 255. Then noise consists of light grey area without black. The multiplication makes that the total range between white and black is used to generate noise. line (x, y, x + 1, y + 1); This line of code generates minimal line segments two pixels long. Why? point (x, y); I replaced the line (x, y, x + 1, y + 1); with the above point function. The result is that noise does show up. But it produces an image composed of much lighter grey values. So the line function works for noise visually better than the point function. That in itself is a curious conclusion. With the line function, the grayscale values from 0 to 255 do show up well. So in Processing lines are better at alpha values than points.

5


6


Variations

A two dimensional noise grid

LFMP_05_01_01

size (1000, 1000); As usual, I changed the size from 300 x 300 to 1000 x 1000. ynoise += 0.1; The only thing I changed in the program was to replace ynoise += 0.01 with ynoise += 0.1. That gives a horizontal kind of noise. With a little imagination similar to the ripple of a water surface.

LFMP_05_01_02

xnoise += 0.8; In this variation, I reduced ynoise back to 0.01. But xnoise is now at 0.8. And that gives vertical lines. But strangely, there is some kind of repeating structure in them. Also, the lines form new thicker lines that are at an angle of about 280º. It‘s actually already a kind of three-dimensional structure.

LFMP_05_01_03

int alph = int (noise (xnoise / 2, ynoise) * 255); What happens if you divide xnoise by 2? First, it takes about four seconds for the display window to open. What you see then is not really a cloud situation. Surely there is some horizontal structure to it. By the way xnoise and ynoise are back to 0.01.

LFMP_05_01_04

int alph = int (noise (xnoise, ynoise / 10) * 255); Also in this setup, the display window opens only after four seconds. Here ynoise is divided by 10, giving a vague curtain-like vertical structure.

LFMP_05_01_05

xnoise += 0.8; Here xnoise is slightly increased to 0.8. I am trying to enhance the previous curtain effect here. It now looks more like a curtain you see on stage performances. int alph = int (noise (xnoise / 8, ynoise / 4) * 255); This structure has become more refined. But you only get this effect when you divide xnoise and ynoise by a number. In this case, 8 and 4. If you don't do that then you get a similar structure as in LFMP_05_01_02

LFMP_05_01_06

int alph = int (noise (xnoise * 8, ynoise / 32) * 255); The more you multiply xnoise and divide ynoise by a larger number the tighter the vertical lines become. The curtain comparison is gone.

LFMP_05_01_07

int alph = int (noise (xnoise / 8, ynoise * 5) * 255); Of course, you can also reverse it: divide xoise and multiply ynoise. This will make the curtain hang horizontally. Although this image seems less natural to me than the vertical version.

7


8


Variations

The noise grid, rewritten into neat function blocks

This program is not very different from the previous one. The only difference is that the visualisation part is now included in a function block. LFMP_05_02_00

rect (x, y, len, len); Instead of lines, rectangles are now used. This is the most significant change for the shape.

LFMP_05_02_01

for (int y = 0; y <= height; y += 4) { A step of 4 pixels on the y-axis is used to see the grid. This also applies to the x-axis. float len = 2 * noiseFactor; If len is 1 then there is no noise to be seen. The same is true, by the way, when len exceeds 50.

LFMP_05_02_02

for (int x = 0; x <= width + 10; x += 4) { On the right side of the display window a kind of starting point of the lines appears. I gave 10 pixels extra space to move this starting point sideways. rotate (noiseFactor * radians (360)); This is just a side trip where again we do use a line but now we also use rotation. stroke (0, 32); I found the lines far too heavy. So to begin with I reduced them from 150 to 32.

LFMP_05_02_03

for (int x = -100; x <= width + 100; x += 4) { If you change the length of the line it affects the filling of the display window. That means that x now has as start point —100 and as end point +100. With that, interruptions in the structure are fixed for now. rotate (noiseFactor * radians (48)); This one was 360. Let‘s see how this behaves at different angles. stroke (0); Removed all transparency. This will give more contrast.

LFMP_05_02_04

rotate (noiseFactor * radians (1440)); From 128 to 1440. The larger the number the more refined the details. stroke (0, 32); Applied slightly less contrast (in other words, more transparency).

LFMP_05_02_05

for (int y = -100; y <= height + 100; y += 32) { for (int x = -100; x <= width + 100; x += 32) { I reduced the grid spacing from 4 to 2. ynoise += 0.01; xnoise += 0.01; Reduced the values of ynoise and xnoise to 0.01. rotate (noiseFactor * radians (360)); Made rotate four times larger.

9


10


Variations

The noise grid, rewritten into neat function blocks

LFMP_05_02_06

for (int y = 0; y <= height; y += 2) { Decreased the space between the grid points to 2. ynoise += 0.1; xnoise += 0.1; Returned the values of ynoise and xnoise to 0.1. for (int x = 0; x <= width; x += 4) { When x += 4 then a vertical line of noise is displayed every 4 pixels. It looks like the image is stretched horizontally.

LFMP_05_02_07

for (int y = 0; y <= height; y += 8) { If x += 8 then a structure is displayed with small white squares. float len = 4 * noiseFactor; If you increase len to 4 then the noise becomes heavier. It also creates a rhythmic pattern of repeats. The pattern is approximately at a 340º angle and it is slightly visible.

LFMP_05_02_08

for (int x = 0; x <= width; x += 1) { Horizontally, pixels are now shifted minimally. float len = 8 * noiseFactor; The strange thing is that the horizontal lines now also generate a vertical wave pattern.

LFMP_05_02_09

ynoise += 0.5; xnoise += 0.5; Both ynoise and xnoise are now at 0.5. In itself not very special. float len = 12 * noiseFactor; The number 12 gave the most beautiful result for me. And that is also important. stroke (0); In these versions, we work with squares. But I haven‘t seen those so far. In this version they come out by turning on the stroke (the outline). I didn‘t specify a thickness so strokeWeight is default 1 pixel. But the largest square is 8 x 8 pixels. So y += 8 and x += 8

LFMP_05_02_10

for (int y = 0; y <= height; y += 16) { The squares doubled in size. ynoise += 8; The number 8 gave the best visual feedback for me. for (int x = 0; x <= width; x += 16) { For it to actually become squares, x += is also 16. xnoise += 0.5; I chose to leave xnoise += 0.5 as this gave the most interesting picture. float len = 32 * noiseFactor; If you specify len = 2 you get a black area with a grid of dots. So len is raised to 32 here to get the right image. By the way the elements look a lot like a font I once designed in the past. But this aside.

11


12


Variations

The noise grid, rewritten into neat function blocks

LFMP_05_02_10

rectMode (CENTER); The default mode is rectMode (CORNER), which interprets the first two parameters of rect () as the upper-left corner of the shape. rectMode (CENTER) interprets the first two parameters of rect () as the shape's center point. And that‘s what you want.

LFMP_05_02_11

In fact, this is the inverted version of LFMP_05_02_04. No other new things have been introduced.

LFMP_05_02_12

float len = 24 * noiseFactor; By enlarging len to 24 you get an optical distortion between the squares. Compare the effect to Victor Vasarely's op-art (optical art). He made this his life's work. For me, the effect was pure coincidence.

LFMP_05_02_13

ynoise += 0.1; Back to LFMP_05_02_04 for a moment. Making ynoise 0.1 and leaving xnoise at 0.5 again gives you a more vertically oriented pattern.

LFMP_05_02_14

xnoise += 0.1; The reverse is also possible. By making xnoise 0.1 and leaving ynoise at 0.5 you get a more horizontally oriented pattern.

LFMP_05_02_15

float len = 12 * noiseFactor; Making len 12 creates interesting ‘islands’ within the structure. xnoise and ynoise are equal (0.1).

13


14


Variations

The noise grid using even more rotation

The following programs go into even more detail about working with rotation. I had briefly approached it sideways in the previous programs. As a result, I was slightly ahead of the work to come. LFMP_05_03_00

void drawPoint(float x, float y, float noiseFactor) { A new interpretation of the draawPoint function by adding rotate. This is an image from the original program of Matt Pearson.

LFMP_05_03_01

rotate (noiseFactor * radians (360)); Rotation is used in the drawPoint function. The noiseFactor determines the angle at which the line is drawn. Strangely, when enlarged, I only see small horizontal and vertical lines. If I replace 360 with 10, 20, 30 and 40, I only get horizontal lines. At 45 a little noise starts to appear. At 90, horizontal and vertical lines appear. At 180, small islands also appear. But at 360, the texture looks like something made of fabric. line (0, 0, 2, 0); In retrospect, this should have been 20 but I was curious to see what 2 would yield.

LFMP_05_03_02

line (0, 0, 4, 0); Making the length of the line a little longer makes the structure a little clearer. But still it looks like the pattern consists only of horizontal, vertical or diagonal lines. It still looks quite strict.

LFMP_05_03_03

for (int y = 0; y <= height; y += 16) { This line is the basis for horizontal stroke of 16 pixels high. for (int x = 0; x <= width; x += 8) { This x = smaller than y because I want horizontal lanes. If I make x equal to y you get a grid of equal squares. If you make x greater than y you get a somewhat vertical layout. rotate (noiseFactor * radians (90)); It seems that the angle of the lines are all between 0 and 90 degrees. And a gradual change occurs horizontally between those angles. But the angle never becomes 0º or 90º because the rotation is also influenced by the noiseFactor.

LFMP_05_03_04

for (int y = 0; y <= height; y += 62) { I brought y to 62 here. That results in 16 horizontal lanes. With some extra residual space at the bottom. for (int x = 0; x <= width + 64; x += 4) { x = reduced to 4. So every four pixels a vertical line is placed at an angle. stroke (255, 96); Added quite a bit of transparency to see the overlap of lines better.

LFMP_05_03_05

15

for (int y = 0; y <= height; y += 126) { y raised to 126. I wanted to emphasise the horizontal bands more. Don‘t ask me why I want that. Because that's purely a matter of feeling. So a lot of the things you change is just a matter of feeling. And you can develop that feeling yourself. Just take a drawing or painting class. Or study graphic design. Or really any artistic profession. But I now have 8 horizontal strips with some residual space in between. That residual space was also created instinctively and through experimentation.


16


Variations

The noise grid using even more rotation

LFMP_05_03_05

for (int x = 0; x <= width + 64; x += 2) { x = now 2. I did that because then the top of the lines get a slightly fainter image. You can't actually see where the lines come from. It's a grey area. line (0, 0, 64, 64); line (0, 0, 32, 32); I added half an extra line. This came about purely by accident because I was trying to do something else. Afterwards, I thought the image became more interesting. So I left it that way. That‘s pretty much how my design process works.

LFMP_05_03_06

for (int y = 0; y <= height; y += 2) { for (int x = 0; x <= width + 64; x += 500) { The effect from the previous variation still slightly exaggerated and magnified. I want to point out that in the previous series of images I came up with totally different variations. So it also has to do with the passage of time.

LFMP_05_03_07

for (int y = -100; y <= height; y += 2) { for (int x = 0; x <= width + 64; x += 250) { A variation with four vertical lanes. Because when you can make two vertical lanes then you can also make four.

LFMP_05_03_08

for (int y = -100; y <= height; y += 2) { for (int x = 0; x <= width + 64; x += 125) { And so, of course, there are countless variations that can be made. These are eight vertical strips with flapping lines.

LFMP_05_03_09

for (int x = 0; x <= width + 64; x += 100) { A division into ten vertical lanes. rotate (noiseFactor * radians (16)); Increased the rotation slightly to get more structure in the vertical orbits. Again, this is a matter of feeling. But I think I find the previous version more surprising.

LFMP_05_03_10

for (int y = -100; y <= height; y += 16) { At that point I decided it had to end and looked for a slightly more chaotic version. For that, y raised to 16. ynoise += 0.45; ynoise is given a value of 0.45. for (int x = -30; x <= width + 64; x += 32) { You want the structure to continue on all sides. So -30 is a reasonable distance. xnoise += 0.45; To get a more chaotic image, I raised xnoise to 0.45. This gives a fairly chaotic image. But again, not too chaotic. rotate (noiseFactor * radians (64)); It is really necessary to raise rotate a little. If you set this to 1 or 2 you will only see vertical lines. So 64 is a nice number. line (0, 0, 8, 256); Because you also want a considerable length in the lines, they are now 256 pixels long. If you set 256 to 0, you will get short lines displayed at an angle in a grid.

17


18


Variations

The noise grid using even more rotation

LFMP_05_03_11

strokeWeight (4); The thickness of the lines is very decisive for the texture. A line thickness of 4 pixels was sufficient for me. line (0, 0, 0, 256); Most importantly, a line is drawn only in the y-direction. This gives a very light structure. With a slight distortion in the overall image.

LFMP_05_03_12

ynoise += 0.02; xnoise += 0.02; Increased both ynoise and xnoise a bit. stroke (255, 64); Increased the transparency as well. This gives you a little more contrast in the image. strokeWeight (3); Increased the line thickness to 3 pixels.

LFMP_05_03_13

rotate (noiseFactor * radians (360)); Raised the rotation considerably. for (int y = -300; y <= height + 300; y += 16) { You want the structure to continue at the bottom of the display window. So an extra 300 pixels is reasonable. stroke (255, 128); Made the lines slightly less transparent. This makes the structure a little clearer.

LFMP_05_03_14

rotate (noiseFactor * radians (270)); The rotation reduced to 270. stroke (255, 160); Made the stroke less transparent. strokeWeight (6); The thickness of the lines doubled. line (0, 0, 0, 96); And made the line itself slightly shorter.

LFMP_05_03_15

rotate (noiseFactor * radians (90)); Time for some more clarity. The lines are now angled from 0 to 90º. This angle is also influenced by the noiseFactor. stroke (255); A clear white stroke. strokeWeight (8); Increased the thickness of the line to 8 pixels. strokeCap (PROJECT); I want the ends of each line segment to be rock-solid straight. The default is round. But what is the difference between SQUARE and PROJECT? I suspect that SQUARE truncates the line segment when it reaches the length you specify in the line function. PROJECT resets half the thickness of the line as a rectangle on the front and back of a line.

19


20


Variations

The noise grid using even more rotation

LFMP_05_03_15

line (0, 0, 0, 48); Made the length of the line slightly shorter. This provides a clear tight structure.

LFMP_05_03_16

stroke (255, 128); Here I have reintroduced some transparency after all. strokeWeight (12); Four pixels extra line thickness. line (0, 0, 0, 128); And a line length of 128. And then again, this is the last variant of this version. I'm pretty sure there are many more variations to create with this program. But for now I'll stop here.

21


22


Variations

2D Perlin noise as little fluffy clouds

I went a little deeper into the fluffy clouds. This is because I thought there was more to the fluffy clouds than I superficially thought. LFMP_05_04_01

In fact, this is the original program as found in the publication. I have changed very little about it. Except for the naming of the variables. But you won‘t see that in the output. for (int y = 0; y <= height; y += 16) { y = raised to 16 here, thus better expressing the grid. for (int x = 0; x <= width; x += 16) { What applies to y also applies to x. Raised to 16. float edgeSize = noiseFactor * 35; The variable edgeSize is a bit unclear to me. If you set it to 1 you get a black area. At 2 some lighter spots already become clear. At 35 it forms a light plane with dark spots. float grey = 150 + (noiseFactor * 120); The variable edgeSize is a bit unclear to me. When you set it to 1 you get a black area. At 2 some lighter spots already become clear. At 35 it forms a light plane with dark spots. float alph = 150 + (noiseFactor * 120); The variable alph is the alpha channel. The transparency. If you set this to 0 you still get a spot pattern. It seems that edgeSize is the most important variable. ellipse (0, 0, edgeSize / 2, edgeSize); In the original program, the height of edgeSize was divided by 2. I divided the width of edgeSize by two.

LFMP_05_04_02

for (int y = 0; y <= height; y += 32) { for (int x = 0; x <= width; x += 32) { Both x and y raised to 32. float edgeSize = noiseFactor * 70; The variable edgeSize doubled to 70. ellipse (0, 0, edgeSize, edgeSize); Undoing the division by 2 of edgeSize. This produces a fairly interesting but also decorative image.

LFMP_05_04_03

for (int y = 0; y <= height; y += 16) { The variable y halved so that the circles overlap. This creates vertical lines made up of circles. rotate (noiseFactor * radians (256)); The noiseFactor almost halved. But since we are talking about rotation this makes little sense since we are using circles the effect of it is not visible. It would be different when using squares. float edgeSize = noiseFactor * 32; EdgeSize halved. So the circles also become smaller. float grey = 128 + (noiseFactor * 120); This makes the gray slightly darker than in the previous version.

23


24


Variations

2D Perlin noise as little fluffy clouds

LFMP_05_04_03

float alph = 128 + (noiseFactor * 120); The circles are now about 50% transparent.

LFMP_05_04_04

float edgeSize = noiseFactor * 64; The variable edgeSize doubled. This means that the shapes become twice as large as in the previous version. rect (0, 0, edgeSize, edgeSize); Because I wanted to know if rotation actually occurs, I substituted the ellipses for squares. And so there is indeed rotation.

LFMP_05_04_05

rotate (noiseFactor * radians (128)); The rotation halved. float edgeSize = noiseFactor * 32; The variable edgeSize also halved. noFill (); In this version, I only work with outlines. strokeWeight (2); A line thickness of two pixels. At one pixel you get jaggies. And the effect I want to see becomes less clear. stroke (grey, alph); I do want to keep the grayscale and transparency.

LFMP_05_04_06

for (int y = 0; y <= height; y += 16) { for (int x = 0; x <= width + 32; x += 16) { Both x and y halved. This brings the squares closer together. And therefore the effect also increases.

LFMP_05_04_07

rotate (noiseFactor * radians (8)); Rotation has been halved. It is now minimal. float edgeSize = noiseFactor * 18; The size of the squares is also almost halved. float grey = 160 + (noiseFactor * 160); float alph = 160 + (noiseFactor * 160); The noiseFactor has been increased for both y and x. That means lighter squares and less transparency. noStroke (); We no longer use an outline.

LFMP_05_04_08

25

ellipse (0, 0, edgeSize, edgeSize); A minor modification. Replaced squares with circles.


26


Variations

2D Perlin noise as little fluffy clouds

LFMP_05_04_09

for (int y = 0; y <= height + 32; y += 24) { The y value increased. for (int x = 0; x <= width + 32; x += 8) { The value of x halved. This creates horizontal lines of squares. Strangely, the rotation is hardly visible. float grey = 160 + (noiseFactor * 128); Darkened the gray slightly. float alph = 160 + (noiseFactor * 96); Transparency increased slightly too. rectMode (CENTER); If all is well, all squares rotate from their centers.

LFMP_05_04_10

for (int y = 0; y <= height + 32; y += 18) { Reduced the y variable slightly. rotate (noiseFactor * radians (192)); The rotation increased. float edgeSize = noiseFactor * 8; The variable edgeSize halved. float alph = 160 + (noiseFactor * 32); Boosted transparency to nearly a third. rect (0, 0, edgeSize * 8, edgeSize); The variable edgesize actually draws elongated vertices lines. But they are also partially covered by each other. This produces an interesting movement.

LFMP_05_04_11

for (int x = -100; x <= width + 32; x += 18) { To get everything within a grid of squares, x is now the same as y. rotate (noiseFactor * radians (360)); Rotation over 360 degrees. float grey = 160 + (noiseFactor * 96); float alph = 160 + (noiseFactor * 96); Gray value and transparency are of equal value. arc (0, 0, 16, 16, edgeSize / 512, edgeSize); Draws an arc. But the full rotation becomes 360 degrees only in a few cases. Then again, this is the latest version. A very meaningful session for me.

27


28


Variations

2D Noise from a 3D perspective

The section of this last chapter goes deeper into the 3D aspects of Processing. In the first version, I changed quite a bit. I did not like the rectangular shape disappearing in depth. However, this one reflects the 3D effect well. LFMP_05_05_01

size (1000, 1000, P3D); First change is that I got an error message: ‘The field PConstants.OPENGL is deprecated.’ So I used P3D from here on. spotLight (255, 255, 255, width / 2, height / 2, 800, 0, 0, -1, PI, 0.5); I have inserted a spotlight. Which gives me more control over the exposure. I may need the exposure at a later stage. for (int y = 100; y <= height - 100; y += 32) { for (int x = 100; x <= width - 100; x += 32) { For both y and x, I made the start point 100 and the end point height and width – 100. y and x position every 32 pixels grid locations. And that leads to a nice square. translate (x, 1000 - y, - y / 32); The position of x remains x. The position of y is transliterated 1000 pixels down. And then y is subtracted from it. - y / 32 required some attention because I didn't want the plane to be in depth. I wanted the plane to be upright. float boxSize = noiseFactor * 40; The variable boxSize replaces sphereSize because I no longer work with spheres. 40 Seemed to be the right size. Not too big and not too small. The cubes then just don‘t touch each other. float grey = 256 + (noiseFactor * 128); 256 Is the lightest I could get the gray. float alph = 128 + (noiseFactor * 64); I still hesitated whether to take out the transaprancy. But then the image becomes very flat. box (boxSize); And indeed sphere replaced by box.

LFMP_05_05_02

for (int y = 100; y <= height - 100; y += 16) { By giving y a value of 16 you create vertical paths. float boxSize = noiseFactor * 22; Making the boxSize 22 keeps all the boxes nicely spaced apart.

29


30


Variations

2D Noise from a 3D perspective

LFMP_05_05_03

for (int y = 100; y <= height - 100; y += 48) { for (int x = 100; x <= width - 100; x += 48) { Both y and x are given a value of 48. float boxSize = noiseFactor * 48; The boxSize has been increased to 48. stroke (grey); The variable alph is of little use in this setup. It makes the picture more unclear. strokeWeight (2); Set the line thickness to 2. To avoid jaggies.

LFMP_05_05_04

for (int y = 100; y <= height - 100; y += 32) { for (int x = 100; x <= width - 100; x += 32) { Both y and x are given a value of 32. float boxSize = noiseFactor * 48; I have tried different sizes. But 48 seems to give the best results.

LFMP_05_05_05

for (int y = 100; y <= height - 100; y += 24) { for (int x = 100; x <= width - 100; x += 24) { Both y and x are given a value of 24. rotateZ (alph); Just used alpha to rotate the cubes in the z-axis.

31


32


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