Remake of dave's helix slinkies.
| // by Jo | |
| // original by beesandbombs: https://twitter.com/beesandbombs/status/1162005331993649152 | |
| void setup() { | |
| size(800, 600, P3D); | |
| smooth(8); | |
| ortho(); | |
| noFill(); | |
| } | |
| float t, tt, c, ia = atan(sqrt(.5)), r = 95; | |
| boolean dir, //toggles the direction of the slinkies | |
| sha; //toggles shadow | |
| void draw() { | |
| t = mouseX*1.0/width; | |
| c = mouseY*1.0/height; | |
| background(#F2BDEB); | |
| translate(width/2, height/2); | |
| strokeWeight(4.5); | |
| int sec; //second movement | |
| if (2*t<1) { | |
| tt = ease(2*t, 1.8); | |
| sec = 0; | |
| } else { | |
| tt = ease(2*t-1, 1.8); | |
| sec = 1; | |
| } | |
| dir = false; | |
| for (int i = -1; i <= 2; i++) { | |
| sha = false; | |
| helixSlinky(tt, 2*r*(2*i-sec)); | |
| sha = true; | |
| helixSlinky(tt, 2*r*(2*i-sec)); | |
| } | |
| dir = true; | |
| for (int i = -2; i <= 1; i++) { | |
| sha = false; | |
| helixSlinky(tt, 2*r*(2*i+1+sec)); | |
| sha = true; | |
| helixSlinky(tt, 2*r*(2*i+1+sec)); | |
| } | |
| smiley(); | |
| } | |
| void helixSlinky(float pct, float off) { | |
| int n = 200; | |
| for (int j = 0; j < 8; j++) { | |
| PVector curr = new PVector(); //current (spine of helix slinky) | |
| PVector last = new PVector(0, 0); //last (spine of helix slinky) | |
| PVector v = new PVector(); //twisty helix part | |
| stroke(j%2==0?#6FE5D1:#84B2FD); | |
| if (sha) | |
| stroke(#EFB0E7); | |
| beginShape(); | |
| for (int i = 0; i <= n; i++) { | |
| float th = PI*i/n*map(pct, 0, 1, 1, -1); | |
| curr.set(0, -r*PI/n).rotate(th).add(last); | |
| last.set(curr); | |
| v.set(r*0.34, -r*PI*i/n*0); //r*0.34 determines the radius of the cylindric helix thing | |
| v = rotY(v, QUARTER_PI*j-TAU*2.5*i/n); | |
| v.rotate(th).add(curr); | |
| vert(v.x+off-r, v.y, v.z); | |
| } | |
| endShape(); | |
| } | |
| } | |
| void vert(float x, float y, float z) { //every drawn point goes through this function | |
| PVector v = new PVector(x, y, z); | |
| if (dir) | |
| v = rotY(v, HALF_PI); //switches direction of traffic | |
| v = rotY(v, QUARTER_PI); //viewing angle | |
| if (sha) { | |
| v.x+=1.8*-v.y/PI; //shadow amount depending on height | |
| v.y=0; //shadow on the floor | |
| } | |
| v = rotX(v, -ia); //also viewing angle | |
| vertex(v.x, v.y, v.z); | |
| } | |
| PVector rotX(PVector v, float th) { | |
| return new PVector(v.x, v.y*cos(th)-v.z*sin(th), v.y*sin(th)+v.z*cos(th)); | |
| } | |
| PVector rotY(PVector v, float th) { //matrix rotation about y-axis | |
| return new PVector(v.x*cos(th)+v.z*sin(th), v.y, v.z*cos(th)-v.x*sin(th)); | |
| } | |
| float ease(float p, float g) { | |
| if (p < 0.5) | |
| return 0.5 * pow(2*p, g); | |
| else | |
| return 1 - 0.5 * pow(2*(1 - p), g); | |
| } | |
| void smiley() { | |
| sha = false; | |
| stroke(0); | |
| strokeWeight(2); | |
| int np = 20; | |
| float rr = 5; | |
| PVector p = new PVector(); | |
| beginShape(); | |
| for(int i=0;i<np;i++) { | |
| p.set(rr*cos(TAU*i/np)+rr*1.8, -2, rr*sin(TAU*i/np)+rr); | |
| p = rotY(p, QUARTER_PI); | |
| vert(p.x, p.y, p.z); | |
| } | |
| endShape(CLOSE); | |
| beginShape(); | |
| for(int i=0;i<np;i++) { | |
| p.set(rr*cos(TAU*i/np)-rr*1.8, -2, rr*sin(TAU*i/np)+rr); | |
| p = rotY(p, QUARTER_PI); | |
| vert(p.x, p.y, p.z); | |
| } | |
| endShape(CLOSE); | |
| beginShape(); | |
| for(int i=0;i<=np;i++) { | |
| p.set(2.5*rr*cos(PI*i/np), -2, -rr*1.5*sin(PI*i/np)-rr*1.4); | |
| p = rotY(p, QUARTER_PI); | |
| vert(p.x, p.y, p.z); | |
| } | |
| endShape(CLOSE); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment