// ------------------------------------------------------------ // Class for an individual hair. // ------------------------------------------------------------ class Hair { // MEMBER VARIABLES // The location of the base of the hair (or at least the angles from the centre of the sphere) // is fixed at the creation of the hair object instance. // Use different methods to choose angles phi and theta, since using // random(TWO_PI) for both tends to make the distribution of hairs clumpy. float phi; float theta; // The length of the hair is fixed at the creation of the hair object instance. float hairLength; // CONSTRUCTORS Hair() { this(random(TWO_PI), asin(random(-1, 1)), 1); } Hair(float phi, float theta, float hairLength) { this.phi = phi; this.theta = theta; this.hairLength = hairLength; } // METHODS // The draw method for the hair. void draw(float baseRadius, int clockMillis) { // Calculate the position of the base of the hair on the sphere float rct = baseRadius * cos(theta); float x = rct * cos(phi); float y = rct * sin(phi); float z = baseRadius * sin(theta); // Determine some offset angle(s) for the tip of the hair float offTheta = ( noise( clockMillis * 0.0005, sin(phi) ) - 0.5 ) * PI; float offPhi = ( noise( clockMillis * 0.0007, sin(z) * 0.01) - 0.5 ) * PI; float tipTheta = theta + offTheta; float tipPhi = phi + offPhi; // Calculate the position of the tip of the hair (which will be the hairLength from the base of the hair) float hct = hairLength * cos(tipTheta); float x1 = x + hct * cos(tipPhi); float y1 = y + hct * sin(tipPhi); float z1 = z + hairLength * sin(tipTheta); beginShape(LINES); // The base of the hair is black and opaque stroke(0); vertex(x, y, z); // The tip of the hair is lighter and transparent stroke(200, 150); vertex(x1, y1, z1); endShape(); } }