NoC (W01): Generative Visuals with Transformations and Objects
Generative Pattern with Transformations
p5js Link: https://editor.p5js.org/AndyHyprillion/sketches/1rGYeJvfe
Idea
The first idea that came to mind is the aero engine. I’m a great fan of airplanes and can deeply appreciate these giant machines’ beauty. In addition, the fan blade of the aero engine consists of various shapes and curves which is a great chance to review the knowledge of p5js. Moreover, since it’s rotational symmetry, the translate() and rotate() functions become essential here. This may let me have a further understanding of these functions.
Design
Since the aero engine’s beauty significantly comes from its extraordinary aerodynamic design, I decided to make an electronic copy to show my respect to one of the largest aero engines that currently exist which is the GE9X from General Electric.
One of the biggest difficulties in drawing the engine is the fan blade. The fan blade of this engine is an irregular curve(in order to get better aerodynamic performance). Also, the golden spiral line at the center of the engine is also a big challenge to me.
Drawing
My idea of drawing these blades is using the for loop since they are rotational symmetry. So after using translate() to shift the origin point to the center of the canvas, I started drawing the shape of one blade.
I use curveVertex() to draw the curve. However, the shape of the blade is much more complicated than I thought.
The first problem that I’ve encountered is the sharp corners at the bottom of the blade. Since it’s an acute angle that the curve function can’t handle it properly. In this case, I add 2 more extra anchor points at the bottom part of the blade and finally make it extremely thin and sharp:
code for the shape:
beginShape(); curveVertex(0, -275); curveVertex(0, -275); curveVertex(10, -200); curveVertex(-10, -100); curveVertex(0, 20); curveVertex(15, -100); curveVertex(80, -180); curveVertex(130, -270); curveVertex(130, -270); endShape();
Then I add a silver curve on the left side of the blade to stress the color of the material of the blade. I rotate the silver curve and change the color to transparent black to simulate the shadow of the blade. It finally looks like this:
When the shape of a blade has almost reached my expectation, I use the for loop to copy them rotationally. Another problem has occurred which is that there’s always one blade at the very top while my goal is to make every blade overlap the one next to it:
Suddenly, I came out with a great idea: make the silver part and the shadow be drawn separately after drawing the blade body. Then they won’t be overlapped by the last drawn blade:
Although the outer shape is not very neat, we can use the outer circle to cover them:
Then comes the golden spiral line at the center. Since the math problem is not my field, I cited the code from https://www.php.cn/js-tutorial-403577.html.
for (var n = 0; n < 9; n++) { var m = n <= 1 ? 1 : Fibonacci[n - 1] + Fibonacci[n - 2]; Fibonacci.push(m); arc(0, 0, m * 2, m * 2, 0, PI / 2); rotate(PI / 2); translate(-Fibonacci[n - 1], 0); }
Afterward, I add the 2nd blade under the big blades to fill the emptiness between the blades. The color in the 2nd blade is according to the RPM. The higher the rpm is, the redder the color will be. Also, the green value of the background color is set as random and the red value is also according to the RPM.
After these decorations, it looks quite similar to the engine:
Animation & Interaction
Although the animation is not mandatory, I still want to make the engine move. The movement of the engine is simply rotating all the components using rotate() function. There’s another thing that needs to be mentioned is that in the GE9X aero engine, the 2nd fan blades rotate a contrary direction from the 1st fan blade and I’ve reconstructed this feature.
In order to make the user better see the static shape of the engine and enjoy the animation and the visual illusion of rotation, I designed a slide bar to let the user can adjust the RPM(revolutions per minute) by themselves. I use constrain() to limit the movement of the slide bar and the user can only adjust the RPM in a fixed range. I also use floor() to calculate the number of RPM which can let the RPM becomes an integer. Also, I use map() to shift the maximum RPM from 1908 to 1000.
And here is the final work:
https://editor.p5js.org/AndyHyprillion/full/1rGYeJvfe
Generative Visuals with Objects
p5js Link: https://editor.p5js.org/AndyHyprillion/sketches/1rGYeJvfe
Idea
My initial idea is to make a stellar system and add some random planets to it. However, the degree of freedom of the stellar system is quite low and I want to control the gravity by myself. So I change my idea into making various bouncing balls and the user can attract the ball using the mouse. When the friction index is 0, there will be no friction. The balls will do the orbit movement following the center of the mouse. When adding more friction and gravity, it can simulate some physical phenomenon on the earth like bouncing onto the floor. In all, it’s more like a physics simulator.
Features
In this project, I mainly use OOP to make the balls. They have random sizes and random initial speeds.
class Marble { constructor(gravity, friction) { this.diameter = random(30, 100); this.x = random(this.diameter / 2, width - this.diameter / 2); this.y = random(this.diameter / 2, height - this.diameter / 2); this.sinY = random(-1, 1); this.speedX = random(-10, 10); this.speedY = random(-10, 10); this.friction = friction; this.gravity = gravity; this.count = 0; this.tX = 0; this.tY = 0; }
I gave 4 behavior to it. The first one is to update themselves. They will move in the canvas so they have to update their position every frame. In addition, since the whole system has the friction index and gravity, they have to update their speed according to these variables. The second behavior is changing its color according to the x-position of the ball. The object at different positions will have different colors. The third behavior is bouncing on the wall. When the bouncing mode is on, the ball can bounce on the wall. The last behavior is following the mouse. When the mouse is pressed, the ball will be attracted by the mouse like the planet following a stellar.
The movement function is using two variables to achieve, the first one is speed and the second one is the translate position. The speed will be updated by the gravity and friction index and added to the translate value.
The gravity function is continuing adding a certain value to the speed. The friction is using the speed value to multiply a certain index.
update() { this.friction = friction; this.tX += this.speedX; this.sinY += 0.1; this.tY += this.speedY; if (this.speedX >= 0) { this.speedX *= this.friction; } else { this.speedX *= this.friction; } if (this.speedY >= 0) { this.speedY *= this.friction; } else { this.speedY *= this.friction; }
attract() { //mouse attract the marble if (mouseIsPressed & (mouseY > 50)) { push(); noCursor(); fill(0); circle(mouseX, mouseY, 10); pop(); this.speedX -= (this.tX + this.x - mouseX) / 1000; this.speedY -= (this.tY + this.y - mouseY) / 1000; } if (groundGravity == true) { this.speedY += this.gravity; } }
The bouncing function is using an if statement to determine whether the ball is out of the canvas. If it’s out of the canvas, set the speed to the negative value of the original value.
turn() { if (this.tX >= width - this.x - this.diameter / 2) { if (this.speedX >= 0) { this.speedX = -this.speedX; } this.count++; } if (this.tX <= -this.x + this.diameter / 2) { if (this.speedX <= 0) { this.speedX = -this.speedX; } this.count++; } if (this.tY >= height - this.y - this.diameter / 2) { if (this.speedY <= 2) { this.speedY = 0; } if (this.speedY >= 0) { this.speedY = -this.speedY; } if (groundGravity == true) { this.speedY *= this.friction; } this.count++; } if (this.tY <= -this.y + this.diameter / 2) { if (this.speedY <= 0) { this.speedY = -this.speedY; } this.count++; } }
After everything is set up, we can use some interesting presets to simulate the physical world.
Preset 01
Bounce: off
Gravity: off
Friction Index: 0
Continuing press the mouse button
In this preset, you can see the balls like the planet and the orbit movement around the stellar(your mouse).
Preset 02
Bounce: on
Gravity: on
Friction Index: around 0.5
Do not press the mouse button
In this preset, you can see the balls fall and bounce on the floor.
Preset 03
Bounce: on
Gravity: off
Friction Index: 0
Do not press the mouse button
In this preset, you can see the balls bounce between borders.
Experience it on your own!
https://editor.p5js.org/AndyHyprillion/full/CgoBflFQZ
However, a problem that currently exists is that when the friction is set to 0.3 or fewer, the ball will continuing bounce on the floor which I don’t know the reason why.
I’d greatly appreciate it if you know what may cause the problem and comment at the bottom of this blog 😉
Reflections
Through this mini project, I get a great chance to review the functions in p5js. In my project, I’ve utilized many functions including:
- Transformations: push(), pop(), translate(), rotate()
- Math functions: random(), constrain(), floor()
Moreover, for those functions that I haven’t used in my project, I went to the reference page and checked their descriptions.
In addition, I get familiar with the OOP again. Now I can write the OOP-object without seeing the reference page and have a further understanding of OOP’s advantages.
However, I’ve encountered many problems with this project. Some of them are solved while some of them are not. Hope I can fully understand and get the ability to solve them by the end of this semester.