Context/ Inspiration:
The primary reason I was drawn toward Mathematics, ultimately toward Computer Science, was symmetry — whether that be the pattern of infinity or the Kanizsa triangle. The habit persists; irrespective of the discipline I am currently involved in, I tend to experiment with said patterns. That’s why, for this assignment, I have chosen to implement Bézier curves as I create a self-portrait using pre-defined functions of p5.js.
Project Idea:
A Bézier curve is used to produce smooth curves with the help of two ‘anchor points’ (which determine the initial and the final points of the curve) and two ‘control/ handle points’ (which determine the pull of the curve). In other words, it can be understood as “a linear interpolation of a linear interpolation” of a curve. I have incorporated the idea of the Bézier curve as a background of my self-portrait, which I consider to be the highlight of my project too.
I started with a canvas of “900×900” pixels, and my first focus was on the creation of Bézier curves. The project is divided into numerous functions; one of which is ‘draw_background’ which produces Bézier curves. For the starting point, I initially used the random() function to generate unique values (almost!). However, I changed it to mouseX and mouseY so that the starting point of each curve is determined by the position of the cursor. Even if the cursor remains static, the initial point is set to be (0,0). Similarly, for the remaining points (final anchor point and control points), I combined noise() function to create Perlin noise, which essentially extends to infinite n-dimensional space unlike random() function, and randomly generated numbers with some algebraic manipulations. This YouTube video introduced me to the noise() function, while for more technical information, I relied on the reference page of p5.js. Thus, a series of Bézier curves are generated. The value of ‘counter’ is increased after each frame to produce a unique curve. In addition, the function includes two additional functionalities: (1) after 10,000 frames or (2) when the user clicks on the screen, whichever occurs first will reset the background to its predetermined stage.
In addition to the default setup() and draw() functions, the actual self-portrait is categorized into twelve additional functions that are included in the draw() function in the order of positioning. Each of these functions utilizes the fundamental idea of primitive shapes taught in the lecture.
After implementing the background function, I moved to draw the face of the character. To pick the desired RGB value, I used a color-picker extension, fired up Google to open a real person’s image and copied the RGB value that I found appropriate; thus, I had the color of the character’s skin. Then, I used arc() function to create the upper and the lower section of the head while feeding the required parameters into the function. Similarly, the draw_eyes() function was implemented using the arc() and the circle() modules to create the outline of the eyes and pupil respectively, while draw_ears() required the use of arc() and ellipse() functions. This way, the remaining functions utilized a combination of existing functions like line(), rectangle(), arc() and ellipse() to draw an outline of different parts of the character’s body.
Another unique function was draw_hair() function, which required the use of beginShape() and endShape() functionality. Using this combination, I was able to plot a number of vertices using curveVertex(), thus a curve was created and filled with RGB values to replicate the structure of human hair. The function itself is positioned such that it appears on the bottom of the draw_hat() function.
This way, I kept on coding and the project is programmed to represent my self-portrait.
Reflection:
Overall, I am satisfied with my project. But, there are a few things I could have definitely restructured to come up with an efficient final product:
- The canvas design is determined by two variables — w and h — set at the very beginning of the program: the target was to create a dynamic canvas size. However, with a number of shapes included, small tweaks (for instance: width/2 + some number) had to be implemented to position those shapes. Thus, changing the value of w and h create a chaotic design.
- While implementing beginShape() and endShape() functions, the value of vertices had to be hard-coded, which felt quite limiting. Thus, proper pre-planning combined with object-oriented and reading from local file methods could have improved the project.
In short, it was an interesting project — the project itself felt like a unique amalgamation of ‘generative’ art (in some ways) and elementary art. It was a fresh experience for me, and I look forward to completing such creative projects in the days to come.
That said, what could be more interesting than integrating ‘randomness’ in fixed lines of computer code?