The Fountain of Polaris
About this creative coding animation.
It's an animation made with Processing programming language and Kdenlive video editor.I tried to express the water droplet in this code. And I learned about 3D light also.
Thanks to nice music:
Juillet by Monplaisir
2017/03/17
http://freemusicarchive.org/music/Monplaisir/A_Monplaisir_Best-Of__Lets_hear_that_crap/Monplaisir_-_A_Monplaisir_Best-of__Lets_here_that_crap_-_17_Juillet
Juillet by Monplaisir is licensed under a CC0 1.0 Universal License.
For more permissions:
contact artist
Processing example code.
// The Fountain of Polaris
// Processing 3.2.1
// 2017.04.19
import java.util.Random;
Utils ut;
World wd;
FountainSurface fs;
FloatingDrops[] fd;
int NUM_FLOAT_LINE = 3;
float BACK_WIDTH = 500;
float BACK_HEIGHT = 500;
float FOUNTAIN_RADIUS = 190;
/* ---------------------------------------------------------------------- */
class World {
StarElement st;
PVector[] locateStars;
float[] brightStars, colorStars;
float[] noiseBF;
int numStars;
World() {
numStars = 240;
st = new StarElement();
st.setElementFill(230, 75, 30, 10);
float divWidth = width / numStars;
locateStars = new PVector[numStars];
brightStars = new float[numStars];
colorStars = new float[numStars];
noiseBF = new float[numStars];
for (int i = 0; i < numStars; ++i) {
locateStars[i] = new PVector(
map(i, 0, numStars - 1, -width, width),
ut.gaussdist(-height / 5, height * 2 / 3, height / 2),
ut.gaussdist(-700, 400, 150)
);
brightStars[i] = ut.gaussdist(60, 20, 15);
colorStars[i] = ut.gaussdist(200, 40, 20);
noiseBF[i] = random(numStars);
}
}
void redraw() {
// draw smoke
strokeWeight(3);
for (float i = height; i > 0; --i) {
stroke(
map(i, height, 0, 160, 220),
80,
map(i, height, 0, 25, 0),
100
);
pushMatrix();
translate(0, i, -500);
line(-width, 0, width, 0);
popMatrix();
}
noStroke();
// draw stars
for (int i = 0; i < numStars; ++i) {
pushMatrix();
translate(locateStars[i].x, locateStars[i].y, locateStars[i].z);
// st.changeBright(ut.gaussdist(brightStars[i], 40, 8));
st.changeBright(brightStars[i] + map(ut.sigmoid(noise(noiseBF[i]), 2.0, 5.0), 0, 1, -20, 40));
st.changeColor(colorStars[i]);
st.show();
popMatrix();
noiseBF[i] += 0.05;
}
// for half surface & diagonally drops flow
rotateX(PI/2);
rotateZ(PI/10);
rotateY(PI/8);
}
}
/* ---------------------------------------------------------------------- */
class FountainSurface {
SurfaceElement se;
PVector locateSe;
float radiusV;
float divIdo, divKdo;
float noiseCIS, noiseCKS;
float noiseSIS, noiseSKS;
float noiseBIS, noiseBKS;
FountainSurface() {
radiusV = FOUNTAIN_RADIUS * 0.99;
divIdo = 2;
divKdo = 0; // dummy
noiseCIS = random(50);
noiseCKS = random(50);
noiseSIS = random(50);
noiseSKS = random(50);
noiseBIS = random(50);
noiseBKS = random(50);
se = new SurfaceElement();
se.setElementFill(0, 0, 0, 0);
se.changeSize(divIdo * 3.55, divIdo * 4.10, 1);
locateSe = new PVector(0, 0, 0);
}
void makeSurface() {
float ido, kdo;
float radianIdo, radianKdo;
noiseCKS += 0.006;
noiseCIS += 0.012;
noiseSKS += 0.016;
noiseSIS -= 0.008;
noiseBKS -= 0.018;
noiseBIS += 0.018;
float noiseCIF = noiseCIS;
float noiseSIF = noiseSIS;
float noiseBIF = noiseBIS;
for (ido = 0; ido <=180; ido += divIdo) { // Y
radianIdo = radians(ido);
divKdo = 180 / max(160 / divIdo * sin(radianIdo), 1);
float noiseCKF = noiseCKS;
float noiseSKF = noiseSKS;
float noiseBKF = noiseBKS;
for (kdo = 0; kdo <= 150; kdo += divKdo) { // Z
// for (kdo = 0; kdo <= 360; kdo += divKdo) { // Z
// element point
radianKdo = radians(kdo);
locateSe.set(
radiusV * cos(radianKdo) * sin(radianIdo),
radiusV * sin(radianKdo) * sin(radianIdo),
radiusV * cos(radianIdo)
);
se.setElementFill(
map(noise(noiseCIF, noiseCKF), 0, 1, 180, 255),
map(noise(noiseSIF, noiseSKF), 0, 1, 60, 110),
map(noise(noiseBIF, noiseBKF), 0, 1, 10, 50),
80
);
pushMatrix();
translate(locateSe.x, locateSe.y, locateSe.z);
rotateZ(radianKdo); // must be this order Z -> Y
rotateY(radianIdo);
se.show();
popMatrix();
noiseCKF += 0.020;
noiseSKF += 0.008;
noiseBKF += 0.012;
}
noiseCIF += 0.010;
noiseSIF += 0.016;
noiseBIF += 0.012;
}
}
void makeSphere() {
pushMatrix();
translate(0, 0, 0);
fill(240, 100, 20, 50);
sphere(FOUNTAIN_RADIUS);
popMatrix();
}
}
/* ---------------------------------------------------------------------- */
class FloatingDrops {
DropElement[] dp;
PVector[] locateDp;
int numDrops;
float radiusV;
float noiseRIS, noiseRKS, noiseRRS;
float speedRotation;
FloatingDrops() {
numDrops = 120;
radiusV = FOUNTAIN_RADIUS * 1.2;
noiseRIS = random(50);
noiseRKS = random(50);
noiseRRS = random(50);
dp = new DropElement[numDrops];
locateDp = new PVector[numDrops];
for (int cntDrop = 0; cntDrop < numDrops; ++cntDrop) {
float rnd = ut.gaussdist(3.0, 2.0, 1.5);
dp[cntDrop] = new DropElement();
dp[cntDrop].changeSize(
rnd,
rnd * ut.gaussdist(1.0, 0.3, 0.1),
rnd * ut.gaussdist(1.0, 0.4, 0.2)
);
dp[cntDrop].setElementFill(210,
map(rnd, 0, 7, 55, 75),
60,
100);
locateDp[cntDrop] = new PVector(0, 0, 0);
}
speedRotation = 0;
}
void floatDrops() {
noiseRIS += 0.003;
noiseRKS += 0.001;
noiseRRS += 0.008;
float ido, kdo;
float radianIdo, radianKdo;
float fnumDrops = numDrops - 1.0;
float noiseRIF = noiseRIS;
float noiseRKF = noiseRKS;
float noiseRRF = noiseRRS;
for (int cntDrop = 0; cntDrop < numDrops; ++cntDrop) {
float divZ = 0.3 + pow(2.6 * (cntDrop / fnumDrops - 0.5), 2);
ido = map(cntDrop, 0., fnumDrops, 30.0, 150.0) *
map(noise(noiseRIF), 0, 1, 0.8, 1.2);
kdo = map(cntDrop, 0., fnumDrops, 580.0, -430.0) *
map(noise(noiseRKF), 0, 1, 0.8, 1.2);
radiusV = FOUNTAIN_RADIUS * map(noise(noiseRRF), 0, 1, 1.20, 1.50);
radianIdo = radians(ido);
radianKdo = radians(kdo);
locateDp[cntDrop].set(
radiusV * cos(radianKdo) * sin(radianIdo),
radiusV * sin(radianKdo) * sin(radianIdo),
radiusV * cos(radianIdo) * divZ
);
pushMatrix();
rotateZ(radians(speedRotation));
translate(locateDp[cntDrop].x, locateDp[cntDrop].y, locateDp[cntDrop].z);
dp[cntDrop].rotate(0.03, 0.012, 0.08);
dp[cntDrop].show();
popMatrix();
noiseRIF += 0.18;
noiseRKF += 0.25;
noiseRRF += 0.02;
}
speedRotation += 0.25;
}
}
/* ---------------------------------------------------------------------- */
abstract class FountainElement {
PShape anElement;
float elementColor, elementSaturation, elementBright, elementAlpha;
FountainElement() {
anElement = pscreateElement();
elementColor = 0;
elementSaturation = 0;
elementBright = 0;
elementAlpha = 0;
}
abstract PShape pscreateElement();
void setElementFill(float pcolor, float psaturation, float pbright, float palpha) {
elementColor = pcolor;
elementSaturation = psaturation;
elementBright = pbright;
elementAlpha = palpha;
resetColor();
}
void resetColor() {
anElement.setFill(color(elementColor, elementSaturation, elementBright, elementAlpha));
}
void changeColor(float scolor) {
elementColor = scolor;
resetColor();
}
void changeBright(float sbright) {
elementBright = sbright;
resetColor();
}
void resetSize() {
anElement.resetMatrix();
}
void changeSize(float scaleX, float scaleY, float scaleZ) {
anElement.scale(scaleX, scaleY, scaleZ);
}
void rotate(float radX, float radY, float radZ) {
anElement.rotateX(radX);
anElement.rotateY(radY);
anElement.rotateZ(radZ);
}
void show() {
shape(anElement);
}
}
/* ---------------------------------------------------------------------- */
class SurfaceElement extends FountainElement {
SurfaceElement() {
super();
}
PShape pscreateElement() {
noStroke();
PShape psSe = createShape(RECT, 0, 0, 1, 1);
return psSe;
}
}
/* ---------------------------------------------------------------------- */
class DropElement extends FountainElement {
DropElement() {
super();
}
PShape pscreateElement() {
noStroke();
PShape psDp = createShape(SPHERE, 1);
return psDp;
}
}
/* ---------------------------------------------------------------------- */
class StarElement extends FountainElement {
StarElement() {
super();
}
PShape pscreateElement() {
noStroke();
PShape psDp = createShape(GROUP);
PShape psCh;
for (int i = 0; i < 5; ++i) {
float rad = 1 + i * i;
psCh = createShape(ELLIPSE, 0, 0, rad, rad);
psDp.addChild(psCh);
}
return psDp;
}
}
/* ---------------------------------------------------------------------- */
class Utils {
Random obj_random;
Utils() {
obj_random = new Random();
}
float sigmoid(float x, float pcenter, float pgradient) {
/**
Sigmoid function
1.parameters.
x : 1 > x value > 0
pcenter : center of curve. 1 - 1 / pcenter
ex. 10 > pcenter > 1 : 0.9 > center of curve > 0
pgradient : gradient of curve.
ex. 20 > pgradient > 4 : steep > gradient of curve > gentle
2.return.
1 > y value > 0
**/
float modx = pcenter * (x - 1) + 1;
return (float)(1.0 / (1.0 + Math.exp(-modx * pgradient)));
}
float gaussdist(float pmean, float plimit, float pdevi) {
/**
Gaussian distribution
1.parameters.
pmean : mean value
plimit : max value of abs(deviation)
ex. plimit >= 0
pmean = 0.5, plimit = 0.5 -> return value = from 0.0 to 1.0
pdevi : standard deviation value
ex. good value? -> pdevi = plimit / 2
2.return.
gaussian distribution
**/
if (plimit == 0) {
return pmean;
}
float gauss = (float) obj_random.nextGaussian() * pdevi;
// not good idea
if (abs(gauss) > plimit) {
gauss = pow(plimit, 2) / gauss;
}
return pmean + gauss;
}
}
/* ---------------------------------------------------------------------- */
void setup() {
size(1280, 720, P3D);
colorMode(HSB, 360, 100, 100, 100);
smooth();
background(0, 0, 0);
frameRate(30);
ut = new Utils();
wd = new World();
fs = new FountainSurface();
fd = new FloatingDrops[NUM_FLOAT_LINE];
for (int i = 0; i < NUM_FLOAT_LINE; ++i) {
fd[i] = new FloatingDrops();
}
}
void draw() {
background(0, 0, 0);
translate(0, 0, 0);
camera(0, 0, 600,
0, 0, 0,
0, 1, 0);
lightFalloff(0.3, 0.0008, 0.0);
pointLight(0, 0, 100, -80, -140, 300);
ambientLight(0, 0, 60);
wd.redraw();
for (int i = 0; i < NUM_FLOAT_LINE; ++i) {
fd[i].floatDrops();
}
fs.makeSurface();
fs.makeSphere();
saveFrame("frames/####.png");
if (frameCount >= 4590) {
exit();
}
}
/*
Copyright (C) 2017- deconbatch
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see
*/


