[processing]魔方陣とかSF円とか(Processing Advent Calendar 2011 – 20日目)

Posted under processing by uechoco on 火曜日 20 12月 2011 at 01 : 02 : 20

Processing Advent Calendar 2011の2回目の登場です。
20日目の担当ということで、最近Processingと疎遠でphpやらpythonやらと戯れている私は既にネタ切れですw

Processingは何かのプロダクトのプロトタイプを作ったり、自分が作りたいアニメーションを作ったりするのに向いていると言われています。
今回は私の趣味で、魔方陣とかSFちっくな円とか、そういうものを2種類公開いたします。

ミッドチルダ式魔方陣

Processing:
  1. /**
  2.  * ミッドチルダ式魔法陣 (元ネタ:魔法少女リリカルなのは)
  3.  *
  4.  * @title mugityax | 背景作成
  5.  * @link http://www.mugityax.com/weblog/2006/06/post_1.html
  6.  *
  7.  * @title ミッドチルダフォント置き場
  8.  * @link http://midfont.refy.net/
  9.  */
  10.  
  11. float rot1, rot2;
  12. PFont font1, font2;
  13.  
  14.   size(400, 400);
  15.   colorMode(HSB, 100);
  16.   frameRate(30);
  17.   smooth();
  18.   background(0);
  19.  
  20.   textAlign(CENTER, CENTER);
  21.  
  22.   font1 = loadFont("MID-CHILDA_Regular-30.vlw");
  23.   font2 = loadFont("MID-CHILDA_Regular-15.vlw");
  24.   //font1 = createFont("mid-childa_R.ttf", 30, true);
  25.   //font2 = createFont("mid-childa_R.ttf", 15, true);
  26.  
  27.   rot1 = rot2 = 0;
  28. }
  29.  
  30.   background(0);
  31.   {
  32.     noFill();
  33.     translate(width / 2, height / 2);
  34.     final float rl = 120 / sqrt(2); // 84.85281
  35.     final float ro = 149;
  36.    
  37.     // 固定円
  38.     {
  39.       drawLightEllipse(0, 0, 180*2, 180*2); // 外周円-二重外円
  40.       drawLightEllipse(0, 0, 175*2, 175*2); // 外周円-二重外円
  41.       drawLightEllipse(0, 0, 120*2, 120*2); // 外周円-内円
  42.       drawLightEllipse(0, 0, rl*2, rl*2); // 内周方形内-外円
  43.       drawLightEllipse(0, 0, 60*2, 60*2); // 内周方形内-内円
  44.     }
  45.    
  46.     // 外周小円・内周方形1
  47.     pushMatrix();
  48.     {
  49.       rotate(rot1);
  50.       // 外周小円
  51.       final float[] rm = {50, 45};
  52.       for (int i = 0; i <rm.length; i++) {
  53.         drawLightEllipse(0, -ro, rm[i], rm[i]);
  54.         drawLightEllipse(ro, 0, rm[i], rm[i]);
  55.         drawLightEllipse(0, ro, rm[i], rm[i]);
  56.         drawLightEllipse(-ro, 0, rm[i], rm[i]);
  57.       }
  58.       // 内周方形1
  59.       drawLightQuad(0,-120,120,0,0,120,-120,0);
  60.     }
  61.     popMatrix();
  62.    
  63.     // 内周方形2
  64.     pushMatrix();
  65.     {
  66.       rotate(rot2);
  67.       drawLightQuad(-rl,-rl,rl,-rl,rl,rl,-rl,rl);
  68.     }
  69.     popMatrix();
  70.    
  71.     final String[][] ot = {
  72.       {"Y","S","T","D","U","X","K","j","L","z","D","K","F","A","M","B","Y","o","h","Z","O","T","U","V","i"},
  73.       {"J","Z","p","V","A","Y","F","r","j","s","v","W","T","h","G","S","c","H","X","K","k","o","d","B","u"},
  74.       {"b","F","M","r","g","R","V","y","N","B","A","x","q","C","T","p","E","L","K","a","w","j","k","J","P"},
  75.       {"H","a","G","d","W","S","n","M","X","s","E","x","A","o","Z","C","b","f","k","U","V","i","Y","B","D"},
  76.       {"E","y","t","H","L","o","Q","W","T","h","a","d","C","B","b","w","v","D","s","Y","z","e","R","n","S"},
  77.       {"K","B","f","T","k","R","e","d","w","z","S","m","D","J","P","F","j","o","n","r","u","x","g","v","b"},
  78.       {"z","G","q","e","u","w","W","a","U","X","i","r","A","Y","D","t","N","V","k","P","Q","p","g","E","K"},
  79.       {"b","v","d","B","g","z","D","h","j","Q","n","U","G","Z","q","u","F","r","T","X","a","m","W","t","Y"},
  80.       {"Z","K","U","T","e","A","G","c","X","i","Q","o","R","F","k","t","p","D","J","d","r","q","n","V","E"},
  81.     };
  82.     final int[][] a_set = {
  83.       {14, 78, 4},
  84.       {102, 170, 4},
  85.       {192, 260, 4},
  86.       {282, 350, 4}
  87.     };
  88.  
  89.     // 外周文字
  90.     pushMatrix();
  91.     {
  92.       rotate(rot1);
  93.       fill(100);
  94.       textFont(font1);
  95.       for (int i = 0; i <4; i++) {
  96.         int c = 0;
  97.         for (int a = a_set[i][0]; a <a_set[i][1]; a+=a_set[i][2]) {
  98.           pushMatrix();
  99.           rotate(radians(a));
  100.           translate(ro, 0);
  101.           rotate(HALF_PI);
  102.           text(ot[i][c++], 0, 0);
  103.           popMatrix();
  104.         }
  105.       }
  106.     }
  107.     popMatrix();
  108.  
  109.     // 内周文字
  110.     pushMatrix();
  111.     {
  112.       rotate(rot2);
  113.       fill(100);
  114.       textFont(font2);
  115.       for (int i = 0; i <4; i++) {
  116.         int c = 0;
  117.         for (int a = a_set[i][0]; a <a_set[i][1]; a+=a_set[i][2]) {
  118.           pushMatrix();
  119.           rotate(radians(a));
  120.           translate(70, 0);
  121.           rotate(HALF_PI);
  122.           text(ot[i][c++], 0, 0);
  123.           popMatrix();
  124.         }
  125.       }
  126.     }
  127.     popMatrix();
  128.    
  129.   }
  130.   popMatrix();
  131.   update();
  132. }
  133.  
  134. void update() {
  135.   rot1 += 0.04;
  136.   rot2 -= 0.04;
  137. }
  138.  
  139. void drawLightEllipse(float a, float b, float c, float d) {
  140.   stroke(100, 100, 80, 40);
  141.   ellipse(a, b, c, d);
  142.   stroke(95, 100, 80, 60);
  143.   ellipse(a, b, c, d);
  144.   stroke(90, 100, 80, 80);
  145.   ellipse(a, b, c, d);
  146.   strokeWeight(1.5);
  147.   stroke(100);
  148.   ellipse(a, b, c, d);
  149. }
  150.  
  151. void drawLightQuad(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) {
  152.   stroke(100, 100, 80, 40);
  153.   quad(x1, y1, x2, y2, x3, y3, x4, y4);
  154.   stroke(95, 100, 80, 60);
  155.   quad(x1, y1, x2, y2, x3, y3, x4, y4);
  156.   stroke(90, 100, 80, 80);
  157.   quad(x1, y1, x2, y2, x3, y3, x4, y4);
  158.   strokeWeight(1.5);
  159.   stroke(100);
  160.   quad(x1, y1, x2, y2, x3, y3, x4, y4);
  161. }
  162.  
  163.   save("mid_tilde_magic_circle.jpg");
  164. }

