2008/09/29

なんですとー


なんですとー

いつの間にか知らないところで自分のブログのアクセス数が一気に8〜9倍近く上昇していたようで。
こんなちまちまやってる小規模ブログに一体なぜ…と思って調べてみたら、どうやら前回のエッシャーくんオレンジニュースに掲載されたのと、はてブ経由で集まってきたのが原因のようですね。

まぁこれが過ぎればまた見る人だけ見るちっちゃいブログに戻りますし、これからもちまちま自分がおもしろいと思えるものを作っていきます。すべて世は事もなし。

追記

http://atmarkjojo.org/archives/2008/2008-09-25-001740.html

ついさっき知りました。ゴゴゴゴゴ…スタンドも月までブッ飛ぶこの衝撃…よりによってそこかぁ…

2008/09/20

エッシャーっぽい絵を生成する「エッシャーくん」を作ってみた。

エッシャーくん

エッシャーっていう画家は知っていますか?分かんない人のために説明しますと、こんな感じのふしぎーな絵を書いている人です。名前は知らなくても一度は見たことがあるのではないでしょうか。

それでなんですが、適当な画像からなんかエッシャーっぽいふしぎな画像を生成するフィルタ「エッシャーくん(仮称)」をPython Imaging Library(PIL)で作ってみました。これを使えばどんな画像もエッシャーっぽい世界にご招待です。ソースは近々公開します。

追記(09/24)

ソースコードをアップロードしました。subversionで管理されてますので、
svn checkout http://svn.coderepos.org/share/lang/python/escher Somewhere
でチェックアウトしてください。


たとえば、こんな感じのイラストにエッシャーくんを適用させてみると…


こんな感じの絵が出来上がりました。これはどこまでズームさせても終わりがない、無限に続いている絵になっています。


この、なんかごっついリングもエッシャーくんの手によれば…
(Photo by the justified sinner, "Roofing Nail Ring 1")


どこまでも続く絵に早変わり!なんかうにょんうにょんしています。


この画像はどーなるんだろ…


なんかコーヒーっぽい…

どーやって作っているのか

エッシャーくんは"A logarithmic image transformation"っていう論文を元に作られているので、気になる人はこれを見れば大体のことが分かると思いますが、一応大まかな解説をしてみると、複素平面をlog(z)で変形して、絵が循環するように座標をスケール、回転させてからexp(z)で繋げているようです…

あーやっぱ説明が下手くそなので、見てもらったほうが早いです。

余談

本当はprocessingで作る予定だったんですけど、あまりにもprocessingの数学ライブラリがアレだったんで途中からpythonで作り直しました。(対数関数すらないのにはビックリした。そりゃああんま使わないかもしれないけどさー)

それにしてもpythonの開発速度の早さは半端ない。まさか100行未満で出来るとは思わんかったです。

2008/09/16

リーマン破産法申請したんですって

三連休明けの東京市場やアジアの株式市場は、急落が避けられないだろう。バンク・オブ・アメリカ(バンカメ)(BAC.N: 株価, 企業情報, レポート)によるメリルリンチ(MER.N: 株価, 企業情報, レポート)買収の話しが15日の米株市場でどの程度好感されるかわからないが、日経平均は年初来安値をトライする展開となる可能性が高いとみている。
リーマン破産法申請:識者はこうみる | Reuters

いや、たぶん全員知っているとは思うんですが、自分は前回のとは別の旅行に4日間くらい滞在して今帰ってきましたので、さっき始めてこのニュースを目にしました。やばい時代の流れに完璧に取り残されてる。
あんだけ救済するだのなんだのやっといてこの結果ですか!こりゃあさらなる信用不安が引き起こされて、株式市場は大荒れですよ。

頼みの綱であったBRICsも成長が軟化していますし、今や世界経済は下落するリスクはあれど、上昇するリスクは殆どありません。
最悪のパターンは信用不安の連鎖で「第2のリーマン」となる金融機関が次々と登場することですね。流石にそうなる前に政府が何らかの対応策を講じるとは思いますが、はたしてそれで信用が回復するかどうか…

2008/09/12

Flight404のソースコードを読み解く part4


