pg11

テーマ アートとプログラム

2019年度向けメモ:

P5.jsを新エディタに移行する。旧エディタ上ではコードのぷれびゅうが出来ないのかも。2018.11.29の時点でExamplesに掲載のコードがブラウザで実行されない状態。2018.12.05復旧確認

2019.2.21 CanTree のサイトに接続できない。ドメイン名からIPアドレスがでてこない。-> 2019.11.26復旧確認。

ジェネラティブアート

今回取り組む分野。

映像・サウンド・画像などを生成するルールを決め、主にコンピュータでプログラムを実行して作品を制作する。

人工的なパターン:

編み物や布の柄・壁紙・レンガやタイルの敷き詰めなど

規則的で幾何学的な図形

プログラムで数学的規則を元に描画する

ネットで見かけた作品例)

Twitterで見かけたモーショングラフィックス ←この方が作成したモーフィングCGの記事: Processing で簡単モーフィング @deconbatch

自然界のパターン:

動物の毛皮や魚の体表の紋様・雪の結晶・植物の形・地形・樹木の形など

規則的な操作の積み重ねにより表現することも可能

不規則性がある

パターン生成に利用される理論の例

自己相似図形

フラクタル図形

カオス理論

反応拡散系

補足)

自然なノイズについて:自然な不規則性に関する理論

パーリンノイズを理解する @POSTDcc

フラクタル図形

ネットで調べてみよう。

ウィキペディア フラクタル コッホ曲線シェルピンスキーギャスケット の生成過程のアニメーションを確認する。

フラクタルツリー の画像検索

フラクタルツリー をパラメーター調整で生成

※ 枝の比率を100%にすると、画面を覆う模様を生成できる。

※ 枝の広がりは 45度 や 60度 など、360度を単純な整数で分割した角度は規則的な模様を生成する

※ 枝の広がりを 0度~180度までスライドすると、全角度でツリーを生成し、アニメーション表示

ネタ テレビアニメのOPで使われていた

都市の自動生成 Wave Function Collapse

迷路の自動生成 Wave Function Collapse

他にもプログラムによる自動生成について調べてみよう。

ダンジョンの自動生成

迷路の自動生成

家具のデザインの自動生成

キャラクターデザインの自動生成

模様の自動生成(布の柄・CGテクスチャなど)

木の自動生成 Blenderや他のCGソフト、Unityなどのゲームエンジンでも利用可能

景観の自動生成 Terragenなど様々なソフトがある。Terragen4が実習室PCにインストール済み。

※演習の注意

ブラウザは、 Google Chrome を使用してください。

インターネットエクスプローラー(IE)では、課題プログラムが動作しない、作成したプログラムが消える などの不具合が発生します。

課題提出

課題1 か 課題2 か 課題3 の3の中から 2つ以上(全部でもOK)の課題に取り組み、作成したCGをスクリーンショットで WebClass にアップロードする。

課題1:木のCGの作成

課題2:敷詰め模様と螺旋模様の作成

応用例:自然景観CGの作成(課題1 または 課題2 の代わりにこれに取り組んでもOK)

授業では、以下の課題3を主に進める。他の課題は、残りの時間または宿題で進める。

課題3

p5.js によるアニメーションとサウンド作成

demo(音がでます。ボリューム調整に注意)

作成準備

p5.js をクリックして P5.jsのサイトを開く。

p5.js は、メディアアート系プログラミング言語 Processing(略称 p55) を JavaScript と HTML5によりブラウザで利用可能にしたものです。

※英語版サイトはExamplesに掲載のコードが動かないようです。2018.11.29の時点では。 日本語版サイトはこちら 2018.12.05復旧確認。 2019年度は日本語版サイトは使用しない。

Start creating with the p5 Editor! をクリックしてコードの入力と実行画面を開く。

Examples から一部解説(課題とは別)

Interactivity 1 マウスに反応するプログラムの例。クリックで丸い図形を表示

Oscillator Frequency サウンドのサンプル(※音声有り。要ボリューム調整) マウスの位置xy座標に応じて音が変化

Random ランダムな太さの線を引き続ける

作成手順

アニメーション処理の基本形 のプログラムを開いて、下記のコード例を参考にして修正していく。

メニューの File → Examples → 検索窓から animate を検索

このリンクを開いてもOK

マウスをクリックした位置に円の座標を移動するコード↓を追加する。場所は元のコードの最下行に。

// When the user clicks the mouse

function mousePressed() {

x = mouseX;

y = mouseY;

}

↓の赤い部分の追加修正により、緑のドットを弾として発射する丸に変更する。

※追加修正する代わりに、 コード全体をコピペ して入れ替えてもよい。

// Where is the circle

let x, y;

let mx, my;

