India Ink

An animation of bleeding ink.

Description of this creative coding animation.

This creative coding animation was made with Processing.

I want to make some animate about bleeding ink.
I used the code of another work 'Indian Ink Splash', and I thought out how to animate handwriting and bleed of ink.

Processing code example.

Please feel free to use this example code.
To see another works based on my code is my pleasure. And my honor.


// India Ink
// 2018.02.18

class Spots {
  // calculate writing stroke beforehand

  float spot[][];
  
  Spots(float radiusBase) {

    spot = new float[720][4];

    float noiseX = random(10.0, 20.0);
    float noiseY = random(30.0, 40.0);
    float noiseS = random(5.0, 15.0);
    float noiseA = random(100.0);
    float noiseXDiv = random(0.0005, 0.0015);
    float noiseYDiv = random(0.0010, 0.0030);
    float noiseSDiv = random(0.0015, 0.0030);
    float noiseADiv = random(0.0004, 0.0008);
    
    for (int i = 0; i < 720; ++i) {

      float customX = customNoise(noiseX);
      float customY = customNoise(noiseY);
      float radius = radiusBase * map(customX + customY, -2.0, 2.0, 0.9, 1.1);

      spot[i][0] = map(cos(radians(i / 2.0 + customX)), -1.0, 1.0, -radius, radius); // x
      spot[i][1] = map(sin(radians(i / 2.0 + customY)), -1.0, 1.0, -radius, radius); // y
      spot[i][2] = 5.0 + abs(customNoise(noiseS)) * 30.0; // size
      spot[i][3] = sin(radians(i / 4.0)) * 15.0 + customNoise(noiseA) * 5.0; // alpha

      noiseX += noiseXDiv;
      noiseY += noiseYDiv;
      noiseS += noiseSDiv;
      noiseA += noiseADiv;

    }
    
  }

  float getX(int i) {
    return spot[i][0];
  }

  float getY(int i) {
    return spot[i][1];
  }

  float getSize(int i) {
    return spot[i][2];
  }

  float getAlpha(int i) {
    return spot[i][3];
  }
  
  float customNoise(float value) {
    return pow(sin(value), 3) * cos(pow(value, 2));
  }

}

/* ---------------------------------------------------------------------- */
class Brush {

  float radiusRatio;
  int writingCnt, writingCntMax;
  int bleedCnt, bleedCntMax;
  float noiseWater;
  float rotation;

  Brush(float radiusRatio) {
    
    this.radiusRatio = radiusRatio;
    writingCnt = 0;
    bleedCnt = 0;
    writingCntMax = ceil(random(480, 720));
    bleedCntMax = ceil(random(400, 500));
    noiseWater = random(10);
    rotation = radians(random(360));
    
  }

  boolean writingEnd() {
    return (writingCnt >= writingCntMax) ? true : false;
  }

  float writingSpot() {

    noStroke();
    rotate(rotation);
    
    fill(
         240,
         100,
         30,
         spots.getAlpha(writingCnt) * radiusRatio
         );
    ellipse(
            spots.getX(writingCnt) * radiusRatio,
            spots.getY(writingCnt) * radiusRatio,
            spots.getSize(writingCnt),
            spots.getSize(writingCnt)
            );

    float eSize = pow((spots.getSize(writingCnt) + spots.getAlpha(writingCnt) * 2.0) / 5.0, 2) * (radiusRatio + 1.0) * noise(noiseWater);
    fill(
         240,
         40,
         55,
         spots.getAlpha(writingCnt) * (radiusRatio + 0.3) * 0.05 * (1.0 - noise(noiseWater))
         );
    ellipse(
            spots.getX(writingCnt) * radiusRatio,
            spots.getY(writingCnt) * radiusRatio,
            eSize,
            eSize * 0.75
            );
    noiseWater += 0.02;
    
    ++writingCnt;
    rotate(-rotation);

    return spots.getSize(writingCnt);

  }

  boolean bleedEnd() {
    return (bleedCnt >= bleedCntMax) ? true : false;
  }

  void bleedSpot() {

    noFill();
    rotate(rotation);

    ++bleedCnt;
    if (bleedCnt % 20 == 0) {

      for (int i = 0; i < writingCntMax; ++i) {

        float eSize = sqrt(spots.getSize(i) * bleedCnt * 0.06) * (radiusRatio + 1.5);
        stroke(
               240,
               100,
               50,
               (spots.getAlpha(i) + 30.0) * 0.01 * (radiusRatio + 0.6)
               );
        ellipse(
                spots.getX(i) * radiusRatio,
                spots.getY(i) * radiusRatio,
                eSize,
                eSize
                );

      }
    
    }

    rotate(-rotation);
  
  }

}

/* ---------------------------------------------------------------------- */
Spots spots;
Brush brush[];
int brushCnt, brushCntMax;
float noiseSave;

void setup() {

  size(900, 900);
  colorMode(HSB, 360, 100, 100, 100);
  background(0, 0, 90, 100);
  smooth();

  spots = new Spots(min(width / 2.0, height / 2.0));

  brushCnt = 0;
  brushCntMax = ceil(random(1.8, 3.9)); // 3 or 4, rarely 2
  brush = new Brush[brushCntMax];
  for (int i = 0; i < brushCntMax; ++i) {
    brush[i] = new Brush(1.0 * (brushCntMax - i) / brushCntMax);
  }

  noiseSave = random(100.0);

  backdrop();

}

void draw() {

  float spotSize = 0;
  translate(width / 2.0, height / 2.0);

  // handwriting
  if (brushCnt < brushCntMax) {
    spotSize = brush[brushCnt].writingSpot();
    if (brush[brushCnt].writingEnd()) {
      ++brushCnt;
    }
  }

  // bleed after handwriting
  for (int i = 0; i < brushCnt; ++i) {
    if (!brush[i].bleedEnd()) {
      brush[i].bleedSpot();
    }
  }

  // save last figure as first frame
  if (brushCnt == brushCntMax && brush[brushCntMax - 1].bleedEnd()) {
    saveFrame("frames/iisa0000.png");
    exit();
  }

  // thin line = fast, thick line = slow
  float step = map(min(35.0, spotSize), 0.0, 35.0, 4.0, 1.0) + noise(noiseSave) * 2.0;
  if (frameCount % step < 1.0) {
    saveFrame("frames/iisa####.png");
  }
  noiseSave += 0.0002;

}

void backdrop() {

  noStroke();
  rotate(radians(-15.0));
  for (int i = 0; i < 100; ++i) {

    float bright = map(i, 0, 100, 70.0, 90.0);
    float location = map(i, 0, 100, 1100.0, 500.0);
    fill(
         0,
         0,
         bright,
         100
         );
    rect(
         -250.0,
         location,
         1100.0,
         200.0
         );

  }
  
}

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



Next Post Previous Post
No Comment
Add Comment
comment url