パーティクルを放出させる

旅行から帰ってきましたので、ようやっと更新することができました。まだまだ飽きてはいませんよ。
前回はエミッタを放出させるところまで行ったので、今回はパーティクルを等速で放出させるところまでやっていきます。

今回のソースは以下。相変わらず_gl.pdeは変わっていないので省略。新しくparticle.pdeを加えました。

Particle3.pde(draw()の関数だけ変更されているので、その部分だけ記載。)

void draw(){
background( 0.0 );
perspective( PI/3.0, (float)width/(float)height, 1, 5000 );

gl.glDepthMask(false);
gl.glEnable( GL.GL_BLEND );
gl.glBlendFunc( GL.GL_SRC_ALPHA, GL.GL_ONE );

pgl.beginGL();
emitter.exist();
pgl.endGL();

if( mousePressed ){
emitter.addParticles(20);
}

}

emitter.pde

class Emitter {
Vec3D loc;
Vec3D vel;
Vec3D velToMouse;

color myColor;

ArrayList particles;

Emitter(){
loc = new Vec3D();
vel = new Vec3D();
velToMouse = new Vec3D();

myColor = color( 1, 1, 1 );

particles = new ArrayList();
}

void exist(){
setVelToMouse();
findVelocity();
setPosition();

//rendering Emitter
gl.glEnable( GL.GL_TEXTURE_2D ); //Enable texture mapping
iterateListExist();
render();
gl.glDisable( GL.GL_TEXTURE_2D );
}

void setVelToMouse(){
velToMouse.set( mouseX - loc.x, mouseY - loc.y, 0 );
}

void findVelocity(){
vel.interpolateToSelf( velToMouse, 0.2 );
}

void setPosition(){
loc.addSelf( vel );
}

void iterateListExist(){
pgl.bindTexture( particleImg );

for( Iterator it = particles.iterator(); it.hasNext(); ){
Particle p = (Particle)it.next();
if(!p.ISDEAD){
p.exist();
} else {
it.remove();
}
}
}

void render(){
pgl.bindTexture( emitterImg );
renderImage( loc, 200, myColor, 1.0 );
}

void addParticles( int _amt ){
for( int i=0; i<_amt; i++ ){
particles.add( new Particle( loc, vel) );
}
}
}

particle.pde

class Particle {
int len;
Vec3D[] loc;
Vec3D startLoc;
Vec3D vel;

float radius;
float age;
int lifeSpan;
float agePer;
boolean ISDEAD;

Particle( Vec3D _loc, Vec3D _vel ){
radius = random( 20, 60 );
len = (int)radius;
loc = new Vec3D[len];

startLoc = new Vec3D( _loc.add( new Vec3D().randomVector().scaleSelf( random(5.0) ) ) );

for( int i=0; i
loc[i] = new Vec3D( startLoc );
}

vel = new Vec3D( _vel.scale( 0.5 ).addSelf( new Vec3D().randomVector().scaleSelf( random( 10.0 ) ) ) );

age = 0;
lifeSpan = (int)radius;
agePer = 1.0;
}

void exist(){
setPosition();
render();
setAge();
}

void setPosition(){
for ( int i=len-1; i>0; i-- ){
loc[i].set(loc[i-1]);
}
loc[0].addSelf( vel );
}

void render(){
color c = color( agePer, agePer*0.75, 1.0 - agePer );
renderImage( loc[0], radius*agePer, c, 1.0 );
}

void setAge(){
age++;

if( age > lifeSpan ){
ISDEAD = true;
}else{
agePer = 1.0 - age/(float)lifeSpan;
}
}
}

emitter.pdeの中で特に注目すべきなのは、iterateListExist()の追加。これによって各パーティクルのレンダリング処理を行い、死んだパーティクルをリストから除外している。

particle.pde の中で特によくわかんなかったのが、loc[]の存在について。別に1個だけでいいじゃんと思っていたが、これは後に尻尾というか、パーティクルの軌跡を描画するために使うようだ。loc[0]に一番最新のパーティクルの位置が格納されていて、時が経つごとに順次入れ替えを行っている。

