Here’s one approach you can take.
import java.util.Iterator;
import java.lang.Math;
/**
* Esfera
* by David Pena.
*
* Distribucion aleatoria uniforme sobre la superficie de una esfera.
*/
int cuantos = 40000;
ArrayList<Pelo> lista;
float radio = 400;
float rx = 0;
float ry =0;
void setup() {
//size(1024, 1000, P3D);
fullScreen(P3D, 1);
reset();
}
void reset() {
radio = height/3.5;
lista = new ArrayList<Pelo>();
for (int i = 0; i < cuantos; i++) {
Pelo p = new Pelo();
lista.add(p);
}
noiseDetail(3);
}
void draw() {
background(0);
radio = 400;
//print( "x: " + mouseX + " y: " + mouseY, mouseX, mouseY );
if (!mousePressed) {
//velocity?
float rxp = (mouseX-(width/2)) * 0.005;
float ryp = (mouseY-(height/2)) * 0.005;
rx = rx*0.9 + rxp*0.1;
ry = ry*0.9 + ryp*0.1;
}
translate(width/2, height/2);
rotateY(rx);
rotateX(ry);
fill(0);
noStroke();
sphere(radio);
Iterator itr = lista.iterator();
ArrayList<Pelo> removeThese = new ArrayList<Pelo>();
while (itr.hasNext()) {
Pelo p = (Pelo) itr.next();
if (p.dead) {
removeThese.add(p);
} else {
p.dibujar();
grow(p);
}
}
for (Pelo p : removeThese) {
lista.remove(p);
}
}
void keyPressed() {
if (key == ' ') {
reset();
}
}
void grow(Pelo p) {
if(!p.near) return;
++p.age;
if (p.dying) {
if (p.largo > .84) {
p.largo -= p.growthRate * .01;
} else {
p.largo = 0;
p.c = color(0, 0, 0);
p.dead = true;
}
} else {
if (p.largo < p.maxHeight) {
p.largo += p.growthRate * .05;
p.thickness += p.growthRate * .025;
}
if ((p.type == 1) && (p.age >= 250)) {
p.dying = true;
p.c = color(79, 34, 9);
} else if ((p.type == 2) && (p.age >= 300)) {
p.dying = true;
p.c = color(135, 206, 235);
} else if ((p.type == 3) && (p.age >= 160)) {
p.dying = true;
p.c = color(135, 206, 235);
} else if ((p.type == 4) && (p.age >= 160)) {
p.dying = true;
p.c = color(139, 69, 19);
} else if ((p.type == 5) && (p.age >= 140)) {
p.dying = true;
p.c = color(139, 69, 19);
} else if ((p.type == 7) && (p.age >= 1200)) {
p.dying = true;
p.c = color(10, 10, 10);
}
}
}
//should calculate the position on the sphere corresponding to your mouse position and then find the pelos within a certain radius of that point
/*
ArrayList<Pelo> findPelos() {
float realX = mouseX - (width/2);
float realY = mouseY - (height/2);
double realZ = Math.sqrt(Math.pow(radio, 2) + Math.pow(realX, 2) + Math.pow(realY, 2));
return new ArrayList<Pelo>();
}
*/
class Pelo
{
float z = random(-radio, radio);
float phi = random(TWO_PI);
float largo = random(.85, .90);
float theta = asin(z/radio);
float rand = random (0.00, 1.01);
int type;
int age = 0;
boolean dying = false;
boolean dead = false;
color c;
float thickness;
float maxHeight;
float growthRate;
boolean near;
Pelo() { // what's wrong with a constructor here - nothing.
z = random(-radio, radio);
phi = random(TWO_PI);
largo = random(.85, .90);
theta = asin(z/radio);
rand = random (0.00, 1.02);
age = 0;
dying = false;
dead = false;
if (rand <= .75) { //tree
type = 1;
c = color(0, 100, 0);
thickness = 1.5;
maxHeight = 1.1;
growthRate = .1;
} else if (rand <= .90) { //blue tree
type = 2;
c = color(0, 0, 100);
thickness = 1.2;
maxHeight = 1.1;
growthRate = .1;
} else if (rand <= .95) { //red flower
type = 3;
c = color(240, 0, 0);
thickness = 1;
maxHeight = .01;
growthRate = .07;
} else if (rand <= .99) { //yellow flower
type = 4;
c = color(240, 240, 0);
thickness = .8;
maxHeight = .05;
growthRate = .08;
} else if (rand <= 1.00) { //orange up shoot
type = 5;
c = color(255, 69, 0);
thickness = .9;
maxHeight = 1.4;
growthRate = 3;
} else if (rand <= 1.005) { //rock
type = 6;
c = color(128, 128, 128);
thickness = 1;
maxHeight = 0;
growthRate = 0;
} else { //purple tree
type = 7;
c = color(50, 0, 50);
thickness = 5;
maxHeight = 1.3;
growthRate = .007;
}
}
void dibujar() {
float off = (noise(millis() * 0.0005, sin(phi))-0.5) * .3;
float offb = (noise(millis() * 0.0007, sin(z) * 0.01)-0.5) * .3;
float thetaff = theta+off;
float phff = phi+offb;
float x = radio * cos(theta) * cos(phi);
float y = radio * cos(theta) * sin(phi);
float z = radio * sin(theta);
float xo = radio * cos(thetaff) * cos(phff);
float yo = radio * cos(thetaff) * sin(phff);
float zo = radio * sin(thetaff);
float xb = xo * largo;
float yb = yo * largo;
float zb = zo * largo;
strokeWeight(thickness);
beginShape(LINES);
stroke(c);
vertex(x, y, z);
near = dist(mouseX, mouseY, screenX(x,y,z), screenY(x,y,z)) < 60;
stroke(c, 50);
vertex(xb, yb, zb);
endShape();
}
}
Here’s how this works: When you draw the line for a hair, you work out a position in space, (x,y,z), where the base of the hair is. Using screenX()
and screenY()
, it is possible to know where on the 2D screen that 3D point would be drawn. You can then check to see if that point is near the mouse pointer (mouseX, mouseY).
This check is happening for each hair. It’s this line:
near = dist(mouseX, mouseY, screenX(x,y,z), screenY(x,y,z)) < 60;
So each hair now knows if it is near the mouse. Knowing this, each hair can decide not to grow if it is not near the mouse:
void grow(Pelo p) {
if(!p.near) return; // Not near? No growing for you!
The downside to this is that it also grows the hairs near a spot on the opposite side of the ball. If this is not a problem for you, great!
You are, of course, free to use this near-to-mouse detecting abilities however you like. Maybe try drawing only the hairs near the mouse?
Oh, also I fixed how you should be doing your reset()
function.