function setup() {

createCanvas(720, 400);

noSmooth();

mx = 0;

my = 0;

// Starts in the middle

x = width / 2;

y = height;

}

function draw() {

background(0);

// Draw a circle

stroke(50);

fill(100);

ellipse(mx,my, 24, 24);

// Jiggling randomly on the horizontal axis

x = x + random(-1, 1);

// Moving up at a constant speed

y = y - 1;

// Reset to the bottom

if (y < 0) {

y = height;

}

// Draw white points

stroke(0,255,0);

strokeWeight(4);

point(x, y);

}

// When the user clicks the mouse

function mousePressed() {

mx = mouseX;

my = mouseY;

x = mx;

y = my;

}

三角波の音源(osc)を追加する。

音の高さ(周波数 freq)を 緑のドットの x 座標に対応させる。

音の大きさ(amp)を 同じく y 座標に対応させる。

※追加修正する代わりに、 コード全体をコピペ して入れ替えてもよい。

// Where is the circle

let x, y;

let mx, my;

let osc;

function setup() {

createCanvas(720, 400);

noSmooth();

mx = 0;

my = 0;

// Starts in the middle

x = width / 2;

y = height;

osc = new p5.TriOsc(); // set frequency and type

osc.amp(.5);

osc.start();

}

function draw() {

background(0);

// Draw a circle

stroke(50);

fill(100);

ellipse(mx,my, 24, 24);

// Jiggling randomly on the horizontal axis

x = x + random(-1, 1);

// Moving up at a constant speed

y = y - 1;

// Reset to the bottom

if (y < 0) {

y = height;

}

// Draw green points

stroke(0,255,0);

strokeWeight(4);

point(x, y);

// change oscillator frequency based on mouseX

let freq = map(x, 0, width, 40, 880);

osc.freq(freq);

let amp = map(y, 0, height, 0.1, 1.0);

osc.amp(amp);

}

// When the user clicks the mouse

function mousePressed() {

mx = mouseX;

my = mouseY;

x = mx;

y = my;

}

残りの時間の実験内容:

・音の触れ幅を変化させてみよう random(-1,1) を random(-10,10) に修正

・音の触れ幅を偏らせてみよう random(-1,1) を random(-4, 5) に修正

・弾のスピード(yの変化量)を -1 から別の値に変えて速度を上げてみよう(例 -3)。

・音の大きさ(アンプ)や高さ(周波数)は、map関数でドットのxy座標から変換して設定している。

map( 参照座標 , 参照元最小値, 参照元最大値, 変換先最小値, 変換先最大値)

x座標の 0 ~ width(画面サイズ) に対して、周波数を 40~880 まで変更する場合、

map(x, 0, width, 40, 880);

ヒント:周波数を2倍にすると、1オクターブ音程が上昇する。

※コードを修正して結果を確認したら、課題提出の準備をする。

その他の調整例:

・残像効果。画面更新の際に、背景色で塗りつぶすbackground(0)の代わりに、半透明の黒で塗りつぶすように変更。

function draw() {

//background(0);

fill(0,0,0,30);

rect(0,0,width,height);

・微調整

画面外に消えたドット(サンプルコード Animation に追加した最初の緑の点)が

画面の下端にループ(heightの位置)して登場するようになっている

マウスをクリックした位置(円の位置)へループするように修正。

// Reset to the bottom

if (y < 0) {

y = my;

}

課題3の提出

p5.js で作成したプログラムが動いている様子が分かるタイミングで、スクリーンショットを撮る。

※ 弾の動きが早いので、 キーボードの PrintScreen キー を押してメモリーにスクショを記録

→ ペイントブラシ(スタート→検索→pbrush)に貼り付け

を利用するとよい。

例)

応用例)

・多数の弾を表示する座標を記録するため、配列(Array)で、1000個のメモリを準備。

・マウスを押したときに、マウスのxy座標を弾の位置として記録。

pop()で配列から一番古い弾の座標を削除。

push()で配列にマウスクリックをしたときに発射した弾の座標を記録。

・記録された全ての弾を移動させ、表示するための for ループの追加。

・音の周波数(高さ) freq は y に対応 var freq = map(y, 0, height, 40, 880);

音の大きさ amp は x に対応 var amp = map(x, 0, width, 1, .01);

// Where is the circle

let x, y;

let mx, my;

let osc;

let ax = new Array(1000);

let ay = new Array(1000);

function setup() {

createCanvas(720, 400);

noSmooth();

mx = 0;

my = 0;

// Starts in the middle

x = width / 2;

y = height;

osc = new p5.TriOsc(); // set frequency and type

osc.amp(.5);

osc.start();

}

