ango-Clock

Clock Tower

This week, I kept it simple. As the year begins and work pours in, I’ve started to perceive time more and more as a material substance. When I wake, the day feels empty, as if waiting to be inevitably filled by people, events, emotional and physical experiences. By the end, it feels heavy like a sponge, having absorbed all of these things. For this reason, I chose to continue exploring the Processing 3D and jBullet physics libraries to render time as tangible, interactive components in motion.

Process

Here’s an early sketch of how I imagined I would visualize text as interactive 3D assets to demonstrate the accumulation of time.

I imagined three towers of stacking elements, each representing the seconds, minutes, and hours of the day. In future iterations, I’m interested in creating different “heaps” of time, representing maybe the quantity of objects or experiences someone might accumulate over the course of a day, week or year.

Thoughts

– This is far from done :'( On a structural level however, I think the current implementation of my sketch articulates the concept well, but lacks the visual finesse that could make it more memorable and engaging. I’ve never felt more motivated to iterate endlessly on a sketch!!! What I’m content with is the basic code structure I managed to achieve which will let me do so. I also really enjoy the sense of tension and release as the numbers stack up and fall.

Once again, big thanks to Golan for helping my brainstorm “filthy hacks” for implementing 2D as 3D (though not accomplished in my *final* sketch), and for Aman Tiwari for getting me started on jBullet and the vector math and logic for physics simulations! <3 Never going back.

// Anna Gusman / Time Tower / 
//Utilizes source code from bRigid: 
// bRigid statement: "bRigid provides classes for an easier handling of jBullet in Processing. bRigid is thought as a kind of Processing port for the bullet physics simulation library written in C++. 
// This library allows the interaction of rigid bodies in 3D. Geometry/ Shapes are build with Processing PShape Class, for convinient display and export (c) 2013 Daniel Köhler, daniel@lab-eds.org"
// see: http://www.offramp-la.com/pile-city/
 
import javax.vecmath.Vector3f;
import peasy.*;
import bRigid.*;
 
BObject mesh1;
BObject mesh2;
BObject mesh3;
 
PeasyCam cam;
BPhysics physics;
 
float targetDistance = 600;
float camDist = 600;
 
ArrayList importedBodies;
ArrayList meshbois = new ArrayList();
ArrayList minuteMeshbois = new ArrayList();
ArrayList hourMeshbois = new ArrayList();
 
int numBuildings = 60;
 
Vector3f position = new Vector3f(10, 100, 10);
Vector3f positionMinutes = new Vector3f(400, 100, 10);
Vector3f positionHours = new Vector3f(800, 100, 10);
 
Vector3f dimension = new Vector3f(50, 50, 50); 
 
 
public void drawTimeArray(ArrayList arr, color col) {
  for (int i = 0; i &lt; arr.size(); i++) { BObject mesh = arr.get(i); Matrix4f mat = mesh.transform.getMatrix(new Matrix4f()); pushMatrix(); applyMatrix(mat.m00, mat.m01, mat.m02, mat.m03, mat.m10, mat.m11, mat.m12, mat.m13, mat.m20, mat.m21, mat.m22, mat.m23, mat.m30, mat.m31, mat.m32, mat.m33); //translate(pos.x, pos.y, pos.z); fill(col); if (i == (arr.size()-1)){ fill(255); } textSize(100); text(i, 0, 0, 0); noFill(); popMatrix(); mesh.display(); } } public void settings() { size(800, 720, P3D); } public void setup() { cam = new PeasyCam(this, targetDistance); cam.pan(100, 200); fill(250); textMode(SHAPE); //PFont mono; //mono = loadFont("andalemo.ttf"); //textFont(mono); pixelDensity(displayDensity()); // create a rigid physics engine with a bounding box Vector3f min = new Vector3f(-500, -600, -100); Vector3f max = new Vector3f(1000, 600, 100); //create new physics container physics = new BPhysics(min, max); physics.world.setGravity(new Vector3f(0, 200, 0)); //simulate without display, much faster physics.setStepSimulation(8); //file path of all objs to import } public void draw() { background(0); lights(); // update time arrays while (second() &gt; meshbois.size()) {
    noFill();
    noStroke();
    BObject mesh = new BBox(this, 1, position, dimension, true);
    setupBody(mesh);
    meshbois.add(mesh);
  }
 
  while (minute() &gt; minuteMeshbois.size()) {
    noFill();
    noStroke();
    BObject mesh = new BBox(this, 1, positionMinutes, dimension, true);
    setupBody(mesh);
    minuteMeshbois.add(mesh);
  }
 
  while (hour() &gt; hourMeshbois.size()) {
    noFill();
    noStroke();
    BObject mesh = new BBox(this, 1, positionHours, dimension, true);
    setupBody(mesh);
    hourMeshbois.add(mesh);
  }
 
  //for seconds
  print(meshbois.size());
  println(" "+second());
 
  drawTimeArray(meshbois, color(0, 10, 255));
 
 
  if (second() &lt; meshbois.size()) {
    for (int i = 0; i &lt; meshbois.size(); i++) {
      physics.removeBody(meshbois.get(i));
    }
    meshbois.clear();
  }
  //for minutes
  drawTimeArray(minuteMeshbois, color(255, 100, 20));
 
  if (minute() &lt; minuteMeshbois.size()) {
    for (int i = 0; i &lt; minuteMeshbois.size(); i++) {
      physics.removeBody(minuteMeshbois.get(i));
    }
    minuteMeshbois.clear();
  }
  //physics.update();
  //physics.display();
 
  //for hours
 
  drawTimeArray(hourMeshbois, color(255, 0, 0));
  if (hour() &lt; hourMeshbois.size()) {
    for (int i = 0; i &lt; hourMeshbois.size(); i++) {
      physics.removeBody(hourMeshbois.get(i));
    }
    hourMeshbois.clear();
  }
  //saveFrame();
  physics.update();
  //physics.display();
}
 
 
 
void setupBody(BObject mesh) {
  //add body to the physics container
  physics.addBody(mesh);
  //set tangentional friction, between 0-1
  mesh.rigidBody.setFriction(.995f);
  //set friction in normal direction, between 0-1
  mesh.rigidBody.setRestitution(.0000099f);
  //overall force damping, between 0-1
  mesh.rigidBody.setDamping(.98f, .98f);
}