Takkong Larva: Exploring Organic 3D Forms with Object-Oriented Processing


Concept and Technical Approach

This project is a creative coding experiment focused on organic motion. It represents a personal milestone: my first real dive into Object-Oriented Programming (OOP) and 3D environments within Processing.

Thanks to nice music:

Glass Structures by Unheard Music Concepts
2017/01/02
http://freemusicarchive.org/music/Unheard_Music_Concepts/Home_1808/19_Glass_Structures
Glass Structures by Unheard Music Concepts is licensed under a Attribution License.
Based on a work at http://www.unheardmusicconcepts.com
Permissions beyond the scope of this license may be available at http://www.unheardmusicconcepts.com or contact artist via email.

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

Inspiration: The Mighty Takkong

This is Kaiju-inspired animation.

The name and form are a tribute to the "Oil Kaiju" Takkong from Return of Ultraman. Here is the adult form that inspired this digital larva:

Takkong adult from Ultraman

The Code: Experimenting Organic Motion with Perlin Noise

The "larva" is constructed from series of ellipses arranged in circular paths. By applying Perlin noise to the coordinates and rotation of each "tentacle" object, I achieved a wriggling effect that mimics the breathing and movement of a deep-sea creature.

Example code version 1.1


// Takkong Larva 1.1
// Processing 3.2.1
// 2017.07.30

float start_noise_ido = random(100);
float start_noise_kdo = random(100);

World wd;
Larva lv;

void setup() {

  size(720, 720, P3D);
  smooth(8);
  hint(DISABLE_DEPTH_TEST);
  hint(DISABLE_DEPTH_SORT);
  frameRate(100);

  wd = new World();
  lv = new Larva();

}

void draw() {

  wd.redraw();
  wd.rotate();

  lv.grow();
  lv.breath();
  lv.tentacles();


    saveFrame("frames/####.png");
    if (frameCount >= 6600) {
    exit();
    }


}

/* ---------------------------------------------------------------------- */
class World {

  float r_X;
  float r_Y;
  float noise_seed;

  World() {

    r_X = 0;
    r_Y = 10;
    noise_seed = random(100);

  }

  void redraw() {

    background(40);

  }
    
  void rotate() {

    float rollnoise = noise(noise_seed);
    r_X += 0.0001 + 0.00005 * rollnoise;
    r_Y -= 0.0030 + 0.0005 * pow(rollnoise, 2);

    translate(width / 2, height / 2, 0);
    rotateX(r_X);
    rotateY(r_Y);

    noise_seed += 0.005;

  }

}

/* ---------------------------------------------------------------------- */
class Larva {

  float body_radius;
  float radius_min;
  float radius_max;
  int tentacle_max;
  int tentacle_no;
  float tentacle_no_delay;
  float tentacle_grow_time;
  float body_grow_speed;
  float noise_grow;
  Tentacle[] tl;

  Larva() {

    body_radius = 40; //50
    radius_min = 25;
    radius_max = 255;
    tentacle_max = 8;
    tentacle_no = 1;
    tentacle_no_delay = 1.0;
    tentacle_grow_time = 400; //600
    body_grow_speed = 0.2; //0.1
    noise_grow = random(100);
    
    tl = new Tentacle[tentacle_max];
    for (int i = 0; i < tentacle_max; i++) {
      tl[i] = new Tentacle();
    }

  }

  void grow() {

    body_radius += body_grow_speed * noise(noise_grow);
    noise_grow += 0.01;
    radius_check();

    if (tentacle_no < tentacle_max) {
      if (frameCount % tentacle_grow_time == 0) {
        ++tentacle_no;
      }
    }

  }
    
  void breath() {

    float cicle_breath = (frameCount % 181) * 3.00 ; cicle_breath = sin(radians(cicle_breath));
    body_radius += pow(cicle_breath, 3) * (1.5 - noise(noise_grow)) / 2 - body_grow_speed / 4;
    noise_grow += 0.01;
    radius_check();

  }
  
  void radius_check() {

    if (body_radius <= radius_min) {
      body_radius = radius_min;
    } else if (body_radius >= radius_max) {
      body_radius = radius_max;
    }

  }

  void tentacles() {

    if (tentacle_no_delay <= tentacle_no) {
      tentacle_no_delay += 0.004;
    }

    for (int i = 0; i < tentacle_no; i++) {
      tl[i].twist(i * 360 / tentacle_no_delay, body_radius);
    }

  }

  int getTentacleNo() {

    return tentacle_no;

  }

}

/* ---------------------------------------------------------------------- */
class Tentacle {

  float div_ido;
  float div_kdo;
  float noise_ido_start;
  float noise_kdo_start;
  float cicle_kdo;
  int wart_max;
  int wart_no;
  float wart_grow;
  float wriggle_size;
  float wriggle_speed;

  Tentacle() {

    div_ido = 9;
    div_kdo = 6;
    noise_ido_start = random(100);
    noise_kdo_start = random(100);
    cicle_kdo = 0;
    wart_max = 180;
    wart_no = 0;
    wart_grow = 0;
    wriggle_size = 0.05;
    wriggle_speed = 0.007;

  }

