Context Free Art で楽しくアート

ゆっくりしていってねっ!!


公式サイト:
Context Free Art

概要

ContextFree Artは最小のコーディングでアートを描くアプリケーションです。
文脈自由言語 - Wikipediaの応用?まぁ、よくわかりませんが、難しい理論に裏付けされたソフト!という認識で、とりあえず、
プログラミングの能力の是非はあまり関係なく、誰でもペイントで描くように使えると思います。


すぐに始められるというのも、うれしい。
アプリケーションは、WindowsMac OS XLinux等のメジャーな多くのOSで動作します。
そして、最小のプログラム記述でアートが描けるということからは想像出来ないほど文法がシンプルです。
Context Free Artを使うときは、リファレンスカードをプリントアウトしておくと便利かと思います。
驚くことにこれがたったの2ページ!
さすがに、これだけではじめるのは難しいので、公式ページのギャラリーやドキュメンテーションを見たりしながら試行錯誤することになると思います。


以下に、自分なりに触れてみたことを簡単にまとめてみたいと思います。一部公式サイトとかぶります。
記述はすべて正確なわけではないかもしれません。使ってみてこんな感じかなという程度です。いや、ドキュメント読めよという話ですがw

超基本

まずは一番簡単な、円を描てみます。

startshape main

rule main {
	CIRCLE {}
}

実行(Render)すると次のように表示されます。
ちなみに、CIRCLE { } を TRIANGLE { } や SQUARE { } とすると三角、四角を描くことが出来ます。

プログラムの先頭の startshape はその rule から描画するという命令。
上のプログラムでは startshape main としたので、rule main のブロック{ }を評価します。
基本、Context Free Artのプログラムは一つの startshape と一つ以上の rule ブロック等から構成されることになると思います。


次はHome · MtnViewJohn/context-free Wiki · GitHubを参考に経験値UPを試みます。

遠近感の演出

2次元上で擬似的に3次元を表現するとき、遠近法やパースペクティブ(←一緒?www)を用いると思います。
これを実践してみます。

startshape main
 
rule main { 
	CIRCLE { }
	main { z -1 s .7 y .7 x -1.5 }
	main { z -1 s .7 y .7 x 1.5 }
}

やっていることは公式サイトのそれと一緒です。実行してみます。

遠近感の演出に成功しています。やったねっ!!
問題はプログラムの方。mainの中にmain?これがポイント。
動作確認のためにもう少しシンプルなプログラムで確認してみます。
上のプログラムを次のように変更します。

startshape main
 
rule main { 
	CIRCLE { }
	//main { z -1 s .7 y .7 x -1.5 }
	main { z -1 s .7 y .7 x 1.5 }
}

実行してみます。

// はコメントアウトするときに使います。以降の記述をスキップさせることが出来ます。
つまり、このプログラムはmainの中にmainが一つ入れ子になった状態というわけです。先のではmainの中にmainが2つ入っていました。
この入れ子構造を取ることで、再帰的に描画させることが出来ます。
再帰構造で大事なのは終了条件です。これを忘れると無限ループに陥ります。


C言語や他のプログラム言語で再帰で階乗計算したり、関数型言語でプログラムしたことがある人なら、そう思うはず。
しかし、上の再帰構造には終了条件が見当たりません。何故?と自分でもはじめは不思議でした。


その答えの前に main { z -1 s .7 y .7 x 1.5 } も気になります。
これは、main { } ルールに引数を渡すための記述です。
main を描画するのだけれど、そのときz軸に-1、サイズを70%に、y軸に-0.7、x軸に1.5だけ移動したものを描いてね、という意味です。
小数を記述するときの先頭の0を省略して、 . (ポイント:小数点)からはじめて大丈夫です。


そして、この s .7という、サイズを0.7倍する記述が実は再帰の終了に一役買っているようです。
ちなみに、再帰でこの s の記述を忘れると、何も表示されないか、一瞬表示されるだけなどとなる模様。
上のプログラムを日本語文にすると次のようになります。

描画するときは main からはじめてよねっっっ!!

