2021プログラミング7:乱数とジェネラティブな表現

生成される予測できない数列の要素を乱数と呼びます。Processingではrandom()関数を使って乱数を擬似的に生成することができます。

ランダムな線の描画
random()関数は呼び出すたびに異なる数値を返します。パラメータで値の上限あるいは値の範囲を指定することができます。たとえばrandom(10)とすると、0以上、10未満の乱数が生成されます。生成される数値は浮動小数点になるため、変数は float型を使います。
それでは、乱数を使って線を描画してみましょう。線の配色も乱数で生成しています。

function setup(){
   createCanvas(400, 400);
   background(255);
}

function draw(){
  for(let i = 0; i < 100; i++){
    stroke(random(255), random(255), random(255));
    line(random(width), random(height), random(width), random(height));
  }
}

ランダムな円の描画
次に円を乱数を使って描画してみましょう。

let speed = 5;
let x = 200;
let y = 200;

function setup(){
   createCanvas(400, 400);
   background(255);
}

function draw(){
    x += random(-speed, speed);
    y += random(-speed, speed);
    noStroke();
    fill(random(255), random(255), random(255));
    ellipse(x, y, 100, 100);
}

これらのグラフィックは、コードが実行されるたびに、その実行結果が異なることに気がついたでしょうか。
コードに規則を与えることで、予測は可能だが確定的ではないグラフィックスなどを生成することができます。

ジェネラティブなグラフィック表現
ここからは、参考書籍「ジェネラティブ・アート Processingによる実践ガイド マット・ピアソン著」を参考にジェネラティブ(生成的)なグラフィック表現に挑戦してみましょう。

円の描画
まずは、これまでどうりの方法で円を描いてみましょう。

let radius = 200;
let centerx = 400;
let centery = 400;

function setup(){
  createCanvas(800,800);
  background(255);
  strokeWeight(2);
  smooth();
}

function draw(){
  stroke(200, 200, 200);
  noFill();
  ellipse(centerx, centery, radius*2, radius*2);
}

円を描画する別の方法
次に三角関数を用いて点で円を描いてみましょう。

let radius = 200;
let centerx = 400;
let centery = 400;
let x, y;
let lastx = -999;
let lasty = -999;
let ang;
let rad; 

function setup(){
  createCanvas(800,800);
  background(255);
  strokeWeight(2);
  smooth();
}

function draw(){
  stroke(0, 0, 0);
  for(ang = 0; ang <= 360; ang += 2){
    rad = radians(ang);
    x = centerx + (radius * cos(rad));
    y = centery + (radius * sin(rad));
    point(x,y);
  }
}

円かららせんを描画する
円のコードをもとにして、らせんを描いてみましょう。

let radius = 10;
let centerx = 400;
let centery = 400;
let x, y;
let lastx = -999;
let lasty = -999;
let ang;
let rad; 

function setup(){
  createCanvas(800,800);
  background(255);
  strokeWeight(2);
  smooth();
}

function draw(){
  stroke(0, 0, 0);
  for(ang = 0; ang <= 1440; ang += 2){
    radius += 0.5;
    rad = radians(ang);
    x = centerx + (radius * cos(rad));
    y = centery + (radius * sin(rad));
    point(x,y);
  }
}

らせんを線で描画する
らせんを点ではなく線で描きましょう。

let radius = 10;
let centerx = 400;
let centery = 400;
let x, y;
let lastx = -999;
let lasty = -999;
let ang;
let rad; 

function setup(){
  createCanvas(800,800);
  background(255);
  strokeWeight(0.5);
  smooth();
}

function draw(){
  stroke(0, 0, 0);
  for(ang = 0; ang <= 1440; ang += 2){ radius += 0.5; rad = radians(ang); x = centerx + (radius * cos(rad)); y = centery + (radius * sin(rad)); if(lastx > -999){
      line(x, y, lastx, lasty);
    }
    lastx = x;
    lasty = y;
    lasty = y;
  }
}

