猫マップ


~別に猫属性を保存するわけじゃないよ~




■はじめに

今回は、シェーダとは関係ない話で、Arnold's cat map と呼ばれる画像変換を行います。

まぁ、いつものように適当にファイルが入っています。

draw.cppメインの描画部分。
draw.h描画の各関数の定義。
main.h基本的な定数など。
main.cpp描画に関係しないシステム的な部分。
cat.bmp (元絵)

あと、実行ファイル及び、プロジェクトファイルが入っています。

■やってること

猫マップは、ロシア人の数学者である Vladimir I. Arnold によって発見された画像で、 一番最初に猫の絵を使ったことから "Cat Map" と呼ばれています。
この変換は「パイこね変換」のひとつで、隣接するピクセルと指数関数的に離れていくので、カオスの1つと捕らえられます。
その一方で、数学的には「可逆」な変換で、変換した途中から逆変換をすると元に戻る時があるので、 散逸をしないカオスの例として知られています。

実際の変換は、

x = (x+ y) mod ピクセルサイズ
y = (x+2y) mod ピクセルサイズ

という簡単な変換が行われます。
簡単といってもつかみずらいので、図で描くと次のようになります。

横に2倍、縦に3倍をゆがめつつ引き伸ばします。 次にその画像を元の画像サイズで切りとって、1つの画像につなげ合わせます。
基本的に切って張るだけで、半透明で合成するなどの特別なことはしていません (この画像をつかってしまうと、「ヤママヤーマップ」ですね)

ポリゴンとして張るときには、ポリゴンの座標とUV値を

              座標1       座標2       座標3        UV1         UV2         UV3
ポリゴン1:(0.0, 0.0) - (0.5, 0.0) - (0.0, 1.0) : (0.0, 0.0) - (1.0, 0.5) - (1.0, 1.0)
ポリゴン2:(0.5, 0.0) - (1.0, 0.0) - (0.0, 1.0) : (0.0, 0.5) - (1.0, 1.0) - (0.0, 1.0)
ポリゴン3:(0.0, 1.0) - (1.0, 0.0) - (0.5, 1.0) : (0.0, 0.0) - (1.0, 0.0) - (1.0, 0.5)
ポリゴン4:(0.5, 1.0) - (1.0, 0.0) - (0.1, 1.0) : (0.0, 0.5) - (0.0, 0.0) - (1.0, 1.0)

で張れば、Cat Map が実現します。

この変換を次々と行っていけば、

と、ピクセルがどんどん混ざっていきます。
ピクセルの解像度が無限の時には、元のピクセルと変換後のピクセルの色の分布は全く変化しませんが、 我々が使っている有限な解像度のテクスチャーの場合は、引き伸ばしと畳み込みが起きるので、 情報の消去が一部行われます。
しかし、ある程度の大きさであれば、(双線形フィルタリング等を行わない限りは) 色が混ざることが無く、100FPSで数時間置いておいても一色になりません。

■最後に

なぜ、いきなりこのようなことをやったかというと、「火種」を作りたかったからです。
火のエフェクトを作っていたのですが、「火種」として何を使うか考えてしまいました。
ライフゲームを火種として使うのは有名ですが、ちょっと大げさだったので、 ポリゴン4枚でできる効果を使いました。
まさか大学で聞いた話をこんな形で使うとは思ってもいなかったでした。




もどる

imagire@gmail.com