Cutting Glass Curtain


About this video.

It's a generative art made with Processing programming language and Kdenlive video editor.
It creates moving cutting glass animation.

Thanks to nice music:
Warm Breeze by Evan Schaeffer
2015/02/21
http://freemusicarchive.org/music/Evan_Schaeffer/Glow_1216/Evan_Schaeffer_-_06_-_Warm_Breeze
Warm Breeze by Evan Schaeffer is licensed under a Attribution License.
For more permissions:
contact artist


クリエイティブ・コモンズ・ライセンス

Processing example codes.

I tried to draw these shape with Gaussian distribution and Sigmoid function.

Code ver. 180318 Refactoring done.

Why I wrote such complex code like ver 170320?

// Cutting Glass Handkerchief 2
// Processing 3.2.1
// 2018.03.18

import java.util.Random;

void setup() {
  size(900, 900, P3D);
  colorMode(HSB, 360, 100, 100, 100);
  blendMode(SCREEN);
  hint(DISABLE_DEPTH_TEST);
  noFill();
  smooth(8);
  noLoop();
  //  frameRate(1);
}

void draw() {

  background(0, 0, 0);
  ambientLight(0, 0, 100);
  camera(0, 0, 900,
         0, 0, 0,
         0, 1, 0);


  int spacing = ceil(random(15, 25));
  float sizeRate =random(0.8, 1.0);
  float distanceMax = sqrt(width * width / 4 + height * height / 4);
  float hueBase = random(360);
  float nxStart = random(100);
  float nyStart = random(100);
  
  for (float z = 360; z >= 0; z -= 120) {
    float nx = nxStart;
    for (int x = -width / 2; x < width / 2; x += spacing) {
      float ny = nyStart;
      for (int y = -height / 2; y < height / 2; y += spacing) {

        float distance = sqrt(x*x+y*y) + 1;
        float hueDiv = min(45, 6 * distanceMax / distance);
        if (hueBase > 50 && hueBase < 160) {
          // yellow and green
          hueDiv += 15;
        }
        
        stroke(
               (hueBase + map(random(1), 0, 1, -hueDiv, hueDiv)) % 360,
               map(random(1), 0, 1, 10, 80),
               (2 + gaussdist(1.5, 1.0, 0.5) * distance / distanceMax) * spacing,
               100
               );
        
        pushMatrix();
        translate(x, y, -z + map(noise(nx, ny), 0, 1, -100 , 100));
        strokeWeight(2);
        rect(-spacing * sizeRate/2, -spacing * sizeRate/2, spacing * sizeRate, spacing * sizeRate);
        strokeWeight(2);
        ellipse(0, 0, spacing * sizeRate * 0.7, spacing * sizeRate * 0.7);
        popMatrix();

        ny += 0.0005 * spacing;

      }

      nx += 0.0005 * spacing;

    }
  }
  
  saveFrame("frames/####.png");
  exit();

}

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
  **/

  Random obj_random = new Random();
    
  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;
    
}

/*
Copyright (C) 2018 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 
*/




Code ver. 170320


// Cutting Glass Curtain
// Processing 3.2.1
// 2017.03.20
import processing.opengl.*;
import java.util.Random;

World wd;
Particle[] pt;

int pline = 35;  // line number of particles
int pcolumn = 63; // column number of particles
int divline = 8;
int divcolumn = divline;
int pwidth = divline;
int pnum = pline * pcolumn;
float nl_start, nc_start;

void setup() {
  size(1280, 720, OPENGL);
  colorMode(HSB, 360, 100, 100, 100);
  blendMode(SCREEN);
  hint(DISABLE_DEPTH_TEST);
  noStroke();
  smooth();
  //  noLoop();
  frameRate(20);

  // noise for curtain fluttering
  nl_start = random(100);
  nc_start = random(100);

  wd = new World();
  pt = new Particle[pnum];
  
  // particle objects
  float maxlen = sqrt(pow(pcolumn / 2, 2) + pow(pline / 2, 2));
  for (int l = 0; l < pline; l++) {
    for (int c = 0; c < pcolumn; c++) {
      float x = (c - pcolumn / 2);
      float y = (l - pline / 2);
      pt[l * pcolumn + c] = new Particle(
                                         x * divcolumn,
                                         y * divline,
                                         pwidth,
                                         sqrt(x*x+y*y) / maxlen
                                         );
    }
  }
}

void draw() {

  wd.redraw();

  // curtain depth & center color
  float cicle_rotate = (frameCount % 1801) / 10.0 ; cicle_rotate = sin(radians(cicle_rotate));
  float cdivz  = 2 + cicle_rotate * 2;
  float ccolor = map(cicle_rotate, 0, 1, 0, 360);

  for (float divz = 0; divz <= pwidth * cdivz * 5; divz += pwidth * cdivz) {
    //float divz = 0;

    float nl = nl_start;
    for (int l = 0; l < pline; l++) {
      float nc = nc_start;
      for (int c = 0; c < pcolumn; c++) {
        int i = l * pcolumn + c;
        pt[i].paint(ccolor);
        pt[i].fluttering(noise(nc, nl));
        pt[i].plotparticle(divz);
        nc += 0.007;
      }
      nl += 0.005;
    }

  }

  nl_start += 0.007;
  nc_start += 0.002;
    
/*
  saveFrame("frames/####.png");
  if (frameCount >= 1801) {
    exit();
  }
*/

}

class World {

  World() {
  }

  void redraw() {
    background(0, 0, 5);
    ambientLight(0, 0, 100);
    camera(0, 0, 300,
           0, 0, 0,
           0, 1, 0);
  }


}

class Particle {
  Random obj_random;
  float pcolor, psatur, pbright;
  float sigcenter, sigcurve;
  float sx, sy, sz, sweight;

  Particle(float x, float y, float w, float s) {
    obj_random = new Random();

    sx = x;
    sy = y;
    sz = 0;
    sweight = w;

    // steep > s > tender
    sigcenter = 2;
    sigcurve = 1.0 + abs(gaussdist(0, s * s * 20, s * s * 10));

    pcolor = 0;
    psatur = 0;
    pbright = 0;
  }

  void paint(float center_color) {
    pbright = 30 + 30 * sigmoid(gaussdist(0.5, 0.5, 0.25), sigcenter, sigcurve);
    psatur  = 30 + 40 * sigmoid(gaussdist(0.5, 0.5, 0.25), sigcenter, sigcurve);
    pcolor  = center_color + 80 - map(sigmoid(gaussdist(0.5, 0.5, 0.1), sigcenter, sigcurve), 0, 1, 0, 160);
    if (pcolor > 360) {
      pcolor -= 360;
    } else if (pcolor < 0) {
      pcolor += 360;
    }
  }

  void fluttering(float noise_sz) {
    sz = map(noise_sz, 0, 1, -50, 50);
  }

  void plotparticle(float divz) {

    pushMatrix();
    translate(sx, sy, sz + divz);
    fill(
         pcolor,
         psatur,
         pbright,
         100
         );
    // rect(0, 0, sweight, sweight);
    ellipse(0, 0, sweight*0.8, sweight*0.8);
    popMatrix();

  }


  float sigmoid(float x, float pcenter, float pgradient) {
    /**
       Sigmoid function
       1.parameters.
       x : x value
       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.
       y value
    **/

    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;
    
  }

}

/*
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 
*/




Next Post Previous Post
No Comment
Add Comment
comment url