らせんの線にノイズを加える
線にノイズを加えることで手書きの描線のようなゆらぎが現れます。

let radius = 10;
let centerx = 400;
let centery = 400;
let x, y;
let lastx = -999;
let lasty = -999;
let ang;
let rad; 
let radiusNoise;
let thisRadius;

function setup(){
  createCanvas(800,800);
  background(255);
  strokeWeight(0.5);
  smooth();
}

function draw(){
  stroke(0, 0, 0);
  radiusNoise = random(10);
  for(ang = 0; ang <= 1440; ang += 5){ radiusNoise += 0.05; radius += 0.5; thisRadius = radius + (noise(radiusNoise) * 200)-100; rad = radians(ang); x = centerx + (thisRadius * cos(rad)); y = centery + (thisRadius * sin(rad)); if(lastx > -999){
      line(x, y, lastx, lasty);
    }
    lastx = x;
    lasty = y;
  }
}

らせんに乱数を加え複数重ねて描画する
らせんの描線に乱数を加えながら複数のらせんを重ねて描いてみましょう。

let radius;
let centerx = 400;
let centery = 400;
let x, y;
let lastx;
let lasty;
let ang;
let rad; 
let radiusNoise;
let thisRadius;
let startangle;
let endangle;
let anglestep;

function setup(){
  createCanvas(800,800);
  background(255);
  strokeWeight(0.5);
  smooth();
}

function draw(){
  for(let i = 0; i < 100; i++){
    lastx=-999;
    lasty=-999;
    radius = 10;
    stroke(random(255), random(255), random(255),50);
    startangle = int(random(360));
    endangle = 1440 + int(random(1440));
    anglestep = 5 + int(random(3));
    radiusNoise = random(10);
    for(ang = startangle; ang <= endangle; ang += anglestep){ radiusNoise += 0.05; radius += 0.5; thisRadius = radius + (noise(radiusNoise) * 200)-100; rad = radians(ang); x = centerx + (thisRadius * cos(rad)); y = centery + (thisRadius * sin(rad)); if(lastx > -999){
        line(x, y, lastx, lasty);
      }
      lastx = x;
      lasty = y;
    }
  }
}

 

ジェネラティブ・アート
ジェネラティブ・アートと呼ばれる、数学的な手順(アルゴリズム)によって生成される芸術作品のジャンルが存在します。ジェネラティブ・アートを植物を例に解説していきます。植物は、同じ種類であれば、同じ葉や花のかたちで構成されますが、まったく同じではありません。陽の光や、水、土など生育環境からの要因によって、葉や花の大きさや、角度などが違って成長します。それらは、タネの段階では、どのように育つのかは確定的でなく、植えてから植物が育ってはじめて、その姿形が確認できます。また、常に成長している過程にあるので、その姿形は変化を続けています。このような植物の生育にも似た特徴を持つのが、ジェネラティブ・アートになります。

こうした、生成的な特徴を持つグラフィック作品を制作していきましょう。

課題:
乱数を用いてジェネラティブ・アートの概念をもったグラフィック作品を5点作成する。

ヒント:
繰り返し構文(for文)を使って、一定時間生成をし続けるような作品。
マウスボタンのクリックごとに新たな形態を生成させる作品。
音楽の音量にあわせて形態を無限に変化させ続ける作品。
など

締切:2022年1月20日(木)の授業内で作品発表する
課題提出について
コードのシェア機能を使って作成した作品のコードをシェアするリンクをWordにコピーアンドペーストし、
作品のリンク集を作成してください。
授業名、学籍番号、氏名を明記し、各作品ごとにタイトルと200字程度のコメントを付して、書類を完成させ、
PDF形式に変換してCSのデジタルコンテンツ実習Ⅵ(プログラミング)「プログラミング全課題提出」掲示板に
提出してください。

提出締切:2022年1月27日(木)まで

