頭と尻尾はくれてやる!

パソコンおやじのiPhoneアプリ・サイト作成・運営日記


Metalでチューリングパターンを作ってみる

初めてチューリングパターンってのを聞いたのは
所さんの目がテン!
ってテレビ番組。
知識の宝庫!目がテン!ライブラリー
↑第1274回(2015年5月3日)の分みたいだな。ちなみに関西では1週くらい遅れて放送されてるんじゃないかな。

調べたらいろいろと見つかるので勉強はできる、としていざシミュレーションしてみようとすると

[作ってみた] [プログラミング] 反応拡散方程式で遊ぶ | ぞうさんの何でもノート
↑このページがとても役に立ったわ。サンプルコード(C++)もダウンロードできる。ありがたや、ありがたや。

でもいざコードを読んでいくと、、、はて、微分方程式をどうやってシミュレーションするのよ?って思ったんだけど、、、

微分方程式と差分方程式(漸化式)
↑このあたりが助けになったよ。この辺りをヒントに調べれば理解が深まると思う。

Metalでいうとシェーダに現在のテクスチャを与えて、計算、別なテクスチャに出力すればOKってことになるよね。

そうそう、微分方程式に出てくる三角形はなんなの?見るページによってxだけで微分してるけど?なんなの?って頭がこんがらがってきた場合は
ラプラス作用素 - Wikipedia
↑この辺りを参考に。ラプラシアン、、、大昔に習ったような気がしますがこんなところで再会するとは。

ラプラス方程式を差分法で解いてみる - Kiの研究部屋
↑ラプラシアンを差分化する時にここもとても参考になった。なるほど、そういうことかとこれでようやくサンプルコードでやってることに納得。

というわけで、これをMetalのシェーダでやってみるんだけど、テクスチャのメモリを確保しといてcompute shaderに現在のテクスチャと出力用の新しいテクスチャを渡してやる、、、って流れは画像処理のサンプルと同じだね。
シェーダ内はこんな感じ。u,vはそれぞれRGBAのr,gにそれぞれ割りあててる。
fとkとru,rv(拡散係数)はCPU側からFKD_tって構造体使って渡してる。
実行される時のピクセル位置が簡単にわかるのがcompute shaderのいいところだなあ。
kernel void turing(texture2d<half, access::read>  inTexture   [[ texture(0) ]],
                     texture2d<half, access::write> outTexture  [[ texture(1) ]],
                     constant FKD_t &coefficients [[ buffer(0) ]],
                      uint2 gid  [[ thread_position_in_grid ]],
                        uint2 imageSize [[ threads_per_grid ]])
{
    uint xx = gid[0];
    uint yy = gid[1];
    
    float f = coefficients.f;
    float k = coefficients.k;
    float ru = coefficients.ru;
    float rv = coefficients.rv;

    float u_next , v_next;
    
    
    if ( (xx == 0)||(yy == 0)||(xx == imageSize[0]-1)||(yy == imageSize[1]-1) ) {
        u_next = 0.0;
        v_next = 0.0;
    } else {
        half4 inColor  = inTexture.read(gid);
        half u = inColor[0];// r
        half v = inColor[1];// g
        
        half4 inColor1 = inTexture.read(uint2(xx+1,yy));
        half4 inColor2 = inTexture.read(uint2(xx-1,yy));
        half4 inColor3 = inTexture.read(uint2(xx,yy+1));
        half4 inColor4 = inTexture.read(uint2(xx,yy-1));
        float u_xm1_y = inColor2[0];
        float u_xp1_y = inColor1[0];
        float u_x_ym1 = inColor4[0];
        float u_x_yp1 = inColor3[0];
        float v_xm1_y = inColor2[1];
        float v_xp1_y = inColor1[1];
        float v_x_ym1 = inColor4[1];
        float v_x_yp1 = inColor3[1];
        
        u_next = u + ru*( (u_x_ym1 - 2.0*u + u_x_yp1) + (u_xm1_y - 2.0*u + u_xp1_y)) - u*v*v + f*(1.0-u);
        v_next = v + rv*( (v_x_ym1 - 2.0*v + v_x_yp1) + (v_xm1_y - 2.0*v + v_xp1_y)) + u*v*v - (f+k)*v;
        
    }
    
    half4 outColor = half4(u_next, v_next, 0.0, 1.0);
    
    outTexture.write(outColor, gid);
}

チューリングパターン結果
↑u,vを赤と緑に割りあてたもんだから見栄えはさほどよろしくないどころか目に悪そうなので動画はやめて写真だけにしとくわ。

係数を少し変えるだけでいろんな模様になっていくのは面白いね。

<< 移行アシスタントでMacの引っ越し  TopPage  コタツの足を長くしたい(3) >>

コメント


管理者にだけ表示を許可する
 

トラックバック

トラックバックURL
http://ringsbell.blog117.fc2.com/tb.php/988-37ce2902




Copyright ©頭と尻尾はくれてやる!. Powered by FC2 Blog. Template by eriraha.

FC2Ad