function draw() {

background(0);

// Draw a circle

stroke(50);

fill(100);

ellipse(mx,my, 24, 24);

// Jiggling randomly on the horizontal axis

x = x + random(-10, 10);

// Moving up at a constant speed

y = y - 1;

// Reset to the bottom

if (y < 0) {

y = height;

}

// Draw white points

stroke(0,255,0);

strokeWeight(4);

point(x, y);

// change oscillator frequency based on mouseX

let freq = map(y, 0, height, 40, 880);

osc.freq(freq);

let amp = map(x, 0, width, 1, .01);

osc.amp(amp);

for(var i=0; i<ax.length; i++) {

ax[i] = ax[i] + random(-1, 1);

ay[i] = ay[i] - 1;

point(ax[i], ay[i]);

}

}

// When the user clicks the mouse

function mousePressed() {

mx = mouseX;

my = mouseY;

x = mx;

y = my;

ax.pop();

ay.pop();

ax.unshift(mx);

ay.unshift(my);

}

・残像効果。画面更新の際に、背景色で塗りつぶす代わりに、半透明の黒で塗りつぶすように変更。

function draw() {

//background(0);

fill(0,0,0,30);

rect(0,0,width,height);

・弾を連射するように変更する。mousePressed() 内の以下の4行を、 draw() の内部に移動する。

ax.pop();

ay.pop();

ax.unshift(mx);

ay.unshift(my);

・微調整:

音を出すタイミングを発射位置に合わせる。

osc2.freq(map(ax[my-y-1], 0, width, 40, 880));

・ドットのx座標の変化を時間に対して周期的にする。

y の値をcos関数で処理すればよい。

以下のコードでは -10 ~ 0 ~ +10 ~ 0 ~ -10 のループになる。

ax[i] = ax[i] + 10*cos(200*PI*y/height);

ay[i] = ay[i] - 5;

ax[i] = ax[i] + 3*cos(8*PI*y/height);

ay[i] = ay[i] - 3;

数値の組み合わせによっては、このようなパターンも生成可能。(この例で使用した数値の組み合わせは不明。各自で探ってみよう。)

(ヒント) 画面の高さは 400ピクセル。cosの中の式は、上の例で 8 の値をwと書くと、

w*PI*y/height

になる。

さらに、PIはπの値で固定、yは時間に応じて変化する。y以外の時間で変化しない値は、height=400 なら w/400*π となる。

三角関数 cos の性質から、w = 800 や 400 や 200 の時には弾は特殊な軌跡を描く。

400をちょうど割り切ることが出来る100や50の時もやや特殊な軌跡となる。

特殊な軌跡となる値から少しずれた値、799 や 99 等を指定すると面白い。

例)

ax[i] = ax[i] + 50*cos(395*PI*y/height);

ay[i] = ay[i] - 2;

変化しない軌跡を描くコード。赤い数字の部分を調整してみよう。

ax[i] = ax[i] + 5*cos(2*map(ay[i],0,0.5*height,-PI,PI));

ay[i] = ay[i] - 2;

おまけ:音をさらに追加する。追加する音の高さは、x座標の配列から時間に応じて読み出した値。yの変化量は -1 程度に抑え目にしておく。

変数追加

let osc,osc2;

setup()に音源の追加

osc2 = new p5.TriOsc(); // set frequency and type

osc2.amp(.5);

osc2.start();

draw()に周波数変更コードの追加。

位置は draw()の最後の方でunshift()のコード(弾を追加するコード)の下に以下の1行を張り付ける。

osc2.freq(map(ax[y], 0, width, 40, 880));

draw()にあるyの値を変更するコードを調整

y = y - 1;

余力のある人向け

P5.jsのサンプルから Multiple Particle Systems を改造してみよう。

解説:

パーティクルの初期値を決めているコード

// A simple Particle class

var Particle = function(position) {

this.acceleration = createVector(0, 0.05);

this.velocity = createVector(random(-1, 1), random(-1, 0));

this.position = position.copy();

this.lifespan = 255.0;

};

パーティクルの寿命を決めているコード

// Method to update position

Particle.prototype.update = function(){

this.velocity.add(this.acceleration);

this.position.add(this.velocity);

this.lifespan -= 2;

};

パーティクルの種類(Particle と CrazyParticleの2種類)を選択するコード

ParticleSystem.prototype.addParticle = function () {

// Add either a Particle or CrazyParticle to the system

if (int(random(0, 2)) == 0) {

p = new Particle(this.origin);

}

else {

p = new CrazyParticle(this.origin);

}

this.particles.push(p);

};

パーティクルの形を描画するコード

CrazyParticle.prototype.display=function() {

// Render the ellipse just like in a regular particle

Particle.prototype.display.call(this);

// Then add a rotating line

push();

translate(this.position.x, this.position.y);

rotate(this.theta);

stroke(255,this.lifespan);

line(0,0,25,0);

pop();

}