2013年5月31日 星期五

[對照]蝦爸的p5範例 8-2 繼承應用

讓音樂的音量,影響球體上節點離中心點的距離。

[Processing code] ↓

float r;
float theta;
float phi;
ArrayList group;

import ddf.minim.*;

Minim minim;
AudioPlayer player;

void setup() {
  size(600, 300, OPENGL);
  group=new ArrayList();
  r=200;
  theta=0;
  phi=0;

  minim = new Minim(this);
  player = minim.loadFile("topas.wav"); 
  player.loop();
}


void draw() {
  background(0);
  //camera(mouseX, -mouseY, 400, 0, 0, 0, 0, 1, 0);
  camera(500, -300, 400, 0, 0, 0, 0, 1, 0);
  for (int i=0;i<group.size();i++) {

    ((Music)group.get(i)).update();
    if ( ((Music)group.get(i)).life==0) {
      group.remove(i);
    }
  }

  for (int i=0;i<group.size();i++) {
    for (int j=i+1;j<group.size();j++) {
      ((Music)group.get(i)).MusicGraphic((player.left.level()+player.right.level())/2);

      Music aa=((Music)group.get(i));
      Music bb=((Music)group.get(j));

      float t_x1=aa.get_x();
      float t_y1=aa.get_y();
      float t_z1=aa.get_z();

      float t_x2=bb.get_x();
      float t_y2=bb.get_y();
      float t_z2=bb.get_z();

      if (Distance( t_x1, t_x2, t_y1, t_y2, t_z1, t_z2) < 50) {
        stroke(150);
        strokeWeight(1);
        line(t_x1, t_y1, t_z1, t_x2, t_y2, t_z2);
      }
    }
  }
}

void mousePressed() {
  for (int i=0;i<5;i++) {
    group.add(new Music(r, 0, 0, color(0, 0, 200, 100)));
  }
}


class Music extends e_point {
  float add_r;
  float T_r;
  Music(float e_r, float e_theta, float e_phi, color e_c ) {
    r=e_r;
    theta=e_theta;
    phi=e_phi;
    cc=e_c;
    v_t=random(0, 1);
    v_p=random(0, 1);
    life=(int)random(500, 1000);
    size=random(5, 20);
    add_r=random(1,r);
  }

  void MusicGraphic(float vol) {
    float px=(r+vol*add_r)*cos(radians(theta))*cos(radians(phi));
    float py=(r+vol*add_r)*sin(radians(phi));
    float pz=(r+vol*add_r)*sin(radians(theta))*cos(radians(phi));
    T_r = (r+vol*add_r);
    stroke(cc);
    strokeWeight(size*0.5);
    point(px, py, pz);
  }
  float get_x() {
    return (T_r)*cos(radians(theta))*cos(radians(phi));
  }
  float get_y() {
    return (T_r)*sin(radians(phi));
  }
  float get_z() {
    return (T_r)*sin(radians(theta))*cos(radians(phi));
  }
  
}

class e_point {

  float r, theta, phi;
  color cc;
  float v_t, v_p;
  int life;
  float size;

  e_point() {
  }
  e_point(float e_r, float e_theta, float e_phi, color e_c ) {
    r=e_r;
    theta=e_theta;
    phi=e_phi;
    cc=e_c;
    v_t=random(0, 1);
    v_p=random(0, 1);
    life=(int)random(500, 1000);
    size=random(5, 20);
  }

  void graphic() {
    float px=r*cos(radians(theta))*cos(radians(phi));
    float py=r*sin(radians(phi));
    float pz=r*sin(radians(theta))*cos(radians(phi));
    stroke(cc);
    strokeWeight(1);
    point(px, py, pz);
  }

  void update() {
    theta=theta+v_t;
    phi=phi+v_p;
    life--;
  }

  float get_x() {
    return r*cos(radians(theta))*cos(radians(phi));
  }
  float get_y() {
    return r*sin(radians(phi));
  }
  float get_z() {
    return r*sin(radians(theta))*cos(radians(phi));
  }
}