main のルールは次の通りだからっ!勘違いしないでよね
一つ CIRCLE を描いて。
もいっかい、 main 実行してよね。そのときはz軸に-1、サイズを70%に、y軸に-0.7、x軸に1.5だけ移動したものを描きなさいよね

そしたら、main -> main -> main ってなってくでしょ?え?終わらないじゃないかって?
ばかね、サイズが小さくなってくんだから、そのうち描けなくなるでしょ?そしたら勝手にこっちで終わらせるわよ!
す、少しくらいは私を信用しなさいよね!で、でも別にアンタのためにやってんじゃないわよっ?!

ということかな、という理解です。合っているのか知りません(ぇ。


main {} の中に main {} が2つ入ったサンプルは、2つ入れることで左右に広がりながら再帰していく、という構造を実現しているわけです。

公式からのコピペ。

startshape forest
 
rule forest { 
   tree { }
   forest { z -1 s .7 y .7 x -1.5 b .1 }
   forest { z -1 s .7 y .7 x 1.5 b .1 }
}
rule tree {
    CIRCLE { s .5 1.2 }
    tree { s .97 y .3 r 3 }
}
rule tree .1 { 
    tree { flip 90 }
}
rule tree .1 { 
    tree { r 10 } 
    tree { r -30 s .6 } 
}

実行のたびにランダムさが加えられるので、毎回違ったものが描かれます。

おおおおおおおっ!!かっくいー。と思ったのは俺だけじゃないはず。
これは、先に述べた遠近感の演出とは異なっています。
こちらは、b .1 とい記述でbrightness(明るさ)を徐々に変えていくことで、奥の木に靄がかかったような演出をしています。
そんなに長くないプログラムですが、このような複雑怪奇な描画も簡単にできるのがすごいですね!!


ちなみに上のプログラムにもいくつかポイントがあります。
forest {} から描画をはじめ、forest {} 内で再び forest {} を呼ぶことで再帰していることは先を同じです。


問題は tree ルールが3つあることです。
実は、同名ルールを複数記述すると、どのルールが採択されるかのランダムさを実現できるようです
そして、2つ目と3つ目の tree ルールの記述では、tree のすぐあとに .1 と加えられているのが分かります。
これは、確率に重み付けしている部分です。ちなみにルールの後ろに数値を書かない場合(デフォルト)は1と見なされるようです。
そしてこの確率計算を上の tree の場合で考えると次のようになります。


tree {} -> 重み:1
tree .1 {} -> 重み:0.1
なので上のサンプルでは1つ目は1、2つ目、3つ目は0.1の重みを持ち、
1つ目が表示される確率は、
1 / ( 1 + 0.1 + 0.1 ) = 5/6
2つ目、3つ目が表示される確率は、
0.1 / ( 1 + 0.1 + 0.1 ) = 1/12
となります。


また、r は rotate の省略形で、回転を表します。
flip は原点を通る、水平軸から指定した角度だけ原点から回転した軸に関して線対称に移動する命令――だと思います。
flip を使うことで左右にランダムに枝分かれさせています。
よって、flip 0 でx軸対象(上下反転)、flip 90 でy軸対象(左右反転)となります。

何か、作ってみる―その1

自分もそんなに理解しているわけではないので大したことは出来ませんが、ここまでで基本的な文法、アプローチに関しての理解が進んだかな?と思われるので、自分でも何か作ってみたいと思います。


基本図形で描けるもの――と考えたときに、よくWC等で見かける、男女を表すマークならいけそうかな?

こんな感じのプログラムになりました。

startshape couples

rule couples {
	couple {}
	couples { s .7 z -1 x -.8 y .8 h 40 }
	couples { s .7 z -1 x  .8 y .8 h -40 }
}

rule couple {
	man { x .5 }
	woman { x -.5 }
}

rule couple {
	man { x -.5 }
	woman { x .5 }
}

rule man {
	CIRCLE { s .7  y 1.2  h 250 sat 1 b 1 }
	2* { y -.5 } SQUARE { s .7 y .5 h 250 sat 1 b 1 }
}

rule woman {
	CIRCLE { s .6 y 1 h 1 sat 1 b 1 }
	TRIANGLE { y .3 h 1 sat 1 b 1 }
	2* { y -.2} SQUARE { s .3 h 1 sat 1 b 1 }
}

実行してみます。

上で言及していない文法について少し書いておきます。


まず、man { } 内の、 2 * { ... } SQUARE { ... } について。
これは、2回だけSQUARE { ... } を繰り返すという文です。
再帰だと不便な場合はこのように回数を指定して繰り返し描くことで表現できます。
繰り返すとき、 "繰り返し回数" * { ... } の { ... } でいろいろな指定をします。

また、カラフルにする場合はHSBで指定します。h(hueの省略形)、sat (saturationの省略形)、b (brightnessの省略形)がそれです。
ちなみに、これら3つとも指定しておかないとカラフルにはならないようです。1つでも記述を忘れると何も描かれないかもしれません。


シンプルだけどカラフルで、楽しくなるサンプル。楽しくなる――よね?(笑

startshape main

rule main {
	c { s .5 }
	main { s .95 x 1 r 30  h 30 }
}

rule c {
	CIRCLE { h 0 sat 1 b 1 }
}


何か、作ってみる―その2

もう一つ習作を作りました。
世界一危険な目にあっていることで有名な?ピクトさん――ライクな人物を作ってみました。
プログラムは以下のようになりました。

startshape pict

rule pict {
	// head
	CIRCLE { s .6 }

	// body
	13* { y -.05 x .02 } CIRCLE { s .5 y -.6 x .1 }

	// arms
	left_arm { s .4 x -.01 y -.55 }
	right_arm { s .4 x .87 y -.97 }

	// legs
	left_leg { s .6 x .3 y -1.3 }
	right_leg { s .6 x .46 y -1.25 }
}

// left_arm
rule left_part1 {
	13* { y -.07 x -.07 } CIRCLE { s .7 }
}
rule left_part2 {
	left_part1 { y -.4 flip 100 }
}
rule left_arm {
	left_part1 {}
	left_part2 { x -2 }
}

// right_arm
rule right_arm {
	left_arm { flip 348 }
}

// left_leg
rule left_leg {
	25* { x -.05 y -.07 } CIRCLE { s .5 }
}

// right_leg
rule right_leg {
	15* { x .01 y -.08 } CIRCLE { s .5 }
	13* { x .1 } CIRCLE { s .5 x .2 y -1.12 }
}

Try and Error でゴリゴリ試しながら書きを繰り返していったので、そんな感じのプログラムになってます。
実行結果。

それっぽくなったかなーと個人的には満足。
(追記:重大なミスっ!!ピクトさん、同じ側の手足が同時に前に出ているかの記述をしてしまってます。スルーでお願いしますw)


そして、これをインクルードして男女の例のようにしてみたいと思います。
こういった、1つのオブジェクトをファイルに用意しておけば、他のプログラムにインクルードして使えるので便利!
あと、このプログラムの記述はあまり美しくないのでw


上のプログラムを pict.cfdg として保存しておきます。同じフォルダに escape.cfdg を作成。以下のように記述。

include pict.cfdg

startshape escape

rule escape {
	pict { h 160 sat 1 b .6 }
	escape { s .6 z -1 x -1 y .5 h  60 b .3 }
	escape { s .6 z -1 x  1 y .5 h -60 b .3 }
}

rule escape {
	pict { flip 90 h 160 sat 1 b .6 }
	escape { s .6 z -1 x -1 y .5 h  60 b .3 }
	escape { s .6 z -1 x  1 y .5 h -60 b .3 }

}

1行目で pict.cfdg を読み込みます。実行結果は以下のようになります。

長々と駄文を書いてしまいました。
はじめは自分のメモのつもりで書こうと思っていたのでかなり適当ですが、参考になれば幸いです。
日本語での解説のみならず、英語での解説もあまり見つからなかったので。


これからは、公式サイトや以下のサイトを参考にしていろいろ学んでいきたいです。
http://contextfree.lazymoon.org/
ちなみに、 tile と path が未だよく分かってません。Help me, ERINNNNNNNNNNNN!


Let's enjoy our Context Free Art Life !