  void twist(float start_kdo, float radius) {

    float noise_ido = noise_ido_start;
    float noise_kdo = noise_kdo_start;
    float kdo = start_kdo;
    cicle_kdo = (frameCount % 1801) / 5.00; cicle_kdo = sin(radians(cicle_kdo));

    if (wart_no < wart_max) {
      wart_grow += div_ido * (noise(noise_kdo, noise_ido) / 2 + pow(cicle_kdo,2)) / 30;
      if (wart_grow > div_ido) {
        wart_no += div_ido;
        wart_grow = 0;
      }
    }
    
    for (float ido = 0; ido <= wart_no; ido += div_ido) {
      float noise_ido_val = noise(noise_ido);
      float noise_kdo_val = noise(noise_kdo);

      kdo += map(cicle_kdo, -1.0, 1.0, 3.0, 8.0);

      float radian_ido = radians(ido);
      float radian_kdo = radians(kdo + (noise_ido_val - 0.5) * 40 * sin(radian_ido));
      float radius_val = radius * (1 + pow(noise_kdo_val, 3) * sin(radian_ido) / 3);
      float thisx = radius_val * cos(radian_kdo) * sin(radian_ido);
      float thisy = radius_val * sin(radian_kdo) * sin(radian_ido);
      float thisz = radius_val * cos(radian_ido);

      float radius_wart_basic = sin(radians(div_ido)) * radius * (1 + sin(radian_ido)) / 3;
      if (wart_no < wart_max && wart_no == ido) {
        radius_wart_basic = 0;
      }

      this.warts(thisx, thisy, thisz, radian_kdo, radian_ido, radius_wart_basic, noise_kdo_val);

      noise_ido += wriggle_size;
      noise_kdo += wriggle_size;
    }

    noise_ido_start += wriggle_speed;
    noise_kdo_start += wriggle_speed;

  }
  
  void warts(float thisx, float thisy, float thisz, float radian_kdo, float radian_ido, float radius_wart_basic, float radius_wart_noise) {

    pushMatrix();
    translate(thisx, thisy, thisz);
    rotateZ(radian_kdo);
    rotateY(radian_ido);
    float radius_wart = (5 + sqrt(radius_wart_basic)) * (3 + 2 * pow(radius_wart_noise, 3) * sin(radian_ido));
    float color_wart = 200 - 150 * pow(radius_wart_noise, 2);
    strokeWeight(radius_wart * 0.03);
    stroke(color_wart + 10, 128);
    fill(color_wart + 20, 128);
    ellipse(0, 0, 4 + radius_wart * 0.3, 4 + radius_wart * 0.3);
    fill(color_wart, 128);
    ellipse(0, 0, radius_wart, radius_wart);
    popMatrix();

  }
  
}

/*
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 <http://www.gnu.org/licenses/>
*/




Example code version 1.0

Click to view the version 1.0 source code

// Takkong Larva
// Processing 3.2.1
// 2017.01.22
import processing.opengl.*;

int div_ido = 6;
int div_kdo = 25;
float radius = 80;
float radius_min = radius;
float radius_max = 265;
float start_kdo = 0;
float start_noise_ido = random(100);
float start_noise_kdo = random(100);
int tentacle_count = 1;
int t_limit = 0;
int t_limit_save = 0;
boolean t_limit_flg = true;

World wd;
Larva lv;

void setup() {
  size(720, 720, OPENGL);
  smooth();
  frameRate(30);
  wd = new World();
  lv = new Larva();
}

void draw() {
  wd.redraw();

  float noise_ido = start_noise_ido;
  float noise_kdo = start_noise_kdo;

  // rotate the world
  wd.rotate();

  // tentacles
  lv.grow();
  lv.breath();
  lv.tentacles();

  /*
    saveFrame("frames/####.png");
    if (frameCount >= 6600) {
    exit();
    }
  */

}

class World {
  float r_X;
  float r_Y;
  float noise_seed;

  World() {
    r_X = 0;
    r_Y = 10;
    noise_seed = random(100);
  }

  void redraw() {
    background(40);
  }
    
  void rotate() {
    float rollnoise = noise(noise_seed);
    r_X += 0.0001 + 0.00005 * rollnoise;
    r_Y -= 0.0030 + 0.0005 * pow(rollnoise, 2);
    translate(width / 2, height / 2, 0);
    rotateX(r_X);
    rotateY(r_Y);
    noise_seed += 0.005;
  }

}


class Larva {
  float body_radius;
  float radius_min;
  float radius_max;
  int tentacle_max;
  int tentacle_no;
  float tentacle_no_delay;
  float tentacle_grow_time;
  float body_grow_speed;
  float noise_grow;
  Tentacle[] tl;

