// ------------------------------------------------------------ // 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(0, 0, 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() { draw(0); } void draw(float baseOffset){ // Calculate the position of the base of the hair on the sphere float r = outerOscillator.value() + baseOffset; float rct = r * cos(theta); float x = rct * cos(phi); float y = rct * sin(phi); float z = r * sin(theta); // Determine some offset angle(s) for the end of the hair float off = ( noise( millis() * 0.0005, sin(phi) ) - 0.5 ) * PI; float offb = ( noise( millis() * 0.0007, sin(z) * 0.01) - 0.5 ) * PI; float thetaff = theta + off; float phff = phi + offb; // Calculate the position of the end of the hair (which will be the hairLength from the base of the hair) float x1 = x + hairLength * cos(thetaff) * cos(phff); float y1 = y + hairLength * cos(thetaff) * sin(phff); float z1 = z + hairLength * sin(thetaff); beginShape(LINES); stroke(0); // No stroke when locating to the base of the hair vertex(x, y, z); // The base of the hair stroke(200, 150); vertex(x1, y1, z1); // The tip of the hair endShape(); } }