• Like
メディア・アートII  第2回 openFrameworks基礎 配列、くりかえし、乱数 ベクトルを使用したアニメーション
Upcoming SlideShare
Loading in...5
×

メディア・アートII 第2回 openFrameworks基礎 配列、くりかえし、乱数 ベクトルを使用したアニメーション

  • 4,512 views
Uploaded on

 

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
4,512
On Slideshare
0
From Embeds
0
Number of Embeds
8

Actions

Shares
Downloads
54
Comments
0
Likes
11

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. メディア・アートII 第2回 openFrameworks基礎 配列、くりかえし、乱数 ベクトルを使用したアニメーション 2013年9月16日 多摩美術大学情報デザイン学科メディア芸術コース 田所淳
  • 2. 本日の内容 ‣ openFrameworksのプログラムの基礎 ‣ 今後の作品制作のための基礎体力をつけていきます! ‣ 乱数(ランダム) ‣ 配列とくりかえし ‣ 条件分岐 ‣ ベクトルを使用した運動の表現 ‣ 大量の物体を動かす
  • 3. 本日の内容 ‣ ただ、プログラミングを書き写すだけではつまらない… ‣ クイズ形式で進めてみます!
  • 4. 準備 ‣ まずは、先週の復習 ‣ 新規プロジェクトの生成 - ProjectGeneratorの使い方
  • 5. Q1: 乱数について
  • 6. Q1: 乱数について ‣ ランダム(規則性のない)場所に、静止した円を描きなさい ‣ プログラムを実行するたびに、違う場所に描かれるように ‣ ヒント: ‣ 円を描く - ofCircle(x, y, radius); ‣ ランダムな数を生成 - ofRandom(min, max);
  • 7. #include "testApp.h" void testApp::setup(){ // 画面基本設定 ofSetFrameRate(60); ofBackground(63); ofSetCircleResolution(32); } void testApp::update(){ } void testApp::draw(){ // ランダムな場所に半径40pxの円を描く ofCircle(ofRandom(ofGetWidth()), ofRandom(ofGetHeight()), 40); } ... 後略 Q1: 乱数について ‣ よくある間違い - testApp.cpp ‣ どうなるか、実験してみる
  • 8. Q1: 解答
  • 9. Q1: 乱数について - 解答 ‣ setup() であらかじめランダムな座標を生成しておく ‣ 生成した座標は、グローバルな変数に格納 (testApp.hに) ‣ その変数の値を参照して、draw() で円を描く
  • 10. #pragma once #include "ofMain.h" class testApp : public ofBaseApp{ public: void setup(); void update(); void draw(); ... // 円の位置 float posX; float posY; }; Q1: 乱数について - 解答 ‣ testApp.h
  • 11. #include "testApp.h" void testApp::setup(){ // 画面基本設定 ofSetFrameRate(60); ofBackground(63); ofSetCircleResolution(32); // 画面内のランダムな場所を指定 posX = ofRandom(ofGetWidth()); posY = ofRandom(ofGetHeight()); } ... void testApp::draw(){ // 設定した場所に円を描く ofSetHexColor(0x3399cc); ofCircle(posX, posY, 20); } ... Q1: 乱数について - 解答 ‣ testApp.cpp
  • 12. Q1: 乱数について - 解答 ‣ 実行するたびに、ランダムな場所に円が描かれる
  • 13. Q2: たくさんの図形をランダムな場所に描く
  • 14. Q2: たくさんの図形をランダムな場所に描く ‣ 100個の静止した円をランダムな場所に描く ‣ 半径は40pxで統一
  • 15. Q2: たくさんの図形をランダムな場所に描く ‣ ヒント 1: 配列 - たくさんの値を保存する ‣ 例えば、100個のposXを保存するための「箱」は以下のように したら準備できる ‣ この箱には、[] で囲まれた部分に連番でナンバリングされる ‣ この仕組みで、100個の、posXとposYが確保できる float posX[100]; posX[0] posX[1] posX[2] ... posX[99] ← 0から開始する ← 0∼99までで100個ぶん
  • 16. Q2: たくさんの図形をランダムな場所に描く ‣ ヒント 2: くりかえし ‣ for文を使用する ‣ 例えば、0∼99の100回くりかえす構文 ‣ カウンタ変数 i を賢く利用する for (int i = 0; i < 100; i++) { 《処理の内容》 } for (int i = 0; i < 100; i++) { posX[i] = ????; posY[i] = ????; }
  • 17. Q2: 解答
  • 18. #pragma once #include "ofMain.h" class testApp : public ofBaseApp{ public: void setup(); void update(); void draw(); ... // 位置の配列を生成 float posX[100]; float posY[100]; }; Q2: 解答 ‣ testApp.h
  • 19. #include "testApp.h" void testApp::setup(){ // 画面基本設定 ofSetFrameRate(60); ofBackground(63); ofSetCircleResolution(32); // 画面内のランダムな場所を円の数だけ指定 for (int i = 0; i < 100; i++) { posX[i] = ofRandom(ofGetWidth()); posY[i] = ofRandom(ofGetHeight()); } } ... void testApp::draw(){ ofSetHexColor(0x3399cc); // 画面内のランダムな場所を円の数だけ描画 for (int i = 0; i < 100; i++) { ofCircle(posX[i], posY[i], 20); } } Q2: 解答 ‣ testApp.cpp
  • 20. Q2: 解答 ‣ 100個の円が、ランダムな場所に描かれる
  • 21. Q2: 解答 ‣ 参考: ‣ 数を変更したい場合、いろいろ修正箇所あり ‣ 1箇所だけを変更すると、数がすぐに変更できるようにしたい! ‣ testApp.hに、クラスの定数(const)として数を指定する ‣ 正式には、静的メンバ変数による定数 ‣ クラスの定数は、以下のような書式になる ‣ 例: 定数「CIRCLE_NUM」を100と定義 static const int 変数名 = 値; static const int CIRCLE_NUM = 100;
  • 22. #pragma once #include "ofMain.h" class testApp : public ofBaseApp{ public: void setup(); void update(); void draw(); ... // 描画する円の数を指定 static const int CIRCLE_NUM = 100; // 位置の配列を生成 float posX[CIRCLE_NUM]; float posY[CIRCLE_NUM]; }; Q2: 解答 ‣ 定数で数を定義バージョン: testApp.h
  • 23. #include "testApp.h" void testApp::setup(){ // 画面基本設定 ofSetFrameRate(60); ofBackground(63); ofSetCircleResolution(32); // 画面内のランダムな場所を円の数だけ指定 for (int i = 0; i < CIRCLE_NUM; i++) { posX[i] = ofRandom(ofGetWidth()); posY[i] = ofRandom(ofGetHeight()); } } ... void testApp::draw(){ ofSetHexColor(0x3399cc); // 画面内のランダムな場所を円の数だけ描画 for (int i = 0; i < CIRCLE_NUM; i++) { ofCircle(posX[i], posY[i], 20); } } Q2: 解答 ‣ 定数で数を定義バージョン: testApp.cpp
  • 24. Q2: 解答 ‣ 例: 円の数を、100 → 400個に
  • 25. Q3: たくさんの図形をアニメーション
  • 26. Q3: たくさんの図形をアニメーション ‣ 次に表示するプログラムを改造して、100個の円が同時に動き まわるアニメーションにする ‣ 開始位置と、円の移動速度と方向はランダムに
  • 27. #pragma once #include "ofMain.h" class testApp : public ofBaseApp{ public: void setup(); void update(); void draw(); ... // 位置 float positionX; float positionY; // 速度 float velocityX; float velocityY; }; Q3: たくさんの図形をアニメーション ‣ ヒントプログラム: testApp.h
  • 28. #include "testApp.h" void testApp::setup(){ // 画面基本設定 ofSetFrameRate(60); ofBackground(63); ofSetCircleResolution(32); // ランダムな場所と速度を指定 positionX = ofRandom(ofGetWidth()); positionY = ofRandom(ofGetHeight()); velocityX = ofRandom(-10, 10); velocityY = ofRandom(-10, 10); } void testApp::update(){ // 円の座標を更新 positionX += velocityX; positionY += velocityY; // 画面からはみ出ないように if (positionX < 0 || positionX > ofGetWidth()) { velocityX *= -1; } if (positionY < 0 || positionY > ofGetHeight()) { velocityY *= -1; } } Q3: たくさんの図形をアニメーション ‣ ヒントプログラム: testApp.cpp
  • 29. void testApp::draw(){ ofSetHexColor(0x3399cc); // 円を描画 ofCircle(positionX, positionY, 20); } Q3: たくさんの図形をアニメーション ‣ ヒントプログラム: testApp.cpp
  • 30. Q3: たくさんの図形をアニメーション ‣ ヒント: 位置と速度をそれぞれ配列にする ‣ 定数を定義して、数はすぐに変更できるように ‣ static const int CIRCLE_NUM ‣ positionX[CIRCLE_NUM] ‣ positionY[CIRCLE_NUM] ‣ velocity X[CIRCLE_NUM] ‣ velocityY[CIRCLE_NUM] ‣ 最初の位置と速度、座標の変更、描画、すべての処理をくりか えして100回行う → for文
  • 31. Q3: 解答
  • 32. #pragma once #include "ofMain.h" class testApp : public ofBaseApp{ public: ... // 描画する円の数を指定 static const int CIRCLE_NUM = 100; // 位置の配列を生成 float posX[CIRCLE_NUM]; float posY[CIRCLE_NUM]; // 速度の配列を生成 float speedX[CIRCLE_NUM]; float speedY[CIRCLE_NUM]; }; Q3: 解答 ‣ testApp.h
  • 33. #include "testApp.h" void testApp::setup(){ // 画面基本設定 ofSetFrameRate(60); ofBackground(63); ofSetCircleResolution(32); // 画面内のランダムな場所と速度を円の数だけ指定 for (int i = 0; i < CIRCLE_NUM; i++) { posX[i] = ofRandom(ofGetWidth()); posY[i] = ofRandom(ofGetHeight()); speedX[i] = ofRandom(-10, 10); speedY[i] = ofRandom(-10, 10); } } void testApp::update(){ // 円の座標を全て更新 for (int i = 0; i < CIRCLE_NUM; i++) { posX[i] += speedX[i]; posY[i] += speedY[i]; Q3: 解答 ‣ testApp.cpp
  • 34. // 画面からはみ出たらバウンドさせる if (posX[i] < 0 || posX[i] > ofGetWidth()) { speedX[i] *= -1; } if (posY[i] < 0 || posY[i] > ofGetHeight()) { speedY[i] *= -1; } } } //-------------------------------------------------------------- void testApp::draw(){ ofSetHexColor(0x3399cc); // 画面内のランダムな場所を円の数だけ描画 for (int i = 0; i < CIRCLE_NUM; i++) { ofCircle(posX[i], posY[i], 20); } } ... Q3: 解答 ‣ testApp.cpp
  • 35. Q3: 解答 ‣ 100個の円が、同時に動く(はず!)
  • 36. ベクトルによる運動の表現
  • 37. ベクトルによる運動の表現 ‣ ここまでの、(x, y)座標それぞれに変数を用意する方法 ‣ ビギナー的表現 ‣ より運動を表現するための高度な書式をマスターしたい ‣ 「ベクトル (Vector)」を理解する!
  • 38. ベクトルによる運動の表現 ‣ ベクトル = 幾何学的空間における、大きさと向きを持った量
  • 39. ベクトルによる運動の表現 ‣ 例: 原点(0,0)から(2,3)の座標までのベクトル ‣ このベクトルは、OA = (2,3) と記述される →
  • 40. ベクトルによる運動の表現 ‣ ベクトルは、足し算することができる ‣ 例: a = (-2,3) と b = (4,2) の2つのベクトルを足す ‣ a + b = (-2+4,3+2) = (2,5)
  • 41. ベクトルによる運動の表現 ‣ ベクトルは、引き算も可能 ‣ 例: a = (-2, 3) , b = (4, 2) ‣ a - b = (-2-4,3-2) = (-6,1)
  • 42. ベクトルによる運動の表現 ‣ 位置ベクトル ‣ いままで扱ってきた2次元平面の座標 (x, y) は、原点 (0, 0) を始 点としたベクトルと捉えることができる → 位置ベクトル
  • 43. ベクトルによる運動の表現 ‣ 速度ベクトル ‣ 「速度 (velocity)」とは、単位時間あたりの物体の移動の変位 ‣ 日常的な「速さ (speed)」と「速度 (velocity)」を区分する ‣ 1フレームごとの座標の変化 = 向きと大きさをもった「速度ベ クトル」 位置ベクトル a 位置ベクトル b 速度ベクトル
  • 44. ベクトルによる運動の表現 ‣ openFrameworksで、ベクトルを表現 ‣ 2次元のベクトルは「ofVec2f」を使用する ‣ 例:位置ベクトルと速度ベクトルの宣言 ‣ 「ベクトル名.x」「ベクトル名.y」: ベクトルの、x方向の成分 と y方向の成分をとりだす ‣ 例:位置ベクトルの(x, y)座標を設定する ‣ ofVec2f position; // 位置ベクトルpositionを宣言 ofVec2f velocity; // 速度ベクトルvelocityを宣言 position.x = 100; // 位置ベクトルpositionのx成分を100に position.y = 100; // 位置ベクトルpositionのx成分を50に
  • 45. Q4: ベクトルで運動を表現する
  • 46. Q4: ベクトルで運動を表現する ‣ Q3 で作成した、たくさんの図形を動かすサンプルを、ベクト ル(ofVec2f)で書き直してみる ‣ ヒント:100個ぶんの位置ベクトルと速度ベクトルは以下のよ うに宣言される // 描画する円の数を指定 static const int CIRCLE_NUM = 100; // 位置ベクトルの配列 ofVec2f position[CIRCLE_NUM]; // 速度ベクトルの配列 ofVec2f velocity[CIRCLE_NUM];
  • 47. Q4: 解答
  • 48. #pragma once #include "ofMain.h" class testApp : public ofBaseApp{ public: ... // 描画する円の数を指定 static const int CIRCLE_NUM = 100; // 位置ベクトルの配列 ofVec2f position[CIRCLE_NUM]; // 速度ベクトルの配列 ofVec2f velocity[CIRCLE_NUM]; }; Q4: 解答 ‣ testApp.h
  • 49. #include "testApp.h" void testApp::setup(){ // 画面基本設定 ofSetFrameRate(60); ofBackground(63); ofSetCircleResolution(32); // 画面内のランダムな場所と速度を円の数だけ指定 for (int i = 0; i < CIRCLE_NUM; i++) { position[i].x = ofRandom(ofGetWidth()); position[i].y = ofRandom(ofGetHeight()); velocity[i].x = ofRandom(-10, 10); velocity[i].y = ofRandom(-10, 10); } } void testApp::update(){ // 円の座標を全て更新 for (int i = 0; i < CIRCLE_NUM; i++) { position[i] += velocity[i]; // 画面からはみ出たらバウンドさせる if (position[i].x < 0 || position[i].x > ofGetWidth()) { velocity[i].x *= -1; } Q4: 解答 ‣ testApp.cpp
  • 50. if (position[i].y < 0 || position[i].y > ofGetHeight()) { velocity[i].y *= -1; } } } void testApp::draw(){ ofSetHexColor(0x3399cc); // 画面内のランダムな場所を円の数だけ描画 for (int i = 0; i < CIRCLE_NUM; i++) { ofCircle(position[i], 20); } } Q4: 解答 ‣ testApp.cpp
  • 51. Q4: 解答 ‣ おなじ運動が、とてもすっきりと記述できた!!
  • 52. 応用: さらにリアルな運動の表現 摩擦力
  • 53. 応用: さらにリアルな運動の表現 ‣ 摩擦力 (Friction) を表現してみる ‣ 摩擦力 = その物体の進行方向逆向きに働く力 速度ベクトル 摩擦力
  • 54. 応用: さらにリアルな運動の表現 ‣ 摩擦力を加えた運動の計算アルゴリズム 円の位置と初期速度を設定 力をリセット 摩擦力を加味した力を更新 力から速度を計算、座標を更新 画面からはみ出ていないかチェック
  • 55. 応用: さらにリアルな運動の表現 ‣ プログラムの可読性を高める工夫 ‣ 処理のかたまりを「関数 (function) 」としてまとめる
  • 56. 応用: さらにリアルな運動の表現 ‣ 関数 (function) ‣ 引数 (ひきすう, argument) - 関数に渡す値 (入力) ‣ 返り値 (return value) - 関数が返す値 (出力) 関数 引数1 引数2 引数3 戻り値
  • 57. 応用: さらにリアルな運動の表現 ‣ C++での関数の書き方 ‣ 例えば、int型の数の二乗を計算する関数 ‣ もし戻り値がない関数の場合、戻り値の型は「void」にする 戻り値の型 名前空間::関数名(引数1, 引数2, 引数3...){ 関数の処理の内容 } int testApp::poweroftwo(int a){ ! return a * a; }
  • 58. 応用: さらにリアルな運動の表現 ‣ 先程の処理の流れを以下の関数として定義 void setInit(); void resetForce(); void updateForce(); void updatePos(); void checkBounds();
  • 59. #pragma once #include "ofMain.h" class testApp : public ofBaseApp{ public: ... void setInit(); // 初期設定 void resetForce(); // 力をリセット void updateForce(); // 力を更新 void updatePos(); // 位置の更新 void checkBounds(); // 画面からはみ出たらバウンドさせる static const int CIRCLE_NUM = 100; // 描画する円の数を指定 ofVec2f position[CIRCLE_NUM]; // 位置ベクトルの配列 ofVec2f velocity[CIRCLE_NUM]; // 速度ベクトルの配列 ofVec2f force[CIRCLE_NUM]; // 力ベクトルの配列 float friction = 0.01; // 摩擦係数 }; 応用: さらにリアルな運動の表現 ‣ testApp.h
  • 60. ... void testApp::setup(){ // 画面基本設定 ofSetFrameRate(60); ofBackground(63); ofSetCircleResolution(32); setInit(); // 円を初期化 } void testApp::update(){ resetForce(); // 力をリセット updateForce(); // 力の更新 (摩擦) updatePos(); // 円の座標を全て更新 checkBounds(); // 画面からはみ出たらバウンドさせる } void testApp::draw(){ ofSetHexColor(0x3399cc); // 画面内のランダムな場所を円の数だけ描画 for (int i = 0; i < CIRCLE_NUM; i++) { ofCircle(position[i], 20); } } 応用: さらにリアルな運動の表現 ‣ testApp.cpp
  • 61. void testApp::setInit(){ // 画面内のランダムな場所と速度を円の数だけ指定 for (int i = 0; i < CIRCLE_NUM; i++) { position[i].x = ofGetWidth()/2; position[i].y = ofGetHeight()/2; velocity[i].set(ofRandom(-30, 30), ofRandom(-30, 30)); force[i].set(0, 0); } } void testApp::resetForce(){ // 力をリセット for (int i = 0; i < CIRCLE_NUM; i++) { force[i].set(0, 0); } } void testApp::updateForce(){ // 力の更新 (摩擦) for (int i = 0; i < CIRCLE_NUM; i++) { force[i] = force[i] - velocity[i] * friction; } } 応用: さらにリアルな運動の表現 ‣ testApp.cpp
  • 62. void testApp::updatePos(){ // 円の座標を全て更新 for (int i = 0; i < CIRCLE_NUM; i++) { velocity[i] += force[i]; position[i] += velocity[i]; } } void testApp::checkBounds(){ // 画面からはみ出たらバウンドさせる for (int i = 0; i < CIRCLE_NUM; i++) { if (position[i].x < 0 || position[i].x > ofGetWidth()) { velocity[i].x *= -1; } if (position[i].y < 0 || position[i].y > ofGetHeight()) { velocity[i].y *= -1; } } } 応用: さらにリアルな運動の表現 ‣ testApp.cpp
  • 63. 応用: さらにリアルな運動の表現 ‣ 動きの勢いが、徐々に摩擦で減速していく
  • 64. 応用: さらにリアルな運動の表現 重力
  • 65. 応用: さらにリアルな運動の表現 ‣ 重力 (Gravity) を表現してみる ‣ つねに下にむかって、一定の力をかけ続ける 摩擦力 重力
  • 66. #pragma once #include "ofMain.h" class testApp : public ofBaseApp{ public: ... void setInit(); // 初期設定 void resetForce(); // 力をリセット void addForce(ofVec2f force); // 力を加える void updateForce(); // 力を更新 void updatePos(); // 位置の更新 // 画面からはみ出たらバウンドさせる void checkBounds(float xmin, float ymin, float xmax, float ymax); // 位置を枠内に収める void constrain(float xmin, float ymin, float xmax, float ymax); // 描画する円の数を指定 static const int CIRCLE_NUM = 100; 応用: さらにリアルな運動の表現 ‣ testApp.h
  • 67. // 位置ベクトルの配列 ofVec2f position[CIRCLE_NUM]; // 速度ベクトルの配列 ofVec2f velocity[CIRCLE_NUM]; // 力ベクトルの配列 ofVec2f force[CIRCLE_NUM]; // 摩擦係数 float friction = 0.01; } 応用: さらにリアルな運動の表現 ‣ testApp.h
  • 68. #include "testApp.h" void testApp::setup(){ // 画面基本設定 ofSetFrameRate(60); ofBackground(63); ofSetCircleResolution(32); setInit(); // 円を初期化 } void testApp::update(){ resetForce(); // 力をリセット addForce(ofVec2f(0, 0.5)); // 重力を加える updateForce(); // 力の更新 (摩擦) updatePos(); // 円の座標を全て更新 // 画面からはみ出たらバウンドさせる checkBounds(0, 0, ofGetWidth(), ofGetHeight()); // 枠内に収める constrain(0, 0, ofGetWidth(), ofGetHeight()); } 応用: さらにリアルな運動の表現 ‣ testApp.cpp
  • 69. void testApp::draw(){ ofSetHexColor(0x3399cc); // 画面内のランダムな場所を円の数だけ描画 for (int i = 0; i < CIRCLE_NUM; i++) { ofCircle(position[i], 20); } } void testApp::setInit(){ // 画面内のランダムな場所と速度を円の数だけ指定 for (int i = 0; i < CIRCLE_NUM; i++) { position[i].x = ofGetWidth()/2; position[i].y = ofGetHeight()/2; velocity[i].set(ofRandom(-30, 30), ofRandom(-30, 30)); force[i].set(0, 0); } } void testApp::resetForce(){ // 力をリセット for (int i = 0; i < CIRCLE_NUM; i++) { force[i].set(0, 0); } } 応用: さらにリアルな運動の表現 ‣ testApp.cpp
  • 70. void testApp::addForce(ofVec2f _force){ // 力を加える for (int i = 0; i < CIRCLE_NUM; i++) { force[i] += _force; } } void testApp::updateForce(){ // 力の更新 (摩擦) for (int i = 0; i < CIRCLE_NUM; i++) { force[i] = force[i] - velocity[i] * friction; } } void testApp::updatePos(){ // 円の座標を全て更新 for (int i = 0; i < CIRCLE_NUM; i++) { velocity[i] += force[i]; position[i] += velocity[i]; } } 応用: さらにリアルな運動の表現 ‣ testApp.cpp
  • 71. void testApp::constrain(float xmin, float ymin, float xmax, float ymax){ // 枠内に収める for (int i = 0; i < CIRCLE_NUM; i++) { if (position[i].x < xmin) { position[i].x = xmin; } if (position[i].y < ymin) { position[i].y = ymin; } if (position[i].x > xmax) { position[i].x = xmax; } if (position[i].y > ymax) { position[i].y = ymax; } } } void testApp::checkBounds(float xmin, float ymin, float xmax, float ymax){ // 画面からはみ出たらバウンドさせる for (int i = 0; i < CIRCLE_NUM; i++) { if (position[i].x < xmin || position[i].x > xmax) { velocity[i].x *= -1; } 応用: さらにリアルな運動の表現 ‣ testApp.cpp
  • 72. if (position[i].y < ymin || position[i].y > ymax) { velocity[i].y *= -1; } } } 応用: さらにリアルな運動の表現 ‣ testApp.cpp
  • 73. 応用: さらにリアルな運動の表現 ‣ リアルな運動が再現される
  • 74. 応用: さらにリアルな運動の表現 ‣ 数を大量に増やしてみる!
  • 75. サンプルファイルのダウンロード ‣ 今日は、ここまで! ‣ 全てのサンプルは以下からダウンロードできます ‣ https://github.com/tado/tau_ma2_13