Home> 2011-bアーカイブ

2011-bの最近のブログ記事

b-11 3Dの座標を使う

  • 2011年12月12日 14:40
  • 2011-b

3Dの回転(x軸, y軸, z軸)

2Dの回転をもとに動きを付けてみる

void setup() {
  size(100, 100);
  rectMode(CENTER);
}

void draw() {
  background(0);
  translate(width/2, height/2);
  rotate(frameCount*PI/60);
  rect(0, 0, width/2, height/2);
}

x軸 rotateX

void setup() {
  size(100, 100, P3D);
  rectMode(CENTER);
}

void draw() {
  background(0);
  translate(width/2, height/2);
  rotateX(frameCount*PI/60);
  rect(0, 0, width/2, height/2);
}

y軸 rotateY

void setup() {
  size(100, 100, P3D);
  rectMode(CENTER);
}

void draw() {
  background(0);
  translate(width/2, height/2);
  rotateY(frameCount*PI/60);
  rect(0, 0, width/2, height/2);
}

矩形の描画位置を変更した場合

void setup() {
  size(100, 100, P3D);
  rectMode(CENTER);
}

void draw() {
  background(0);
  translate(width/2, height/2);
  rotateY(frameCount*PI/60);
  rect(width/2, 0, width/2, height/2);
}

z軸 rotateZ

void setup() {
  size(100, 100, P3D);
  rectMode(CENTER);
}

void draw() {
  background(0);
  translate(width/2, height/2);
  rotateZ(frameCount*PI/60);
  rect(0, 0, width/2, height/2);
}

x軸, y軸の両方

void setup() {
  size(100, 100, P3D);
  rectMode(CENTER);
}

void draw() {
  background(0);
  translate(width/2, height/2);
  rotateX(frameCount*PI/60);
  rotateY(frameCount*PI/60);
  rect(0, 0, width/2, height/2);
}

3Dの移動

z軸方向に移動したい場合は、translate関数の引数を1つ追加する。

void setup() {
  size(100, 100, P3D);
  rectMode(CENTER);
}

void draw() {
  background(0); 
  translate(width*2/5, height/2);
  rotateY(PI/6);
  for (int i = 0; i < 5; i++) {
    pushMatrix();
    translate(0, 0, i*10);
    rotateZ(frameCount*(i+1)*PI/600);
    fill(255, 51);
    rect(0, 0, width/2, height/2);
    popMatrix();
  }
}

3Dのオブジェクトを描画する

直方体 box

void setup() {
  size(100, 100, P3D);
}

void draw() {
  background(0);
  translate(width/2, height/2);
  rotateY(frameCount*PI/60);
  box(40, 30, 20); // 幅, 高さ, 奥行きの順。引数を1つにすると立方体になる。
}

sphere

lights関数を用いると光が当たっている状態をシミュレートできる。

void setup() {
  size(100, 100, P3D);
}

void draw() {
  background(0);
  lights();
  translate(width/2, height/2);
  rotateY(frameCount*PI/120);
  translate(50, 0);
  noStroke();
  sphere(10); //半径30pxの球
}
  • Comments (Close): 0
  • TrackBack (Close): 0

b-10 オブジェクト指向プログラミング (OOP)

  • 2011年12月 5日 14:40
  • 2011-b

オブジェクト指向プログラミングとは? → オブジェクト指向プログラミング - Wikipedia

オブジェクト指向プログラミングでプログラムを書く

円を描くプログラムを、オブジェクト指向プログラミングで書いてみる。

oop1

step. 0 これまでの書き方

float x, y, diameter; // x座標, y座標, 直径

void setup() {
  x = 25;
  y = 50;
  diameter = 30;
}

void draw() {
  ellipse(x, y, diameter, diameter);
}

step. 1 クラスを定義する

Spot sp; //オブジェクトを宣言

void setup() {
  sp = new Spot(); //オブジェクトを生成(構築)
  sp.x = 25; //属性(プロパティ)に値を代入。以下同様
  sp.y = 50;
  sp.diameter = 30;
}

void draw() {
  ellipse(sp.x, sp.y, sp.diameter, sp.diameter);
}

//Spotクラスを定義
class Spot {
  //属性を定義
  float x, y, diameter; // x座標, y座標, 直径
}

※「Spot」は、関数を自分で定義したときのように、適切な名前を考えて付ける。その属性も同様。

step. 2 クラスにメソッド(method)の定義を追加する

Spot sp; //オブジェクトを宣言

void setup() {
  sp = new Spot(); //オブジェクトを生成(構築)
  sp.x = 25; //属性(プロパティ)に値を代入。以下同様
  sp.y = 50;
  sp.diameter = 30;
}

void draw() {
  sp.display();
}

//Spotクラスを定義
class Spot {
  //属性を定義
  float x, y, diameter; // x座標, y座標, 直径

  //表示するメソッドを定義
  void display() {
    ellipse(x, y, diameter, diameter);
  }
}

step. 3 クラスにコンストラクタ(constructor)の定義を追加する

Spot sp; //オブジェクトを宣言

void setup() {
  sp = new Spot(25, 50, 30); //オブジェクトを生成(構築)
}

void draw() {
  sp.display();
}

//Spotクラスを定義
class Spot {
  //属性を定義
  float x, y, diameter; // x座標, y座標, 直径

  //コンストラクタを定義
  Spot(float _x, float _y, float _diameter) {
    x = _x;
    y = _y;
    diameter = _diameter;
  }

  //表示するメソッドを定義
  void display() {
    ellipse(x, y, diameter, diameter);
  }
}

step. 4 クラスに移動のメソッドを追加し、アニメーションにする

Spot sp; //オブジェクトを宣言

void setup() {
  sp = new Spot(25, 50, 30, 1); //オブジェクトを生成(構築)
}

void draw() {
  background(204);
  sp.move();
  sp.display();
}

//Spotクラスを定義
class Spot {
  //属性を定義
  float x, y, diameter, speed; // x座標, y座標, 直径, 速さ

  //コンストラクタを定義
  Spot(float _x, float _y, float _diameter, float _speed) {
    x = _x;
    y = _y;
    diameter = _diameter;
    speed = _speed;
  }

  //移動するメソッドを定義
  void move() {
    x += speed;
    if (x > width + diameter/2) x = -diameter/2;
  }

  //表示するメソッドを定義
  void display() {
    ellipse(x, y, diameter, diameter);
  }
}

クラス定義を別ファイルで管理する

manage-class1-1

manage-class2-1

manage-class3-1

manage-class4-1

※以降、Spot.pde ファイルの内容は同じなので省略する

異なる属性を持つ複数のオブジェクトを生成(インスタンス化)する

2個

Spot sp1, sp2; //オブジェクトを宣言

void setup() {
  sp1 = new Spot(25, 50, 30, 1); //sp1 を生成
  sp2 = new Spot(75, 80, 10, 2); //sp2 を生成
}

void draw() {
  background(204);
  sp1.move();
  sp2.move();
  sp1.display();
  sp2.display();
}

60個(配列を使って)

Spot[] sp = new Spot[60];

void setup() {
  for (int i = 0; i < sp.length; i++) {
    sp[i] = new Spot(random(width), random(height), random(5,30), random(0.5,3));
  }
}

void draw() {
  background(204);
  for (int i = 0; i < sp.length; i++) {
    sp[i].move();
    sp[i].display();
  }
}

クラスを継承し、拡張された属性または機能を拡張した子クラスを定義する

Spot クラスを継承し、色を指定できる ColorSpot クラスを定義する

ColorSpot[] sp = new ColorSpot[60];

void setup() {
  colorMode(HSB);
  for (int i = 0; i < sp.length; i++) {
    sp[i] = new ColorSpot(
      random(width), 
      random(height), 
      random(5,30), 
      random(0.5,3), 
      color(random(255), 255, 255)
    );
  }
}

void draw() {
  background(204);
  for (int i = 0; i < sp.length; i++) {
    sp[i].move();
    sp[i].display();
  }
}

ColorSpot.pde

//Spotクラスを継承し、ColorSpotクラスを定義
class ColorSpot extends Spot {
  //属性を定義
  color col; // 色

  //コンストラクタを定義
  ColorSpot(float _x, float _y, float _diameter, float _speed, color _col) {
    super(_x, _y, _diameter, _speed); //親クラス(Spot)のコンストラクタを呼びだす
    col = _col;
  }

  //移動するメソッドを定義
  void move() {
    super.move(); //親クラス(Spot)のメソッドを呼びだす
  }

  //表示するメソッドを定義
  void display() {
    fill(col);
    super.display();
  }
}

Spot.pde

//Spotクラスを定義
class Spot {
  //属性を定義
  float x, y, diameter, speed; // x座標, y座標, 直径, 速さ

  //コンストラクタを定義
  Spot(float _x, float _y, float _diameter, float _speed) {
    x = _x;
    y = _y;
    diameter = _diameter;
    speed = _speed;
  }

  //移動するメソッドを定義
  void move() {
    x += speed;
    if (x > width + diameter/2) x = -diameter/2;
  }

  //表示するメソッドを定義
  void display() {
    ellipse(x, y, diameter, diameter);
  }
}

移動ではなくサイズを変更すると、異なる表現ができる

シンプルな時計をOOPでつくる

  • Comments (Close): 0
  • TrackBack (Close): 0

b-09 ライブラリを利用する

  • 2011年11月28日 14:40
  • 2011-b

Processingは「ライブラリ」という仕組みで、その機能を拡張することができる。以前の授業でライブカメラを使用した際には、videoライブラリというライブラリを利用した。

Processing公式サイトで紹介されているライブラリ一覧(英語)

音を扱う

Processing で音を扱う場合、標準で用意されている Minim を利用するのが一般的である。以下の素材を利用して、Processingで音を扱ってみよう。

音声素材のダウンロード

サンプルファイルを再生する

各種ドラム音のような、サンプルファイルは AudioSample クラスを利用する。

import ddf.minim.*;

Minim minim;
AudioSample kick;
AudioSample snare;

void setup() {
  minim = new Minim(this);
  kick = minim.loadSample("kick.wav", 2048);
  snare = minim.loadSample("snare.wav", 2048);
}

void draw() {
}

void keyPressed() {
  if (key == 'k') kick.trigger();
  if (key == 's') snare.trigger();
}

void stop() {
  kick.close();
  snare.close();
  minim.stop();

  super.stop();
}

サイン波を生成し、マウス位置に応じて音程・パンを調整する

import ddf.minim.*;
import ddf.minim.signals.*;

Minim minim;
AudioOutput out;
SineWave sine;

void setup() {
  minim = new Minim(this);
  out = minim.getLineOut(Minim.STEREO);
  sine = new SineWave(440, 0.5, out.sampleRate());
  sine.portamento(200);
  out.addSignal(sine);
}

void draw() {
}

void mouseMoved() {
  float freq = map(mouseY, 0, height, 1500, 60);
  sine.setFreq(freq);
  float pan = map(mouseX, 0, width, -1, 1);
  sine.setPan(pan);
}

void stop() {
  out.close();
  minim.stop();

  super.stop();
}

一般的な音楽ファイルを再生する

ミュージシャンの楽曲のような、一般的な音楽ファイル(再生時間が長い→ファイル容量が大きい)ものは AudioPlayer クラスを利用する。

利用した音楽ファイル: ccMixter - Wataridori 2 - Cornelius

import ddf.minim.*;

Minim minim;
AudioPlayer player;

void setup() {
  minim = new Minim(this);
  player = minim.loadFile("http://ccmixter.org/contests/freestylemix/Cornelius%20-%20Wataridori%202.mp3", 2048);
  player.play(); //再生
}

void draw() {
}

void stop() {
  player.close();
  minim.stop();

  super.stop();
}

mp3ファイルのメタ情報を表示する

Minim AudioMetaData

import ddf.minim.*;

Minim minim;
AudioPlayer player;
AudioMetaData meta;

void setup() {
  minim = new Minim(this);
  player = minim.loadFile("http://ccmixter.org/contests/freestylemix/Cornelius%20-%20Wataridori%202.mp3", 2048);
  player.play(); //再生
  meta = player.getMetaData();
  //コンソールに音声データのメタ情報を表示
  println("アルバム名: " + meta.album());
  println("曲名: " + meta.title());
  println("アーティスト名: " + meta.author());
}

void draw() {
}

void stop() {
  player.close();
  minim.stop();

  super.stop();
}

※そのほかAudioPlayer にできることはリファレンスを参照 → AudioPlayer

物理シミュレーション

「物が落ちる」といった物理現象を簡単にシミュレートするためのライブラリで、最も有名なのがBox2Dであり、このBox2DをProcessingで利用できるようにしたものがBoxWrap2Dである。

インストール

  • BoxWrap2Dをダウンロード
    • BoxWrap2Dページ内の「Get the library」をクリックしてダウンロード
    • 解凍したフォルダ「boxwrap2d」を、次のフォルダ内に配置:書類 > Processing > libraries ※Macの場合
  • Processing を起動していた場合は、再起動する

Box2D を使ってみる

  • 「画面をクリックすると、マウスポインタの位置から円が落ちる」プログラムを書いてみる
import org.jbox2d.p5.*;

Physics physics;

void setup() {
  size(500, 500);
  frameRate(60);
  physics = new Physics(this, width, height);
  physics.setDensity(1.0); //重さ(密度)
}

void draw() {
  background(204);
}

void mousePressed() {
  physics.createCircle(mouseX, mouseY, 15);
}

反発係数を設定する

import org.jbox2d.p5.*;

Physics physics;

void setup() {
  size(480, 320);
  frameRate(60);
  physics = new Physics(this, width, height);
  physics.setDensity(1.0); //重さ(密度)
  physics.setRestitution(0.9); //反発係数
}

void draw() {
  background(204);
}

void mousePressed() {
  physics.createCircle(mouseX, mouseY, 10);
}

摩擦係数を設定する

import org.jbox2d.p5.*;

Physics physics;

void setup() {
  size(480, 320);
  frameRate(60);
  physics = new Physics(this, width, height);
  physics.setDensity(1.0); //重さ(密度)
  physics.setRestitution(0.2); //反発係数
  physics.setFriction(0.0); //摩擦係数
}

void draw() {
  background(204);
}

void mousePressed() {
  float d = 5;
  physics.createRect(mouseX - d * 2, mouseY - d, mouseX + d * 2, mouseY + d);
}
  • Comments (Close): 0
  • TrackBack (Close): 0

b-07 時間を使う

  • 2011年11月14日 14:40
  • 2011-b

hour, minute, second 時、分、秒

コンソールに日時を表示する

1b-06 時間

void setup() {
  frameRate(1); //フレームレートを1に設定(毎秒1回draw関数を実行)
}

void draw() {
  int h = hour(); //時
  int m = minute(); //分
  int s = second(); //秒
  println(h + ":" + m + ":" + s); //コンソールに日時を表示
}

コンソールに日時を表示する(分と秒は2ケタで表示)

1b-06 時間

void setup() {
  frameRate(1);
}

void draw() {
  int h = hour();
  int m = minute();
  int s = second();
  String t = h + ":" + nf(m, 2) + ":" + nf(s, 2);
  println(t);
}

ウィンドウに日時を表示する

void setup() {
  textSize(18);
  textAlign(CENTER);
  frameRate(1);
}

void draw() {
  background(0);
  int h = hour();
  int m = minute();
  int s = second();
  String t = h + ":" + nf(m, 2) + ":" + nf(s, 2);
  //println(t);
  text (t, 50, 55);
}

時間を視覚化する

長方形の長さで、時計を表現する

1b-06-3

19:45:06

void setup() {
  size(240, 240);
  frameRate(1);
}

void draw() {
  background(204);
  int h = hour();
  int m = minute();
  int s = second();
  //長方形の長さで時計を表現する
  rect(0, 0, h*10, height/3); 
  rect(0, height/3, m*4, height/3);
  rect(0, height*2/3, s*4, height/3);
}

三針時計をつくる

秒針から作ると、やりやすい。

void setup() {
  size(240, 240);
  frameRate(1);
  smooth();
}

void draw() {
  background(204);
  noStroke();
  ellipse (width/2, height/2, 200, 200);
  int h = hour();
  int m = minute();
  int s = second();
  stroke(0);
  //時針
  strokeWeight(4);
  pushMatrix();
  translate(width/2, height/2);
  rotate((h%12+m/60.0)*TWO_PI/12);
  line(0, 0, 0, -60);
  popMatrix();
  //分針
  strokeWeight(2);
  pushMatrix();
  translate(width/2, height/2);
  rotate((m+s/60.0)*TWO_PI/60);
  line(0, 0, 0, -80);
  popMatrix();
  //秒針
  strokeWeight(1);
  pushMatrix();
  translate(width/2, height/2);
  rotate(s*TWO_PI/60);
  line(0, 0, 0, -90);
  popMatrix();
}

このプログラムでは、線を rotate() で回転することにより時計の針を描画している。以下のように三角関数を利用して針を描画することも可能。

void setup() {
  size(240, 240);
  frameRate(1);
  smooth();
}

void draw() {
  background(204);
  noStroke();
  ellipse (120, 120, 200, 200);
  int s = second();
  int m = minute();
  int h = hour();
  stroke(0);
  strokeWeight(4);
  line(120, 120 , 60 * cos((h + m/60.0) % 12 * TWO_PI / 12 - HALF_PI) + 120, 60 * sin((h + m/60.0) % 12 * TWO_PI / 12 - HALF_PI) + 120); //時針の描画
  strokeWeight(2);
  line(120, 120 , 80 * cos((m + s/60.0) * TWO_PI / 60 - HALF_PI) + 120, 80 * sin((m + s/60.0) * TWO_PI / 60 - HALF_PI) + 120); //分針の描画
  strokeWeight(1);
  line(120, 120 , 90 * cos(s * TWO_PI / 60 - HALF_PI) + 120, 90 * sin(s * TWO_PI / 60 - HALF_PI) + 120); //秒針の描画
}

練習

  • 時間に関する関数を利用し、時間(秒)に反応したアニメーションを作成する

参考資料:時計を用いたビジュアル・インタラクティブ表現

  • Comments (Close): 0
  • TrackBack (Close): 0

b-06 ライブカメラを使う

  • 2011年11月 7日 14:40
  • 2011-b

Processing でビデオ映像を扱う場合は、ライブラリを利用する。今回は標準で用意されている Video ライブラリを利用する。

ライブカメラの映像を表示する

そのまま表示する

sketch_1b_10_1

import processing.video.*; // Videoを扱うライブラリをインポート
Capture camera; // ライブカメラの映像をあつかうCapture型の変数

void setup() {
  size(480, 320);
  camera = new Capture(this, width, height, 12); // Captureオブジェクトを生成
}

void draw() {
  image(camera, 0, 0); // 画面に表示
} 

//カメラの映像が更新されるたびに、最新の映像を読み込む
void captureEvent(Capture camera) {
  camera.read();
}

同じ映像を4分割で表示する

sketch_1b_10_2

import processing.video.*;
Capture camera;

void setup() {
  size(480, 320);
  camera = new Capture(this, width/2, height/2, 12); // 1/2サイズでCaptureオブジェクトを生成
}

void draw() {
  image(camera, 0, 0); // 画面に表示
  image(camera, width/2, 0); // 画面に表示
  image(camera, 0, height/2); // 画面に表示
  image(camera, width/2, height/2); // 画面に表示
} 

void captureEvent(Capture camera) {
  camera.read();
}

一般化して n*n 分割で表示する

import processing.video.*;
Capture camera;
int d = 4; //画面を4*4で分割する

void setup() {
  size(480, 320);
  camera = new Capture(this, width/d, height/d, 12);
}

void draw() {
  for (int j = 0; j < d ; j++) {
    for (int i = 0; i < d ; i++) {
      image(camera, i*width/d, j*height/d);
    }
  }
} 

void captureEvent(Capture camera) {
  camera.read();
}

色情報を取得して再描画する

sketch_1b_10_3

import processing.video.*;
Capture camera;

void setup() {
  size(480, 320);
  camera = new Capture(this, width, height, 12);
  smooth();
  noStroke();
}

void draw() {
  background(0);
  camera.loadPixels(); //カメラ画像のpixel情報を読み込み
  int d = 10; //円の直径を定義
  // ライブカメラの映像から、円の直径の間隔ごとに、色情報を取得し、その色で円を描く
  for(int y = d / 2 ; y < height ; y += d) {
    for(int x = d / 2 ; x < width ; x += d) {
      fill(camera.pixels[y * width + x]);
      ellipse(x, y, d, d);
    }
  }
} 

void captureEvent(Capture camera) {
  camera.read();
}

練習

  • 円の大きさをランダムにしてみる
  • 異なる図形や文字で描画してみる
  • 色情報を加工してみる

参考:OpenCV(画像処理ライブラリ)を使う

準備:OpenCVのインストール

  • OPENCV \ library
    • OpenCVのインストール
    • OpenCVの Processing ライブラリを、書類 > Processing > libraries 内に配置

※Mac室では、インストールの権限制限があり、みなさん自身ではインストールができません。利用したい場合は事前に相談ください。

そのまま表示する

sketch_1b_10_5

import hypermedia.video.*; //OpenCVライブラリをインポート
OpenCV opencv; //OpenCV型の変数

void setup() {
  size(480, 320);
  opencv = new OpenCV(this);
  opencv.capture(width, height); ////映像読み込みの初期化
}

void draw() {
  opencv.read(); //映像を読み込む
  image(opencv.image(), 0, 0); //映像を表示
}
  • videoライブラリを使用するときよりも、コードがシンプルになる

加工して表示する

sketch_1b_10_6

import hypermedia.video.*;
OpenCV opencv;

void setup() {
  size(480, 320);
  opencv = new OpenCV(this);
  opencv.capture(width/2, height/2);
}

void draw() {
  opencv.read();
  //左上
  opencv.convert(OpenCV.GRAY); //グレースケールに変換  
  image(opencv.image(), 0, 0); //画面に表示 左上
  //右上
  opencv.invert(); //色を反転
  image(opencv.image(), width/2, 0); // 画面に表示 右上
  //左下
  opencv.restore(); //オリジナルの映像に戻す
  opencv.flip(OpenCV.FLIP_HORIZONTAL); //映像を水平方向に反転する
  image(opencv.image(), 0, height/2); // 画面に表示 左下
  //右下
  image(opencv.image(OpenCV.SOURCE), width/2, height/2); // 画面に表示 オリジナルの映像 右下
}

そのほかOpenCVでできること

  • Comments (Close): 0
  • TrackBack (Close): 0

b-05 ピクセルを操作する

  • 2011年10月31日 14:40
  • 2011-b

pixels[] pixels 配列

  • 画面全体またはPImageオブジェクトを1次元の配列として表したもの
  • color型の配列
  • (x, y)の情報は pixels[y*width + x] で得られる ※下で具体的に解説
  • loadPixels() pixelsを読み込み
  • updatePixels() pixelsの更新

20101106-161835

  • 幅10ピクセル、高さ4ピクセルの画面には、40個の点がある。
    • 左上から図のように、0から39の番号を割り振りふる。これらが pixels 配列のインデックス(番号)と一致する。
  • 幅7ピクエル、高さ4ピクセルの画面には、28個の点がある。
    • 点(5, 2) の情報は pixels[19] で得ることができる。この19という数は2*7+5(y座標*幅+x座標)で得られる。
  • 幅100ピクセル、高さ100ピクセルの画面には、10,000個の点がある。
  • 幅480ピクセル、高さ320ピクセルの画面には、153,600個の点がある。
    • これらの膨大な数の点の色情報を扱えるようにするのが pixels 配列である。

例1 画像の色を調べて表示する(カラーピッカー)

pixels0

PImage myPhoto;

void setup() {
  size(430, 640);
  myPhoto = loadImage("http://dl.dropbox.com/u/446018/processing/mannalisa.jpg"); //画像を読み込み
  noCursor(); //カーソルを非表示
}

void draw() {
  image(myPhoto, 0, 0); //画像を表示
  loadPixels(); //画面全体の色情報を配列pixelsとして読み込む
  //x,y座標に現在のマウスの位置を代入
  int x = mouseX;
  int y = mouseY;
  //マウス位置に縦線・横線を表示
  stroke(255, 51);
  line(x, 0, x, height);
  line(0, y, width, y);
  //マウス位置の色情報を取得し、塗り色に設定
  fill(pixels[y*width + x]);
  //画面左上にマウス位置の色を表示
  stroke(0);
  rect(20, 20, 60, 60);
}

例2 画像の色を調べて、図形や文字で再描画する(モザイク)

pixels1 pixels1

マウスを動かして描く

PImage myPhoto;

void setup() {
  size(430, 640);
  myPhoto = loadImage("http://dl.dropbox.com/u/446018/processing/mannalisa.jpg"); //画像を読み込み
  noStroke();
  smooth();
  background(255);
}

void draw() {
  myPhoto.loadPixels(); //myPhotoに読み込まれた画像の色情報を配列pixelsとして読み込む
  //x,y座標に現在のマウスの位置を代入(x,yの値が画像サイズを超えないようにconstrain関数を利用)
  int x = constrain(mouseX, 0, myPhoto.width-1);
  int y = constrain(mouseY, 0, myPhoto.height-1); 
  //その点の色情報を取得し、塗り色に設定
  fill(myPhoto.pixels[y*width + x]);
  //その点の位置を中心として直径10から20pxの円を描く
  float d = random(10, 20);
  ellipse(x, y, d, d);
}

アニメーションでランダムに描く

PImage myPhoto;
int myPhotoWidth, myPhotoHeight;

void setup() {
  size(430, 640);
  myPhoto = loadImage("http://dl.dropbox.com/u/446018/processing/mannalisa.jpg"); //画像を読み込み
  //画像のサイズを取得し変数に代入
  myPhotoWidth = myPhoto.width;
  myPhotoHeight = myPhoto.height;
  noStroke();
  smooth();
  background(255);
}

void draw() {
  myPhoto.loadPixels(); //myPhotoに読み込まれた画像の色情報を配列pixelsとして読み込む
  //x,y座標をランダムに指定
  int x = int(random(myPhotoWidth));
  int y = int(random(myPhotoHeight));
  //その点の色情報を取得し、塗り色に設定
  fill(myPhoto.pixels[y*width + x]);
  //その点の位置を中心として直径10から20pxの円を描く
  float d = random(10, 20);
  ellipse(x, y, d, d);
}

pixels のカラーデータ

これらを利用すると、さらに詳細な色設定が可能になる。

  • red() 赤成分の値
  • green() 緑成分の値
  • blue() 青成分の値
  • hue () 色相の値
  • saturation() 彩度の値
  • brightness() 輝度の値
  • alpha() アルファ値

pixels1

PImage myPhoto;
int myPhotoWidth, myPhotoHeight;

void setup() {
  size(430, 640);
  colorMode(HSB);
  myPhoto = loadImage("http://dl.dropbox.com/u/446018/processing/mannalisa.jpg"); //画像を読み込み
  //画像のサイズを取得し変数に代入
  myPhotoWidth = myPhoto.width;
  myPhotoHeight = myPhoto.height;
  noStroke();
  smooth();
  background(255);
}

void draw() {
  myPhoto.loadPixels(); //myPhotoに読み込まれた画像の色情報を配列pixelsとして読み込む
  //x,y座標をランダムに指定
  int x = int(random(myPhotoWidth));
  int y = int(random(myPhotoHeight));
  //その点の色情報を取得
  color myPhotoColor = myPhoto.pixels[y*width+x];
  //塗り色に設定(色相と明度は変更なし、輝度は0に設定 ...モノクロになる)
  fill(hue(myPhotoColor), 0, brightness(myPhotoColor));
  //その点の位置を中心として直径10から20pxの円を描く
  float d = random(10, 20);
  ellipse(x, y, d, d);
}

練習:画像の色を調べて、図形や文字で再描画する(元画像の原形をとどめていなくても良い)

pixels4pixels5pixels6pixels7

  • Comments (Close): 0
  • TrackBack (Close): 0

b-04 配列を使う

  • 2011年10月24日 14:40
  • 2011-b

配列とは

似たような複数の変数をプログラムで制御したい場合は「配列」を利用する。

例えば、

How are you? I am fine thank you!

という会話中の単語を用いて何かブログラムを書こうとするとき、配列を用いない場合は

String s0 = "How";
String s1 = "are";
String s2 = "you?";
String s3 = "I";
String s4 = "am";
String s5 = "fine";
String s6 = "thank";
String s7 = "you!";

と1つずつ変数に代入する必要があるが、配列を用いれば

String[] chat = {"How","are","you?","I","am","fine","thank","you!"};

というように、まとめて代入ができる。

array

配列には「インデックス」と呼ばれる0から始まる番地があり、順に値が代入される(マンションの0号室, 1号室, 2号室... とイメージするとわかりやすい)。

配列に代入された値は、このインデックスを用いて利用する。例えば、"How"という文字を利用したければ、0番(1番ではなく、0から始まることに注意)を指定すればよい。具体的には、

String[] chat = {"How","are","you?","I","am","fine","thank","you!"};
text(chat[0], 0, 50);

とすれば、画面中央左に「How」と表示される。chat[0] は「配列chatの0番の値」ということである。

array1

そのほかの単語も画面に表示してみよう。

for文を用いてすべての単語をランダムな位置に表示する

インデックスは0から始まる整数の連番なので、for文を用いた処理と相性が良い。例えば、配列のすべての値を表示したい場合は、以下のように書くことができる。

array1

String[] chat = {"How","are","you?","I","am","fine","thank","you!"};
for (int i = 0; i < chat.length; i++) {
  text(chat[i], random(width), random(height));
}

ポイントはfor文の繰り返しの範囲を chat.length で表しているところ。こうすると「配列 chat の長さ」(この場合は8)が適用される。

※このプログラムでは、文字が画面からはみ出てしまうことがあるので、textAlignの指定を追加したりrandomの指定を調整すると良い。

単語を順に表示する

String[] chat = {"How","are","you?","I","am","fine","thank","you!"};
int count = 0;

void setup() {
  size(100, 100);
  frameRate(3);
}

void draw() {
  background(204);
  fill(0);
  textAlign(CENTER);
  text(chat[count], width/2, height/2);
  count++;
  if(count >= chat.length) count = 0;
}

ポイントは2つ。

  • setupでフレームレート(1秒間に再生するフレーム数)の設定をしている。frameRate(3) は「1秒間に3フレーム再生する」ということ。
  • 1回再生するごとにカウンター(変数countでカウント)を1増やし、countの値が配列の長さ以上になったらカウンターをリセット(countの値を0)している。こうすることで、繰り返し単語が順に表示される。

練習「おみくじ」を作る

  • 大吉、中吉、小吉、吉の4つとする
  • ウィンドウサイズは自由とする

制作の進め方で気を付けたいこと

  • 基本的な機能が動作するシンプルな「プロトタイプ」を作る
  • プロトタイプが出来てから、細部を作り込んでいく

作り方のヒント

  • どのタイミングでおみじくを表示するか?
    • ユーザーがアクションを起こしたとき
  • どうやってユーザーにアクションを起こしてもらうか?
    • マウスやキーボードからの入力
  • おみくじデータの用意方法は?
    • 配列を利用する
  • おみくじをランダムに選ぶには?
    • random関数を利用する
  • 大吉が出にくく、吉が出やすくするには?
    • 「100本のくじのうち、大吉は10本、中吉は20本、小吉は30本、吉は40本」と考える
    • if(...){...}else if(...){...}else if(...){...}else{}

配列を使ったプログラムの例

形の描画を効率化する

void setup() {
  size(600, 300);
}

void draw() {
  //画面のリセット
  fill(204, 10);
  noStroke();
  rect(0, 0, width, height);
  //ランダムな位置・傾き・サイズで☆が描画されるように座標変換する
  translate(random(width), random(height));
  rotate(random(PI));
  scale(random(0.1, 0.5));
  //配列の定義
  int[] x = {50, 29, 83, 17, 71}; //点A,B,C,D,Eのx座標
  int[] y = {18, 82, 43, 43, 82}; //点A,B,C,D,Eのy座標
  // 5つの点A,B,C,D,Eを順に直線で結び☆を描く
  translate(-50, -50); //☆を原点の位置に座標変換する
  fill(255);
  stroke(0);
  beginShape();
  for (int i = 0; i < x.length; i++) {
    vertex(x[i] + random(-5, 5), y[i] + random(-5, 5));
  }
  endShape(CLOSE);
}

カーソルの位置を記憶させる

int num = 50; //円の個数
int[] x = new int[num]; //x座標を記録する配列
int[] y = new int[num]; //y座標を記録する配列

void setup() {
  size(600, 300);
}

void draw() {
   background(204); //画面をリセット
  //配列を参照して円を描画する
  for(int i = 0 ; i < num ; i++) {
    fill(i * 3);
    ellipse(x[i], y[i], i, i);
  }
}

//マウスが動いたときの処理:マウスの座標を記録する
void mouseMoved() {
  //配列の値をひとつ後ろへ移動する
  for(int i = num - 1 ; i > 0 ; i--) {
    x[i] = x[i-1];
    y[i] = y[i-1];
  }
  x[0] = mouseX;
  y[0] = mouseY;
}