まずは、魔方陣です。魔法少女リリカルなのはというアニメの中に出てくるミッドチルダ式魔方陣というものです。元ネタは全く知らないのですが、魔方陣的に描きやすかったので、参考にしました。専用のフォントも使用しています。プログラムは4つの構成要素になっていて、外周や内周の固定や回転する円、内周の正方形、外周円の文字、内周円の文字となっています。rotate()とmatrixを上手く使用して、座標軸を回転させることで描画する方式をとっています。仕組みさえわかってしまえば簡単にバリエーションが作成できます。

SF円

Processing:
  1. float cx, cy;
  2. int ringCount = 0;
  3. Ring[] rings = new Ring[1];
  4.  
  5.   size(400, 400);
  6.   background(0);
  7.   noFill();
  8.   smooth();
  9.   strokeCap(SQUARE);
  10.   ellipseMode(RADIUS);
  11.  
  12.   cx = width / 2;
  13.   cy = height / 2;
  14.  
  15.   float pRadius = 20, pWeight = 2;
  16.   while (pRadius <180) {
  17.     Ring r = addRing();
  18.     r.setWeight(random(2, 25));
  19.     r.setPosition(cx, cy);
  20.     r.setRadius(pRadius + (pWeight + r.weight) / 2 + 1);
  21.     r.setRadians(random(TWO_PI)+PI/3, random(TWO_PI)+PI/3);
  22.     r.setColor(#ffffff);
  23.     r.setRot(random(-0.05, 0.05));
  24.     pRadius = r.r;
  25.     pWeight = r.weight;
  26.   }
  27. }
  28.  
  29.   background(0);
  30.   for (int i = 0; i <ringCount; ++i) {
  31.     rings[i].draw();
  32.     rings[i].move();
  33.   }
  34. }
  35.  
  36. Ring addRing() {
  37.   if (rings.length == ringCount) {
  38.     rings = (Ring[]) expand(rings);
  39.   }
  40.   Ring r = new Ring();
  41.   rings[ringCount++] = r;
  42.   return r;
  43. }
  44.  
  45. class Ring {
  46.   float x, y, r;
  47.   float weight;
  48.   float startRad, endRad;
  49.   float rot;
  50.   color c;
  51.  
  52.   void draw() {
  53.     stroke(c);
  54.     strokeWeight(weight);
  55.     arc(x, y, r, r, startRad, endRad);
  56.   }
  57.  
  58.   void move() {
  59.     startRad += rot;
  60.     endRad += rot;
  61.     if (startRad> TWO_PI && endRad> TWO_PI) {
  62.       startRad -= TWO_PI;
  63.       endRad -= TWO_PI;
  64.     }
  65.   }
  66.  
  67.   void setPosition(float x, float y) {
  68.     this.x = x;
  69.     this.y = y;
  70.   }
  71.  
  72.   void setRadius(float r) {
  73.     this.r = r;
  74.   }
  75.  
  76.   void setRadians(float start, float end) {
  77.     this.startRad = start;
  78.     this.endRad = end;
  79.   }
  80.  
  81.   void setWeight(float weight) {
  82.     this.weight = weight;
  83.   }
  84.  
  85.   void setColor(color c) {
  86.     this.c = c;
  87.   }
  88.  
  89.   void setRot(float rot) {
  90.     this.rot = rot;
  91.   }
  92. }
  93.  
  94.   save("sf_arc_ring_magic_circle.jpg");
  95. }