次によくわかんないというか、感覚的じゃないなと思ったのが、new Vec3D( _loc.add( new Vec3D().randomVector().scaleSelf( random(5.0) ) ) )などのベクトル処理。
randomVector() はベクトルをランダムな単位ベクトルに変更するメソッドで、いろいろと便利。scaleSelf()は文字通り、ベクトルを拡大したり縮小したりするメソッド。この返り値を_locベクトルに加算させていることは理解できるのだが、いかんせん感覚的じゃないのが困り者。vec1+vec2とか出来れば理解しやすいのにとか思うけど、javaは演算子のオーバーロードをサポートしていないから仕様がないのか。

2008/09/03

Flight404のソースコードを読み解く part3

エミッタを表示させる

前回は前準備の段階で終わったので、次はパーティクルを放出させるエミッタを表示してみる。エミッタはマウスに追随するようにばね運動をする。_gl.pdeは前回と変わっていないので省略する。コードは以下。

Particle2.pde

import toxi.geom.*;
import processing.opengl.*;
import javax.media.opengl.*;

// Settings about OPENGL
PGraphicsOpenGL pgl;
GL gl;

// Settings about Emitter
Emitter emitter;

// Settings about images
PImage particleImg;
PImage emitterImg;

void setup(){
size( 600, 600, OPENGL );
colorMode( RGB, 1.0);

hint( ENABLE_OPENGL_4X_SMOOTH );

pgl = (PGraphicsOpenGL) g;
gl = pgl.gl;
gl.setSwapInterval(1);

initGL();

particleImg = loadImage( "particle.png" );
emitterImg = loadImage( "emitter.png");

emitter = new Emitter();
}

void draw(){
background( 0.0 );
perspective( PI/3.0, (float)width/(float)height, 1, 5000 );

gl.glDepthMask(false);
gl.glEnable( GL.GL_BLEND );
gl.glBlendFunc( GL.GL_SRC_ALPHA, GL.GL_ONE );

pgl.beginGL();
emitter.exist();
pgl.endGL();
}

emitter.pde

class Emitter {
Vec3D loc;
Vec3D vel;
Vec3D velToMouse;

color myColor;

Emitter(){
loc = new Vec3D();
vel = new Vec3D();
velToMouse = new Vec3D();

myColor = color( 1, 1, 1 );
}

void exist(){
setVelToMouse();
findVelocity();
setPosition();

//rendering Emitter
gl.glEnable( GL.GL_TEXTURE_2D ); //Enable texture mapping
render();
gl.glDisable( GL.GL_TEXTURE_2D );
}

void setVelToMouse(){
velToMouse.set( mouseX - loc.x, mouseY - loc.y, 0 );
}

void findVelocity(){
vel.interpolateToSelf( velToMouse, 0.2 );
}

void setPosition(){
loc.addSelf( vel );
}

void render(){
pgl.bindTexture( emitterImg );
renderImage( loc, 200, myColor, 1.0 );
}
}

Particle2.pdeについては、Emitterクラスと画像の初期化、並びにemitter.exist()メソッドを付け加えただけ。主な処理はemitter.pdeで行っている。

実際のレンダリングはrender()が担当している。まずbindTexture()で貼り付けるテクスチャを指定して、_gl.pdeで定義したrenderImage()で描画している。その他のメソッドではエミッタの位置をマウスに追随させるようにしている。

interpolateToSelf()はtoxi.geom.Vec3Dで定義されている、自身のベクトルを他のベクトルに置き換えるメソッド。要はvelToMouseを0.2倍したベクトルに置き換えているだけ。この処理によって、エミッタはマウスの周辺でばね運動のような動きをする。

おーし次からが本番だ。

2008/09/02

Flight404のソースコードを読み解く part2

何も表示されないアプリケーションを作る

Flight404のサンプルではOpenGLを使用して平面に別途用意したパーティクルの画像を貼り付けて、表示するという手法をとっている。そのためP3Dと比べて、非常に高速で高精度な3D画像を描画できるのだが、その分生のOpenGLを叩かないといけないため、コードはいささか面倒になってくる。そこでとりあえずソースコードの中から何も表示されないアプリケーションを作って、コードの流れについて調べてみることにした。コードは以下。

particle1.pde

import toxi.geom.*;
import processing.opengl.*;
import javax.media.opengl.*;

// Settings about OPENGL
PGraphicsOpenGL pgl;
GL gl;

// Settings about some functions

void setup(){
size( 600, 600, OPENGL );
colorMode( RGB, 1.0);

hint( ENABLE_OPENGL_4X_SMOOTH );

pgl = (PGraphicsOpenGL) g;
gl = pgl.gl;
gl.setSwapInterval(1);

initGL();
}

void draw(){
background( 0.0 );
perspective( PI/3.0, (float)width/(float)height, 1, 5000 );

gl.glDepthMask(false);
gl.glEnable( GL.GL_BLEND );
gl.glBlendFunc( GL.GL_SRC_ALPHA, GL.GL_ONE );

pgl.beginGL();
// write something...
pgl.endGL();
}

_gl.pde

int squareList;

void initGL(){
pgl.beginGL();
squareList = gl.glGenLists(1);
gl.glNewList(squareList, GL.GL_COMPILE);
gl.glBegin(GL.GL_POLYGON);
gl.glTexCoord2f(0, 0); gl.glVertex2f(-0.5, -0.5);
gl.glTexCoord2f(1, 0); gl.glVertex2f( 0.5, -0.5);
gl.glTexCoord2f(1, 1); gl.glVertex2f( 0.5, 0.5);
gl.glTexCoord2f(0, 1); gl.glVertex2f(-0.5, 0.5);
gl.glEnd();
gl.glEndList();
pgl.endGL();
}

void renderImage( Vec3D _loc, float _diam, color _col, float _alpha){
gl.glPushMatrix();
gl.glTranslatef( _loc.x, _loc.y, _loc.z );
gl.glScalef( _diam, _diam, _diam );
gl.glColor4f( red(_col), green(_col), blue(_col), _alpha );
gl.glCallList( squareList );
gl.glPopMatrix();
}

まずhint( ENABLE_OPENGL_4X_SMOOTH )を指定して、4xのオーバーサンプリングを許可。setSwapInterval()については、主に画面がちらつく現象を防ぐ目的のようだ。その後initGL()を呼び出して、_gl.pdeで書いたOpenGL周辺のセットアップを開始する。

initGL()では、正方形のポリゴンを作って画像を貼り付けるという作業が何回も繰り返されるので、ディスプレイリストの機能を利用する。テクスチャのUV座標と頂点をそれぞれglTexCoord2fとgl.glVertex2fで指定して、正方形を描画している。

renderImage()で実際に画像の描画を行う。glPushMatrix()とglPopMatrix()で行列スタックを取得、開放し、その間に平行移動やスケールをもってくることで、ローカル座標が狂わないようにしているようだ。

次にdraw()の項を見てみる。glDepthMask(false)で陰線消去を行わないようにして、glBlendFunc( GL.GL_SRC_ALPHA, GL.GL_ONE )で画像の加算処理を指定している。そしてbeginGL()とendGL()の間にOpenGLの描画命令を組み込むことで、実際にOpenGLで描画処理が行われるようになるという次第。

Flight404のソースコードを読み解く part1

概要

Processing(Proce55ing)界で知らない人は皆無と言われる(と勝手に思っている)Flight404のRobert Hodgin。とりあえず彼のことについて説明しますと、こんな感じの映像をProcessingで作ってしまうような人です↓

Weird Fishes: Arpeggi from flight404 on Vimeo.
(悔しいことに、ルックスもイケメンだ!)

で、実は彼はブログで「簡単」な(彼にとっては簡単なだけで他の人にとっては難しいです)Proce55ingのソースコードを公開しています。が、ワールドワイドではともかく、日本語のブログで彼のコードについて言及しているサイトやブログが全くない。それで自分の丁度いい勉強にもなりますんで、適当にFlight404SRC: Particle Emitterで気づいたことを書き留めておくことにします。

もしかしたら飽きて、中途半端なところでやめるかもしれませんが、とりあえずそんときはそんときで。てきとーにやっていきます。