ActionScript でスピログラフ


Spirographical Ingot Cast | Si+ (wonderfl.net)


前回、PointSpriteのデモを作成した際、何か面白いパーティクルの動きは出来ないかなーと試行錯誤していました。その中でスピログラフを3次元に展開できたら面白そうだなと思って、いろいろ数式をいじってたら想像以上に面白いものができそうだったので、1つのコンテンツにしてみました。
見せ方次第でまだまだ面白くなりそうでしたが(例えば Point Sprite Particle みたいにスピログラフ上のモーションをBPMに合わせたり)、今回は色々数式をいじって形状を確認できるような方向で丁寧に作ってみました。
3D関連の技術的にはMetallic soft cube - wonderfl build flash onlinePoint Sprite Particle - wonderfl build flash onlineの組み合わせなので新しい事はあまり無いのですが、今回の3次元スピログラフは結構汎用性が高そうなので、そこら辺を中心に書いてみたいと思います。
スピログラフが描く2次元の軌道は非常にシンプルな数式で表せます。具体的な説明はwikipediaにまかせますが、要は2つの異なった半径・周期の円軌道を加算してしまえば良いだけです。コードにすると

x = cos(phase0) * r0 + cos(phase1) * r1;
y = sin(phase0) * r0 + sin(phase1) * r1;

で、これをどうにかして3次元にしようと考えたわけですが、その答えのきっかけになったのがyonatan氏のit's a knot - wonderfl build flash onlineでした。これは三葉結び目と言われる代表的な数学的結び目で、wikipediaにその数式が乗っています(日本語のには載ってなかったので英語版にリンクしてます)。この三葉結び目の平面投影図は周期1:2の内サイクロイドなので、この数式のz値をうまくいじればいけるんじゃないかと考えました。というか考えるまでもなく、z = sin(3t) ですので、葉の枚数の周波数でsinカーブを描けば良いんじゃない?というところに思い至りました。
で、実際やってみた結果、びっくりするほどあっさりと他の線の合間を縫うように美しい軌跡を描いてくれました。スピログラフの葉の枚数は2つの円の周波数の合計を最大公約数で割ったものですので、これでめでたく3次元スピログラフ軌道ができました。

x = cos(phase * freq0) * r0 + cos(phase * freq1) * r1;
y = sin(phase * freq0) * r0 + sin(phase * freq1) * r1;
z = sin(phase * (freq0 + freq1) / GCD(freq0, freq1));
GCD() = 最大公約数

お互いの円の周波数が互いに素であれば最大公約数は1ですので、単純に合計の周波数で良いことになります。


さて、これで無事3次元スピログラフ軌道ができたわけですが、2つの円の周波数が互いに素でない場合、あんまり面白くない事になります。例えば、周波数比1:3の軌道と2:6の軌道は同じで周波数が2倍になります(つまり同じ軌道を2周するだけ)。これではあんまりなので、xy平面上で同じ軌道でもz値をずらすことで面白くならないかと考えました。そこで今回は最大公約数周したところでz値の周期が一致するように補正してみました。

x = cos(phase * freq0) * r0 + cos(phase * freq1) * r1;
y = sin(phase * freq0) * r0 + sin(phase * freq1) * r1;
z = sin(phase * (freq0 + freq1 + GCD(freq0, freq1) - 1);
GCD() = 最大公約数

こうすることで、freq0とfreq1が互いに素でない場合、xy平面上での軌道が一緒でもz値が異なるため、独特の形が形成されるよになりました。


今回のwonderflでは8パラメータで形状を決定しています。それぞれについて簡単に解説しておきます。

  • frequency1: 1つ目の円軌道の周波数です(1~32)。半径は100pxに固定されています。
  • frequency2: 2つ目の円軌道の周波数です(-31~+31)。正値は内サイクロイド、負値は外サイクロイドです。frequency1と互いに素であればxy平面状での軌道は重なりません。
  • z-freq.: z方向の周波数の倍数です(0~4)。z方向の周波数は、(freq0 + freq1 + GCD(freq0, freq1) - 1) * z-freq になります。0なら2次元スピログラフになります。
  • hue-freq.: 色相の周波数です(1-32)。スピログラフが1周する間に色が何周するかです。上三つと周波数が合ってないとサイケな感じになりますが、それはそれで味かもしれません。frequency1・frequency2か、それらを±1した値、または frequency1+frequency2 あたりにすると色の変化が比較的緩やかになりきれいです。
  • z-variance1,2: それぞれスピログラフの中心と外周100pix位置におけるz方向揺らぎ幅です(-3~+3)。(この値)x200pixが実際の揺らぎ幅になります。
  • radius ratio: 2つの円の半径比です(0-3)。 1つ目の円は100pxに固定されているので、2つ目の円の半径は(この値)x100pixです。
  • wire width: 針金の直径です(1~32)。


【追記】yonatan氏に PQ-Torus Knot ってのを教えてもらいました。Thanks yonatan ! http://www.blackpawn.com/texts/pqtorus/default.html