正式に何といったらよいのかわかりませんが、SF映画とかのコンソール画面とかの後ろ側で無駄にかっこ良く回ってるアレですw プログラムの仕組みとしては、円弧(arc)を何十にも重ねてそれぞれ別々の弧の長さや回転速度を持たせているだけです。プログラム上の工夫としては、円弧の部分をRingというクラスにまとめ、draw()ループから呼び出すメソッドはRing.draw()やRing.move()に限定することで、draw()ループを見やすくしています。このように、似たような動作をするオブジェクトをクラスとして定義して、パラメータの違いによって動作を変え、描画や移動の時はdraw()やmove()などのメソッドを作成して呼ばせるような手法は、プログラムをすっきりとさせるし、動作の塊がオブジェクトとしてまとまっているので、大変見やすくなっています。

最後に

と、今回は2つの作品の紹介で終わりでちょっと物足りなかったかと思います。

私はCGクリエイターと言うよりはCGに興味があるプログラマーなので、自分が作りたいものが作れれば良いという考えではなく、「この作品を作るにはどういうプログラムにすると上手く書けるか」という視点でProcessingのコードを書くことが多いです。前回の伝統模様の記事でも、いろんな書き方で伝統模様を書いていたのをご覧になっているかと思います。私の目標としては"CG自体の美"の次くらいに"プログラムコードの美"を追求していきたいと思っています。

めちゃめちゃなコードでもその場限りで描ければ良しとする考えもあるのですが、数カ月後とか、1年後とかにProcessingのコードを見て、何やっているかわからないと困る場合もありますよね。その点、プログラムコードの美しさも最初から追求していれば、後から読んでも読みやすいプログラムなので、理解がしやすいかと思います。

とまぁ、作品紹介ついでに本職プログラマーならではのプログラミングの視点をご紹介してみました。


[p5]Processing情報発信サイト「proce55ing.walker(α)」リリースしました

Posted under processing by uechoco on 日曜日 5 4月 2009 at 14 : 18 : 26

proce55inginfo-captureed-image以前にも告知していましたが、Processingの情報発信サイト「proce55ing.walkerを本日公開いたしました。

管理人が私を含めて3人おり、まずはブログ形式でprocessing関連の入門記事、バージョンアップ情報、関数の使い方、ライブラリの使いあた、マニアックな使い方などを発信していく予定です。

また、フォーラム(質問掲示板)を設置してありますので、随時processingに関する質問、およびサイトに関する質問・要望を受け付けています