float Distance(float x1, float x2, float y1, float y2, float z1, float z2) {
  float Temp;
  Temp= sqrt(sq(x1-x2)+sq(y1-y2)+sq(z1-z2));
  return Temp;
}


[對照]蝦爸的p5範例 8-1 繼承的概念

Pd與P5對抗來到第八週,也是本系列最後一次的對抗。在最後的範例中,蝦爸分享了一些他執行專案上常用的技巧,包含利用繼承的手法,呼叫、使用過往撰寫過的程式碼,以及釋放記憶體,讓電腦處於長期運作時,減低當機風險等等技巧。

八週的友誼對抗下來,我還是認為軟體之間並無決定性的差異,人才是影響作品好壞的關鍵,所以與其斤斤計較軟體的優劣,不如多花時間研究更底層的知識,我想這才是Code Art的王道。

感謝蝦爸這幾週來無私的分享,我們成長過程中知識的養成多半來自網路,也都認為分享與開源都是非常重要的一件事情,所以雖然目前貢獻的並不多,但我們一定會持續創作分享下去,最後引用一句影響我至深的名言來當作本系列分享的結尾:

「If I have seen farther than others, it is because I was standing on the shoulders of giants」,Sir Isaac Newton。
[Processing code] ↓
Big_Car a;
void setup() {
  a=new Big_Car();
}

void draw() {
}


class Big_Car extends Car {
  Big_Car()
  {
    println(px);
  }
}

class Car {
  float px;

  Car() {
    px=5;
  }
}



[Pd code] ↓


Inheritance.zip

「筆記」QC進階筆記1-2

本範透過[mouse]物件以及[javascript]物件,設計了一個簡單常見的互動方式,拖拉矩形。

[draw line]

var first=true;
function (__number x1,__number y1,__number x2,__number y2) 
         main (__number x,__number y,__boolean click )
{
 var result = new Object();
 if(click){
  if(first){
   result.x1=x;
   result.y1=y;
   first=false;
 }
 result.x2=x;
 result.y2=y;
 
 }else {
      first=true;
 }
 return result;
}
在[draw line]的js程式中,有4個輸出,分別是第一個點的(x1,y1)、即第二個點(x2,y2)的座標。


[draw rectangle]

var first=true;
var x1;
var y1;
var x2;
var y2;
function (__number out_x,__number out_y,__number width,__number height) 
         main (__number x,__number y,__boolean click)
{
 var result = new Object();
 if(click){
  if(first){
   x1=x;
   y1=y;
   first=false;
  }
  x2=x;
  y2=y;
  result.out_x=(x1+x2)/2;
  result.out_y=(y1+y2)/2;
  result.width=Math.abs(x1-x2);
  result.height=Math.abs(y1-y2); 
 }else{
 first=true;
 }
 return result;
}
在[draw rectangle]的js程式中,設計了一個繪製矩形的程式,最後會輸出矩形的中心座標(x,y)以及矩形的寬(width)、以及高(height)。


[rect_position]

function (__number x1, __number y1,__number x2, __number y2,__number x3, __number y3,__number x4, __number y4)
 main (__number c_x,__number c_y,__number width,__number height)
{
 var result = new Object();
 result.x1=c_x-width/2;
 result.y1=c_y+height/2;
 
 result.x2=c_x+width/2;
 result.y2=c_y+height/2;
 
 result.x3=c_x+width/2;
 result.y3=c_y-height/2;
 
 result.x4=c_x-width/2;
 result.y4=c_y-height/2;
  
 return result;
}
在[rect_position]程式中,會把矩形的的長寬、中心點等資訊,轉換成四個座標點,分別為(x1,y1)、(x2,y2)、(x3,y4)、(x4,y5)等四點。



(MARCO:NewSquare)

(Main Scence)


ps.本範例須要先安裝 kineme 公司出的[GLTools.plugin]套件。

「筆記」QC進階筆記1-1

本系列筆記為「QC影像進階講座」的內容摘要,如有任何問題,請洽睡不著音像講座,或請加入FB GROUP 跟經堯老師提問。

2013/06/18新增:經堯老師的QC筆記

