├── code ├── unfoldedcubestiling │ ├── data │ │ └── ChakraPetch-Medium.ttf │ ├── README.md │ └── unfoldedcubestiling.pde ├── toruscurve │ ├── README.md │ └── toruscurve.pde ├── spiralmagic │ ├── README.md │ └── spiralmagic.pde ├── spherewave │ ├── README.md │ └── spherewave.pde ├── spiralssphere │ └── README.md ├── sinusoidspacking │ ├── README.md │ └── sinusoidspacking.pde ├── sphereimpacts │ ├── README.md │ └── sphereimpacts.pde ├── twolevelssliding │ ├── README.md │ └── twolevelssliding.pde ├── moorecurvequeue │ ├── README.md │ └── moorecurvequeue.pde ├── hilbertcurvetransforms │ ├── README.md │ └── hilbertcurvetransforms.pde ├── permutationpatternspropagation │ ├── README.md │ └── permutationpatternspropagation.pde ├── mooremiddlecurves │ ├── README.md │ └── mooremiddlecurves.pde ├── pusheddigitssphere │ ├── README.md │ └── pusheddigitssphere.pde ├── fractalsliding2d │ ├── README.md │ └── fractalsliding2d.pde ├── moorevoronoi │ ├── README.md │ ├── moore.pde │ ├── voronoi.frag │ └── moorevoronoi.pde ├── fluidsphereobstacle │ ├── README.md │ └── fluidsphereobstacle.pde ├── spiralwave │ ├── README.md │ └── spiralwave.pde ├── scattereddots │ ├── README.md │ └── scattereddots.pde ├── radialcollapse │ ├── README.md │ └── radialcollapse.pde ├── sunconnections │ ├── README.md │ └── sunconnections.pde ├── sierpinskiloop │ ├── README.md │ └── sierpinskiloop.pde └── sierpinskiloop_simple │ └── sierpinskiloop_simple.pde └── README.md /code/unfoldedcubestiling/data/ChakraPetch-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bleuje/processing-animations-code/HEAD/code/unfoldedcubestiling/data/ChakraPetch-Medium.ttf -------------------------------------------------------------------------------- /code/toruscurve/README.md: -------------------------------------------------------------------------------- 1 | ## Torus curve 2 | 3 | ![torus curve gif](https://bleuje.com/gifset/2023/2023_2_toruscurve.gif) 4 | 5 | ## [code](https://github.com/Bleuje/processing-animations-code/blob/main/code/toruscurve/toruscurve.pde) 6 | 7 | #### some used techniques 8 | 9 | 3D geometry, mesh 10 | 11 | ### links 12 | 13 | On bleuje site: https://bleuje.com/gifanimationsite/single/toruscurve/ 14 | 15 | On social media: 16 | - tumblr: https://necessary-disorder.tumblr.com/post/707155618126020608 17 | - twitter: https://twitter.com/etiennejcb/status/1616885159327825921 18 | -------------------------------------------------------------------------------- /code/spiralmagic/README.md: -------------------------------------------------------------------------------- 1 | ## Spiral magic 2 | 3 | ![spiral magic gif](https://bleuje.com/gifset/2021/2021_4_inverseprojection.gif) 4 | 5 | ## [code](https://github.com/Bleuje/processing-animations-code/blob/main/code/spiralmagic/spiralmagic.pde) 6 | 7 | #### some used techniques 8 | 9 | 3D in P2D, spiral 10 | 11 | ### links 12 | 13 | On bleuje site: https://bleuje.com/gifanimationsite/single/spiralmagic/ 14 | 15 | On social media: 16 | - tumblr: https://necessary-disorder.tumblr.com/post/645014025639526400 17 | - twitter: https://twitter.com/etiennejcb/status/1367592930471469057 18 | -------------------------------------------------------------------------------- /code/spherewave/README.md: -------------------------------------------------------------------------------- 1 | ## Sphere wave 2 | 3 | ![sphere wave gif](https://bleuje.com/gifset/2022/2022_7_sphereorderdisorder.gif) 4 | 5 | ## [code](https://github.com/Bleuje/processing-animations-code/blob/main/code/spherewave/spherewave.pde) 6 | 7 | #### some used techniques 8 | 9 | vector maths, easing, noise 10 | 11 | ### links 12 | 13 | On bleuje site: https://bleuje.com/gifanimationsite/single/spherewave/ 14 | 15 | On social media: 16 | - tumblr: https://necessary-disorder.tumblr.com/post/686420135511310336 17 | - twitter: https://twitter.com/etiennejcb/status/1609340724515901442 18 | -------------------------------------------------------------------------------- /code/spiralssphere/README.md: -------------------------------------------------------------------------------- 1 | ## Spirals sphere 2 | 3 | ![spirals sphere gif](https://bleuje.com/gifset/2023/2023_7_circletodoublespiral.gif) 4 | 5 | ## [code](https://github.com/Bleuje/processing-animations-code/blob/main/code/spiralssphere/spiralssphere.pde) 6 | 7 | #### some used techniques 8 | 9 | spirals, tanh 10 | 11 | ### links 12 | 13 | On bleuje site: https://bleuje.com/gifanimationsite/single/spiralssphere/ 14 | 15 | On social media: 16 | - tumblr: https://necessary-disorder.tumblr.com/post/718402751221170176 17 | - twitter: https://twitter.com/etiennejcb/status/1662141549348810753 18 | -------------------------------------------------------------------------------- /code/sinusoidspacking/README.md: -------------------------------------------------------------------------------- 1 | ## Sinusoids packing 2 | 3 | ![sinusoids packing gif](https://bleuje.com/gifset/2024/2024_sinusoidspacking.gif) 4 | 5 | ## [code](https://github.com/Bleuje/processing-animations-code/blob/main/code/sinusoidspacking/sinusoidspacking.pde) 6 | 7 | #### some used techniques 8 | 9 | circle packing, lighting from normal 10 | 11 | ### links 12 | 13 | On bleuje site: https://bleuje.com/gifanimationsite/single/sinusoidspacking/ 14 | 15 | On social media: 16 | - twitter: https://x.com/etiennejcb/status/1845186249377587605 17 | - instagram: https://www.instagram.com/p/DBGBT2ttI9Z/ 18 | -------------------------------------------------------------------------------- /code/sphereimpacts/README.md: -------------------------------------------------------------------------------- 1 | ## Sphere impacts 2 | 3 | ![sphere impacts gif](https://bleuje.com/gifset/2021/2021_18_sphereimpacts.gif) 4 | 5 | ## [code](https://github.com/Bleuje/processing-animations-code/blob/main/code/sphereimpacts/sphereimpacts.pde) 6 | 7 | #### some used techniques 8 | 9 | particles effects, matrix transforms 10 | 11 | ### links 12 | 13 | On bleuje site: https://bleuje.com/gifanimationsite/single/sphereimpacts/ 14 | 15 | On social media: 16 | - tumblr: https://necessary-disorder.tumblr.com/post/667668153745195008 17 | - twitter: https://twitter.com/etiennejcb/status/1458831084876144641 18 | -------------------------------------------------------------------------------- /code/twolevelssliding/README.md: -------------------------------------------------------------------------------- 1 | ## Two levels sliding 2 | 3 | ![two levels sliding gif](https://bleuje.com/gifset/2021/2021_19_twolevelspermuts.gif) 4 | 5 | ## [code](https://github.com/Bleuje/processing-animations-code/blob/main/code/twolevelssliding/twolevelssliding.pde) 6 | 7 | #### some used techniques 8 | 9 | replacement technique, simulation 10 | 11 | ### links 12 | 13 | On bleuje site: https://bleuje.com/gifanimationsite/single/twolevelssliding/ 14 | 15 | On social media: 16 | - tumblr: https://necessary-disorder.tumblr.com/post/669727600936173568 17 | - twitter: https://twitter.com/etiennejcb/status/1467558127570669575 18 | -------------------------------------------------------------------------------- /code/moorecurvequeue/README.md: -------------------------------------------------------------------------------- 1 | ## Moore curve queue 2 | 3 | ![moore curve queue gif](https://bleuje.com/gifset/2023/2023_12_moorecurvequeue.gif) 4 | 5 | ## [code](https://github.com/Bleuje/processing-animations-code/blob/main/code/moorecurvequeue/moorecurvequeue.pde) 6 | 7 | #### some used techniques 8 | 9 | replacement technique, hilbert curve 10 | 11 | ### links 12 | 13 | On bleuje site: https://bleuje.com/gifanimationsite/single/moorecurvequeue/ 14 | 15 | On social media: 16 | - tumblr: https://necessary-disorder.tumblr.com/post/737345629900177408/work-from-december-2021 17 | - twitter: https://twitter.com/etiennejcb/status/1737906284882501742 18 | -------------------------------------------------------------------------------- /code/hilbertcurvetransforms/README.md: -------------------------------------------------------------------------------- 1 | ## Hilbert curve transforms 2 | 3 | ![hilbert curve transforms gif](https://bleuje.com/gifset/2022/2022_5_hilberttransforms.gif) 4 | 5 | ## [code](https://github.com/Bleuje/processing-animations-code/blob/main/code/hilbertcurvetransforms/hilbertcurvetransforms.pde) 6 | 7 | #### some used techniques 8 | 9 | easing, hilbert curve 10 | 11 | ### links 12 | 13 | On bleuje site: https://bleuje.com/gifanimationsite/single/hilbertcurvetransforms/ 14 | 15 | On social media: 16 | - tumblr: https://necessary-disorder.tumblr.com/post/684049569049395200 17 | - twitter: https://twitter.com/etiennejcb/status/1524499671556796416 18 | -------------------------------------------------------------------------------- /code/permutationpatternspropagation/README.md: -------------------------------------------------------------------------------- 1 | ## Permutation patterns propagation 2 | 3 | ![permutation patterns propagation gif](https://bleuje.com/gifset/2021/2021_11_cyclespropagation2.gif) 4 | 5 | ## [code](https://github.com/Bleuje/processing-animations-code/blob/main/code/permutationpatternspropagation/permutationpatternspropagation.pde) 6 | 7 | #### some used techniques 8 | 9 | simulation 10 | 11 | ### links 12 | 13 | On bleuje site: https://bleuje.com/gifanimationsite/single/permutationpatternspropagation/ 14 | 15 | On social media: 16 | - tumblr: https://necessary-disorder.tumblr.com/post/656611026798772224 17 | - twitter: https://twitter.com/etiennejcb/status/1655991294940807208 18 | -------------------------------------------------------------------------------- /code/mooremiddlecurves/README.md: -------------------------------------------------------------------------------- 1 | ## Moore middle curves 2 | 3 | ![moore middle curve gif](https://bleuje.com/gifset/2024/2024_mooremiddlecurves.gif) 4 | 5 | ## [code](https://github.com/Bleuje/processing-animations-code/blob/main/code/mooremiddlecurves/mooremiddlecurves.pde) 6 | 7 | #### some used techniques 8 | 9 | hilbert curve, delay 10 | 11 | ### comments 12 | 13 | Explaining the trick with an animation there: https://mastodon.social/@bleuje/111709161970031114 14 | 15 | ### links 16 | 17 | On bleuje site: https://bleuje.com/gifanimationsite/single/mooremiddlecurves/ 18 | 19 | On social media: 20 | - mastodon: https://mastodon.social/@bleuje/111705602791994094 21 | - tumblr: https://necessary-disorder.tumblr.com/post/745679464509407232 22 | - twitter: https://twitter.com/etiennejcb/status/1743627507843129377 23 | -------------------------------------------------------------------------------- /code/pusheddigitssphere/README.md: -------------------------------------------------------------------------------- 1 | ## Pushed digits sphere 2 | 3 | ![pushed digits sphere gif](https://bleuje.com/gifset/2023/2023_11_pusheddigitssphere.gif) 4 | 5 | ## [code](https://github.com/Bleuje/processing-animations-code/blob/main/code/pusheddigitssphere/pusheddigitssphere.pde) 6 | 7 | #### some used techniques 8 | 9 | 3D in P2D, replacement technique 10 | 11 | ### other comments 12 | 13 | Inspired by: https://twitter.com/Yugemaku/status/1726559476172616047 14 | 15 | I had to use pen and paper to figure out the maths 16 | 17 | ### links 18 | 19 | On bleuje site: https://bleuje.com/gifanimationsite/single/pusheddigitssphere/ 20 | 21 | On social media: 22 | - mastodon: https://mastodon.social/@bleuje/111523511957973296 23 | - tumblr: https://necessary-disorder.tumblr.com/post/735893075299385344 24 | - twitter: https://twitter.com/etiennejcb/status/1732082415915462824 25 | -------------------------------------------------------------------------------- /code/fractalsliding2d/README.md: -------------------------------------------------------------------------------- 1 | ## Fractal sliding 2D 2 | 3 | ![fractal sliding 2D gif](https://bleuje.com/gifset/2023/2023_4_fractalsliding2d.gif) 4 | 5 | ## [code](https://github.com/Bleuje/processing-animations-code/blob/main/code/fractalsliding2d/fractalsliding2d.pde) 6 | 7 | #### some used techinques 8 | 9 | recursion, fractal zoom, tree structure 10 | 11 | ### other comments 12 | 13 | Done for collaboration with Yann Le Gall (https://twitter.com/Yann_LeGall) 14 | 15 | Our final loop looks like this: https://twitter.com/etiennejcb/status/1645150205443031043 16 | 17 | It was used as entry for Revision party's gif competition. 18 | 19 | ### links 20 | 21 | On bleuje site: https://bleuje.com/gifanimationsite/single/2dfractalslidingsquares/ 22 | 23 | On social media: 24 | - tumblr: https://necessary-disorder.tumblr.com/post/714960118674030592/work-for-a-collaboration-with-yann-le-gall-for 25 | - twitter: https://twitter.com/etiennejcb/status/1646946633085493269 26 | -------------------------------------------------------------------------------- /code/moorevoronoi/README.md: -------------------------------------------------------------------------------- 1 | ## Moore voronoi 2 | 3 | ![moore voronoi gif](https://bleuje.com/gifset/2024/2024_moorevoronoi.gif) 4 | 5 | ## [code](https://github.com/Bleuje/processing-animations-code/blob/main/code/moorevoronoi/moorevoronoi.pde) 6 | 7 | #### some used techniques 8 | 9 | replacement technique, hilbert curve, voronoi edges with shader 10 | 11 | ### other comments 12 | 13 | Combining Moore curve, replacement technique and Voronoi cells drawing. 14 | For the voronoi cells drawing, using exact distance to edges, by using https://www.shadertoy.com/view/ldl3W8 by Inigo Quilez, with this article explaing it: https://iquilezles.org/articles/voronoilines/ 15 | 16 | My first gif animation using Processing + shader! 17 | 18 | ### links 19 | 20 | On bleuje site: https://bleuje.com/gifanimationsite/single/moorevoronoi/ 21 | 22 | On social media: 23 | - mastodon: https://mathstodon.xyz/@bleuje/113346828157692078 24 | - tumblr: https://necessary-disorder.tumblr.com/post/765064008182235136 25 | - twitter: https://x.com/etiennejcb/status/1848760136145436784 26 | - instagram: https://www.instagram.com/p/DBdHa6Dtl3i/ 27 | -------------------------------------------------------------------------------- /code/unfoldedcubestiling/README.md: -------------------------------------------------------------------------------- 1 | ## Unfolded cubes tiling 2 | 3 | ![unfolded cubes tiling gif, truchet version](https://bleuje.com/gifset/2024/2024_unfoldedcubestiling_truchet.gif) 4 | 5 | ![unfolded cubes tiling gif, digits version](https://bleuje.com/gifset/2024/2024_unfoldedcubestiling_digits.gif) 6 | 7 | ## [code](https://github.com/Bleuje/processing-animations-code/blob/main/code/unfoldedcubestiling/unfoldedcubestiling.pde) 8 | 9 | #### some used techniques 10 | 11 | matrix transforms, delay, truchet 12 | 13 | ### other comments 14 | 15 | Inspired by Yann Le Gall, see his unfolded cube animation there: 16 | - https://x.com/Yann_LeGall/status/1813347547454575100 17 | - or https://www.instagram.com/p/C9kmvo-PaPh/ 18 | 19 | The loop technique can illustrate this tutorial: https://bleuje.com/tutorial2/ 20 | 21 | ### links 22 | 23 | On bleuje site: https://bleuje.com/gifanimationsite/single/unfoldedcubestiling_truchet/ 24 | 25 | On social media: 26 | - mastodon: https://mathstodon.xyz/@bleuje/112933792125156917 27 | - tumblr: https://necessary-disorder.tumblr.com/post/758369585555750912 28 | - twitter: https://x.com/etiennejcb/status/1821989299585519712 29 | - instagram: https://www.instagram.com/p/C-doND8tStM/ 30 | -------------------------------------------------------------------------------- /code/fluidsphereobstacle/README.md: -------------------------------------------------------------------------------- 1 | ## Fluid sphere obstacle 2 | 3 | ![fluid sphere obstacle gif](https://bleuje.com/gifset/2017/2017_22_sphereagainsflow_v2.gif) 4 | 5 | ## [code](https://github.com/Bleuje/processing-animations-code/blob/main/code/fluidsphereobstacle/fluidsphereobstacle.pde) 6 | 7 | #### some used techniques 8 | 9 | simulation, replacement technique 10 | 11 | ### other comments 12 | 13 | It's using a simulation of particles following a flow field. 14 | 15 | The flow field is defined by the sum of: 16 | - a constant speed field 17 | - a repulsive field (might be the most technical part of the code) 18 | - some perlin noise 19 | 20 | Once the particle paths are computed, [replacement technique](https://bleuje.com/tutorial4/) is used to show particles following them. It's also using interpolation between computed positions of the simulation [(tutorial)](https://bleuje.com/tutorial7/). 21 | 22 | A black sphere is then simply drawn, its position and size have been adjusted experimentally. 23 | 24 | ### links 25 | 26 | On bleuje site: https://bleuje.com/gifanimationsite/single/fluidsphereobstacle/ 27 | 28 | On social media: 29 | - tumblr: https://necessary-disorder.tumblr.com/post/164452980553 30 | - twitter: https://twitter.com/etiennejcb/status/1439309996471341059 31 | -------------------------------------------------------------------------------- /code/spiralwave/README.md: -------------------------------------------------------------------------------- 1 | ## Spiral wave 2 | 3 | ![spiral wave gif](https://bleuje.com/gifset/2021/2021_9_starryheightspiral.gif) 4 | 5 | ## [code](https://github.com/Bleuje/processing-animations-code/blob/main/code/spiralwave/spiralwave.pde) 6 | 7 | (space to separate text from distracting gif) 8 | 9 | . 10 | 11 | . 12 | 13 | . 14 | 15 | . 16 | 17 | . 18 | 19 | . 20 | 21 | . 22 | 23 | . 24 | 25 | . 26 | 27 | . 28 | 29 | . 30 | 31 | . 32 | 33 | #### some used techniques 34 | 35 | replacement technique, mesh, delay 36 | 37 | ### other comments 38 | 39 | For the surface shape, we have a function that gives the 3D position by basically getting the height in function of position on 2D plane. This height is computed with a sinusoid and with a delay that's the distance to center + the angle to this center (obtained with atan2 function). 40 | 41 | A black mesh is drawn by drawing a lot of tiny triangles on the surface. 42 | 43 | Some particles with random parameters/positions are drawn on the surface, moving outwards (simply moving in lines in the 2D parameters input of the surface). The [replacement technique](https://bleuje.com/tutorial4/) is used, and its parameters make them move at different speed compared to the mesh wave. 44 | 45 | ### links 46 | 47 | On bleuje site: https://bleuje.com/gifanimationsite/single/spiralwave/ 48 | 49 | On social media: 50 | - tumblr: https://necessary-disorder.tumblr.com/post/651898885464326144 51 | - twitter: https://twitter.com/etiennejcb/status/1470031412711641094 52 | -------------------------------------------------------------------------------- /code/scattereddots/README.md: -------------------------------------------------------------------------------- 1 | ## Scattered dots 2 | 3 | ![scattered dots gif](https://bleuje.com/gifset/2018/2018_26_popularlerpdotpath.gif) 4 | 5 | ## [code](https://github.com/Bleuje/processing-animations-code/blob/main/code/scattereddots/scattereddots.pde) 6 | 7 | #### some used techniques 8 | 9 | replacement technique, simulation 10 | 11 | ### other comments 12 | 13 | This animation is simple but has had a lot of success on tumblr. 14 | 15 | It's using particles following a single path with [replacement technique](https://bleuje.com/tutorial4/). 16 | 17 | First the positions of the path are computed at setup, using jumps of random length, in 8 different directions. There are checks to go in opposite direction when the jump crosses a margin. 18 | 19 | From this list, the position at parameter p in [0,1] is found using interpolation between positions of the list [(tutorial)](https://bleuje.com/tutorial7/). The interpolation uses [an easing function](https://patakk.tumblr.com/post/88602945835/heres-a-simple-function-you-can-use-for-easing), which makes the dots stop and move smoothly. Once we've got this parametrization of the path, the [replacement technique](https://bleuje.com/tutorial4/) is used, with less dots on the path than its number of jumps. 20 | 21 | Similarly to position, there is a list of sizes of dot, and interpolation between these sizes. 22 | 23 | ### links 24 | 25 | On bleuje site: https://bleuje.com/gifanimationsite/single/scattereddots/ 26 | 27 | On social media: 28 | - tumblr: https://necessary-disorder.tumblr.com/post/175311166118 29 | - twitter: (TODO: find link) 30 | -------------------------------------------------------------------------------- /code/radialcollapse/README.md: -------------------------------------------------------------------------------- 1 | ## Radial collapse 2 | 3 | ![radial collapse gif](https://bleuje.com/gifset/2020/2020_4_radialcollapse.gif) 4 | 5 | ## [code](https://github.com/Bleuje/processing-animations-code/blob/main/code/radialcollapse/radialcollapse.pde) 6 | 7 | #### some used techniques 8 | 9 | fractal zoom, replacement technique, noise 10 | 11 | ### other comments 12 | 13 | We have a set of block instances, 3D array because of different angle, radius position and height. There are a lot more blocks drawn than the number of instances, because of replacement technique (the radius position of the blocks change). 14 | 15 | The fall of the blocks is controlled by formulas for the delay/offset of the falls. This formula mostly uses block height and noise based on angle. 16 | 17 | This is a fractal zoom on the radius. The ratio of the fractal zoom 0.8, which means that during the time of one loop, the blocks become smaller and closer to center by a factor 0.8. 18 | 19 | The most technical thing in the code, in my opinion, is to define the radius to draw each block in function of parameter p (here p increases by 1 during a loop). The block is drawn using/between these 2 radius: 20 | 21 | - r1 = pow(RATIO,p)\*pow(1/RATIO,1.0\*i/N)*R; 22 | - r2 = pow(RATIO,p)\*pow(1/RATIO,1.0\*(i+1)/N)*R; 23 | 24 | Where i is the "radius index" of the block (0, 1 or 2), and N the number of radius indices (3). You can check that when p increases by 1, r1, r2 and r2-r1 are multiplied by RATIO=0.8. 25 | 26 | pow(1/RATIO,1.0*i/N) is about changing the radius depending on radius index i. 27 | 28 | After we can draw the evolution of a block with parameter p, we can use the [replacement technique (with 3D grid)](https://bleuje.com/tutorial5/) to fill everything and have a perfect loop. 29 | 30 | ### links 31 | 32 | On bleuje site: https://bleuje.com/gifanimationsite/single/radialcollapse/ 33 | 34 | On social media: 35 | - tumblr: https://necessary-disorder.tumblr.com/post/190213558568 36 | - twitter: (TODO: find link) 37 | -------------------------------------------------------------------------------- /code/sunconnections/README.md: -------------------------------------------------------------------------------- 1 | ## Sun connections 2 | 3 | ![sun connections gif](https://bleuje.com/gifset/2018/2018_6_sphereconnexions.gif) 4 | 5 | ## [code](https://github.com/Bleuje/processing-animations-code/blob/main/code/sunconnections/sunconnections.pde) 6 | 7 | #### some used techniques 8 | 9 | interpolation with delay, noise loop 10 | 11 | ### other comments 12 | 13 | First there is a set of points, with different random parameters. Each point moves around a random position (x0,y0), with a looping noise-based path. How to make a noise loop is explained in [this post](https://bleuje.com/tutorial3/), there's also a [video](https://www.youtube.com/watch?v=3_0Ax95jIrk) about it by the coding train on youtube. OpenSimplexNoise is used instead of Processing noise function, but it's similar. 14 | 15 | So the formulas to get the points' position loops are basically like this: 16 | 17 | - x = x0 + L\*noise(seed + r\*cos(t), r\*sin(t)) 18 | - y = y0 + L\*noise(2\*seed + r\*cos(t), r\*sin(t)) 19 | 20 | The random (x0,y0) position is set using formulas so that it's distributed to have this sphere like shape, though this is done in 2D. L is a parameter for how large the movement is, and r how much we have varation with noise. 21 | 22 | Now comes the tricky part: for each pair {i,j} of points, how to draw these connections between them. Let's say we have a parameter q in [0,1] where at 0 we're on dot i, at 1 we're on dot j, and in between we'll be on the curve. At q, the dot j is seen with the delay delayFactor\*(1-q) where delayFactor is a parameter we can tune. No delay when we're at q=1, on j, and delayFactor when we're on i. Still at q, the dot i is seen with the delay delayFactor\*q. No delay when we're at q=0 on i and delayFactor when we're on j. So we have two seen dot positions a and b, seen with these delays when we're at q. To get our current position on the curve we do this linear interpolation: lerp(a,b,q). 23 | 24 | ### links 25 | 26 | On bleuje site: https://bleuje.com/gifanimationsite/single/sunconnections/ 27 | 28 | On social media: 29 | - tumblr: https://necessary-disorder.tumblr.com/post/170688287343/approximated-sun 30 | - twitter: (TODO: find link) 31 | -------------------------------------------------------------------------------- /code/sierpinskiloop/README.md: -------------------------------------------------------------------------------- 1 | ## Sierpinski triangle loop 2 | 3 | ![Sierpinski triangle loop gif](https://bleuje.com/gifset/other/sierpinskiloop.gif) 4 | 5 | ## [code](https://github.com/Bleuje/processing-animations-code/blob/main/code/sierpinskiloop/sierpinskiloop.pde) / [simpler version code](https://github.com/Bleuje/processing-animations-code/blob/main/code/sierpinskiloop_simple/sierpinskiloop_simple.pde) 6 | 7 | #### some used techniques 8 | 9 | recursion, chromatic aberration 10 | 11 | ### other comments 12 | 13 | (made in 2017, revised in 2021) 14 | 15 | First there is a function drawFractal to draw a [Sierpinski triangle fractal](https://en.wikipedia.org/wiki/Sierpi%C5%84ski_triangle). This is done by recursion: to draw the fractal into a triangle, draw the triangle, use the middles of its 3 segments to draw the fractals inside it recusively. Stop after a max number ("depth") of iterations. 16 | 17 | A technical detail is that the stroke weight of the drawn triangles decreases with iteration and a time parameter p. This time parameter is because of the fractals getting smaller and reaching a new depth after the animation movements. That's what this piece of code is doing: float sw = map(iterationsIndex+p,0,DEPTH,SWMAX,0); strokeWeight(sw); 18 | 19 | Then there is a drawThing function to do one example of movement shown in the animation, by drawing 3 fractals, using interpolation towards middles of the segments of the main triangle. There is a time parameter p, used for both interpolation doing the movement, and the calls to draw fractals (there p is used to control stroke weight and have a perfect loop as mentioned before). 20 | 21 | The movement coded in drawThing is reused 3 times with different rotation during the animation. If t is the time of the animation in [0,1], we can get the parameter p of drawThing for a single movement with (3\*t)%1. An [easing function](https://patakk.tumblr.com/post/88602945835/heres-a-simple-function-you-can-use-for-easing) is used for smooth changes. 22 | 23 | A "chromatic aberration" effect is used. It's about having a delay between the red, green and blue color components. So this is drawn 3 times in different colors with blendMode(ADD) and different time delays. 24 | 25 | The thing is also drawn many times with a for loop and delays to have a quite subtle trail effect. 26 | 27 | 28 | 29 | Here is the 2017 version, without trail and chromatic aberration, that probably looks better, actually: 30 | 31 | ![Sierpinski triangle loop gif, 2017 version](https://bleuje.com/gifset/2017/2017_7_pinnedsierpinski.gif) 32 | 33 | ### links 34 | 35 | On bleuje site: https://bleuje.com/gifanimationsite/single/sierpinskiloop/ 36 | 37 | On social media: 38 | - tumblr: https://necessary-disorder.tumblr.com/post/157349897888 39 | - twitter: https://twitter.com/etiennejcb/status/1367173073250758661 40 | -------------------------------------------------------------------------------- /code/moorevoronoi/moore.pde: -------------------------------------------------------------------------------- 1 | int curveSize = 16; // must be a power of 2 2 | int numberOfVertices = curveSize * curveSize; 3 | 4 | float W = 600; // = width in 600x600, it's often useful to avoid Processing's width variable, to be able to change easily the resolution with the scale function 5 | float margin = 0.5*W/curveSize; 6 | 7 | // Hilbert curve algo from Wikipedia in functions d2xy_hilbert and rot below (https://en.wikipedia.org/wiki/Hilbert_curve) 8 | 9 | // convert d (it's an index of a vertex on the curve's path) to (i,j) position 10 | // n * n is the number of vertices, a power of 4 : pow(4,j) where j is the order/level of the curve 11 | PVector d2xy_hilbert(int n, int d) { 12 | int rx, ry, s, t=d; 13 | float x, y; 14 | x = 0; 15 | y = 0; 16 | for (s=1; s1.0 ) 65 | minDist = min( minDist, dot( 0.5*(vToClosestPoint+vToPoint), normalize(vToPoint-vToClosestPoint) ) ); 66 | } 67 | 68 | // now something specific to this animation: 69 | // also using distance to "border points" for nicer design on the borders of the image 70 | int numberOfBorderPoints = curveSize*4; 71 | for (int i = 0; i < numberOfBorderPoints; i++) { 72 | vec2 point = getBorderPoint(i); 73 | vec2 vToPoint = point - uv; 74 | if( dot(vToClosestPoint-vToPoint,vToClosestPoint-vToPoint)>1.0 ) 75 | minDist = min( minDist, dot( 0.5*(vToClosestPoint+vToPoint), normalize(vToPoint-vToClosestPoint) ) ); 76 | } 77 | 78 | 79 | float stripes = 0.47*min(abs(minDist-4),abs(minDist-10)); // function of shape \/\/, for 2 stripes 80 | float brightness = smoothstep(0.7,0.3,stripes); 81 | vec3 color = vec3(brightness); 82 | 83 | gl_FragColor = vec4(color, 1.0); 84 | } 85 | 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Processing animations source code list 2 | 3 | This repo has the source codes of some of my animations. For more context and insights about this project, please read the text below. 4 | 5 | 6 | | | Year | 7 | |-----------------|------| 8 | | [**scattered dots**](https://github.com/Bleuje/processing-animations-code/blob/main/code/scattereddots/) | 2018 | 9 | | [**Sierpinski triangle loop**](https://github.com/Bleuje/processing-animations-code/blob/main/code/sierpinskiloop/) | 2017,2021 | 10 | | [**spiral wave**](https://github.com/Bleuje/processing-animations-code/blob/main/code/spiralwave/) | 2021 | 11 | | [**fluid sphere obstacle**](https://github.com/Bleuje/processing-animations-code/blob/main/code/fluidsphereobstacle/) | 2017 | 12 | | [**sun connections**](https://github.com/Bleuje/processing-animations-code/blob/main/code/sunconnections/) | 2018 | 13 | | [**radial collapse**](https://github.com/Bleuje/processing-animations-code/blob/main/code/radialcollapse/) | 2020 | 14 | | [**moore curve queue**](https://github.com/Bleuje/processing-animations-code/blob/main/code/moorecurvequeue/) | 2021,2023 | 15 | | [**moore middle curves**](https://github.com/Bleuje/processing-animations-code/blob/main/code/mooremiddlecurves/) | 2024 | 16 | | [**sphere impacts**](https://github.com/Bleuje/processing-animations-code/blob/main/code/sphereimpacts/) | 2021 | 17 | | [**two levels sliding**](https://github.com/Bleuje/processing-animations-code/blob/main/code/twolevelssliding/) | 2021 | 18 | | [**sinusoids packing**](https://github.com/Bleuje/processing-animations-code/blob/main/code/sinusoidspacking/) | 2018,2024 | 19 | | [**hilbert curve transforms**](https://github.com/Bleuje/processing-animations-code/blob/main/code/hilbertcurvetransforms/) | 2022 | 20 | | [**sphere wave**](https://github.com/Bleuje/processing-animations-code/blob/main/code/spherewave/) | 2022 | 21 | | [**unfolded cubes tiling**](https://github.com/Bleuje/processing-animations-code/tree/main/code/unfoldedcubestiling) | 2024 | 22 | | [**moore voronoi**](https://github.com/Bleuje/processing-animations-code/tree/main/code/moorevoronoi) | 2024 | 23 | | [**2D fractal sliding squares**](https://github.com/Bleuje/processing-animations-code/blob/main/code/fractalsliding2d/) | 2023 | 24 | | [**spiral magic**](https://github.com/Bleuje/processing-animations-code/blob/main/code/spiralmagic/) | 2021 | 25 | | [**permutation patterns propagation**](https://github.com/Bleuje/processing-animations-code/blob/main/code/permutationpatternspropagation/) | 2021 | 26 | | [**torus curve**](https://github.com/Bleuje/processing-animations-code/blob/main/code/toruscurve/) | 2023 | 27 | | [**pushed digits sphere**](https://github.com/Bleuje/processing-animations-code/blob/main/code/pusheddigitssphere/) | 2023 | 28 | | [**spirals sphere**](https://github.com/Bleuje/processing-animations-code/blob/main/code/spiralssphere/) | 2023 | 29 | 30 | 31 | I'm trying to sort the list from simpler to more complex or time-consuming to fully understand, but this is highly subjective. 32 | 33 | This set of animations is [watchable on my site here](https://bleuje.com/gifanimationsite/single/spiralssphere/) using the bottom arrows/links to navigate. 34 | 35 | Unfortunately I had to give them some kind of names, which is something I don't really like. 36 | 37 | --- 38 | 39 | ## Motivation and information 40 | 41 | In my early animation experiences with [Processing](https://processing.org/), I came across captivating gifs by [beesandbombs (Dave)](https://beesandbombs.com/). Studying even a fraction of the [code he has shared](https://gist.github.com/beesandbombs) greatly enhanced my skills and approach. Over time, I've shared quite raw source codes from my animations, valuing visual outcome over code aesthetics. But with positive feedback and people asking me how the animations are made, I see value in sharing the code with more care. 42 | 43 | This project compiles noteworthy animation source codes, aiming for clarity through commented code. It's a work in progress, aiming to surpass my previous releases despite the imperfections. 44 | 45 | For newcomers or those seeking context, I recommend [**tutorials**](https://bleuje.com/tutorials/) on my website, especially the "[Replacement Technique](https://bleuje.com/tutorial4/)" and the one about beesandbombs' [motion blur template](https://bleuje.com/tutorial6/). 46 | 47 | I hope this collection serves both those diving into Processing-based animations and the simply curious, potentially inspiring others just as beesandbombs inspired me. 48 | 49 | ## Acknowledgments and Licensing 50 | 51 | This repository includes animations that utilize a [motion blur template](https://bleuje.com/tutorial6/) created by Dave. We have permission from him to use this template in our work. 52 | 53 | Please note that while the motion blur template is available for use, the rest of the source code in this repository is generally protected under my copyright, and all rights are reserved. If you wish to use any part of my source code for your own projects or any other purpose, please contact me to obtain permission. 54 | -------------------------------------------------------------------------------- /code/sierpinskiloop_simple/sierpinskiloop_simple.pde: -------------------------------------------------------------------------------- 1 | // Processing code by Etienne JACOB 2 | // motion blur template by beesandbombs, explanation/article: https://bleuje.com/tutorial6/ 3 | // See the license information at the end of this file. 4 | 5 | ////////////////////////////////////////////////////////////////////////////// 6 | // Start of template 7 | 8 | int[][] result; // pixel colors buffer for motion blur 9 | float t; // time global variable in [0,1[ 10 | float c; // other global variable for testing things, controlled by mouse 11 | 12 | // ease in and out, [0,1] -> [0,1], with a parameter g: 13 | // https://patakk.tumblr.com/post/88602945835/heres-a-simple-function-you-can-use-for-easing 14 | float ease(float p, float g) { 15 | if (p < 0.5) 16 | return 0.5 * pow(2*p, g); 17 | else 18 | return 1 - 0.5 * pow(2*(1 - p), g); 19 | } 20 | 21 | void draw() 22 | { 23 | if (!recording) // test mode... 24 | { 25 | t = (mouseX*1.3/width)%1; 26 | c = mouseY*1.0/height; 27 | if (mousePressed) 28 | println(c); 29 | draw_(); 30 | } 31 | else // render mode... 32 | { 33 | for (int i=0; i=DEPTH) return; 93 | 94 | float sw = map(iterationsIndex+p,0,DEPTH,SWMAX,0); 95 | strokeWeight(sw); 96 | 97 | triangle(v1.x,v1.y,v2.x,v2.y,v3.x,v3.y); 98 | 99 | // now let's draw the triangles inside... 100 | 101 | PVector u1 = v1.copy().add(v2).mult(0.5); // position at the middle between v1 and v2 102 | PVector u2 = v2.copy().add(v3).mult(0.5); // position at the middle between v2 and v3 103 | PVector u3 = v3.copy().add(v1).mult(0.5); // position at the middle between v3 and v1 104 | 105 | drawFractal(p,v1,u1,u3,iterationsIndex+1); 106 | drawFractal(p,u1,v2,u2,iterationsIndex+1); 107 | drawFractal(p,u3,u2,v3,iterationsIndex+1); 108 | } 109 | 110 | // first level with some new fractal triangles coming in 111 | void drawThing(float p,PVector v1,PVector v2,PVector v3) 112 | { 113 | PVector u1 = v1.copy().add(v2).mult(0.5); // position at the middle between v1 and v2 114 | PVector u2 = v2.copy().add(v3).mult(0.5); // position at the middle between v2 and v3 115 | PVector u3 = v3.copy().add(v1).mult(0.5); // position at the middle between v3 and v1 116 | 117 | PVector w1 = v2.copy().lerp(u1,p); // go from v2 to u1 with time 118 | PVector w2 = v2.copy().lerp(u2,p); // go from v2 to u2 with time 119 | PVector w3 = v3.copy().lerp(u2,p); // go from v3 to u2 with time 120 | PVector w4 = v3.copy().lerp(u3,p); // go from v3 to u3 with time 121 | 122 | drawFractal(p,v1,w1,w4,0); 123 | drawFractal(p,w1,v2,w2,0); 124 | drawFractal(p,w4,w3,v3,0); 125 | } 126 | 127 | void draw_(){ 128 | background(0); 129 | push(); 130 | translate(width/2,height/2+60*800/600); 131 | scale(800.0/600); 132 | 133 | // defining the main triangle vertices' positions 134 | float a1 = TWO_PI*0.0/3.0-HALF_PI; 135 | PVector v1 = new PVector(R*cos(a1),R*sin(a1)); 136 | float a2 = TWO_PI*1.0/3.0-HALF_PI; 137 | PVector v2 = new PVector(R*cos(a2),R*sin(a2)); 138 | float a3 = TWO_PI*2.0/3.0-HALF_PI; 139 | PVector v3 = new PVector(R*cos(a3),R*sin(a3)); 140 | 141 | noFill(); 142 | stroke(255); 143 | strokeWeight(SWMAX); 144 | 145 | triangle(v1.x,v1.y,v2.x,v2.y,v3.x,v3.y); // drawing the main triangle 146 | 147 | float t2 = 3*t; 148 | 149 | float rotationIndex = floor(t2)%3; // we draw the scene with 3 different successive rotations 150 | float q = t2%1; // fractional part for time inside current rotation 151 | 152 | push(); 153 | rotate(TWO_PI*rotationIndex/3); 154 | drawThing(ease(constrain(q,0,1),1.75),v1,v2,v3); 155 | pop(); 156 | 157 | 158 | pop(); 159 | } 160 | 161 | 162 | /* License: 163 | * 164 | * Copyright (c) 2021, 2024 Etienne Jacob 165 | * 166 | * All rights reserved. 167 | * 168 | * This code after the template and the related animations are the property of the 169 | * copyright holder. Any reproduction, distribution, or use of this material, 170 | * in whole or in part, without the express written permission of the copyright 171 | * holder is strictly prohibited. 172 | */ 173 | -------------------------------------------------------------------------------- /code/sunconnections/sunconnections.pde: -------------------------------------------------------------------------------- 1 | // Processing code by Etienne Jacob 2 | // motion blur template by beesandbombs, explanation/article: https://bleuje.com/tutorial6/ 3 | // opensimplexnoise code (by Kurt Spencer) in another tab is necessary 4 | // --> code here : https://gist.github.com/Bleuje/fce86ef35b66c4a2b6a469b27163591e 5 | // See the license information at the end of this file. 6 | // View the rendered result at: https://bleuje.com/gifanimationsite/single/sunconnections/ 7 | 8 | ////////////////////////////////////////////////////////////////////////////// 9 | // Start of template 10 | 11 | int[][] result; // pixel colors buffer for motion blur 12 | float t; // time global variable in [0,1[ 13 | float c; // other global variable for testing things, controlled by mouse 14 | 15 | void draw() 16 | { 17 | if (!recording) // test mode... 18 | { 19 | t = (mouseX*1.3/width)%1; 20 | c = mouseY*1.0/height; 21 | if (mousePressed) 22 | println(c); 23 | draw_(); 24 | } 25 | else // render mode... 26 | { 27 | for (int i=0; i [0,1], with a parameter g: 19 | // https://patakk.tumblr.com/post/88602945835/heres-a-simple-function-you-can-use-for-easing 20 | float ease(float p, float g) { 21 | if (p < 0.5) 22 | return 0.5 * pow(2*p, g); 23 | else 24 | return 1 - 0.5 * pow(2*(1 - p), g); 25 | } 26 | 27 | //----------------------------------- 28 | 29 | void draw() { 30 | if (!recording) { 31 | t = (mouseX*1.3/width)%1; 32 | c = mouseY*1.0/height; 33 | if (mousePressed) 34 | println(c); 35 | draw_(); 36 | } else { 37 | for (int i=0; i [0,1], with a parameter g: 14 | // https://patakk.tumblr.com/post/88602945835/heres-a-simple-function-you-can-use-for-easing 15 | float ease(float p, float g) { 16 | if (p < 0.5) 17 | return 0.5 * pow(2*p, g); 18 | else 19 | return 1 - 0.5 * pow(2*(1 - p), g); 20 | } 21 | 22 | void draw() 23 | { 24 | if (!recording) // test mode... 25 | { 26 | t = (mouseX*1.3/width)%1; 27 | c = mouseY*1.0/height; 28 | if (mousePressed) 29 | println(c); 30 | draw_(); 31 | } 32 | else // render mode... 33 | { 34 | for (int i=0; i=DEPTH) return; 94 | 95 | float sw = map(iterationsIndex+p,0,DEPTH,SWMAX,0); 96 | strokeWeight(sw); 97 | 98 | triangle(v1.x,v1.y,v2.x,v2.y,v3.x,v3.y); 99 | 100 | // now let's draw the triangles inside... 101 | 102 | PVector u1 = v1.copy().add(v2).mult(0.5); // position at the middle between v1 and v2 103 | PVector u2 = v2.copy().add(v3).mult(0.5); // position at the middle between v2 and v3 104 | PVector u3 = v3.copy().add(v1).mult(0.5); // position at the middle between v3 and v1 105 | 106 | drawFractal(p,v1,u1,u3,iterationsIndex+1); 107 | drawFractal(p,u1,v2,u2,iterationsIndex+1); 108 | drawFractal(p,u3,u2,v3,iterationsIndex+1); 109 | } 110 | 111 | // first level with some new fractal triangles coming in 112 | void drawThing(float p,PVector v1,PVector v2,PVector v3) 113 | { 114 | PVector u1 = v1.copy().add(v2).mult(0.5); // position at the middle between v1 and v2 115 | PVector u2 = v2.copy().add(v3).mult(0.5); // position at the middle between v2 and v3 116 | PVector u3 = v3.copy().add(v1).mult(0.5); // position at the middle between v3 and v1 117 | 118 | PVector w1 = v2.copy().lerp(u1,p); // go from v2 to u1 with time 119 | PVector w2 = v2.copy().lerp(u2,p); // go from v2 to u2 with time 120 | PVector w3 = v3.copy().lerp(u2,p); // go from v3 to u2 with time 121 | PVector w4 = v3.copy().lerp(u3,p); // go from v3 to u3 with time 122 | 123 | drawFractal(p,v1,w1,w4,0); 124 | drawFractal(p,w1,v2,w2,0); 125 | drawFractal(p,w4,w3,v3,0); 126 | } 127 | 128 | void draw_(){ 129 | background(0); 130 | push(); 131 | translate(width/2,height/2+50); 132 | 133 | // defining the main triangle vertices' positions 134 | float a1 = TWO_PI*0.0/3.0-HALF_PI; 135 | PVector v1 = new PVector(R*cos(a1),R*sin(a1)); 136 | float a2 = TWO_PI*1.0/3.0-HALF_PI; 137 | PVector v2 = new PVector(R*cos(a2),R*sin(a2)); 138 | float a3 = TWO_PI*2.0/3.0-HALF_PI; 139 | PVector v3 = new PVector(R*cos(a3),R*sin(a3)); 140 | 141 | noFill(); 142 | 143 | blendMode(ADD); // to add layers of red, green and blue drawings, for chromatic aberration style 144 | 145 | for(int col=0;col<3;col++) // RGB chromatic aberration loop 146 | { 147 | stroke(255*int(col==0),255*int(col==1),255*int(col==2)); // draw in red, green or blue depending on col 148 | 149 | strokeWeight(SWMAX); 150 | triangle(v1.x,v1.y,v2.x,v2.y,v3.x,v3.y); // drawing the main triangle 151 | 152 | int N = 16; 153 | for(int i=0;i [0,1], with a parameter g: 14 | // https://patakk.tumblr.com/post/88602945835/heres-a-simple-function-you-can-use-for-easing 15 | float ease(float p, float g) { 16 | if (p < 0.5) 17 | return 0.5 * pow(2*p, g); 18 | else 19 | return 1 - 0.5 * pow(2*(1 - p), g); 20 | } 21 | 22 | void draw() 23 | { 24 | if (!recording) // test mode... 25 | { 26 | t = (mouseX*1.3/width)%1; 27 | c = mouseY*1.0/height; 28 | if (mousePressed) 29 | println(c); 30 | draw_(); 31 | } 32 | else // render mode... 33 | { 34 | for (int i=0; i positions = new ArrayList(); 93 | ArrayList sizes = new ArrayList(); 94 | 95 | DotPath() 96 | { 97 | float x = startX; 98 | float y = startY; 99 | positions.add(new PVector(x,y)); 100 | 101 | sizes.add(0.0); // start with a size 0 102 | 103 | for(int i=0;iwidth-emptyMargin){ 139 | x -= 2*jumpLength; 140 | } 141 | if(xheight-emptyMargin){ 145 | y -= 2*jumpLength; 146 | } 147 | if(y positions = new ArrayList(); // list of recorded positions with simulation 103 | 104 | float sw = random(1,2); // strokeWeight parameter 105 | int numberOfParticlesOnPath = 3; 106 | float tOffset = random(1); // particles of different paths don't start at the same time thanks to this offset 107 | 108 | Path() 109 | { 110 | positions.add(new PVector(currentX,currentY)); 111 | } 112 | 113 | void update() 114 | { 115 | PVector velocity = field(currentX,currentY); 116 | currentX += timeStep*velocity.x; 117 | currentY += timeStep*velocity.y; 118 | positions.add(new PVector(currentX,currentY)); 119 | } 120 | 121 | void show() 122 | { 123 | strokeWeight(sw); 124 | float tt = (t+tOffset)%1; // particles don't start at the same time on different paths 125 | int arrayLength = positions.size(); 126 | 127 | // replacement technique on path with numberOfParticlesOnPath particles 128 | // and linear interpolation between positions recorded during simulation 129 | for(int i=0;i code here : https://gist.github.com/Bleuje/fce86ef35b66c4a2b6a469b27163591e 5 | // See the license information at the end of this file. 6 | // View the rendered result at: https://bleuje.com/gifanimationsite/single/radialcollapse/ 7 | 8 | // A lot of hidden blocks are drawn, I don't really care, but it's very slow 9 | 10 | ////////////////////////////////////////////////////////////////////////////// 11 | // Start of template 12 | 13 | int[][] result; // pixel colors buffer for motion blur 14 | float t; // time global variable in [0,1[ 15 | float c; // other global variable for testing things, controlled by mouse 16 | 17 | // ease in and out, [0,1] -> [0,1], with a parameter g: 18 | // https://patakk.tumblr.com/post/88602945835/heres-a-simple-function-you-can-use-for-easing 19 | float ease(float p, float g) { 20 | if (p < 0.5) 21 | return 0.5 * pow(2*p, g); 22 | else 23 | return 1 - 0.5 * pow(2*(1 - p), g); 24 | } 25 | 26 | void draw() 27 | { 28 | if (!recording) // test mode... 29 | { 30 | t = (mouseX*1.3/width)%1; 31 | c = mouseY*1.0/height; 32 | if (mousePressed) 33 | println(c); 34 | draw_(); 35 | } 36 | else // render mode... 37 | { 38 | for (int i=0; i=offset which is the same as pp>=0 145 | float pp = p - offset; 146 | float q = max(0,0.5*pp); // no fall while q=0 147 | 148 | float zFall = pow(RATIO,p)*1700*pow(q,2.0); // fall length 149 | float blockHeight = DZ*pow(RATIO,p); // block height, changing with fractal zoom factor 150 | float z = -zFall-l*blockHeight; // fall + height change because of height index 151 | 152 | push(); 153 | translate(0,0,z); 154 | 155 | // changing stroke weight with p and noise 156 | float f = 0.5+5*pow(map((float)noise.eval(seed+1.0*p,0),-1,1,0,1),3.0); 157 | strokeWeight(sw*f); 158 | stroke(col+0.34*z); 159 | fill(0); 160 | 161 | beginShape(); 162 | vertex(x1,y1,0); 163 | vertex(x2,y2,0); 164 | vertex(x3,y3,0); 165 | vertex(x4,y4,0); 166 | endShape(CLOSE); 167 | beginShape(); 168 | vertex(x1,y1,0); 169 | vertex(x2,y2,0); 170 | vertex(x2,y2,-blockHeight); 171 | vertex(x1,y1,-blockHeight); 172 | endShape(CLOSE); 173 | beginShape(); 174 | vertex(x3,y3,0); 175 | vertex(x4,y4,0); 176 | vertex(x4,y4,-blockHeight); 177 | vertex(x3,y3,-blockHeight); 178 | endShape(CLOSE); 179 | beginShape(); 180 | vertex(x1,y1,0); 181 | vertex(x4,y4,0); 182 | vertex(x4,y4,-blockHeight); 183 | vertex(x1,y1,-blockHeight); 184 | endShape(CLOSE); 185 | beginShape(); 186 | vertex(x2,y2,0); 187 | vertex(x3,y3,0); 188 | vertex(x3,y3,-blockHeight); 189 | vertex(x2,y2,-blockHeight); 190 | endShape(CLOSE); 191 | beginShape(); 192 | vertex(x1,y1,-blockHeight); 193 | vertex(x2,y2,-blockHeight); 194 | vertex(x3,y3,-blockHeight); 195 | vertex(x4,y4,-blockHeight); 196 | endShape(CLOSE); 197 | pop(); 198 | } 199 | 200 | // replacement technique : 201 | int K = 5; 202 | void show() 203 | { 204 | for(int ii=-2*K;ii [0,1], with a parameter g: 15 | // https://patakk.tumblr.com/post/88602945835/heres-a-simple-function-you-can-use-for-easing 16 | float ease(float p, float g) { 17 | if (p < 0.5) 18 | return 0.5 * pow(2*p, g); 19 | else 20 | return 1 - 0.5 * pow(2*(1 - p), g); 21 | } 22 | 23 | float c01(float x) 24 | { 25 | return min(1,max(0,x)); 26 | } 27 | 28 | void draw() 29 | { 30 | if (!recording) // test mode... 31 | { 32 | t = (mouseX*1.3/width)%1; 33 | c = mouseY*1.0/height; 34 | if (mousePressed) 35 | println(c); 36 | draw_(); 37 | } 38 | else // render mode... 39 | { 40 | for (int i=0; i=0) // if true, stop recursion 166 | { 167 | if(childIndex==0) // only show if it's a child 0 (not clean :( ) 168 | { 169 | // drawing a dot... 170 | float reduce = constrain(map(param,0.1,0,1,0),0,1)*1.15; // size change parameter if we're close to splitting 171 | strokeWeight(0.95*L*reduce); 172 | stroke(255); 173 | point(0,0); 174 | } 175 | } 176 | else 177 | { 178 | float growth = pow(constrain(map(param,0,-0.1,0,1),0,1),1.7); // size change parameter if we're close to splitting 179 | PVector pos = path2(p); 180 | pos.mult(0.5*L); 181 | push(); 182 | translate(pos.x,pos.y); 183 | 184 | scale(0.5); // with this scale change during recursions, we don't have to adjust pixel positions with factors 185 | scale(growth); // just for splitting, generally at one, no scale change here 186 | 187 | // to show yourself you show your children "one loop time ago" (p-1) 188 | for(int i=1;i [0,1], with a parameter g: 14 | // https://patakk.tumblr.com/post/88602945835/heres-a-simple-function-you-can-use-for-easing 15 | float ease(float p, float g) { 16 | if (p < 0.5) 17 | return 0.5 * pow(2*p, g); 18 | else 19 | return 1 - 0.5 * pow(2*(1 - p), g); 20 | } 21 | 22 | void draw() 23 | { 24 | if (!recording) // test mode... 25 | { 26 | t = (mouseX*1.3/width)%1; 27 | c = mouseY*1.0/height; 28 | if (mousePressed) 29 | println(c); 30 | draw_(); 31 | } 32 | else // render mode... 33 | { 34 | for (int i=0; inewCameraZ) 94 | { 95 | float dotDepthFromCamera = v.z-newCameraZ; 96 | 97 | // 3D -> 2D projection formulas : 98 | float x = viewZoom*v.x/dotDepthFromCamera; 99 | float y = viewZoom*v.y/dotDepthFromCamera; 100 | float sw = 400*sizeFactor/dotDepthFromCamera; 101 | 102 | strokeWeight(sw); 103 | point(x,y); 104 | } 105 | } 106 | 107 | // 2D spiral path with easing 108 | PVector spiralPath(float p) 109 | { 110 | p = constrain(1.2*p,0,1); // for large p we keep the same position at the end of the spiral 111 | p = ease(p,1.8); 112 | int numberOfSpiralTurns = 3; 113 | float theta = TWO_PI*numberOfSpiralTurns*sqrt(p); // sqrt to have smooth spiral curve parametrization 114 | float r = 170*sqrt(p); 115 | // x y from previous polar coordinates 116 | float x = r*cos(theta); 117 | float y = r*sin(theta); 118 | y += startDotYOffset; 119 | return new PVector(x,y); 120 | } 121 | 122 | // one particle 123 | class Star 124 | { 125 | // the random x and y displacements of the star on 2D screen 126 | float dx = 30*random(-1,1); 127 | float dy = 30*random(-1,1); 128 | 129 | float spiralLocation; // parameter for location on the spiral curve 130 | float strokeWeightFactor = pow(random(1),2.0); // random strokeWeight factor 131 | 132 | float z; // fixed z of the star 133 | 134 | Star() 135 | { 136 | z = random(0.5*cameraZ,cameraTravelDistance+cameraZ); // random star z between two bounds 137 | spiralLocation = (1-pow(1-random(1),3.0))/1.3; // location on the spiral curve parameter, with some nice random distribution 138 | z = lerp(z,cameraTravelDistance/2,0.3*spiralLocation); // changing z so that it's further from camera as the parameter of the spiral increases 139 | } 140 | 141 | void show(float p) // p (in [0,1]) increases with time 142 | { 143 | PVector spiralPos = spiralPath(spiralLocation); 144 | float q = p-spiralLocation; 145 | if(q>0) // show only if the time is further than spiral location 146 | { 147 | float displacementProgress = constrain(5*q,0,1); // progress to go to displaced positions, reaches maximum progress of 1 quickly in function of q 148 | float easing = 1-pow(1-displacementProgress,4.0); // easing for the travel to displaced postion (start fast then slow down) 149 | 150 | float screenX = lerp(spiralPos.x,spiralPos.x+dx,easing); 151 | float screenY = lerp(spiralPos.y,spiralPos.y+dy,easing); 152 | // this gave us 2D screen positions we want 153 | 154 | // now we want to find position in 3D space, to be at the star's z 155 | // to do that we invert the projection formulas 156 | float vx = (z-cameraZ)*screenX/viewZoom; 157 | float vy = (z-cameraZ)*screenY/viewZoom; 158 | // this is our 3D position 159 | PVector u = new PVector(vx,vy,z); 160 | 161 | float dotSize = 8.5*strokeWeightFactor; 162 | showProjectedDot(u,dotSize); // now we can project this 3D position to 2D screen and show it 163 | } 164 | } 165 | } 166 | 167 | void drawStartDot() 168 | { 169 | if(t>changeEventTime){ 170 | float dy = cameraZ*startDotYOffset/viewZoom; // some inverted projection again to get y position in 3D space 171 | PVector v = new PVector(0,dy,cameraTravelDistance); // 3D position 172 | showProjectedDot(v,2.5); 173 | } 174 | } 175 | 176 | Star [] array = new Star[numberOfStars]; 177 | 178 | void setup(){ 179 | size(500,500,P2D); 180 | result = new int[width*height][3]; 181 | 182 | randomSeed(1234); 183 | 184 | for(int i=0;i=1) return 1; 171 | return pow(2, -10 * x) * sin((x * 10 - 0.75) * c4) + 1; 172 | } 173 | 174 | void showDot(float p0, float vertexPositionOffset) 175 | { 176 | float p = p0 * numberOfStopPositions; // map p0 input from [0,1] to stop position index range 177 | float frc = (p+1234)%1; // fractional part indicating progress between 2 stop positions 178 | 179 | float moveProgression = constrain(3.8*frc, 0, 1); // speedup + constrain for blocked movement, makes the dots stop 180 | 181 | float q = (floor(p) + moveProgression)/numberOfStopPositions; // q in [0,1] indicates position on the curve 182 | PVector pos = position(q, vertexPositionOffset); 183 | 184 | // dot drawing parameters 185 | float sz = 10; 186 | float intensity = pow(sin(PI*moveProgression), 5.0); 187 | intensity = easeOutElastic(intensity); 188 | 189 | push(); 190 | translate(pos.x,pos.y); 191 | stroke(255); 192 | strokeWeight(1.0); 193 | fill(0); 194 | ellipse(0, 0, sz - 5*intensity, sz - 5*intensity); 195 | 196 | if(vertexPositionOffset == 0) // if first type of dot, show white dot in circle 197 | { 198 | strokeWeight(2.0+(sz-5)*intensity); 199 | point(0,0); 200 | } 201 | pop(); 202 | } 203 | 204 | // replacement technique (https://bleuje.com/tutorial4/) 205 | void showDotsReplacement() 206 | { 207 | int K = numberOfStopPositions - 7; // number of drawn dots, implies there will be 7 moving areas of changes :) 208 | 209 | for(int i=0;i [0,1], with a parameter g: 16 | // https://patakk.tumblr.com/post/88602945835/heres-a-simple-function-you-can-use-for-easing 17 | float ease(float p, float g) { 18 | if (p < 0.5) 19 | return 0.5 * pow(2*p, g); 20 | else 21 | return 1 - 0.5 * pow(2*(1 - p), g); 22 | } 23 | 24 | // defines a map function variant to constrain or not in target interval (exists in openFrameworks) 25 | float map(float x, float a, float b, float c, float d, boolean constr) 26 | { 27 | return constr ? constrain(map(x,a,b,c,d),min(c,d),max(c,d)) : map(x,a,b,c,d); 28 | } 29 | 30 | // short one to map an x from [a,b] to [0,1] and constrain 31 | float mp01(float x, float a, float b) 32 | { 33 | return map(x,a,b,0,1,true); 34 | } 35 | 36 | //----------------------------------- 37 | 38 | void draw() 39 | { 40 | if (!recording) // test mode... 41 | { 42 | t = (mouseX*1.3/width)%1; 43 | c = mouseY*1.0/height; 44 | if (mousePressed) 45 | println(c); 46 | draw_(); 47 | } 48 | else // render mode... 49 | { 50 | for (int i=0; i 0) 128 | { 129 | // 3D -> 2D projection formula 130 | float x2D = projectionFactor * position.x / zDistanceFromCamera; 131 | float y2D = projectionFactor * position.y / zDistanceFromCamera; 132 | 133 | PVector pixelPosition = new PVector(x2D,y2D); 134 | 135 | if(isDigit) 136 | { 137 | float textSz = 29; 138 | float scl = 0.1 * sizeFactor * projectionFactor / zDistanceFromCamera; // size change due to the 3D -> 2D projection 139 | 140 | push(); 141 | translate(pixelPosition.x -0.5*textSz/2, pixelPosition.y + 0.5*textSz/2); // slight correction translate 142 | scale(scl); 143 | rotate(0.03 * sin(TAU*(t-0.3)) * PI); // slight 2D rotation 144 | 145 | fill(255,alphaFactor2 * 275); 146 | noStroke(); 147 | textSize(textSz); 148 | 149 | text(digitValue,0,0); 150 | 151 | pop(); 152 | } 153 | else // simple dot, used for dashed curve drawing 154 | { 155 | float sz = sizeFactor * projectionFactor / zDistanceFromCamera; // size change due to the 3D -> 2D projection 156 | 157 | stroke(255,21 * alphaFactor2); 158 | strokeWeight(sz); 159 | 160 | point(pixelPosition.x,pixelPosition.y); 161 | } 162 | } 163 | } 164 | 165 | void showDashedCurve() 166 | { 167 | int dashParam = 20; // number of dots on each segment of the curve 168 | 169 | float R2 = 1.05*R; // larger sphere radius for dashed curve 170 | 171 | int m = 1000; 172 | for(int i=0;i dashParam) continue; // technique to skip drawing half of the time... 175 | 176 | // spherical coordinates 177 | float theta = map((i + 38 * t * float(dashParam)) % m, 0, m, 0, PI); // theta movement, with loop (%m) 178 | float phi = (t + 0.006) * TAU; 179 | 180 | // cartesian coordiantes from spherical coordinates 181 | float x = R2*sin(theta)*cos(phi); 182 | float y = R2*cos(theta); 183 | float z = R2*sin(theta)*sin(phi); 184 | 185 | PVector pos = new PVector(x,y,z); 186 | float sizeFactor = 0.73; 187 | boolean isDigit = false; 188 | float alphaFactor = 14.0; 189 | 190 | showParticle(pos, sizeFactor, isDigit, 0, alphaFactor); 191 | } 192 | 193 | 194 | // drawing the big dots at the sphere poles... 195 | PVector pole1Position = new PVector(0,R2,0); 196 | PVector pole2Position = new PVector(0,-R2,0); 197 | showParticle(pole1Position, 4, false, 0, 1000); 198 | showParticle(pole2Position, 4, false, 0, 1000); 199 | } 200 | 201 | class Digit 202 | { 203 | PVector position0; 204 | int digitValue; 205 | 206 | Digit(int i) 207 | { 208 | digitValue = i%10; 209 | 210 | // setting (x,y,z) position on black sphere (position at start and end) 211 | // using special formulas to get evenly distributed positions 212 | // see https://stackoverflow.com/a/26127012 213 | float phi = PI * (3. - sqrt(5.)); 214 | float theta = phi*i; 215 | float y = map(i,0,numberOfDigits-1,1,-1); 216 | float radius = sqrt(1 - y * y); 217 | y *= R; 218 | float x = cos(theta) * R * radius; 219 | float z = sin(theta) * R * radius; 220 | 221 | position0 = new PVector(x,y,z); 222 | } 223 | 224 | void show(float p) // p is the progress parameter in [0,1] 225 | { 226 | float delayFromAngle = atan2(position0.z,position0.x)/TAU; 227 | 228 | // without the replacement technique, the wave must pass 2 times 229 | // so the previous delay (delayFromAngle) must be divided by 2 230 | float delay = delayFromAngle / 2; 231 | 232 | float delayedP = (1234 + p - delay)%1; 233 | float angleChangeProgress = -pow(1-delayedP,2.0); // sudden angle change, and stops moving at the end 234 | // this formula was found with pen and paper, for it to match the wave speed 235 | 236 | // getting the position on sphere 237 | PVector position = rotY(position0, angleChangeProgress * TAU); 238 | 239 | 240 | // digit size style... 241 | float wo = (1234 - 4*p + delayFromAngle)%1; 242 | float wv = pow(c01(sin(PI*wo)),3.3); 243 | float sizeFactor = 2.8 + 1.3*wv; 244 | // size bump style stuff when starting to move 245 | float bumpMax = 0.5; 246 | float bump = 1 + bumpMax*pow(1-c01(27*delayedP),2.3); 247 | float bump2 = 1 + bumpMax*pow(1-c01(100*(1-delayedP)),2.0); 248 | 249 | float sizeFactor2 = sizeFactor * bump * bump2; 250 | boolean isDigit = true; 251 | float alphaFactor = 1.0; 252 | 253 | showParticle(position, sizeFactor2, isDigit, digitValue, alphaFactor); 254 | } 255 | 256 | // replacement technique (https://bleuje.com/tutorial4/) 257 | void show() 258 | { 259 | int K = 2; 260 | for(int i=0;i digitsArray = new ArrayList(); 268 | 269 | void setup() 270 | { 271 | size(600,600,P2D); 272 | result = new int[width*height][3]; 273 | smooth(8); 274 | 275 | // the font that was used, deactivated here so that it runs without the font file 276 | //mono = createFont("Manrope-Medium.ttf", 128); 277 | //textFont(mono); 278 | 279 | for(int i=0;i [0,1], with a parameter g: 14 | // https://patakk.tumblr.com/post/88602945835/heres-a-simple-function-you-can-use-for-easing 15 | float ease(float p, float g) { 16 | if (p < 0.5) 17 | return 0.5 * pow(2*p, g); 18 | else 19 | return 1 - 0.5 * pow(2*(1 - p), g); 20 | } 21 | 22 | void draw() 23 | { 24 | if (!recording) // test mode... 25 | { 26 | t = (mouseX*1.3/width)%1; 27 | c = mouseY*1.0/height; 28 | if (mousePressed) 29 | println(c); 30 | draw_(); 31 | } 32 | else // render mode... 33 | { 34 | for (int i=0; i y swap) 160 | if(level%2==0) positions[level-1] = new PVector(positions[level-1].y,positions[level-1].x); 161 | } 162 | } 163 | } 164 | 165 | Point [] array = new Point[n]; 166 | 167 | // go from v1 to v2 with rotation around their middle 168 | PVector rotater(PVector v1,PVector v2,float p,boolean orientation) // p is the progress in this interpolation, in [0,1] 169 | { 170 | PVector middle = v1.copy().add(v2).mult(0.5); 171 | PVector middleToV1 = v1.copy().sub(middle); 172 | 173 | float angle = atan2(middleToV1.y,middleToV1.x); 174 | float o = (orientation?-1:1); 175 | float r = middleToV1.mag(); 176 | 177 | return new PVector(middle.x+r*cos(angle+o*PI*p),middle.y+r*sin(angle+o*PI*p)); 178 | } 179 | 180 | // easing function taken from https://easings.net/#easeOutElastic 181 | float easeOutElastic(float x) 182 | { 183 | float c4 = (2*PI)/3; 184 | if(x<=0) return 0; 185 | if(x>=1) return 1; 186 | return pow(2, -10 * x) * sin((x * 10 - 0.75) * c4) + 1; 187 | } 188 | 189 | void drawCurve(float p) // p (in [0,1)) will simply be the time t 190 | { 191 | p = (p+12345-0.05)%1; // keep p in [0,1[, classic 12345 to make sure it's positive before modulo 192 | 193 | p = constrain(map(p,0,0.88,0,1),0,1); // transform p to do nothing for some time 194 | 195 | stroke(255); 196 | strokeWeight(1.4); 197 | noFill(); 198 | 199 | beginShape(); 200 | for(int i=0;i code here : https://gist.github.com/Bleuje/fce86ef35b66c4a2b6a469b27163591e 5 | // See the license information at the end of this file. 6 | // View the rendered result at: https://bleuje.com/gifanimationsite/single/spherewave/ 7 | 8 | ////////////////////////////////////////////////////////////////////////////// 9 | // Start of template 10 | 11 | int[][] result; // pixel colors buffer for motion blur 12 | float t; // time global variable in [0,1[ 13 | float c; // other global variable for testing things, controlled by mouse 14 | 15 | //----------------------------------- 16 | // some generally useful functions... 17 | 18 | float c01(float x) 19 | { 20 | return constrain(x,0,1); 21 | } 22 | 23 | // ease in and out, [0,1] -> [0,1], with a parameter g: 24 | // https://patakk.tumblr.com/post/88602945835/heres-a-simple-function-you-can-use-for-easing 25 | float ease(float p, float g) { 26 | if (p < 0.5) 27 | return 0.5 * pow(2*p, g); 28 | else 29 | return 1 - 0.5 * pow(2*(1 - p), g); 30 | } 31 | 32 | // defines a map function variant to constrain or not in target interval (exists in openFrameworks) 33 | float map(float x, float a, float b, float c, float d, boolean constr) 34 | { 35 | return constr ? constrain(map(x,a,b,c,d),min(c,d),max(c,d)) : map(x,a,b,c,d); 36 | } 37 | 38 | // short one to map an x from [a,b] to [0,1] and constrain 39 | float mp01(float x, float a, float b) 40 | { 41 | return map(x,a,b,0,1,true); 42 | } 43 | 44 | // reversed pow that does some kind of ease out, [0,1] -> [0,1], with a parameter g 45 | float pow_(float p,float g) 46 | { 47 | return 1-pow(1-p,g); 48 | } 49 | //----------------------------------- 50 | 51 | void draw() 52 | { 53 | if (!recording) // test mode... 54 | { 55 | t = (mouseX*1.3/width)%1; 56 | c = mouseY*1.0/height; 57 | if (mousePressed) 58 | println(c); 59 | draw_(); 60 | } 61 | else // render mode... 62 | { 63 | for (int i=0; i=1) return 1; 162 | return pow(2, -7 * x) * sin((x * 10 - 0.75) * c4) + 1; 163 | } 164 | 165 | class Particle 166 | { 167 | PVector pos1,pos2; 168 | float delay1; 169 | PVector orientation; 170 | float seed = random(10,1000); 171 | 172 | Particle(int i) 173 | { 174 | // setting (x,y,z) position on black sphere (position at start and end) 175 | // using special formulas to get evenly distributed positions 176 | // see https://stackoverflow.com/a/26127012 177 | float phi = PI * (3. - sqrt(5.)); 178 | float theta = phi*i; 179 | float y = map(i,0,n-1,1,-1); 180 | float radius = sqrt(1 - y * y); 181 | y *= blackSphereRadius; 182 | float x = cos(theta) * blackSphereRadius * radius; 183 | float z = sin(theta) * blackSphereRadius * radius; 184 | 185 | pos1 = new PVector(x,y,z); 186 | 187 | // orientation of rotation effect 188 | orientation = orienterField(pos1); 189 | 190 | float radius2 = blackSphereRadius+DR*pow(random(0.75)+0.25,1.4); 191 | pos2 = pos1.copy().normalize().mult(radius2); // position when particle left the black sphere 192 | // but so far without random displacement 193 | 194 | float pw = 2.0; 195 | float rd = random(1); 196 | float rd1 = mp01(rd,0,0.5); 197 | float rd2 = mp01(rd,0.5,1); 198 | float delay0 = 0.5*pow_(rd1,pw)+0.5*pow(rd2,pw); 199 | // delay for particles returning on the sphere with this offset, the above code defines a desired random distribution 200 | delay1 = delay0*0.45; 201 | } 202 | 203 | float sphereSize(float p) 204 | { 205 | float noiseRadius = 6.0; 206 | float ns = map((float)noise.eval(seed+noiseRadius*cos(TWO_PI*p),noiseRadius*sin(TWO_PI*p)),-1,1,0,1); 207 | return pow(ns,3.0)*2+0.5; 208 | } 209 | 210 | // noisy displacement 211 | PVector displacement(float p) 212 | { 213 | float noiseRadius = 1.4; 214 | float amplitude = 8; 215 | float noiseSpaceX = noiseRadius*cos(TWO_PI*p); 216 | float noiseSpaceY = noiseRadius*sin(TWO_PI*p); 217 | float dx = amplitude*(float)noise.eval(2*seed+noiseSpaceX,noiseSpaceY); 218 | float dy = amplitude*(float)noise.eval(3*seed+noiseSpaceX,noiseSpaceY); 219 | float dz = amplitude*(float)noise.eval(4*seed+noiseSpaceX,noiseSpaceY); 220 | // (looping noise but not a necessary property because the displacement is 0 at the begining) 221 | return new PVector(dx,dy,dz); 222 | } 223 | 224 | void show(float p) // p will just be the time t in [0,1] 225 | { 226 | p = (12345+p)%1; 227 | 228 | // IMPORTANT : time is reversed because I experimented and tried reversed time at some point (sorry about this) 229 | // 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 230 | p = 1-p; // maybe try without this line of code to understand it better 231 | 232 | // q is how much the particle left the black sphere 233 | float q = mp01(p-delay1,0,0.25); 234 | q = ease(q,3.0); 235 | 236 | // go from position on sphere to displaced position (when time is not reversed) 237 | PVector pos = pos1.copy().lerp(pos2.copy().add(displacement(p)),q); 238 | 239 | // diagonal delay for main effect 240 | float delay2 = 0.3 - map(0.5*pos.y-0.5*pos.x,-150,150,0,0.3); 241 | 242 | float q2 = mp01(p-delay2,0.3,0.7); 243 | q2 = 1-easeOutElastic(pow(1-q2,2.0)); 244 | 245 | // use rotater function and orientation to go back to position on sphere (when time is not reversed) 246 | PVector v = rotater(pos,pos1,q2,orientation); 247 | 248 | float sz = lerp(1.0,sphereSize(p),0.2+0.8*pow(c01(sin(PI*p)),1.5)); // controlling particle size through time 249 | 250 | v = bounder(v); // keep position outside of black sphere 251 | 252 | push(); 253 | translate(v.x,v.y,v.z); 254 | 255 | sphereDetail(5); 256 | fill(255); 257 | noStroke(); 258 | 259 | sphere(sz*0.82); 260 | 261 | pop(); 262 | } 263 | 264 | } 265 | 266 | Particle [] particlesArray = new Particle[n]; 267 | 268 | void setup(){ 269 | size(600,600,P3D); 270 | result = new int[width*height][3]; 271 | 272 | noise = new OpenSimplexNoise(1234); 273 | 274 | for(int i=0;i [0,1], with a parameter g: 16 | // https://patakk.tumblr.com/post/88602945835/heres-a-simple-function-you-can-use-for-easing 17 | float ease(float p, float g) { 18 | if (p < 0.5) 19 | return 0.5 * pow(2*p, g); 20 | else 21 | return 1 - 0.5 * pow(2*(1 - p), g); 22 | } 23 | 24 | void draw() 25 | { 26 | if (!recording) // test mode... 27 | { 28 | t = (mouseX*1.3/width)%1; 29 | c = mouseY*1.0/height; 30 | if (mousePressed) 31 | println(c); 32 | draw_(); 33 | } 34 | else // render mode... 35 | { 36 | for (int i=0; i mainPath = new ArrayList(); 84 | 85 | int largeGridSize = 7; 86 | int numberOfSimulationSteps = 1700; // simulation steps for small squares movements 87 | int smallSquareGridSize = 6; 88 | 89 | // small square 90 | class SmallSquare 91 | { 92 | PVector [] positions = new PVector[numberOfSimulationSteps+1]; 93 | } 94 | 95 | // an instance of this shows the whole thing, and there's only one instance so a class was not necessary 96 | class System 97 | { 98 | SmallSquare [] smallSquares = new SmallSquare[smallSquareGridSize*smallSquareGridSize]; 99 | 100 | int [][] indexAtPos = new int[smallSquareGridSize][smallSquareGridSize]; 101 | 102 | PVector holePos; 103 | 104 | System() 105 | { 106 | holePos = new PVector(floor(random(smallSquareGridSize)),floor(random(smallSquareGridSize))); 107 | 108 | int k = 0; 109 | for(int i=0;i0.001 || abs(holePos.y-j)>0.001) 114 | { 115 | smallSquares[k] = new SmallSquare(); 116 | smallSquares[k].positions[0] = new PVector(i,j); // initial position in grid 117 | indexAtPos[i][j] = k; // storing that at (i,j) we have the k-th smallSquare 118 | k++; 119 | } 120 | } 121 | } 122 | 123 | PVector comingFrom = new PVector(-100,-100); // dummy initial value for an (i,j) position in grid 124 | // this is used to avoid to have the small hole go back to its previous position 125 | 126 | // simulation in which we move the small hole of the grid and update the small squares positions 127 | for(int stepIndex=0;stepIndex=smallSquareGridSize) 148 | continue; 149 | // (continue implies going dreictly to next wile loop step) 150 | found = true; 151 | } 152 | if(direction==1) 153 | { 154 | target = new PVector(holePos.x+1,holePos.y); 155 | if(round(target.x)==round(comingFrom.x)&&round(target.y)==round(comingFrom.y)) 156 | continue; 157 | if(target.x<0||target.x>=smallSquareGridSize) 158 | continue; 159 | found = true; 160 | } 161 | if(direction==2) 162 | { 163 | target = new PVector(holePos.x,holePos.y-1); 164 | if(round(target.x)==round(comingFrom.x)&&round(target.y)==round(comingFrom.y)) 165 | continue; 166 | if(target.y<0||target.y>=smallSquareGridSize) 167 | continue; 168 | found = true; 169 | } 170 | if(direction==3) 171 | { 172 | target = new PVector(holePos.x,holePos.y+1); 173 | if(round(target.x)==round(comingFrom.x)&&round(target.y)==round(comingFrom.y)) 174 | continue; 175 | if(target.y<0||target.y>=smallSquareGridSize) 176 | continue; 177 | found = true; 178 | } 179 | 180 | if(found) 181 | { 182 | PVector aux = holePos; 183 | holePos = target; 184 | previousHolePos = aux; 185 | availablePositionWasNotFound = false; 186 | } 187 | } 188 | 189 | int smallSquareIndexAtHole = indexAtPos[round(holePos.x)][round(holePos.y)]; 190 | // (we haven't moved the small squares yet) 191 | 192 | // we update indexAtPos because this small square takes the position of the previous hole position 193 | indexAtPos[round(previousHolePos.x)][round(previousHolePos.y)] = smallSquareIndexAtHole; 194 | // we update the position of the hole at the simulation step 195 | smallSquares[smallSquareIndexAtHole].positions[stepIndex+1] = previousHolePos; 196 | // we update the positions of the other small squares (it stays the same) 197 | for(int e=0;e<(smallSquareGridSize*smallSquareGridSize-1);e++) 198 | { 199 | if(e!=smallSquareIndexAtHole) 200 | { 201 | smallSquares[e].positions[stepIndex+1] = smallSquares[e].positions[stepIndex]; 202 | } 203 | } 204 | 205 | comingFrom = previousHolePos; 206 | } 207 | 208 | } 209 | 210 | 211 | 212 | void showGrid(float p) // p progressing in range [0,1] 213 | { 214 | p = lerp(p,ease(p,1.8),0.6); // easing mixed with no easing 215 | // this easing makes holes move faster in the center 216 | 217 | // preparing linear interpolation for small squares movement (but most won't move because we interpolate between two same positions) 218 | float floatIndex = 0.9999*numberOfSimulationSteps*p; 219 | int stepIndex1 = floor(floatIndex); 220 | int stepIndex2 = stepIndex1+1; 221 | float frac = floatIndex-stepIndex1; 222 | 223 | for(int e=0;e<(smallSquareGridSize*smallSquareGridSize-1);e++) 224 | { 225 | PVector pos1 = smallSquares[e].positions[stepIndex1]; 226 | PVector pos2 = smallSquares[e].positions[stepIndex2]; 227 | PVector pos = pos1.copy().lerp(pos2,ease(frac,1.7)); // interpolation done, easing for smooth movement 228 | 229 | // converting to pixel position 230 | pos.add(new PVector(-smallSquareGridSize/2.0+0.5,-smallSquareGridSize/2.0+0.5)); 231 | float A = 14.25; 232 | pos.mult(A); 233 | 234 | // drawing one small square 235 | push(); 236 | translate(pos.x,pos.y); 237 | fill(0); 238 | rectMode(CENTER); 239 | stroke(255); 240 | strokeWeight(1.75); 241 | rect(0,0,9,9); 242 | pop(); 243 | } 244 | } 245 | 246 | // interpolation between two main path positions, with easing 247 | PVector mainPathPos(float p) // here p is in range [0,1] 248 | { 249 | float floatIndex = p*(mainPath.size()-1)*0.999999; 250 | int ind1 = floor(floatIndex); 251 | int ind2 = ind1+1; 252 | float frac = floatIndex-ind1; 253 | 254 | PVector pos1 = mainPath.get(ind1); 255 | PVector pos2 = mainPath.get(ind2); 256 | 257 | float interp = ease(constrain(9*frac,0,1),2.2); // we stop for a long time after moving 258 | 259 | return pos1.copy().lerp(pos2,interp); 260 | } 261 | 262 | PVector mainPathPosToPixelPos(PVector integerPos) 263 | { 264 | float px = map(0.5+integerPos.x,0,largeGridSize,-width/2,width/2); 265 | float py = map(0.5+integerPos.y,0,largeGridSize,0-height/2,height/2); 266 | return new PVector(px,py); 267 | } 268 | 269 | void show(float p) 270 | { 271 | PVector pos = mainPathPos(p); 272 | PVector pixelPos = mainPathPosToPixelPos(pos); // (i,j) to pixel position 273 | 274 | push(); 275 | translate(pixelPos.x,pixelPos.y); 276 | showGrid(p); 277 | pop(); 278 | } 279 | 280 | // replacement technique 281 | int numberOfDrawnGrids = mainPath.size()-5; // (with replacement technique) 282 | void show() 283 | { 284 | for(int i=0;i [0,1], with a parameter g: 25 | // https://patakk.tumblr.com/post/88602945835/heres-a-simple-function-you-can-use-for-easing 26 | float ease(float p, float g) { 27 | if (p < 0.5) 28 | return 0.5 * pow(2*p, g); 29 | else 30 | return 1 - 0.5 * pow(2*(1 - p), g); 31 | } 32 | 33 | // defines a map function variant to constrain or not in target interval (exists in openFrameworks) 34 | float map(float x, float a, float b, float c, float d, boolean constr) 35 | { 36 | return constr ? constrain(map(x,a,b,c,d),min(c,d),max(c,d)) : map(x,a,b,c,d); 37 | } 38 | 39 | //----------------------------------- 40 | 41 | void draw() 42 | { 43 | if (!recording) // test mode... 44 | { 45 | t = (mouseX*1.3/width)%1; 46 | c = mouseY*1.0/height; 47 | if (mousePressed) 48 | println(c); 49 | draw_(); 50 | } 51 | else // render mode... 52 | { 53 | for (int i=0; i cubes; 327 | 328 | PFont chosenFont; 329 | 330 | void setup() 331 | { 332 | size(800,800,P3D); 333 | result = new int[width*height][3]; 334 | smooth(8); 335 | ortho(); // isometric view activated 336 | 337 | chosenFont = createFont("ChakraPetch-Medium.ttf", 128); 338 | textFont(chosenFont); 339 | 340 | cubes = new ArrayList(); 341 | 342 | for(int i=-nCubesGrid;i<=nCubesGrid;i++) 343 | { 344 | for(int j=-nCubesGrid;j<=nCubesGrid;j++) 345 | { 346 | cubes.add(new Cube(i,j)); 347 | } 348 | } 349 | } 350 | 351 | 352 | void draw_() 353 | { 354 | background(0); 355 | push(); 356 | translate(width/2,height/2,-1000); // drawing far from camera to avoid glitch when stuff is too close to camera 357 | // (because of ortho(), it doesn't affect drawing other than correcting glitch) 358 | 359 | scale(800.0/600); // it was coded for width and height = 600, now rescaling for other resolution (800) 360 | 361 | // camera view... 362 | rotateX(0.307*PI); // angle that works for the good "optical illusion"/clean cubes layout that blends with floor grid 363 | rotateZ(0.75*PI); 364 | 365 | drawFloorGrid(); 366 | 367 | for(Cube cube : cubes) 368 | { 369 | cube.show(); 370 | } 371 | 372 | pop(); 373 | } 374 | 375 | 376 | /* License: 377 | * 378 | * Copyright (c) 2024 Etienne Jacob 379 | * 380 | * All rights reserved. 381 | * 382 | * This code after the template and the related animations are the property of the 383 | * copyright holder. Any reproduction, distribution, or use of this material, 384 | * in whole or in part, without the express written permission of the copyright 385 | * holder is strictly prohibited. 386 | */ 387 | -------------------------------------------------------------------------------- /code/toruscurve/toruscurve.pde: -------------------------------------------------------------------------------- 1 | // Processing code by Etienne Jacob 2 | // motion blur template by beesandbombs, explanation/article: https://bleuje.com/tutorial6/ 3 | // See the license information at the end of this file. 4 | // View the rendered result at: https://bleuje.com/gifanimationsite/single/toruscurve/ 5 | 6 | // slow to render/show 7 | // I think the distortion effect makes it a lot more difficult to understand completely 8 | // unfinished commenting 9 | 10 | ////////////////////////////////////////////////////////////////////////////// 11 | // Start of template 12 | 13 | int[][] result; // pixel colors buffer for motion blur 14 | float t; // time global variable in [0,1[ 15 | float c; // other global variable for testing things, controlled by mouse 16 | 17 | float c01(float x) 18 | { 19 | return constrain(x,0,1); 20 | } 21 | 22 | // ease in and out, [0,1] -> [0,1], with a parameter g: 23 | // https://patakk.tumblr.com/post/88602945835/heres-a-simple-function-you-can-use-for-easing 24 | float ease(float p, float g) { 25 | if (p < 0.5) 26 | return 0.5 * pow(2*p, g); 27 | else 28 | return 1 - 0.5 * pow(2*(1 - p), g); 29 | } 30 | 31 | void draw() 32 | { 33 | if (!recording) // test mode... 34 | { 35 | t = (mouseX*1.3/width)%1; 36 | c = mouseY*1.0/height; 37 | if (mousePressed) 38 | println(c); 39 | draw_(); 40 | } 41 | else // render mode... 42 | { 43 | for (int i=0; i [0,1], with a parameter g: 14 | // https://patakk.tumblr.com/post/88602945835/heres-a-simple-function-you-can-use-for-easing 15 | float ease(float p, float g) { 16 | if (p < 0.5) 17 | return 0.5 * pow(2*p, g); 18 | else 19 | return 1 - 0.5 * pow(2*(1 - p), g); 20 | } 21 | 22 | void draw() 23 | { 24 | if (!recording) // test mode... 25 | { 26 | t = (mouseX*1.3/width)%1; 27 | c = mouseY*1.0/height; 28 | if (mousePressed) 29 | println(c); 30 | draw_(); 31 | } 32 | else // render mode... 33 | { 34 | for (int i=0; i=-HALF_PI-QUARTER_PI-eps)&&(angleToLocalCenter<=-HALF_PI+QUARTER_PI-eps)) return new PVector(i+1,j); 119 | if((angleToLocalCenter>=-HALF_PI+QUARTER_PI-eps)&&(angleToLocalCenter<=QUARTER_PI-eps)) return new PVector(i,j+1); 120 | if((angleToLocalCenter>=QUARTER_PI-eps)&&(angleToLocalCenter<=QUARTER_PI+HALF_PI-eps)) return new PVector(i-1,j); 121 | else return new PVector(i,j-1); 122 | } 123 | else // same thing as previous if branch but opposite direction 124 | { 125 | if((angleToLocalCenter>=-HALF_PI-QUARTER_PI+eps)&&(angleToLocalCenter<=-HALF_PI+QUARTER_PI+eps)) return new PVector(i-1,j); 126 | if((angleToLocalCenter>=-HALF_PI+QUARTER_PI+eps)&&(angleToLocalCenter<=QUARTER_PI+eps)) return new PVector(i,j-1); 127 | if((angleToLocalCenter>=QUARTER_PI+eps)&&(angleToLocalCenter<=QUARTER_PI+HALF_PI+eps)) return new PVector(i+1,j); 128 | else return new PVector(i,j+1); 129 | } 130 | } 131 | return new PVector(0,0); // dummy value that will never be returned because we will always have a mainType of 0, 1 or 2 and fall into previous ifs 132 | } 133 | 134 | 135 | 136 | // "slices" pattern : 137 | /* the slices looks like this, the rotation direction changes every other slice 138 | 139 | -- -- 140 | || || 141 | || || 142 | || || 143 | || || 144 | -- -- 145 | 146 | */ 147 | // a and b are "local" i and j, i and j are the global position 148 | PVector sliceNextPosition(int a,int b,int i, int j,int Height) 149 | { 150 | if((i/2)%2==0) // "every other slice" 151 | { 152 | // in the 4 following lines, hard coded next positions on the 4 corner positions (top and bottom of the slice) 153 | if((b==0)&&(a%2==0)) return new PVector(i+1,j); 154 | if((b==0)&&(a%2==1)) return new PVector(i,j+1); 155 | if((b==Height-1)&&(a%2==0)) return new PVector(i,j-1); 156 | if((b==Height-1)&&(a%2==1)) return new PVector(i-1,j); 157 | // for other positions just go down or up depending on the side we're on 158 | if(a%2==0) return new PVector(i,j-1); 159 | if(a%2==1) return new PVector(i,j+1); 160 | } 161 | else // same as previous case but other direction 162 | { 163 | if((b==0)&&(a%2==0)) return new PVector(i,j+1); 164 | if((b==0)&&(a%2==1)) return new PVector(i-1,j); 165 | if((b==Height-1)&&(a%2==0)) return new PVector(i+1,j); 166 | if((b==Height-1)&&(a%2==1)) return new PVector(i,j-1); 167 | 168 | if(a%2==0) return new PVector(i,j+1); 169 | if(a%2==1) return new PVector(i,j-1); 170 | } 171 | return new PVector(0,0); 172 | } 173 | 174 | int numPositionsPerMove = 3; // 3 means we go 2 positions further using the current next positions pattern 175 | int numberOfPatterns = 3; 176 | float transitionTime = 0.27; // fraction of time used for each particle move. Because we have 3 patterns so 3 moves, it can't be larger than 1/3 = 0.333333 177 | // (also has to be smaller than 1/3 due to position change that can create a move request earlier than the one on position before move) 178 | 179 | float iterationsPerCycle = 2000; // simulation quality. timeStep = 1.0/iterationsPerCycle later; 180 | int numberOfRepeats = 4; // repeating the loop many times to try to achieve stability and perfect looping 181 | float time = 0; // will be incremented during simulation 182 | 183 | 184 | // class to have the list of positions of each move, 185 | // and a function ("unMappedPosition") to give the continuous change of position from continuous time 186 | class Move 187 | { 188 | int start_i; 189 | int start_j; 190 | int type; 191 | float startTime,endTime; 192 | PVector endPos; 193 | 194 | PVector [] path = new PVector[numPositionsPerMove]; 195 | 196 | Move(PVector startPos,int type_,float tm) 197 | { 198 | start_i = round(startPos.x); 199 | start_j = round(startPos.y); 200 | type = type_; 201 | startTime = tm; 202 | endTime = startTime+transitionTime; 203 | 204 | 205 | // finding the move's path iteratively, using the next positions field... 206 | int curi = start_i; 207 | int curj = start_j; 208 | for(int k=0;k positions = new ArrayList(); // not in pixels, just with grid indices 267 | 268 | void update() // simulation update 269 | { 270 | // if we're not moving we check is the waves trigger a new move 271 | if(!isMoving && time >= triggerer(currentPos,doneMoves)) 272 | { 273 | currentMove = new Move(currentPos,doneMoves%numberOfPatterns,time); 274 | isMoving = true; 275 | doneMoves++; 276 | } 277 | else if(isMoving && time >= currentMove.endTime) // if we were moving we check if we're now past the move's endTime, in this case we set isMoving to false 278 | { 279 | isMoving = false; 280 | currentPos = currentMove.endPos; 281 | } 282 | 283 | // now adding the current position to the list 284 | if(!isMoving) 285 | { 286 | positions.add(currentPos); 287 | } 288 | else 289 | { 290 | positions.add(currentMove.unMappedPosition(time)); // when we're moving, the Move class has a member function to give position in function of time 291 | } 292 | } 293 | 294 | 295 | 296 | // show() using the list of positions from simulation to get position at any time of the loop, 297 | // with linear interpolation, 298 | // using positions of the last cycle of the simulation 299 | void show() 300 | { 301 | float t2 = (t+(numberOfRepeats-1))*0.9999999; 302 | float ifl = iterationsPerCycle*t2; 303 | int i1 = floor(ifl); 304 | int i2 = i1+1; 305 | float lp = ifl-i1; 306 | 307 | PVector v1 = positions.get(i1); 308 | PVector v2 = positions.get(i2); 309 | 310 | PVector u = v1.copy().lerp(v2,lp); 311 | 312 | PVector pixelPos = convertToPixelPosition(u.x,u.y); 313 | 314 | // design : drawing the particle with an ellipse with a smaller white dot inside it 315 | stroke(255); 316 | strokeWeight(1.5); 317 | fill(0); 318 | ellipse(pixelPos.x,pixelPos.y,12,12); 319 | 320 | strokeWeight(2.6); 321 | point(pixelPos.x,pixelPos.y); 322 | } 323 | } 324 | 325 | Particle [][] array = new Particle[gridSize][gridSize]; 326 | 327 | void simulate() 328 | { 329 | println("Starting simulation..."); 330 | float timeStep = 1.0/iterationsPerCycle; 331 | for(int k=0;k