  Larva() {
    body_radius = 50;
    radius_min = 25;
    radius_max = 255;
    tentacle_max = 8;
    tentacle_no = 1;
    tentacle_no_delay = 1.0;
    tentacle_grow_time = 600;
    body_grow_speed = 0.1;
    noise_grow = random(100);
    
    tl = new Tentacle[tentacle_max];
    for (int i = 0; i < tentacle_max; i++) {
      tl[i] = new Tentacle();
    }
  }

  void grow() {
    body_radius += body_grow_speed * noise(noise_grow);
    noise_grow += 0.01;
    radius_check();

    if (tentacle_no < tentacle_max) {
      if (frameCount % tentacle_grow_time == 0) {
        ++tentacle_no;
      }
    }
  }
    
  void breath() {
    float cicle_breath = (frameCount % 181) * 2.00 ; cicle_breath = sin(radians(cicle_breath));
    body_radius += pow(cicle_breath, 3) * (1.5 - noise(noise_grow)) / 2 - body_grow_speed / 4;
    noise_grow += 0.01;
    radius_check();
  }
  
  void radius_check() {
    if (body_radius <= radius_min) {
      body_radius = radius_min;
    } else if (body_radius >= radius_max) {
      body_radius = radius_max;
    }
  }

  void tentacles() {
    if (tentacle_no_delay <= tentacle_no) {
      tentacle_no_delay += 0.004;
    }

    for (int i = 0; i < tentacle_no; i++) {
      tl[i].draw(i * 360 / tentacle_no_delay, body_radius);
    }
  }

  int getTentacleNo() {
    return tentacle_no;
  }

}

class Tentacle {
  float div_ido;
  float div_kdo;
  float noise_ido_start;
  float noise_kdo_start;
  float cicle_kdo;
  int wart_max;
  int wart_no;
  float wart_grow;
  float wriggle_size;
  float wriggle_speed;

  Tentacle() {
    div_ido = 9;
    div_kdo = 6;
    noise_ido_start = random(100);
    noise_kdo_start = random(100);
    cicle_kdo = 0;
    wart_max = 180;
    wart_no = 0;
    wart_grow = 0;
    wriggle_size = 0.05; //0.05
    wriggle_speed = 0.007; //0.008
  }

  void draw(float start_kdo, float radius) {
    float noise_ido = noise_ido_start;
    float noise_kdo = noise_kdo_start;
    float s = start_kdo;
    cicle_kdo = (frameCount % 1801) / 5.00; cicle_kdo = sin(radians(cicle_kdo));

    if (wart_no < wart_max) {
      wart_grow += div_ido * (noise(noise_kdo, noise_ido) / 2 + pow(cicle_kdo,2)) / 30;
      if (wart_grow > div_ido) {
        wart_no += div_ido;
        wart_grow = 0;
      }
    }
    
    for (float t = 0; t <= wart_no; t += div_ido) {
      float noise_ido_val = noise(noise_ido);
      float noise_kdo_val = noise(noise_kdo);

      s += div_kdo * (pow(cos(radians(t + (cicle_kdo - 0.5) * 8)), 3) - sin(radians(t + 90 * cicle_kdo ))) + (noise_kdo_val - 0.5) * 4;

      float radian_ido = radians(t);
      float radian_kdo = radians(s + (noise_ido_val - 0.5) * 40 * sin(radian_ido));
      float radius_val = radius * (1 + pow(noise_kdo_val, 3) * sin(radian_ido) / 3);
      float thisx = radius_val * cos(radian_kdo) * sin(radian_ido);
      float thisy = radius_val * sin(radian_kdo) * sin(radian_ido);
      float thisz = radius_val * cos(radian_ido);

      float radius_wart_basic = sin(radians(div_ido)) * radius * (1 + sin(radian_ido)) / 3;
      if (wart_no < wart_max && wart_no == t) {
        radius_wart_basic = 0;
      }

      this.warts(thisx, thisy, thisz, radian_kdo, radian_ido, radius_wart_basic, noise_kdo_val);

      noise_ido += wriggle_size;
      noise_kdo += wriggle_size;
    }

    noise_ido_start += wriggle_speed;
    noise_kdo_start += wriggle_speed;
  }
  
  void warts(float thisx, float thisy, float thisz, float radian_kdo, float radian_ido, float radius_wart_basic, float radius_wart_noise) {
    pushMatrix();
    translate(thisx, thisy, thisz);
    rotateZ(radian_kdo);
    rotateY(radian_ido);
    float radius_wart = (5 + sqrt(radius_wart_basic)) * (3 + 2 * pow(radius_wart_noise, 3) * sin(radian_ido));
    float color_wart = 200 - 150 * pow(radius_wart_noise, 2);
    strokeWeight(radius_wart * 0.03);
    stroke(color_wart + 10, 128);
    fill(color_wart + 20, 128);
    ellipse(0, 0, 4 + radius_wart * 0.3, 4 + radius_wart * 0.3);
    fill(color_wart, 128);
    ellipse(0, 0, radius_wart, radius_wart);
    popMatrix();
  }
  
}

/*
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 <http://www.gnu.org/licenses/>
*/



Next Post Previous Post
No Comment
Add Comment
comment url