數學運算

function (__number out) main (__number a,__number b)
{
 var result = new Object();
 result.out = a - b
 return result;
}
QC可以透過javascript物件來撰寫複雜邏輯,在上述的程式碼中,宣告了a、b兩個變數,並且算試a-b的結果會輸出給變數c。


 圖中a的數值為5,b的數值為1,因此5-1=4;c=4。
qc2_w1-1.qtz

-------------------------------------------------

圓座標公式


透過數學公式,讓圓球繞圓移動。
function (__number x,__number y) main (__number angle,__number radius)
{
 var result=new Object();
 
 result.x=Math.cos(angle*2*Math.PI)*radius;
 result.y=Math.sin(angle*2*Math.PI)*radius;
 
 return result;
}
qc2_w1-2.qtz

2013年5月26日 星期日

[作品]CROSS


這是在寫voronoi演算法的時候,無意間產生的作品。
方法:當兩條線重疊時會產生正弦頻率,並且越靠近起始端點時,振幅越大;而線條的長度則影響頻率,線條越長音高越高。

2013年5月25日 星期六

[作品] Voronoi Diagram

Voronoi diagrams可以用來計算平面上散落的點身處的勢力範圍。身處哪個勢力範圍就代表你離那個目標點最近。
在這一個範例中,我用了最笨的方法去計算,讓每個pixel去掃秒座標上的所有的目標點,如果pixel(A)離目標B點最近,那就會去抓B所代表的顏色。這個方法很笨的原因是,他沒有效率的計算每個點,如果是200*200 pixel,就需要計算4萬次,所以產生一張圖要花費數秒,圖法煉鋼總是會遇到瓶頸的,囧。


File Download,你可能還需要[gemvertexbuffer]這個物件。

2013年5月18日 星期六

[作品]自走路徑



這個作品的產生是蝦爸給我的靈感,在第七堂P5與pd的挑戰中,蝦爸分享了迷宮路徑的寫法,我本來以為這只能用來訓練解題,以及練習遞迴寫法,對實際做作品的幫助不大。沒想到在我胡亂的測試中,發現迷宮的演算,非常適合來繪製對稱圖形,並且只要稍加修改排列的方法,讓演算時的位置稍微錯誤,就能夠產生出非常有趣圖形!

我自己在看這件作品時,會聯想到鋼鐵人頭罩裡的人機界面,這是一直以來我很想要做的視覺,以前一直覺得應該不好寫,沒想到竟然在亂試的結果中產生,這下真是賺到了XD。

更多作品的截圖>

2013年5月16日 星期四

[Pd筆記-62] [sigmund~]頻譜分析工具

[sigmund~]跟[fiddle~]一樣都是頻譜分析工具的一種,透過加上pitch、env等標籤,[sigmund~]物件便能分析音訊並輸出偵測數值。


[Pd筆記-61] [arraysize]讀取陣列大小

[arraysize]這個物件的使用方式很簡單,只要在該物件後方打上陣列名稱,並在第一個inlet上送進一個bang,就可以得知該鎮烈的大小。


[對照]蝦爸的p5範例 7-2 「運用遞迴概念,製造迷宮材質」

[Processing Example]

本練習將透過遞迴概念的運用,製造有趣的迷宮材質貼圖。
迷宮的產生邏輯由二要素構成:
  • 不管從任何一點出發,迷宮都會佈滿所有路徑
  • 路徑會隨機增長,死路時會回到上一個還能選擇的路口,往其他方向增長。

[Processing code] ↓

int[][] Maze=new int[10][10];
int[][] Temp=new int[21][21];

int outline;
PGraphics Maze_Texture;

void setup() {
  size(600, 400, OPENGL); 
  outline=17;
  
  Maze_Texture=createGraphics(outline*10, outline*10, OPENGL);
  
  for (int i=0;i<10;i++) {
    for (int j=0;j<10;j++) {
      if ((i==0 ||i==9)||(j==0 ||j==9)) {
        Maze[i][j]=2;
      }
      else {
        Maze[i][j]=0;
      }
    }
  }//初始化,邊緣不計算

  for (int i=0;i<outline;i++) {
    for (int j=0;j<outline;j++) {
      if ((i==0 ||(i==outline-1))||(j==0 ||j==(outline-1))) {
        Temp[i][j]=2;
      }
      else {
        Temp[i][j]=0;
      }
    }
  }

  Walker(1, 1);

  for (int i=0;i<10;i++) {
    for (int j=0;j<10;j++) {
      if (Maze[i][j]==2) {
        fill(255, 0, 0);
      }
      else if (Maze[i][j]==1) {
        fill(0, 255, 0);
      }
      else {
        fill(0, 0, 255);
      }
      rect(i*10, j*10, 10, 10);
    }
  }
  
  //---將影像寫入buffer
  Maze_Texture.beginDraw(); 
  for (int i=0;i<outline;i++) {
    for (int j=0;j<outline;j++) {
      Maze_Texture.noStroke();
      if (Temp[i][j]==2) {
        Maze_Texture.fill(50, 50, 50);
      }
      else if (Temp[i][j]==1) {
        Maze_Texture.fill(200, 200, 200);
      }
      else {
        Maze_Texture.fill(100, 100, 100);
      }
     Maze_Texture. rect(i*10, j*10, 10, 10);
    }
  }
  Maze_Texture.endDraw();
  //---結束寫入
}

void draw() {
  background(0);
  camera(mouseX, mouseY, 200, 0, 0, 0, 0, 1, 0);
  beginShape();
  textureMode(NORMAL);
  texture(Maze_Texture);
  vertex(-100, -100, 0, 0, 0);
  vertex(100, -100, 0, 1, 0);
  vertex(100, 100, 0, 1, 1);
  vertex(-100, 100, 0, 0, 1);
  endShape();
}

void Walker(int x, int y) {
  Temp[x*2-1][y*2-1]=1;
  Maze[x][y]=1;
  for (;;) {
    if ((Maze[x-1][y]!=0)&&(Maze[x][y+1]!=0)&&(Maze[x+1][y]!=0)&&(Maze[x][y-1]!=0)) {
      break;
    }
    int Dircet=(int)random(4)%4;//Direct:0 left,1 down,2 right,3 up
    if ((Dircet==0) && (Maze[x-1][y] !=0 )) continue;
    if ((Dircet==1) && (Maze[x][y+1] !=0 )) continue;
    if ((Dircet==2) && (Maze[x+1][y] !=0 )) continue;
    if ((Dircet==3) && (Maze[x][y-1] !=0 )) continue;

    if ((Dircet==0) && (Maze[x-1][y] == 0)) {
      Temp[x*2-2][y*2-1]=1;
      Walker(x-1, y);
    }
    if ((Dircet==1) && (Maze[x][y+1] == 0)) {
      Temp[x*2-1][y*2]=1;
      Walker(x, y+1);
    }  
    if ((Dircet==2) && (Maze[x+1][y] == 0)) {
      Temp[x*2][y*2-1]=1;
      Walker(x+1, y);
    }
    if ((Dircet==3) && (Maze[x][y-1] == 0)) {
      Temp[x*2-1][y*2-2]=1;
      Walker(x, y-1);
    }
  }
}

[Pd Example]


P5 的迷宮貼圖是透過遞迴所產生,而Pd的範例中,則得利用讀取陣列的方式才能達成,且P5的座標是儲存在二維陣列中,當程式走到死路時,很快就能夠利用break退到上一個選擇點,在Pd則是利用一維陣列去模擬二維陣列的座標,再加上Pd並沒有continue 及break的概念,因此我是利用[spigot]來阻斷訊息,以及[delay]來阻止程式stack overflow。

在我的經驗裡,撰寫簡單的圖形及互動時,Pd會比P5好用,可是如果是像本範例中的邏輯演算,那P5實在比Pd好寫太多,用Pd寫是真的是自討哭吃(但我就是戒不掉呀..)

[Pd code] ↓

(maze.pd)

(pd setup============)

(pd class-Walker)

(pd write-Walker)

(pd back)