コードのシェア
作成したコードをシェア(他者と共有)することができます。p5js Editorにログインし、Fileメニューから
Shareを選択すると、コードをシェアするためのウィンドウメニューが表示されます。メニューのEditの欄に
表示されている文字列をコピーしてWordなどにコピーすると、コーディングで作成した作品へのリンクができる
ようになります。

2018プログラミング講座14:サウンド

サウンドの再生

はじめに、サウンドの再生を実行します。サウンドを扱うためにminimというサウンドライブラリを用います。(ライブラリとは、processingなどプログラミング言語の開発環境に様々な機能を追加するプログラムの集まりのようなものだと理解するとよいでしょう。)また、今回はminimを使うためにprocessing バージョン2を使用しますので注意してください。

まず、processingを起動しておきます。次にフリーの音源データをインターネット上から探してデスクトップにダウンロードします。ダウンロードする音源データは必ずmp3形式を選んでください。ダウンロードした音源データの名称をtest.mp3と変更します。

次に、デスクトップにダウンロードした音源データをprocessingで扱えるように追加します。processingのメニューからSketchを選択し、Add File…を選びます。デスクトップから先ほどダウンロードした音源データを選択しopenボタンを押して追加します。

以下のコードを記述して実行ボタンを押すと音源データが再生されます。

import ddf.minim.*; //サウンドライブラリminimの読み込み
 
Minim sound; //minim型変数の宣言
AudioPlayer player;//サウンドデータ格納用変数の用意
 
void setup(){
  size(100, 100);
  sound = new Minim(this); //minim型変数の初期化
  player = sound.loadFile("test.mp3"); //サウンドデータの読み込み
  player.play(); //サウンドデータの再生
}
 
void draw(){
  background(0);
}
 
void stop(){ 
  player.close(); //サウンドデータの終了
  sound.stop(); //minimプログラムの停止
  super.stop(); //プログラムの停止
}

マウスクリックでサウンドを再生する

次にマウスをクリックすることでサウンドが再生されるプログラムを作成してみましょう。(新規でプログラムを作成する場合は、先ほどと同じようにあらかじめ音源データを追加しておきます。)

import ddf.minim.*;
 
Minim sound;
AudioPlayer player;
 
void setup(){
  size(100, 100);
  sound = new Minim(this);
  player = sound.loadFile("test.mp3");
}
 
void draw(){
  background(0);
}
 
void stop(){
  player.close();
  sound.stop();
  super.stop();
}
 
void mousePressed() { //マウスを押下したときに動作する関数
    player.play();
    player.rewind(); //サウンドデータの巻き戻し
}

音量の視覚化

サウンドの音量(ボリューム)とグラフィックスを関連づけてみましょう。

import ddf.minim.*;
 
Minim sound;
AudioPlayer player;
 
void setup(){
  size(400, 400);
  sound = new Minim(this);
  player = sound.loadFile("test.mp3");
}
 
void draw(){
  background(0);
  float d = player.mix.level() * 2000; //サウンドデータの音量を数値化して変数dに代入
  ellipse(width/2, height/2, d, d);
}
 
void stop(){
  player.close();
  sound.stop();
  super.stop();
}
 
void mousePressed() {
    player.play();
    player.rewind();
}

複数のサウンドを再生する

複数のサウンドをマウスクリックで再生するプログラムを作成します。2種類の音源(mp3データ)を用意して、それぞれ、test1.mp3、test2.mp3と名称変更します。2種類の音源データをprocessingに追加します。
準備ができたら、以下のコードを記述しましょう。

import ddf.minim.*;
 
Minim sound;
AudioPlayer player1, player2; //サウンドデータ格納用変数を2種類用意する
 
void setup(){
  size(800, 800);
  sound = new Minim(this);
 //下記で2種類のサウンドデータを読み込む
  player1 = sound.loadFile("test1.mp3"); 
  player2 = sound.loadFile("test2.mp3");
  fill(255); //オブジェクトの塗りの初期設定
}
 
void draw(){
  background(0);
  rect(50, 50, 100, 100);
  rect(200, 50, 100, 100);
  rect(350, 50, 100, 100);
  rect(500, 50, 100, 100);
  float d1 = player1.mix.level() * 2000;
  float d2 = player2.mix.level() * 2000;
  ellipse(width/2, height/2, d1, d1);
  ellipse(width/2, height/2, d2, d2);
}
 
void stop(){
  player1.close();
  player2.close();
  sound.stop();
  super.stop();
}

void mousePressed() {
 if (mouseX > 50 && mouseX < 150 && mouseY > 50 && mouseY < 150) { 
    player1.play(); 
    player1.rewind(); 
}
 if (mouseX > 200 && mouseX < 300 && mouseY > 50 && mouseY < 150) { 
    player1.pause(); 
    player1.rewind(); 
}
 if (mouseX > 350 && mouseX < 450 && mouseY > 50 && mouseY < 150) { 
    player2.play(); 
    player2.rewind(); 
}
 if (mouseX > 500 && mouseX < 600 && mouseY > 50 && mouseY < 150) {
    player2.pause();
    player2.rewind();
  }
}
 
void mouseReleased() {
  fill(255);
}
総合課題2:
上記のサウンド再生ソフトを改良し独自のデザインにする。
ただし以下の機能は全て必ず実装すること。
画面のサイズやボタンの配置は自由とする。
・サウンドデータを3種類以上用意し再生と停止ができるようにする。
・サウンドの音量で独自に用意した画像を変形させる。
・背景画像を用意し配置する。
・ボタンを画像に変更する。

2017プログラミング講座7:Processingと繰り返し構造

繰り返し構造について
プログラムでは繰り返しの構造を使うことで、ひとまとまりのコードを繰り返し実行することができます。繰り返しの構造を使うことで複雑な構造のプログラムを短いコードにできたり、プログラムにパターンを生み出すことなどができます。

forループ文
繰り返し構造を記述するコードとしてforループ文を使ったプログラムを作成してみましょう。
forループ文は以下のように記述します。

for(初期値; 条件式; 更新){
 繰り返し実行されるコード
}

例)
for(i = 0; i < 100; i+=10){  繰り返し実行されるコード } ・「初期値」で最初の値を設定します。  forループ文では慣例的に変数 i が使われることが多い。 ・「条件式」で変数 i を評価します。  変数 i の値を比べて条件にあわなくなるまで「繰り返し実行されるコード」を実行する。  i > A Aより大きい
 i < A Aより小さい  i >= A A以上
 i <= A A以下  i == A Aと等しい  i != A Aと等しくない ・「更新」で変数 i の値をどのように変化させるかを設定します。  i+=10ならコードが実行されるごとに変数 i に10加算 i-=10なら10減算 i++は1加算 i--は1減算。 それでは、forループ文を使った繰り返し構造のプログラムを記述してみましょう。

void setup(){
  size(400,200);
}

void draw(){
  for(int i = 20; i < 400; i += 20){
    ellipse(i,100,20,20);
  }
}

二重の繰り返し構造
forループ文のなかにforループ文を記述することができます。
それでは、二重の繰り返し構造のプログラムを記述してみましょう。

void setup(){
  size(400,400);
  background(0);
  noStroke();
}

void draw(){
  for(int i = 0; i <= 400; i += 20){
    for(int j = 0; j <= 400; j += 20){
      fill(255,48,203);
      ellipse(i,j,15,15);
   }
  }
}

二重の繰り返し構造を使った別のプログラムを記述してみましょう。

void setup(){
  size(400,400);
}

void draw(){
  background(0);
  fill(252,145,3);
  stroke(250,240,48);
  for(int i = 0; i <= 400; i += 20){
    for(int j = 0; j <= 400; j += 20){
      ellipse(i,j,10,10);
      line(i,j,mouseX,mouseY);
   }
  }
}

課題2:
これまでに学んだ、点、線、面および色のコードと繰り返しの構造を組み合わせてグラフィック作品を作成してください。