// Processing code by Etienne JACOB // motion blur template by beesandbombs, explanation/article: https://bleuje.com/tutorial6/ // opensimplexnoise code (by Kurt Spencer) in another tab is necessary // --> code here : https://gist.github.com/Bleuje/fce86ef35b66c4a2b6a469b27163591e // See the license information at the end of this file. // View the rendered result at: https://bleuje.com/gifanimationsite/single/spherewave/ ////////////////////////////////////////////////////////////////////////////// // Start of template int[][] result; // pixel colors buffer for motion blur float t; // time global variable in [0,1[ float c; // other global variable for testing things, controlled by mouse //----------------------------------- // some generally useful functions... float c01(float x) { return constrain(x,0,1); } // ease in and out, [0,1] -> [0,1], with a parameter g: // https://patakk.tumblr.com/post/88602945835/heres-a-simple-function-you-can-use-for-easing 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); } // defines a map function variant to constrain or not in target interval (exists in openFrameworks) float map(float x, float a, float b, float c, float d, boolean constr) { return constr ? constrain(map(x,a,b,c,d),min(c,d),max(c,d)) : map(x,a,b,c,d); } // short one to map an x from [a,b] to [0,1] and constrain float mp01(float x, float a, float b) { return map(x,a,b,0,1,true); } // reversed pow that does some kind of ease out, [0,1] -> [0,1], with a parameter g float pow_(float p,float g) { return 1-pow(1-p,g); } //----------------------------------- void draw() { if (!recording) // test mode... { t = (mouseX*1.3/width)%1; c = mouseY*1.0/height; if (mousePressed) println(c); draw_(); } else // render mode... { for (int i=0; i=1) return 1; return pow(2, -7 * x) * sin((x * 10 - 0.75) * c4) + 1; } class Particle { PVector pos1,pos2; float delay1; PVector orientation; float seed = random(10,1000); Particle(int i) { // setting (x,y,z) position on black sphere (position at start and end) // using special formulas to get evenly distributed positions float phi = PI * (3. - sqrt(5.)); float theta = phi*i; float y = map(i,0,n-1,1,-1); float radius = sqrt(1 - y * y); y *= blackSphereRadius; float x = cos(theta) * blackSphereRadius * radius; float z = sin(theta) * blackSphereRadius * radius; pos1 = new PVector(x,y,z); // orientation of rotation effect orientation = orienterField(pos1); float radius2 = blackSphereRadius+DR*pow(random(0.75)+0.25,1.4); pos2 = pos1.copy().normalize().mult(radius2); // position when particle left the black sphere // but so far without random displacement float pw = 2.0; float rd = random(1); float rd1 = mp01(rd,0,0.5); float rd2 = mp01(rd,0.5,1); float delay0 = 0.5*pow_(rd1,pw)+0.5*pow(rd2,pw); // delay for particles returning on the sphere with this offset, the above code defines a desired random distribution delay1 = delay0*0.45; } float sphereSize(float p) { float noiseRadius = 6.0; float ns = map((float)noise.eval(seed+noiseRadius*cos(TWO_PI*p),noiseRadius*sin(TWO_PI*p)),-1,1,0,1); return pow(ns,3.0)*2+0.5; } // noisy displacement PVector displacement(float p) { float noiseRadius = 1.4; float amplitude = 8; float noiseSpaceX = noiseRadius*cos(TWO_PI*p); float noiseSpaceY = noiseRadius*sin(TWO_PI*p); float dx = amplitude*(float)noise.eval(2*seed+noiseSpaceX,noiseSpaceY); float dy = amplitude*(float)noise.eval(3*seed+noiseSpaceX,noiseSpaceY); float dz = amplitude*(float)noise.eval(4*seed+noiseSpaceX,noiseSpaceY); // (looping noise but not a necessary property because the displacement is 0 at the begining) return new PVector(dx,dy,dz); } void show(float p) // p will just be the time t in [0,1] { p = (12345+p)%1; // IMPORTANT : time is reversed because I experimented and tried reversed time at some point (sorry about this) // after this line of code the progress with p is actually to go from sphere surface to displaced position and then doing the elastic easing to come back to the sphere's surface p = 1-p; // maybe try without this line of code to understand it better // q is how much the particle left the black sphere float q = mp01(p-delay1,0,0.25); q = ease(q,3.0); // go from position on sphere to displaced position (when time is not reversed) PVector pos = pos1.copy().lerp(pos2.copy().add(displacement(p)),q); // diagonal delay for main effect float delay2 = 0.3 - map(0.5*pos.y-0.5*pos.x,-150,150,0,0.3); float q2 = mp01(p-delay2,0.3,0.7); q2 = 1-easeOutElastic(pow(1-q2,2.0)); // use rotater function and orientation to go back to position on sphere (when time is not reversed) PVector v = rotater(pos,pos1,q2,orientation); float sz = lerp(1.0,sphereSize(p),0.2+0.8*pow(c01(sin(PI*p)),1.5)); // controlling particle size through time v = bounder(v); // keep position outside of black sphere push(); translate(v.x,v.y,v.z); sphereDetail(5); fill(255); noStroke(); sphere(sz*0.82); pop(); } } Particle [] particlesArray = new Particle[n]; void setup(){ size(600,600,P3D); result = new int[width*height][3]; noise = new OpenSimplexNoise(1234); for(int i=0;i