[對照]蝦爸的p5範例 7-1 「把影像繪製在buffer在貼回polygon」

在白色的polygon內透過[PGraphic]繪製一條線

[Processing Example]

本週的對抗裡,蝦爸提出了一個有趣的概念,企圖把過往繪製的圖形,當成貼圖材質,讓材質本身也是及時運算的結果。
因此本週重點分為兩項,如何在虛擬攝影機中繪製影像並貼回原本物件,以及製造有趣複雜的貼圖材質。

[Processing code] ↓

PGraphics b;

void setup() {
  size(600, 300, OPENGL);
  b=createGraphics(400, 400, OPENGL);
}

void draw() {

  b.beginDraw();
  b.background(255);
  b.strokeWeight(5);
  b.stroke(255, 0, 0);
  b.line(0, 0, 400, 400);
  b.endDraw();

  //image(a, 0, 0);
  background(0);
  camera(mouseX, mouseY, 200, 0, 0, 0, 0, 1, 0);
  beginShape();
  textureMode(NORMAL);
  texture(b);
  vertex(-100, -100, 0, 0, 0);
  vertex(100, -100, 0, 1, 0);
  vertex(100, 100, 0, 1, 1);
  vertex(-100, 100, 0, 0, 1);
  endShape();
}

[Pd Example]

在Pd中,把繪製好的圖檔存在[gemframebuffer]物件中,並且以[GEMgl]等原生的OPENGL物件,來繪製頂點。

[Pd code] ↓


2013年5月7日 星期二

[教學]測試VBO在pd的效能



之前這個範例,用[GEMglVertex3f]物件做過,不過效能非常差,基本上動態完全不行。
在本範例練習中,同樣的電腦但改用[gemvertexbuffer]寫法後,效能顯著提升,雖然也不是到完美,但其實已經不錯了,以下是程式碼。





2013年5月6日 星期一

[筆記]在mac中編譯[gemvertexbuffer]物件

VBO是Vertex Buffer Object的簡稱,是OpenGL的一種功能,它提供利用顯示卡的記憶體來儲存資料,並且因為直接在GPU運算,所以大大提高了程式的運算效能。