画像を読み込んでアニメーションにする

int numFrames = 60; //アニメーションのフレーム数
PImage[] images = new PImage[numFrames]; //アニメーション画像の配列

void setup() {
  size(320, 240);
  frameRate(30);
  // 画像の読み込み
  for (int i = 0; i < images.length; i++) {
    images[i] = loadImage("http://dl.dropbox.com/u/446018/sq_iinaiina/animation-" + nf(i, 3) + ".jpg");
  }
}

void draw() {
  int frame = frameCount % numFrames; //現在のフレームをアニメーションのフレーム数で割った余りを代入
  image(images[frame], 0, 0); //画像を表示
}
  • Comments (Close): 0
  • TrackBack (Close): 0

b-03 文字を使う

  • 2011年10月17日 14:40
  • 2011-b

text() 文字を描く関数

text1

text("あいうえお愛", 10, 35); // 表示するテキスト, x座標, y座標

text2

text("あいうえお愛", 10, 35, 40, 40); // 表示するテキスト, x座標, y座標, 表示領域の幅, 表示領域の高さ

text3

fill(0); //塗色を設定する
text("あいうえお愛", 10, 35, 40, 40);

textSize() 文字サイズを指定する

textSize

fill(0);
textSize(16);
text("あいうえお愛", 10, 35);

textAlign() 文字揃えを指定する

textAlign

fill(0);
textAlign(CENTER);
text("あいうえお愛", 50, 35);

String 文字列のデータ型

text1

文字列を変数で扱う場合は String 型を用いる。

String s = "あいうえお愛";
text(s, 10, 35);

ランダムに表示する

ランダムな位置に、ランダムな数字を表示する

text1

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

void draw() {
  fill(random(256));
  textSize(random(12, 36));
  textAlign(CENTER);
  text(int(random(10)), random(width), random(height));
}

キーボードを押すと、その文字をランダムな位置に表示する

text2

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

void draw() {
}

void keyPressed() {
  fill(random(256), random(102, 256));
  textSize(random(36, 64));
  textAlign(CENTER);
  text(key, random(width), random(height));
}

指定したフォントで文字を描く

準備

以下のようにフォントデータを生成しておく

08-12 08-13

PFont 変数でフォントデータを扱う場合のデータ型 , textFont 使用するフォントを指定

08-14

size(500, 200);

PFont myFont = loadFont("HelveticaNeue-Bold-24.vlw");
textFont(myFont);

text("I Love Processing!", 0, 100);
  • Comments (Close): 0
  • TrackBack (Close): 0

b-02 反応させる(マウス、キーボードからの入力に)

  • 2011年10月10日 14:40
  • 2011-b

mouseX, mouseY マウスポインタの位置(座標)

現在のマウスポインタの位置に円が描かれる。

ib_4_0

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

void draw() {
  ellipse(mouseX, mouseY, 60, 60);
}

pmouseX, pmouseY 前フレームのマウスポインタの位置(座標)

前フレームのマウスポインタの位置から現フレームのマウスポインタの位置に線が描かれる。(マウスを動かすと、線が描かれるように見える)

1b_4_1

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

void draw() {
  line(mouseX, mouseY, pmouseX, pmouseY);
}

mousePressed マウスボタンが押されている(== true)、押されていない(== false)

マウスボタンを押している間、線が描かれる。

1b_4_2

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

void draw() {
  if (mousePressed == true){
    line(mouseX, mouseY, pmouseX, pmouseY);
  }
}

mousePressed() {...} マウスボタンが押されたときに1回だけ {...} の中を実行する

マウスボタンを押すと、円が描かれる。

1b_4_3

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

void draw() {
}

void mousePressed() {
  ellipse(mouseX, mouseY, 60, 60);
}

mouseReleased() {...} マウスボタンが離されたときに1回だけ {...} の中を実行する

マウスボタンを押している間、線が描かれる。ボタンが離されると線が消える。

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

void draw() {
  if (mousePressed == true){
    line(mouseX, mouseY, pmouseX, pmouseY);
  }
}

void mouseReleased() {
  background(204); //マウスボタンが離されると画面がリセットされる
}

練習:次のような動作をするプログラムを書く

マウスポインタの位置に赤い円が描かれる。マウスボタンを押すと、円の塗り色が変わる。

ib_4_5

マウスボタンを押すと、前回マウスボタンを押した位置からの折れ線が描ける。

ib_4_4

keyPressed キーが押されている(== true)、押されていない(== false)

キーが押されているとき、円が左から右にすすむ

1b_05_1

float x = 0.0;
float speed = 1.0;

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

void draw() {
  background(204);
  if (keyPressed == true) {
    x += speed;
    //println(key);
  }
  ellipse(x, height/2, 60, 60);
}

key 押されたキーの文字や記号を納める変数

キーのa(小文字のエー)が押されているとき、円が左から右にすすむ

float x = 0.0;
float speed = 1.0;

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

void draw() {
  background(204);
  if ((keyPressed == true) && (key == 'a')) {
    x += speed;
  }
  ellipse(x, height/2, 60, 60);
}

※大文字小文字を問わないようにするためには、次のように「aまたはAが押されているとき」で条件を設定する

float x = 0.0;
float speed = 1.0;

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

void draw() {
  background(204);
  if ((keyPressed == true) && ((key == 'a') ||  (key == 'A'))) {
    x += speed;
  }
  ellipse(x, height/2, 60, 60);
}

keyPressed() {...} キーが押されたときに1回だけ {...} の中を実行する

※キーを押しっぱなしにして一定時間経つと、キーの連続入力状態になり、そのスピードに合わせ連続して実行される。

キーが押されると、円が1ピクセルだけ左から右にすすむ

