đŸ’»

Computational Media: Self Portrait

Computational Media: Self Portrait

Concept

Sketch Link

I started out with a question: what are we, humans? To make a self portrait, you must choose a few traits to showcase. Are we our physical bodies - as in, do I literally draw myself for this assignment? Or should I define myself through my taste and passions? Are we the way we treat others? Are we the way we’re perceived by others? I ended up going with a personality trait (hyper focus) and a passion (dancing), with a goal to understand the math behind p5.

This self-portrait brings attention to my favourite aspect of the human experience - bringing all my energy to an interaction and one of my favourite releases - dancing. To be more explicit, when user hovers over head, all the "contents" of my brain immediately move in that direction. That’s what happens when the outside world makes contact. The moving shoulders resemble dancing. The color combination is one of my favourites.

Interactive Head

How to place points in a circular shape

First, we’re calling a custom function called drawGridPoints and filling up an array, points, with an object called single_point.

let points = [];
let maxRadius = 126;
let spacing = 20;
let centerHeadX, centerHeadY;

function setup() {
	createCanvas(600, 600);
	centerHeadX = width / 2;  // 300
  centerHeadY = height / 3.2; // 187.5
	drawGridPoints();
}

function draw() {
	background(60, 21, 78);
  stroke(123, 182, 97); // Coloring points green
  
  for (let single_point of points) {
    strokeWeight(10);
    // Using x and y values in the object single_point as arguments for the built in function point.
    point(single_point.x, single_point.y);
    // print(`Point coordinates: x = ${single_point.x}, y = ${single_point.y}`);
  }
}

If you console.log the array points, you’ll see it consists of 121 single_point vector objects with coordinates x, y, z. We’re storing the originalX coordinate and originalY, so we can simulate movement for that same point later.

The x and y of those vectors in each object single_point will be used as arguments for the built-in function point, however many times there are objects inside the points array.

image

How do we decide where to place points and therefore simulate that circular shape? I’d like to make a note that I used an AI coding assistant to help me work out the math for this, as well as couple of examples creating circular shapes with points, like zapra and NanoDano. Programming.Guide also has an interesting resource on how to generate random points within a circle uniformly. Other resources to figure out syntax include StackOverflow and this p5 tutorial on how to repeat with loops.

image
function drawGridPoints() {
  for (let x = -maxRadius; x <= maxRadius; x += spacing) {
    for (let y = -maxRadius; y <= maxRadius; y += spacing) {
      // Is point within circle? If yes, 
      if (x*x + y*y <= maxRadius*maxRadius) {
        let single_point = createVector(centerHeadX + x, centerHeadY + y)

        // Storing positions that we'll need later
        single_point.originalX = single_point.x;
        single_point.originalY = single_point.y;
        
        points.push(single_point);
      }
    }
  }
};

Interaction on mouseMoved

Now that we’ve placed our points, let’s figure out how to move them. Intially I wanted to make the points change in different directions and become all ‘scrambled’, but eventually settled here due to time constraint.

New values for coordinates are calculated for each point but function is also firing constantly for the same point to give appearance of movement.

image
// How much the points move in response to the mouse
let movementRate = 5;

function mouseMoved(){
  for (let single_point of points){
    if (
      mouseX > points[0].x - spacing*3 && 
      mouseX < points[points.length - 1].x + spacing*3
    ){ 
      
      let distance = dist(mouseX, mouseY, single_point.originalX,  single_point.originalY);
      // Dist calculates the distance between two points in a straight line.
      // For these canvas dimensions, it will be larger than 1.
      
      let dx = mouseX - single_point.originalX;
      // Distance from mouseX to point's X original position 
        // -> gives direction of movement because we're calculating this value both for X and Y
      
      single_point.x =  single_point.originalX + (dx * movementRate / distance);
      // The x of the vector object will now be replaced by: 
            // originalX value
            // +
   
            // dx -> difference between X of mouse and single_point
            // X
            // movementRate (5) divided by distance (different for all points) -> will be a tiny value.
      
      // Same process for Y coordinate:
      let dy = mouseY - single_point.originalY;
      single_point.y =  single_point.originalY + (dy * movementRate / distance); 
      
      // console.log(`Distance: ${distance}`);
    }
  } 
}

Constrained interaction with mouse areas

function mouseMoved(){
  for (let single_point of points){
    if (
      mouseX > points[0].x - spacing*3 && 
      mouseX < points[points.length - 1].x + spacing*3
    ){ 
	    // Code to run 
    }
  } 
}
image

Shoulders

// Shoulder variables
let shoulderLeftY = 450; // height*0.75; // Height is uninitialized here
let shoulderRightY = 360; // height*0.60;
let speedSlower1 = 4; // Tiny values for coordinates to appear to dislocate in a certain direction
let speedSlower2 = 5;

function draw() { 
  // SHOULDERS
  fill(123, 182, 97);
    
  quad(width*0.15, height*0.85, width/4, shoulderLeftY, width*(3/4), shoulderRightY, width*0.85, height*0.85);
  
  shoulderLeftY -= speedSlower1;
  shoulderRightY += speedSlower2;
  
  // Reverse direction at a certain point
  if (shoulderLeftY <= 350 || shoulderLeftY >= 450) (
    speedSlower1 = -speedSlower1
  )
  if (shoulderRightY >= 460 || shoulderRightY <= 360) (
    speedSlower2 = -speedSlower2
  )
}

Random Element

I struggled thinking of a random element to add to my sketch, so instead I added it as part of my debug efforts.

// Getting info for 1 random point:
let randomPoint = random(points);
console.log(`Random Point - x: ${randomPoint.x}, y: ${randomPoint.y}, dx: ${randomPoint.dx}, dy: ${randomPoint.dy}, distance: ${randomPoint.distance}`);

Questions

  • What’s the difference in scope between the variables placed in the set up function and outside?
  • Is describe something necessary for accessibility?

Next Steps for this sketch

  • Head triggers music being played when interacted with
  • Web cam and body tracking can command sketch