Pd的GEM雖然是使用OpenGL當作開發引擎,可是因為使用版本過舊(OpenGL 1.5),所以並沒有VBO這功能,不過好在CHDH的Cyrille以及Antoine開發了[gemvertexbuffer]這功能,不然Pd在vertex上的大量運算,效能始終很差。(大量vertex節點,在Pd通常是利用[GEMglvertex3f] 此物件來製作,可以參考此範例

目前[gemvertexbuffer]的功能還沒放置於Pd-extended 的版本內,因此要透過自己編譯來使用它。

步驟一:下載原始程式碼,檔案在這原始開發討論串

步驟二:http://puredata.info/downloads/opencv/releases/0.2,安裝OpenCV,把檔案下載後,解壓縮後將整個資料夾(OpenCV.framework)移至入徑/Library/Frameworks內。

步驟三:下載此makefile檔,原始開發討論串

步驟四:講下載下來的makefile檔案,覆蓋至原本gemvertexbuffer資料夾內的makefile檔,並且用記事本打開檔案
搜尋:INCLUDES ,並且找到下述路徑
本來:-I/Applications/Pd-extended.app/Contents/Resources/include/
更改路徑如下:-I/Applications/Pd-extended.app/Contents/Resources/extra/Gem/dev

步驟五:打開終端機(terminal),
$cd 進入gemvertexbuffer的資料夾
並鍵入$ make

步驟六:看到gemvertexbuffer.pd_darwin,及代表編譯成功

步驟七:這裡是我編譯好的檔案 [gemvertexbuffer.pd_darwin],另外這裡則有gemvertexbuffer-help.pd檔,把兩個檔案放置同資料夾,即可使用[gemvertexbuffer]的功能。



步驟八:或者也可以透過Xcode 編譯,這裡是我的Xcode 的專案檔,下載

2013年5月5日 星期日

[筆記]如何在Xcode中,撰寫Pd擴充物件

本筆記是參閱下述三個網址撰寫而成↓↓

http://puredata.info/docs/developer/PdExternalsInXcode

http://musicgrad.ucsd.edu/~cbaker/Home/Code/Pd/

http://iem.at/pd/externals-HOWTO/

內文可能會有些疏失,因為自己對Xcode也還不熟,請大家多包含。
  • 系統:OSX 10.8.3
  • Xcode 版本:4.6.2
  • Pd版本:Pd-extended  0.42.5
步驟一:打開Xcode,建立一個新的Project(Create a new Xcode project)



步驟二:在範本選擇裡,挑選OS X標籤下的 > Framework & Library > C/C++ Library


步驟三:建立專案的名稱,這裡命名為「HelloWorld」,下面的作者名稱可以填上自己的姓名。接著它會問你專案儲存入徑,我暫且把專案儲存在桌面上。

步驟四:建立完成後,會出現如下圖的顯示,並且還未進行任何的編譯動作,所以在產品那欄會出現紅字顯示,Products:libHelloWorld.dylib

步驟五:建立一個新的檔案,Menu bar>File>New>File,並選擇C and C++標籤下的C File,並且取名為HelloWorld.ch。

步驟六:建立完成後,在HelloWorld 計劃下,會出現一個HelloWorld.c的檔案,並且HelloWorld.c會有預設的程式碼如下:
//
//  HelloWorld.c
//  HelloWorld
//
//  Created by aluan on 13/5/6.
//  Copyright (c) 2013年 aluan. All rights reserved.
//

#include 
步驟七:把下述程式碼,增添入HelloWorld.c ,這是一個簡單的擴充物件,當你把[bang]的訊號送入[helloworld]這個自製物件時,會在pd console 視窗,秀出自定的文字。程式碼複製於:http://iem.at/pd/externals-HOWTO/node3.html
#include "m_pd.h"
static t_class *helloworld_class;

typedef struct _helloworld {
    t_object  x_obj;
} t_helloworld;

void helloworld_bang(t_helloworld *x)
{
    post("Hello world !! You do a good job ");//放入你想要秀出的字串
}
void *helloworld_new(void)
{
    
    t_helloworld *x = (t_helloworld *)pd_new(helloworld_class);
    
    return (void *)x;
}
void helloworld_setup(void) {
    
    helloworld_class = class_new(gensym("helloworld"),
                                 (t_newmethod)helloworld_new,
                                 0,
                                 sizeof(t_helloworld),
                                 CLASS_DEFAULT,
                                 0);                          
    
    class_addbang(helloworld_class, helloworld_bang); 
}

步驟八:這時候Xcode應該會出現一個緊告標誌,告知你他找尋不到「m_pd.h」這個檔案,「m_pd.h」這標頭檔是由Miller所撰寫的,檔案包含Pd 內建的一些函數宣告,所以如果沒有這個檔案,就無法編譯擴充物件。所以必須透過User Header Search Paths指定路徑到「m_pd.h」這檔案。


「m_pd.h」這檔案在我電腦是放置在應用程式>Pd-extended.app裡面
/Applications/Pd-extended.app/Contents/Resources/include/pdextended
,所以你可以把這路徑加入其中,如下圖。


步驟八:接著還需要設計幾個屬性,才能開始編譯
  • Set Deployment Location as checked


  • Set Installation Build Products Location to /
  • Set Installation Directory to (你的擴充物件放置處,或者之後再透過Pd 去 path此檔案也可以 )


  • Set Other Linker Flags to -undefined dynamic_lookup


  • Set Executable Prefix to be blank (設置為空白,不然產出的物件會帶lib的名稱)

  • Set Product Name to helloworld

  • Set Executable Extension to pd_darwin

版本選擇:32-bit intel 
SDK:OS X 10.7
OS X Deployment Target:OS X 10.7



步驟九:按下Build 按鈕,如果在你剛剛指定的資料夾Installation Directory的地方,看到helloworld.pd_darwin 這個檔案,及代表編譯成功,

步驟十:重開Pd,建立物件[helloworld],並送[bang]的訊號進去,大功告成!!