Skip to content

Instantly share code, notes, and snippets.

@cwillmor
Created January 30, 2021 22:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cwillmor/30daddba73cca2a31c7136caadd95d33 to your computer and use it in GitHub Desktop.
Save cwillmor/30daddba73cca2a31c7136caadd95d33 to your computer and use it in GitHub Desktop.
unfold animation
// unfold animation https://twitter.com/cwillmore/status/1355644262835122176
// developed in processing 3.5.4
static final int FRAME_RATE = 30;
static final float ITER_DURATION = 2.0; // seconds
static final int TOTAL_FRAMES = (int)(FRAME_RATE * ITER_DURATION);
static final int WIDTH = 500;
static final int HEIGHT = 500;
static final boolean SAVE_FRAMES = false;
static final float eps = 0.00003;
import com.jogamp.opengl.GL;
import com.jogamp.opengl.GL2ES2;
PJOGL pgl;
GL2ES2 gl;
color[] colors;
void setup() {
frameRate(FRAME_RATE);
size(500, 500, P3D);
rectMode(CENTER);
fill(#ff0000);
noStroke();
colors = new color[] { #845ec2, #ff5e78, #f9f871 }; // https://colorhunt.co/palette/252741
}
float ease(float x) {
if (x < 0) {
return 0;
} else if (x < 1) {
return -(cos(PI * x) - 1) / 2;
} else {
return 1;
}
}
void enableBackfaceCulling() {
// https://forum.processing.org/two/discussion/25272/how-to-enable-backface-culling-in-p3d
pgl = (PJOGL) beginPGL();
gl = pgl.gl.getGL2ES2();
gl.glEnable(GL.GL_CULL_FACE);
gl.glCullFace(GL.GL_BACK);
}
// draw a triangular flap with fixed corners (0, 1, 0) and (0, -1, 0) and free corner rotating from (0, 0, 0) to (2, 0, 0) about the fold through +z space as s goes from 0 to 1.
// also draw the section of the center square under the flap, and the shadow on that section due to the flap.
void drawFlap(color outerColor, color innerColor, color shadowColor, float s) {
push();
translate(1, 0, 0);
// draw flap
push();
if (s == 0) {
translate(0, 0, 2 * eps); // avoid z-fighting
}
rotateY(PI * s);
// - outer face of flap
fill(outerColor);
normal(0, 0, 1);
triangle(0, 1, -1, 0, 0, -1);
// - inner face of flap
fill(innerColor);
normal(0, 0, -1);
triangle(-1, 0, 0, 1, 0, -1);
pop();
// draw inner square section under flap
push();
fill(innerColor);
normal(0, 0, 1);
triangle(0, 1, -1, 0, 0, -1);
pop();
// draw shadow under flap
if (s < 0.5) {
push();
fill(shadowColor);
translate(0, 0, 1 * eps);
normal(0, 0, 1);
triangle(0, 1, -cos(PI * s), 0, 0, -1);
pop();
}
pop();
}
void draw() {
float t = (float)(frameCount % TOTAL_FRAMES) / TOTAL_FRAMES;
float delta1 = 0.4; // time from flap A1 start to flap A2 start
float delta2 = 0.0; // time from flap A2 end to flap B1 start
float shadowFactor = 0.7;
int iter = (frameCount / TOTAL_FRAMES) % colors.length;
color outerColor = colors[iter];
color middleColor = colors[(iter + 1) % colors.length];
color middleShadowColor = lerpColor(#000000, middleColor, shadowFactor);
color innerColor = colors[(iter + 2) % colors.length];
color innerShadowColor = lerpColor(#000000, innerColor, shadowFactor);
background(255);
enableBackfaceCulling();
// set up camera, lights
translate(WIDTH/2, HEIGHT/2, 0);
scale(WIDTH/4);
scale(1.2);
translate(0, 0, -0.3); // nudge a bit so we don't get cut off at the bottom
rotateX(PI/4);
lights();
rotateZ(-5*PI/8);
//rotateZ(-t * PI/4);
rotateZ(iter * PI/4);
rotateZ(-(t + iter) * (PI/4 - 2 * PI/3)); // make it so big flap isn't unfolding in the same place every iter
scale(pow(sqrt(2), -t)); // square unfolds by sqrt(2) each iteration, scale to compensate
scale(1/sqrt(2)); // we got outer flaps now :(
float flapDuration = 1 - delta1 - delta2;
// draw middle flaps
for (int i = 0; i < 4; i++) {
float flapStart = -1 + i * delta1;
float s = ease((t - flapStart) / flapDuration);
push();
rotateZ(i * PI/2);
// draw flap
drawFlap(outerColor, middleColor, middleShadowColor, s);
pop();
}
// draw outer flaps
push();
translate(0, 0, 2 * eps);
for (int i = 0; i < 4; i++) {
float flapStart = i * delta1;
float s = ease((t - flapStart) / flapDuration);
if (s == 0) {
continue;
}
push();
scale(sqrt(2));
rotateZ(i * PI/2 + PI/4);
// draw flap
drawFlap(middleColor, innerColor, innerShadowColor, s);
pop();
}
pop();
// save frames
if (SAVE_FRAMES && frameCount < colors.length * TOTAL_FRAMES) {
saveFrame("fr#####.png");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment