一般的に、プログラミング言語にはランダム値(乱数)を発生させる仕組みがあります。ランダム値とは、サイコロの目のように不規則で予測できない数値のことを指しますが、特にゲームなどで必ずと言っていいほど利用されています。また、ノイズ(パーリン・ノイズ)はランダムと同じように不規則ですが、波の形のように連続的に変化するのが特徴です。
ここでは、ランダムやノイズを積極的に使って造形的な工夫をおこなうことを考えてみます。
4.8.1 ランダムとは
まずは、図形は作らずに数値だけ出力してみましょう。setup()内には何も書かず、draw()の中にprintln()を書いて、その中でrandom()を実行します。
void setup() {
}
void draw() {
println(random(5)); //0.0~5.0(5.0は含まれない)の値を出力
}
すると、0.0~5.0までの間の数値がひたすら出力されます。ここでのポイントはふたつです。
・random(a)の結果は、float型で0.0~aの数値が返される。
aがマイナスの値の場合は、a~0.0になる。
・random(5)の場合、5は含まれない。つまり5になることはない。
4.9999999…は出る可能性はある。
いろいろな数値を入れて試してみましょう。
また、引数をふたつ取る場合は、最小値から最大値の範囲を示します。例えば、random(-5, 5)の場合は、-5.0~5.0です。
void setup() {
}
void draw() {
println(random(-5, 5)); //-5.0~5.0(5.0は含まれない)の値を出力
}
また、float型の値が返されるので、例えばint型の変数に値を入れるとエラーになります。
その場合には、floatからintに型変換(キャスト)してください。
int i;
i = random(5); //エラーになる
int j;
j = int(random(5)); //強制的に型変換(キャスト)する
4.8.2 ランダムを形態と色彩に使ってみる
それでは、次にランダムを使って円を画面内に配置してみます。このサンプルは、クリックするごとに値がリセットされ、常に新しい画像を生成します。
boolean drawFlag = true; //クリックごとに描画するためのフラッグ
float eSize;
void setup() {
size(400, 400);
}
void draw() {
if (drawFlag) { //drawFlagがtrueだったら
background(255);
for (int i = 0; i < 100; i ++) {
eSize = 50;
//円の位置はランダム
ellipse(random(width), random(height), eSize, eSize);
}
drawFlag = false; //描画後にfalseにする
}
}
void mousePressed() {
drawFlag = true; //クリックでdrawFlagをtrue
}
次に、大きさをランダムにしてみます。次のサンプルは、5~60ピクセルの範囲でランダムの値を生成します。
for (int i = 0; i < 100; i ++) {
//円のサイズを10~50で決定
eSize = random(5, 60);
//円の位置はランダム
ellipse(random(width), random(height), eSize, eSize);
}
今度は円の縁に色をつけてみます。青、赤の順番に色が出やすくし、全体的に少し暗めの色が選ばれるように値を調整します。
for (int i = 0; i < 100; i ++) {
//円のサイズを10~50で決定
eSize = random(5, 60);
//線は青、赤がを強く暗い色にする
stroke(random(50, 150), random(0, 100), random(50, 200), 200);
//円の位置はランダム
ellipse(random(width), random(height), eSize, eSize);
}
最終的に円も塗りつぶしてみます。
for (int i = 0; i < 100; i ++) {
//円のサイズを10~50で決定
eSize = random(5, 60);
//線は青、赤がを強く暗い色にする
stroke(random(50, 150), random(0, 100), random(50, 200), 200);
//塗りは青と赤を強くして明るめにする
fill(random(0, 200), random(0, 100), random(100, 255), 50);
//円の位置はランダム
ellipse(random(width), random(height), eSize, eSize);
}
最終的なコードは次のとおりです。
boolean drawFlag = true; //クリックごとに描画するためのフラッグ
float eSize;
void setup() {
size(400, 400);
}
void draw() {
if (drawFlag) { //drawFlagがtrueだったら
background(255);
for (int i = 0; i < 100; i ++) {
//円のサイズを10~50で決定
eSize = random(5, 60);
//線は青、赤がを強く暗い色にする
stroke(random(50, 150), random(0, 100), random(50, 200), 200);
//塗りは青と赤を強くして明るめにする
fill(random(0, 200), random(0, 100), random(100, 255), 50);
//円の位置はランダム
ellipse(random(width), random(height), eSize, eSize);
}
drawFlag = false; //描画後にfalseにする
}
}
void mousePressed() {
drawFlag = true; //クリックでdrawFlagをtrue
}
4.8.3 運動にランダムを使う
ランダムは様々な場面で使うことができますが、例えば使い方によってはオブジェクトが振動するような効果を出すことができます。
次のサンプルは、「4.7.5 クリックで円のサイズがバウンドする」サンプルをアレンジしたものです。
振動する要素のため、R3の値にランダムを使っています。再生して動きを確認してみてください。
int angle = 0; //角度を時間として扱う変数
int speed = 10; //アニメーションのスピード
float damping = 0.98; //拡大縮小の減衰率
float maxSize = 100.0; //円の最大サイズ
float R1 = 100.0; //基準円のサイズ
float R2 = 0.0; //拡大縮小する範囲
float R3; //振動させるための変数
void setup() {
size(400, 400);
noStroke();
fill(0);
}
void draw() {
background(255);
//0 ~ R2の70%の間でランダム値を返す
R3 = random(R2*0.7);
//円のサイズを計算
float r = R1 + R2*sin(radians(angle)) + R3;
ellipse(width/2, height/2, r, r); //円を描画
angle += speed; //時間を進める
if (angle > 360) angle = 0; //360度でリセット
R2 *= damping; //徐々に0に近づける
}
void mousePressed() {
angle = 0; //マウスを押すと時間をリセット
R2 = maxSize; //円のサイズを最大値にする
}
4.8.4 色彩の変化にランダムを使う
同じように、色彩の変化にランダムを使うと、色がチカチカ瞬くような効果を得ることができます。「3.1.6 色彩の変化」で作成したサンプルをアレンジしてみましょう。このサンプルでは、10 ~ 245の間で色が明るくなったり暗くなったりするのに加え、R, G, Bそれぞれランダムに-10 ~ 10の値が追加されています。
int gray; //grayの値
int speed; //色の変化のスピード
//初期化
void setup() {
size(400, 400);
gray = 10; //grayの初期初期値は10
speed = 2; //スピードの初期設定
}
//プログラムが終了するまで、draw()の中は繰り返される
void draw() {
gray += speed; //grayの値にspeedを足す
//もし、grayの値が255より大きくなるか、0より小さくなったら
if (gray > 245) {
speed = -speed; //speedの増える値を反転する
gray = 245; //grayを白にする
} else if (gray < 10) {
speed = -speed; //speedの増える値を反転する
gray = 10; //grayを黒にする
}
float r = gray + random(-10, 10); //r, g, bそれぞれにランダム値を足す
float g = gray + random(-10, 10);
float b = gray + random(-10, 10);
background(r, g, b); //背景を描く
}
4.8.5 ノイズ
ランダムについて理解が深まったでしょうか?次はノイズです。ここではプログラミングの世界で最もよく使われているパーリンノイズを使います。このパーリンノイズは、波や炎など、連続的に変化する形態を作ることに適しています。
float myNoise = 0.0; //ノイズの初期値
float step = 0.02; //ステップの数値が少ないと変化が滑らかになる
size(400, 400);
background(255);
for (int x = 0; x < width; x += 3) {
//noise()の引数がいくつでも、必ず結果は0.0 ~ 1.0の間の値が返される
//0.0 ~ 1.0にheightを掛けているので、結果は0.0 ~ 400.0
//ノイズを使ってy座標を設定
float y = noise(myNoise)*height;
line(x, 0, x, y);
//ランダムを使った場合は連続性がない
//line(x, 0, x, random(height));
myNoise += step; //ノイズの値を更新
}
このサンプルは、lineの2点目のy座標を決定する際にnoise()を使っています。ポイントはふたつです。
・myNoiseには規則的に増加する値を入れる。このサンプルではstep
・stepの値は少なければ連続的変化が小さく(形は滑らか)、大きければ変化が大きく(形は荒く)なる
stepの値を変えて確認してみましょう。
また、myNoiseの初期値を変えると全く違った図形を得ることができます。次のサンプルはクリックするごとに0.0 ~ 10.0の間でランダムに初期値を設定します。初期値が変わることによって、形が大きく変わることを確認してみましょう。
float myNoise = 0.0; //ノイズの初期値
float start = 0.0; //myNoiseのスタート地点
float step = 0.02; //ステップの数値が少ないと変化が滑らかになる
void setup() {
size(400, 400);
}
void draw() {
background(255);
myNoise = start; //myNoiseをスタート地点で初期化
for (int x = 0; x < width; x += 3) {
//ノイズを使ってy座標を設定
float y = noise(myNoise)*height;
line(x, 0, x, y);
//ランダムを使った場合は連続性がない
//line(x, 0, x, random(height));
myNoise += step; //ノイズの値を更新
}
}
void mousePressed() {
start = random(10); //myNoiseのスタート位置を変える
}
4.8.6 stepの値をリアルタイムに変えてみる
このサンプルでは、マウスのx座標の動きに合わせてstepの値を変化させています。画面左下にstepの値を出力しているので、値を確認しながらマウスを動かしてみましょう。
float myNoise = 0.0; //ノイズ変数
float start = 0.0; //myNoiseのスタート地点
float step = 0.0; //ステップの数値が少ないと変化が滑らかになる
PFont myFont; //フォント用変数
void setup() {
size(400, 400);
myFont = createFont("Arial", 12); //フォント作成
textFont(myFont, 14); //テキストのサイズを設定
}
void draw() {
background(255);
myNoise = start;
step = map(mouseX, 0, width, 0.0, 0.1);
for (int x = 0; x < width; x += 3) {
float y = noise(myNoise)*height;
line(x, 0, x, y);
//ランダムを使った場合は連続性がない
//line(x, 0, x, random(height));
myNoise += step; //ノイズの値を更新
}
fill(0);
text("step = " + step, 20, height - 20); //月を描画
}
void mousePressed() {
start = random(10); //myNoiseのスタート位置を変える
}
4.8.7 色彩にノイズを使ってみる
それでは、色彩にノイズを使ってみたらどのような応用ができるでしょうか。
次のサンプルは縦に1ピクセルずつ描画される線にノイズを使ってみました。x軸方向の変化が滑らかになっています。
float myNoise = 0.0; //ノイズ変数
float start = 0.0; //myNoiseのスタート地点
float step = 0.02; //ステップの数値が少ないと変化が滑らかになる
void setup() {
size(400, 400);
}
void draw() {
background(255);
myNoise = start; //myNoiseをスタート地点で初期化
for (int x = 0; x < width; x ++) {
//ノイズによる値を色にする
float myColor = noise(myNoise)*255;
stroke(myColor);
line(x, 0, x, height);
myNoise += step; //ノイズの値を更新
}
}
void mousePressed() {
start = random(10); //myNoiseのスタート位置を変える
}
それでは、R、G、Bそれぞれにノイズを使ったらどうなるでしょうか。無数のバリエーションによるストライプになります。
float rNoise; //赤用ノイズ変数
float gNoise; //緑用ノイズ変数
float bNoise; //青用ノイズ変数
float rStart; //赤ノイズのスタート地点
float gStart; //緑ノイズのスタート地点
float bStart; //青ノイズのスタート地点
float step = 0.01; //ステップの数値が少ないと変化が滑らかになる
void setup() {
size(400, 400);
rStart = random(10); //スタート地点をrandom()で初期化
gStart = random(10);
bStart = random(10);
}
void draw() {
background(255);
rNoise = rStart; //ノイズをスタート地点で初期化
gNoise = gStart;
bNoise = bStart;
for (int x = 0; x < width; x ++) {
//noise(rNoise)*255の結果は0 ~ 255
float r = noise(rNoise)*255;
float g = noise(gNoise)*255;
float b = noise(bNoise)*255;
stroke(r, g, b);
line(x, 0, x, height);
rNoise += step; //ノイズの値を更新
gNoise += step;
bNoise += step;
}
}
void mousePressed() {
rStart = random(10); //ノイズのスタート位置を変える
gStart = random(10);
bStart = random(10);
}
4.8.8 2次元のノイズ
これまでの例は1次元のノイズでしたが、2次元のノイズ(実は3次元も)というものがあります。このノイズを使うと横方向と縦方向に連続的なノイズを得ることができ、結果的に雲のようなテクスチャを作ることができます。ステップ数を変えるとテクスチャの密度が変わります。
float noiseX = 0.0; //x座標用ノイズ変数
float noiseY = 0.0; //y座標用ノイズ変数
float start = 0.0; //noiseX, noiseYのスタート地点
float step = 0.02; //ステップの数値が少ないと変化が滑らかになる
void setup() {
size(400, 400);
}
void draw() {
loadPixels(); //ピクセルをロードする
noiseY = start; //noiseYをスタート地点で初期化
for (int y = 0; y < height; y ++) {
noiseX = start; //noiseXをスタート地点で初期化
for (int x = 0; x < width; x ++) {
float c = noise(noiseX, noiseY)*255;
//決定した色をピクセルに反映
pixels[y*width + x] = color(c);
noiseX += step; //noiseXを更新
}
noiseY += step; //noiseYを更新
}
updatePixels(); //ピクセルを更新
}
void mousePressed() {
start = random(10); //myNoiseのスタート位置を変える
}
4.8.9 運動にノイズを使ってみる
この2次元のノイズは、発想を変えてみると1次元分は形に、もう1次元分は運動に使うこともできます。次のサンプルは1次元分を運動に使った例です。
float myNoise = 0.0; //ノイズの初期値
float noiseT = 0.0;
float start = 0.0; //myNoiseのスタート地点
float step = 0.02; //ステップの数値が少ないと変化が滑らかになる
void setup() {
size(400, 400);
}
void draw() {
background(255);
myNoise = start; //myNoiseをスタート地点で初期化
for (int x = 0; x < width; x += 3) {
//ノイズを使ってy座標を設定
float y = noise(myNoise, noiseT)*height;
line(x, 0, x, y);
//ランダムを使った場合は連続性がない
//line(x, 0, x, random(height));
myNoise += step; //ノイズの値を更新
}
noiseT += 0.005;
}
void mousePressed() {
start = random(10); //myNoiseのスタート位置を変える
}
この考え方で、3次元のノイズを作って、1、2次元分は縦横の連続的変化に使い、最後の3次元目は運動に使うとテクスチャの動きになります。色々なパラメータを変えて実験してみてください。
float noiseX = 0.0; //x座標用ノイズ変数
float noiseY = 0.0; //y座標用ノイズ変数
float noiseT = 0.0; //時間経過用ノイズ
float start = 0.0; //noiseX, noiseYのスタート地点
float step = 0.02; //ステップの数値が少ないと変化が滑らかになる
void setup() {
size(400, 400);
}
void draw() {
loadPixels(); //ピクセルをロードする
noiseY = start; //noiseYをスタート地点で初期化
for (int y = 0; y < height; y ++) {
noiseX = start; //noiseXをスタート地点で初期化
for (int x = 0; x < width; x ++) {
float c = noise(noiseX, noiseY, noiseT)*255;
pixels[y*width + x] = color(c); //決定した色をピクセルに反映
noiseX += step; //noiseXを更新
}
noiseY += step; //noiseYを更新
}
noiseT += 0.005;
updatePixels(); //ピクセルを更新
}
void mousePressed() {
start = random(10); //myNoiseのスタート位置を変える
}