ゆくゆくは日本で一番のprocessingポータル・コミュニティサイトにしていこうという意気込みです。processingに興味のある方は是非ご覧になってください。また「こんなコンテンツがあるといいよね」「こんな記事書いてほしい」などのご要望がありましたら、お気軽にフォーラムに書き込んでいただけると助かります。


[processing]新サイトを準備中です

Posted under processing by uechoco on 日曜日 15 3月 2009 at 19 : 43 : 24

Processingだけを扱った新サイトを準備中です。私だけでなく、共同で立ち上げを予定しています。そのうちこのブログに投稿したProcessing関連の記事の多くを寄稿する予定です。近日中に開設する予定です。

っていう告知だけ。


[Processing]PVectorサンプル(1.0リリース記念)

Posted under processing by uechoco on 水曜日 3 12月 2008 at 22 : 45 : 12

Processing 1.0リリース記念として、いくつか新しい機能のサンプルコードを書いてみました。

まずはPVectorクラス。リファレンスには英語で主な使い方は書いてあるものの、実際のソースコードはありませんでした。

リファレンスに従い、position(位置)、velocitiy(速度)、acceleration(加速度)をPVectorクラスで表した実用的なサンプルを書いてみたので、PVectorクラスの1つの使い方として参考にしてみてください。

Processing:
  1. PFont font;
  2. PVector position, velocity, acceleration;
  3. final int WIDTH = 250, HEIGHT = 250;
  4. final int STATUS_HEIGHT = 50;
  5.  
  6.   // 画面の初期化
  7.   size(WIDTH, HEIGHT + STATUS_HEIGHT);
  8.  
  9.   noStroke();
  10.   colorMode(RGB, 256);
  11.   background(255, 255, 255);
  12.  
  13.   // フォントの初期化
  14.   font = loadFont("ArialNarrow-14.vlw");
  15.   textFont(font);
  16.  
  17.   // 自機の初期化
  18.   position = new PVector(WIDTH / 2, HEIGHT / 2, 0);
  19.   velocity = new PVector(3, 4, 0);
  20.   acceleration = new PVector(0.01, 0.01, 0);
  21. }
  22.  
  23.   // 背景消去
  24.   fill(255, 255, 255, 30);
  25.   rect(0, 0, WIDTH, HEIGHT);
  26.   fill(255, 255, 255);
  27.   rect(0, HEIGHT, WIDTH, STATUS_HEIGHT);
  28.  
  29.   // 自機描画
  30.   fill(255, 0, 0);
  31.   ellipse(position.x, position.y, 10, 10);
  32.  
  33.   // 速度表示
  34.   fill(0, 0, 0);
  35.   text("Position: " + position, 0, height - STATUS_HEIGHT + 14);
  36.   text("Velocity: " + velocity.mag(), 0, height - STATUS_HEIGHT + 14 * 2);
  37.   text("Acceleration: " + acceleration.mag(), 0, height - STATUS_HEIGHT + 14 * 3);
  38.  
  39.   // 場所の更新
  40.   position.add(velocity);
  41.   if (position.x <= 0 || position.x>= WIDTH) {
  42.     velocity.x *= -1;
  43.     acceleration.x *= -1;
  44.     position.x += velocity.x;
  45.   }
  46.   if (position.y <= 0 || position.y>= HEIGHT) {
  47.     velocity.y *= -1;
  48.     acceleration.y *= -1;
  49.     position.y += velocity.y;
  50.   }
  51.   velocity.add(acceleration);
  52. }

実行画面(クリックで拡大)

サンプルコードのダウンロード:PVectorSample.zip


[Processing]1.0リリース

Posted under processing by uechoco on 水曜日 3 12月 2008 at 19 : 23 : 31

そういえば、いつのまにかProicessingの正式版となる1.0がリリースされました。内部リビジョン番号は0162です。

Processing 1.0での変更点

  • ライブラリの変更
  • P2Dレンダラの復活
  • PShapeクラスによるSVG読み込みの対応
  • PVectorクラスの追加
  • コンパイラの変更
  • ソースコードのUTF-8化
  • JRE(JDK) 6.0 update 10への対応(ただし、genericsや拡張for文などのJava 1.5文法は未対応)
  • etc...

まだまだ知名度は低いものの、徐々に名前は広まっています。特に情報デザイン工学などを勉強している学生にとっては、常識に近くなっている気がします。

また、最近では、processing.jsなど、エンジンを移植する人もいるようです。

ゆっくりと、着実にProcessingは浸透していきます。


次ページへ »

Copyright © 2012 うえちょこ@ぼろぐ. WP Theme created by Web Top.