float x = 0.0;
float speed = 1.0;

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

void draw() {
}

void keyPressed() {
  background(204);
  x += speed;
  ellipse(x, height/2, 60, 60);
  //println(key);
}

keyReleased() {...} キーが離されたときに1回だけ {...} の中を実行する

キーが離されると、円が止まる

float x = 0.0;
float speed = 1.0;

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

void draw() {
  background(204);
  x += speed;
  ellipse(x, height/2, 60, 60);
}

void keyReleased() {
  speed = 0.0;
}
  • Comments (Close): 0
  • TrackBack (Close): 0

b-01 動かす

  • 2011年10月 3日 14:40
  • 2011-b

正方形を横に動かす

step.1 静止した正方形を描く

//最初に1回だけ実行する
void setup() {
  size(200, 200);
}

//毎フレーム繰り返し実行する
void draw() {
  rect(0, height/2, 10, 10); //画面中央左に一辺が10pxの正方形を描く
}

rectのx座標がじょじょに大きくなれば、正方形は数のように左に移動し、動いているように見える。

1b-02-1-26 1b-02-1-52 1b-02-1-79

step.2 正方形のx座標を変数で置き換え、変数の値がじょじょに大きくなるようにする

float x; //小数型の変数xを宣言
void setup() {
  size(200, 200);
  x = 0; //xの初期値を0とする
}

void draw() {
  x += 1; //毎フレームで正方形のx座標を1ずつ増やす
  rect(x, height/2, 10, 10);
}

motion-linear01

正方形が動くようになったが、黒い帯が残る。これは、正方形が描き重ねられているからである。毎フレームで画面をクリアした後に正方形を描けば、黒い帯は残らないようになる。

step. 3 画面をクリアしてから正方形を描画する

float x;
void setup() {
  size(200, 200);
  x = 0;
}

void draw() {
  background(204); //背景色を設定することで画面をクリアする
  x += 1;
  rect(x, height/2, 10, 10);
}

正方形が画面右に消える(正方形のx座標が200を超える)と、画面に変化がなくなってしまい退屈である。次に、右に消えたら再び左から現れるようにしよう。

step. 4 ループ移動させる

float x;
void setup() {
  size(200, 200);
  x = 0;
}

void draw() {
  background(204);
  x += 1;
  if (x > width) x = -10; //正方形が画面からはみ出たら、正方形を画面の左外に戻す
  rect(x, height/2, 10, 10);
}

step. 5 正方形の出現位置をランダムに設定する

if文を実行する際、正方形のy座標をランダムに設定するし、さらに変化を付ける。

float x, y; //変数にyを追加
void setup() {
  size(200, 200);
  x = 0;
  y = height/2; //yの初期値を画面の中央にする
}

void draw() {
  background(204);
  x += 1;
  if (x > width) { 
    x = -10;
    y = random(width - 10); //正方形が画面内に収まる範囲で、yの値をランダムに設定
  }
  rect(x, y, 10, 10);
}

練習 - 上記のプログラムを改変してみる

  1. 正方形の幅を変数wで表し、任意の大きさの正方形がループ移動するプログラムに書きかえる
  2. 正方形の移動するスピードを速くする、または遅くする
  3. 正方形の移動するスピードを変数speedで表し、任意のスピードで正方形が移動するプログラムに書きかえる
  4. 正方形を右から左に動かす(ヒント:元のプログラムを書きかえる際、if文はコメントアウトしておき、移動の部分を書きかえてから、if文でのループ移動の条件を書きかえる)
  5. 正方形を上から下に動かす
  6. 円を動かす

座標を移動する

座標を移動することで、正方形が動いているように見せることができる。このやり方の方が汎用性がある。

float x, y;
float speed;
int w;
void setup() {
  size(200, 200);
  x = 0.0;
  y = height/2.0;
  speed = 1.0;
  w = 10;
}

void draw() {
  background(204);
  x += speed;
  if (x > width) {
    x = -w;
    y = random(width - w);
  }
  translate(x, y); //座標を移動する
  rect(0, 0, w, w); //座標を移動するので、正方形は固定の位置に描画する
}

応用例:バスを動かす

float x, y;
float speed;
void setup() {
  size(200, 200);
  x = 0.0;
  y = height/2.0;
  speed = 1.0;
}

void draw() {
  background(204);
  x += speed;
  if (x > width+60) {
    x = -60;
    y = random(30, width-45);
  }
  translate(x, y);
  //draw Bus
  rectMode(CENTER);
  rect(0,0,120,60);
  ellipse(-35,30,30,30);
  ellipse(35,30,30,30);
  ellipse(-35,30,20,20);
  ellipse(35,30,20,20);
  rectMode(CORNER);
  rect(45,-20,15,20);
  rect(-5,-20,30,20);
  rect(-50,-20,30,20);
}
  • Comments (Close): 0
  • TrackBack (Close): 0

Index of all entries

Home> 2011-bアーカイブ

カテゴリ
アーカイブ
購読
Recommends
Processing: A Programming Handbook for Visual Designers and Artists Learning Processing: A Beginner's Guide to Programming Images, Animation, and Interaction (Morgan Kaufmann Series in Computer Graphics and Geometric Modeling) FORM+CODE -デザイン/アート/建築における、かたちとコード Form+Code in Design, Art, and Architecture (Design Briefs) Generative Gestaltung Generative Art Built with Processing[Ver. 1.x対応版] -デザイン/アートのためのプログラミング入門 Getting Started With Processing Arduinoをはじめよう ビジュアライジング・データ ―Processingによる情報視覚化手法 +GAINER―PHYSICAL COMPUTING WITH GAINER
Powerd By

Return to page top