メディア芸術演習 VI - メディア・アート II
openFrameworks – いろいろな方法で円を描く、インタラクションを付加する
先週の課題「円を描く」の講評
まず始めに先週の授業の課題「円を描く」の講評を行います。
課題:openFrameworksで円を描く
openFrameworksで円を描く方法について考えてください。ただし、ofCircleやofEllipseを使用してはいけません。
円というのは、どのようにしたら描くことができるのか、いろいろ考えてみてください。効率やスピードは特に要求していません。とてもまわりくどい方法でも、最終的に円が出力されればOKです。
- 三角関数を利用する(sin, cos)
- キャンバスを回転しながら図形を描く ofRotate()
- 多角形を分割していく
など、円の描き方をイメージしながら考えてみてください。
解答例1:三角関数を用いて円を描く
まずはじめに、円に関する数学的な公式を素直に適用した「正攻法」のアプローチを紹介します。
まず三角関数の定義についておさらいします。三角関数は、直角三角形の直角でない角の大きさから、三角形の三辺の比率を求める関数です。これは、三角形の内角の和が180度であることから、他の1つの角度が決まれば、もう1つの角の角度も自動的決まり、さらにそこから全ての辺同士の比率が決まるという性質から導かれています。
下図のような直角三角形があります。
このとき、角A = θを与えると、三角関数は以下のように定義されています。
- sinθ = a / h
- cosθ = b / h
- tanθ = a / b
これを踏まえて、以下のように半径1の円を描いて、その中心点を角Aとして、円周に角Bが接する下図のような直角三角形について考えます。
角Aの角度をθとして、この図の円の半径を1なので、h = 1 とすると、そこから下記の式が導きだされます。
- sinθ = a / 1 = a
- cosθ = b / 1 = b
つまり、円周上にある角Bの座標(x, y)は、そのまま(cosθ, sinθ)と置きかえられます。このまま角度を少しずつ変化させていくと、角Bの座標の軌跡はそのまま円軌道になります。つまり三角関数の中心角を 0°〜360°まで変化させて、その軌跡の座標(cosθ, sinθ)をプロットしていくと、円を描くことができるのです。
この方式で円を描くやりかたを、openFrameworksで実装してみましょう。
testApp.cpp
[sourcecode language=”cpp”]
/*
* 三角関数による円の描画
*/
#include "testApp.h"
float phase;
//————————————————————–
void testApp::setup(){
//画面の基本設定
ofSetFrameRate(60);
ofSetBackgroundAuto(false);
ofBackground(255, 255, 255);
}
//————————————————————–
void testApp::update(){
// 位相を更新
phase += 0.01;
}
//————————————————————–
void testApp::draw(){
ofPoint pos;
//半径の設定
float radius = 200.0;
//原点を画面の中心点に
ofTranslate(ofGetWidth()/2, ofGetHeight()/2);
//円の座標を三角関数を利用して計算
pos.x = cos(phase) * radius;
pos.y = sin(phase) * radius;
//色を指定
ofSetColor(0, 127, 255);
//円の描画
ofRect(pos.x, pos.y, 4, 4);
}
/* 後略 */
[/sourcecode]
解答例2:座標を回転する
次に、数学的な観点からではなく、より直感的な方法で円を描いてみます。
コンパスで円を描くにはどうするでしょうか。コンパスの針を紙の中心点に固定して一定距離をたもったままコンパスを1周させます。すると円起動が描かれます。これを、コンパスを基準にして考えてみます。すると、コンパスの位置はそのままで紙をぐるっと360°回転したというように捉えることも可能です。
このコンパスによる円の描き方をそのまま応用してみます。座標の中心点を画面の中央に移動して、中心点から一定の間隔に点を打ちます。次に ofRotateZ() 関数を使用して、画面全体の座標系を少し回転させます。そしてまた中心点から一定間隔の場所に点を打ちます。これを繰り返すことで円軌道が描かれるはずです。
このやり方で円を描いたサンプルは次のようになります。
testApp.cpp
[sourcecode language=”cpp”]
/*
* 座標の回転による円の描画
*/
#include "testApp.h"
float rot;
//————————————————————–
void testApp::setup(){
//画面の基本設定
ofSetFrameRate(60);
ofSetBackgroundAuto(false);
ofBackground(255, 255, 255);
rot = 0;
}
//————————————————————–
void testApp::update(){
//回転角の更新
rot += 1;
}
//————————————————————–
void testApp::draw(){
//半径の設定
float radius = 200.0;
//原点を画面の中心点に
ofTranslate(ofGetWidth()/2, ofGetHeight()/2);
//座標系全体を回転
ofRotateZ(rot);
//色の設定
ofSetColor(0, 127, 255);
//円の描画
ofRect(radius, 0, 4, 4);
}
/* 後略 */
[/sourcecode]
解答例3:ランダムに点を打ち、中心からの距離を測る
つぎに、もう少し変った方法を考えてみましょう。まず円の公式について考えてみます。円の公式は以下の式で求められます。
- x2 * y2 = r2
この式から、円の領域の範囲は、中心点から等距離の範囲の内側にある点の集合と考えることも可能です。この性質を利用して、円を描いてみます。
まず画面の中のランダムな場所に点を指定します。次にこの点と中心点からの距離を計測し、その距離が半径よりも小さい場合のみ点を描画します。するとその点の集合が大量に蓄積するにつれて徐々に円が浮びあがってくるはずです。
openFrameworksで2点間の距離を計測するには、ofDist(x1, y1, x2, y2) という関数を利用すると便利です。
下記のサンプルでは、一度に100個の点を生成し距離に応じて点を描くか判定するという処理を繰り返しています。
testApp.cpp
[sourcecode language=”cpp”]
/*
* 中心からの距離による円の描画
*/
#include "testApp.h"
//————————————————————–
void testApp::setup(){
//画面の基本設定
ofSetFrameRate(60);
ofSetBackgroundAuto(false);
ofBackground(255, 255, 255);
}
//————————————————————–
void testApp::update(){
}
//————————————————————–
void testApp::draw(){
//半径の設定
float radius = 200.0;
//原点を画面の中心点に
ofTranslate(ofGetWidth()/2, ofGetHeight()/2);
//一度に100点づつ更新
for (int i = 0; i < 100; i++) {
//ランダムな場所に点を設定
ofPoint pos;
pos.x = ofRandom(-radius, radius);
pos.y = ofRandom(-radius, radius);
//中心点からの距離を測る
float dist = ofDist(pos.x, pos.y, 0, 0);
//中心からの距離が設定した半径の内側だったら点を打つ
if (dist < radius) {
ofSetColor(0, 127, 255);
ofRect(pos.x, pos.y, 1, 1);
}
}
}
/* 後略 */
[/sourcecode]
回答例4:計算効率重視の描画アルゴリズム1 – Michenerの円描画
デジタル座標で円を描く場合、実際には1ピクセル以下の単位を計算することは意味がありません。それ以下の差異は画面上で表現することができないからです。そのことから、より効率良くコンピュータ画面で円を描画するアルゴリズムがいつくか考案されています。
その中から、MichenerのアルゴリズムとBresenhamのアルゴリズムという円描画のための代表的なアルゴリズムを紹介します。このアルゴリズムは、まずある1点から円を描き始めて、1ピクセルずつ移動判定しながら円を描いていく、という考えかたを基本としています。この移動判定をいかに効率良く行うかがアルゴリズムの根幹となっています。また、8分割された円の座標のみ計算し、あとは「鏡像」を描くことで計算効率を高める工夫も行っています。
アルゴリズムの詳細は以下のリンクを参照してください。
まず、Michenerの円描画のアルゴリズムをopenFrameworksに移植してみましょう。
testApp.cpp
[sourcecode language=”cpp”]
/*
* Michenerのアルゴリズムによる円の描画
*/
#include "testApp.h"
//————————————————————–
void testApp::setup(){
//画面の基本設定
ofSetFrameRate(60);
ofSetBackgroundAuto(false);
ofBackground(255, 255, 255);
}
//————————————————————–
void testApp::update(){
}
//————————————————————–
void testApp::draw(){
float cx, cy, d, radius, lineWidth;
//座標の原点を画面中央に
ofTranslate(ofGetWidth()/2, ofGetHeight()/2);
//半径と線の太さの設定
radius = 200.0;
lineWidth = 2.0;
//色の設定
ofSetColor(0, 127, 255);
// Michenerのアルゴリズムで円を描画
d = 3 – 2 * radius;
cy = radius;
ofRect(0, radius, lineWidth, lineWidth);
ofRect(0, -radius, lineWidth, lineWidth);
ofRect(radius, 0, lineWidth, lineWidth);
ofRect(-radius, 0, lineWidth, lineWidth);
for (cx = 0; cx <= cy; cx++) {
if (d < 0) {
d += 6 + 4 * cx;
} else {
d += 10 + 4 * cx – 4 * cy–;
}
ofRect(cy, cx, lineWidth, lineWidth);
ofRect(cx, cy, lineWidth, lineWidth);
ofRect(-cy, cx, lineWidth, lineWidth);
ofRect(-cx, cy, lineWidth, lineWidth);
ofRect(-cy, -cx, lineWidth, lineWidth);
ofRect(-cx, -cy, lineWidth, lineWidth);
ofRect(cy, -cx, lineWidth, lineWidth);
ofRect(cx, -cy, lineWidth, lineWidth);
}
}
/* 後略 */
[/sourcecode]
回答例5:計算効率重視の描画アルゴリズム2 – Bresenhamの円描画
次に計算効率を重視したアルゴリズムの2つめとして、Bresenhamの円描画のアルゴリズムをopenFrameworksに移植します。
testApp.cpp
[sourcecode language=”cpp”]
/*
* Bresenhamのアルゴリズムによる円の描画
*/
#include "testApp.h"
//————————————————————–
void testApp::setup(){
//画面の基本設定
ofSetFrameRate(60);
ofSetBackgroundAuto(false);
ofBackground(255, 255, 255);
}
//————————————————————–
void testApp::update(){
}
//————————————————————–
void testApp::draw(){
float cx, cy, d, dH, dD, radius, lineWidth;
//座標の原点を画面中央に
ofTranslate(ofGetWidth()/2, ofGetHeight()/2);
//色の設定
ofSetColor(0, 127, 255);
//半径と線の太さの設定
radius = 200.0;
lineWidth = 2.0;
// Bresenhamアルゴリズムで円を描画
d = 1 – radius;
dH = 3;
dD = 5 – 2 * radius;
cy = radius;
for (cx = 0; cx <= cy; cx++) {
if (d < 0) {
d += dH;
dH += 2;
dD += 2;
}
else{
d += dD;
dH += 2;
dD += 4;
–cy;
}
ofRect(cy, cx, lineWidth, lineWidth);
ofRect(cx, cy, lineWidth, lineWidth);
ofRect(-cy, cx, lineWidth, lineWidth);
ofRect(-cx, cy, lineWidth, lineWidth);
ofRect(-cy, -cx, lineWidth, lineWidth);
ofRect(-cx, -cy, lineWidth, lineWidth);
ofRect(cy, -cx, lineWidth, lineWidth);
ofRect(cx, -cy, lineWidth, lineWidth);
}
}
/* 後略 */
[/sourcecode]
いったい、円描画のアルゴリズムはいくつあるのか?
ここでは5つの解答例を紹介しました。しかし、円を描くアルゴリズムはまだまだ沢山あるでしょう。いったい、いくつの円を描く方法があるのでしょうか。
コンピュータ科学者のJim Blinnは、著書 Jim Blinn’s Corner – A Trip Down the Graphics Pipeline の中の「あなたは何通りの方法で円を描けますか?」という章で、円を描くアルゴリズムについて徹底的に考察しています。この中では15種類の円を描くアルゴリズムを紹介しています。参考として、それぞれの円を描く手法のタイトルだけ列挙します。
- Trigonometry
- Polynomial Approximation
- Forward Differences
- Incremental Rotation
- Extreme Approximation
- Unskewing the Approximation
- Rational Polynomials
- Differential Equation
- Half Interval
- Fill Disk
- Solve for X Range Covered
- Various Approximatons to SQRT
- Driving X Away
- Bresenham
- Improved Bresenham
インタラクション
先週の授業でとりあげたサンプルは、プログラムを実行すると、静止画であってもアニメーションであっても、ユーザがプログラムを終了するまではプログラムされた通りに自動的に再生されていました。言い換えると、このプログラムにユーザが介入する要素は、プログラムの起動と終了のみと言えるでしょう。
openFrameworksでは、様々な手段でプログラムを実行している最中にも、ユーザがプログラムに対して介入することが可能です。ユーザがアクションを起こし、それに反応してプログラムは何らかのリアクションをする。ユーザはさらにその反応を見て、別のアクションを起こす。そうした、2つ以上の要素(この場合は、人間とコンピュータ上で動いているプログラム)の相互作用のことを、インタラクション(interaction)と呼びます。
プログラムにインタラクションを付加することで、より意外性に富んだ豊かな表現が可能となります。また、インタラクションをデザインしていくことは、これまでの伝統的なデザインの枠を越えた、新たな領域と言えるでしょう。どのようにしたら、効果的なインタラクションを実現できるのか、どのようにデザインすれば自然なインタラクションが生まれるのか、といったようにまだまだ未知の領域が残された刺激的な世界が拡がっています。
openFrameworksでは、あらかじめ様々なインタラクションの仕組みが用意されています。このセクションでは、まずマウスとキーボードを用いて簡単なインタラクションのサンプルを作成してみましょう。
マウスによるインタラクション 1:マウスの位置
プログラムにインタラクションを加える最も簡単な方法は、マウスの現在位置を利用する方法でしょう。マウスの現在位置は、とても簡単に取得することが可能です。mouseX、mouseYという特殊な変数を使用します。それぞれ現在のマウスのx座標とy座標が常に最新の状態で代入されています。
- mouseX:現在のマウスのx座標
- mouseY:現在のマウスのy座標
マウスの現在位置を利用した簡単なサンプルを作成してみます。マウスの現在位置に円を描くプログラムを作成してみましょう。
testApp.cpp
[sourcecode language=”cpp”]
/*
* マウスの位置に円を描く
*/
#include "testApp.h"
//————————————————————–
void testApp::setup(){
ofBackground(0, 0, 0); //背景色の設定
ofSetFrameRate(60); //フレームレートの設定
ofSetCircleResolution(64); //円の解像度設定
}
//————————————————————–
void testApp::update(){
}
//————————————————————–
void testApp::draw(){
ofSetColor(31, 63, 255); //描画色の設定
ofCircle(mouseX, mouseY, 40); //マウスの現在位置を中心に円を描く
}
/* 後略 */
[/sourcecode]
マウスによるインタラクション 2:移動、マウスダウン、マウスアップ、ドラッグ
マウスポインタの位置と、ユーザがマウスやキーボードを用いて行った動作を組み合わせることで、より複雑なインタラクションが実現可能です。
openFrameworksでは、ユーザがマウスで行った動作を検知し、その状態に応じて処理をするための関数が豊富に用意されています。今までのサンプルで、draw()関数以下に空白のまま未使用であった関数が、たくさん並んでいました。実はそれらはユーザからのマウスとキーボードの様々な入力を受けとるための機能だったのです。
まずはマウスに関する関数から見ていきます。マウスのボタン、マウスの動き、現在のマウスの位置を組合せることで、様々なインタラクションが実現可能となっています。openFrameworksで用意されているマウスの状態を検知する関数には以下のものがあります。
- mouseMoved(int x, int y)
- マウスを移動した時
- x:現在のマウスのx座標、y:現在のマウスのy座標
- mouseDrugged(int x, inty)
- マウスをドラッグ(マウスポインタを押したままで移動したとき
- x:現在のマウスのx座標、y:現在のマウスのy座標
- mousePressed(int x, int y, int button)
- マウスのボタンを押した瞬間
- x:現在のマウスのx座標、y:現在のマウスのy座標、button:ボタンの種類(0:左ボタン、1:中ボタン、2:右ボタン)
- mouseReleased(int x, int y, int button)
- 押されていたマウスボタンを離した瞬間
- x:現在のマウスのx座標、y:現在のマウスのy座標、button:ボタンの種類(0:左ボタン、1:中ボタン、2:右ボタン)
では、マウスを移動する、ドラッグする、押す、離すという動作でそれぞれ状態が変化するサンプルを作成してみましょう。それぞれの動作で以下のように状態を変化させてみます。
- マウスを動かす:円の色をグレー(127, 127,127)に
- マウスをドラッグ:円の中心位置をマウスポインタの場所へ
- マウスボタンを押す:円の色を赤(255, 63, 31)に、円の中心位置をマウスポインタの場所へ、半径を60に
- マウスボタンを離す:円の色を青(31, 63, 255)に、半径を40に
[sourcecode language=”cpp”]
/*
* マウスインタラクション
*/
#include "testApp.h"
ofPoint circlePos;
ofColor circleColor;
float radius;
//————————————————————–
void testApp::setup(){
ofBackground(0, 0, 0); //背景色の設定
ofSetFrameRate(60); //フレームレートの設定
ofSetCircleResolution(64); //円の解像度設定
//円の初期位置
circlePos.x = ofGetWidth() / 2;
circlePos.y = ofGetHeight() / 2;
//円の色、初期値
circleColor.r = 31;
circleColor.g = 63;
circleColor.b = 255;
//半径の初期値
radius = 40;
}
//————————————————————–
void testApp::update(){
}
//————————————————————–
void testApp::draw(){
ofSetColor(circleColor.r, circleColor.g, circleColor.b); //描画色の設定
ofCircle(circlePos.x, circlePos.y, radius); //マウスの現在位置を中心に円を描く
}
/* 中略 */
//————————————————————–
void testApp::mouseMoved(int x, int y ){
//円の色をグレーに
circleColor.r = 127;
circleColor.g = 127;
circleColor.b = 127;
}
//————————————————————–
void testApp::mouseDragged(int x, int y, int button){
//円の中心位置をマウスの位置に
circlePos.x = x;
circlePos.y = y;
}
//————————————————————–
void testApp::mousePressed(int x, int y, int button){
//円の中心位置をマウスの位置に
circlePos.x = x;
circlePos.y = y;
//円の色を赤に
circleColor.r = 255;
circleColor.g = 63;
circleColor.b = 31;
//半径を60に
radius = 60;
}
//————————————————————–
void testApp::mouseReleased(int x, int y, int button){
//円の色を青に
circleColor.r = 31;
circleColor.g = 63;
circleColor.b = 255;
//半径を40に
radius = 40;
}
/* 後略 */
[/sourcecode]
マウスによるインタラクション 3:ドローアプリを作成する「万華鏡メーカー」
マウスのインタラクションを利用して、もう少し複雑なアプリケーションを作成してみましょう。
マウスをドラッグしている時にだけ、マウスの位置に円を描くようにして、背景の更新をfalseにつまり ofSetBackgroundAuto(false) にします。そうするとマウスドラッグで描いた軌跡が残ることになり、簡易的なドローアプリとなります。
そのままでは、あまりに機能的に退屈なので、さらに工夫してみます。まず、毎回の MousePressed() のタイミングで描画色がランダムに変化するようにしてみます。さらに、座標を工夫して、画面の中心点を対象点にして、X軸、Y軸、中心を通過する左右の45°の斜め線を軸に、線対称になるように8この点を配置するようにしてみます。
それぞれの「鏡像」と座標の関係は下記のようになります。
以上の方針でopenFrameworksでプログラムしてみましょう。
[sourcecode language=”cpp”]
/*
* 万華鏡メーカー
*/
#include "testApp.h"
ofPoint circlePos;
ofColor circleColor;
float radius;
bool drawing;
//————————————————————–
void testApp::setup(){
ofBackground(0, 0, 0); //背景色の設定
ofSetFrameRate(60); //フレームレートの設定
ofSetCircleResolution(64); //円の解像度設定
ofSetBackgroundAuto(false); //背景を書き換えない
//画面の混色の設定を加算合成にする
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
//円の色、初期値
circleColor.r = ofRandom(0, 255);
circleColor.g = ofRandom(0, 255);
circleColor.b = ofRandom(0, 255);
//半径の初期値(線の太さに相当)
radius = 10;
//最初は描画状態ではなくする
drawing = false;
}
//————————————————————–
void testApp::update(){
}
//————————————————————–
void testApp::draw(){
ofTranslate(ofGetWidth()/2, ofGetHeight()/2);
if (drawing) {
ofSetColor(circleColor.r, circleColor.g, circleColor.b, 7); //描画色の設定
//X軸,Y軸,斜め45°の軸を境界に「鏡像」を描いていく
ofCircle(circlePos.x, circlePos.y, radius);
ofCircle(-circlePos.x, circlePos.y, radius);
ofCircle(circlePos.x, -circlePos.y, radius);
ofCircle(-circlePos.x, -circlePos.y, radius);
ofCircle(circlePos.y, circlePos.x, radius);
ofCircle(-circlePos.y, circlePos.x, radius);
ofCircle(circlePos.y, -circlePos.x, radius);
ofCircle(-circlePos.y, -circlePos.x, radius);
}
}
/* 中略 */
//————————————————————–
void testApp::mouseMoved(int x, int y ){
}
//————————————————————–
void testApp::mouseDragged(int x, int y, int button){
//円の中心位置をマウスの位置に
circlePos.x = x – ofGetWidth() / 2;
circlePos.y = y – ofGetHeight() / 2;
}
//————————————————————–
void testApp::mousePressed(int x, int y, int button){
//描画モードに
drawing = true;
//円の中心位置をマウスの位置に
circlePos.x = x – ofGetWidth() / 2;
circlePos.y = y – ofGetHeight() / 2;
//円の色を赤に
circleColor.r = ofRandom(0, 255);
circleColor.g = ofRandom(0, 255);
circleColor.b = ofRandom(0, 255);
}
//————————————————————–
void testApp::mouseReleased(int x, int y, int button){
drawing = false;
}
/* 後略 */
[/sourcecode]
キーボードからのインタラクション:キー入力
次にキーボードを利用したインタラクションについて考えてみましょう。キーボードからの入力の処理もマウスの入力と類似しています。用意されている関数は以下の2つです。
- keyPressed(int key)
- キーを押したとき
- key:現在押しているキーの種類 (Asciiコード)
- keyReleased(int key)
- 押していたキーを離したとき
- key:現在押しているキーの種類 (Asciiコード)
keyPressed、keyReleasedとも、引数に入力されたキーの種類がAsciiコードで入力されます。このキーを判定するには、下記のような条件式で判定できます。
[sourcecode language=”cpp”]
void keyPressed(int key){
if (key == ‘キーの種類’){
処理内容;
}
}
[/sourcecode]
キー入力によるインタラクションの利用法としては、アプリケーション全体に関する操作を、キーごとに割り振っておくと便利です。試しに、先程のドローアプリの追加機能として、以下のようにキー入力に機能を割り当ててみます。
- [f]キー:画面の全画面表示とウィンドウ表示の切り替え – ofToggleFullscreen() 関数を使用。
- [r]キー:画面の初期化
[sourcecode language=”cpp”]
/*
* 万華鏡メーカー (キーメニュー付き)
*/
/* 中略 */
//————————————————————–
void testApp::keyPressed(int key){
//もしキー入力が[f]だったら
if (key == ‘f’)
{
//フルスクリーン on/off の切り替え
ofToggleFullscreen();
}
//もしキー入力が[r]だったら
else if (key == ‘r’)
{
//加算合成のブレンドを一時的にOFFに
glDisable(GL_BLEND);
//黒で画面を塗り潰す
ofSetColor(0, 0, 0);
ofSetRectMode(OF_RECTMODE_CENTER);
ofRect(0, 0, ofGetWidth(), ofGetHeight());
//画面の混色の設定を加算合成に戻す
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
}
}
/* 後略 */
[/sourcecode]
サンプルファイルのダウンロード
ここまでで紹介した全てのサンプルは、以下からダウンロード可能です。
次週までの課題:Generative (生成的) な表現についてのリサーチ
ここ数年、最初から完成状態を決めるのではなく、特定のアルゴリズムを使用してその法則から生まれる形態や音響を作品とするような、Generative (生成的) な表現がまた脚光を浴びつつあります。これは、コンピュータ黎明期である1950年代から発生したコンピュータ・アートのリバイバルとも考えられる興味深い現象です。(参考:多摩美術大学美術館「20世紀コンピュータ・アートの軌跡と展望 -現代アルゴリズム・アートの先駆者・現代作家の作品・思想- 展」)
しかし、1950年代のコンピュータの性能と現在のコンピュータの性能は比較にならない進歩を遂げています。現在の超高速なコンピュータの性能を生かした、新たな生成的なコンピュータ・アートの表現領域は、まだまだ未開拓な部分が多く残されているのではないでしょうか。
そこで、生成的な表現をするにあたって、いったいどのような生成的表現があるのか、またその表現はどのようなアルゴリズムで生成されているのか各自リサーチしてください。
幸いなことに、ここ数年、こうしたGenerativeな表現をとり扱ったすばらしい書籍がいくつか刊行されています。また、それぞれの書籍のWebページでは、そのソースコードが公開されているものもあり、とても良い教材となります。
これらの資料を参考にして、以下のことを行ってください。
- 掲載されているソースコードを、一通り実行する。(大量にあります…)
- その中から自分で気にいったサンプルを1つピックアップする
- その作品はどのようなアルゴリズムを使用しているのか解析して、同じプログラムをopenFrameworksに移植する
- もし余裕があれば、そのプログラムを自分なりに変更して、新たな作品にする
次回の授業で講評をおこないたいと思います。