Assignment 1: Self Portrait | Hasibur

For this assignment, we were asked to create a self-portrait using p5.js. I started by looking into the listed self-portraits and previous students work. I was heavily inspired by a few of them and later incorporated a few styles from their portraits. [1. https://editor.p5js.org/Sarthak-Malla/full/3NRqaQVKQ, 2. Koala portrait, 3. Assignment 1: Self-portrait]

I wanted to have a full-body portrait. However, I could not settle on one. Later, I came across this portrait online and decided to follow a similar structure. I initiated the process by sketching a rudimentary outline, focusing initially on the facial features. I used the bezier for the eye brows and the curveVertex for the hair. For the bezier shape, I used this tutorial. In the rest of the portrait, I just used the primitive shapes.

Each cell is a dynamic entity, its behavior governed by its position and the cursor’s proximity. The canvas isn’t just a static backdrop but a living part of the portrait, changing its hues and vibrancy in real-time. Each cell on the canvas pulsates with an oscillating brightness, creating a mesmerizing wave effect. This is not just a pre-programmed animation; the cells also react to the position of your mouse, creating an interactive dance of light and shadow.

function drawBackground() {
  for (let r = 0; r < rows; r++) {
    for (let c = 0; c < columns; c++) {
      let distance = dist(mouseX, mouseY, c * cellWidth, r * cellHeight);
      let offset = map(distance, 0, sqrt(sq(width) + sq(height)), 1, 0);

      let wave = (sin(time - c * r * 0.1) + 1) / 2;
      let brightness = map(wave, 0, 1, 100, 255) * offset;

      cells[r][c] = brightness;

      fill(brightness * 0.9, brightness * 0.7, brightness); 
      noStroke();
      rect(c * cellWidth, r * cellHeight, cellWidth, cellHeight);
    }
  }
}

The eyes follow your cursor, adding a layer of depth and engagement. The mouth opens and closes, reacting to the cursor’s vertical position, making the portrait not just seen but also felt.

function drawMouth() {
  noStroke();

  // calculate the openness of the mouth based on mouseY position
  let deltay = ((400 - mouseY) / 400) * 13 + 6;
 
  if(deltay <= 9.5) deltay=9.5;

  // outer mouth (lips)
  fill(255, 150, 122); // color for lips
  ellipse(200, 173, 27, deltay);

  // inner mouth (white part to represent teeth or inside of mouth)
  let innerMouthHeight = deltay - 2; 
  fill(255); // white color for the inner mouth
  if (innerMouthHeight > 8) {
    // show inner mouth only if it's significantly open
    ellipse(200, 173, 20, innerMouthHeight);

    // black line to split the white part (teeth or mouth separation)
    if (innerMouthHeight > 10) {
      fill(0); // black color for the separation
      let separationHeight = 4; // height of the separation line
      rect(200 - 10, 173 - separationHeight / 2, 20, separationHeight, 10); // centered black line
    }
    else {
      fill(0)
      let separationHeight = 1; // height of the separation line
      rect(200 - 10, 173 - separationHeight / 2, 20, separationHeight, 10); 
    }
  }
}

While working, I couldn’t figure out the nose style. Most portraits that I have seen use triangles or similar shapes. I found this portrait to have a very distinctive style, which I followed. Creating the hair shape took a lot of time for me. I am still not particularly happy with the hair. I wanted more realism for the hair shape.

In the future, I want to create a Lego character resembling my character and try to create a self-portrait based on the Lego character, which I believe would be easily achievable using the primitive shapes.

Leave a Reply