Inspiration and Concept
I wanted my self-portrait to highlight two main things: my glasses and my big curly hair. There were also a few artistic elements I identified early on that I wanted to incorporate. Growing up, the first thing I learned to draw was flowers. Since then, I have incorporated flowers, specifically sunflowers, into much of my artwork. Hence, I planned to have flowers as a recurrent motif in my self-portrait. Another thing I wanted to stand out in my self-portrait is good color coordination. A specific self-portrait I found that resonated with all of these ideas and captured the essence of what I wanted to create is by Erika Norma, which can be found in this Medium article she wrote.
Process and Implementation
I started by creating a rough sketch of the outline. The majority of the outline is composed of curves and smooth lines. To ensure that my shapes looked smooth, I relied on curveVertex() to specify vertices (points) along which a curve would be drawn. I used curves to draw the face and the hair. To make the self-portrait look more animated, I decided to add a wave movement animation to the hair. I was able to create the desired effect by adding curves with vertices whose x and y coordinates are defined by sinusoidal functions (this example was a very helpful demonstration of simulating sine waves in p5.js and I derived inspiration from it as I animated the hair). I played around for some time with different angle increments, amplitude, and shifts until I was happy with the result. Although it is not perfect and is probably not the cleanest way to implement this effect, I would say this portion of the code for drawing and animating the hair is the one I am most proud of as it perfectly demonstrates how mathematics can be directly used to generate art. It also took me the most amount of time to get right so I was very satisfied once all the components fell into place.
function hair() { push(); beginShape(); fill(72, 60, 50); stroke(72, 60, 50); // right side for (let i = 0; i < 20; i++) { // calculate x and y positions dynamically using the counter i and sinusoidal functions to create wave movement // used helpful demonstration of using sinusoidal functions for waves https://p5js.org/examples/math-sine-wave.html let x = 350 + i * 20; let y = i * 15 + sin(hairAngle + (i * PI) / 2) * 10 + 90; // add vertex to the curve curveVertex(x, y); } // left side for (let i = 20; i > 0; i--) { let x = 310 - i * 20 ; let y = i * 13 - sin(hairAngle + (i * PI) / 2) * 10 + 50; curveVertex(x, y); } endShape(CLOSE); // close the shape to connect the last and first points // bottom of the hair noFill(); strokeWeight(200); // use large stroke to cover the bottom edge of the conjoined left and right hair shape beginShape(); for (let i = 0; i < 30; i++) { let x = i * 40 + cos(hairAngle + (i * PI) / 2) * 10 - 100; let y = 400 + sin(hairAngle + (i * PI) / 2) * 10; curveVertex(x, y); } endShape(); pop(); }
One obstacle I had with the hair was creating one closed-shaped curve that would be the moving hair. When I attempted to join the two sides of the hair by closing the shape formed by them, I realized that the bottom would be automatically closed with a straight line. I resorted to a rather gimmicky way of resolving this by adding a bottom moving curve with a large stroke that would cover that straight line. If I were to redo this, I would try and dynamically create all sides of the hair using one shape and be more careful with calculating the vertices.
I also used curves and cosine functions to animate the movement of the earrings using the same principles.
The implementation of the flowers was a modification of this reference. The flowers were used to create the dress and are a part of the interactive background that is displayed when the mouse is clicked. The flower petals are implemented using ellipses. To create the rotation animation, all flower components rotate by an angle that is dynamically changing each frame. For the sake of generalization, I implemented the following drawFlower()
function to allow for the creation of all the different colors, shapes, and types of flowers (including sunflowers!) that I needed.
function drawFlower( r, g, b, dx, dy, petalX, petalY, petalW, petalH, centerR, rotationAngle, isSunFlower = false ) { // helpful guide: https://editor.p5js.org/xinxin/sketches/0j7vGT3u6 push(); noStroke(); ellipseMode(CENTER); translate(dx, dy); rotate(radians(rotationAngle)); fill(r, g, b); for (let i = 0; i < 20; i++) { // flower petals ellipse(petalX, petalY, petalW, petalH); rotate(PI / 10); } // fill center with a darker color if sunflower if (isSunFlower) { fill(r - 11, g - 22, b); } ellipse(0, 0, centerR, centerR); pop(); }
To add a small interactive component, the background of the sunflower would display a falling sunflower animation once the mouse is clicked. The original background and the animated background alternate with every click. In the setup function, a number of sunflower object literals with x, y, and speed attributes are defined. All values are randomized from a certain range (e.g. the y position is randomized between -1000 px and -50 to ensure that each flower is initially displayed above the canvas). Each flower is then added to a global array,fallingFlowers
.
The animation itself was done by incrementing each flower’s y position by its speed attribute in every frame, ensuring its position is reset again above the canvas at a random position once it hits the bottom.
Reflections and ideas for future work or improvements
I am overall satisfied with the outcome. It was close to how I envisioned it would look like. I especially loved the aesthetics of the moving hair and earrings. I also enjoyed playing with colors – especially daring to choose yellow and purple for the glasses – and the process of making creative decisions, such as adding in lips last minute. As I mentioned, however, I would have loved to find a cleaner way to implement the hair shape and animation without having to resort to adding in an extra curve shape. In my next projects, I aim to delve deeper into creating more complex curves and exploiting mathematical relations to create interesting animations.