LoginSignup
10
12

More than 5 years have passed since last update.

Unity Shaderことはじめ3 マンデルブローフラクタル図

Posted at

Unityでマンデルブローフラクタル図を書いてみた。

UV座標(0〜1)を複素数座標として、複素数座標を使った漸化式の結果が発散なら色を塗るとフラクタル図形がかけるみたい。シェーダーコードみると簡潔でびっくり。

漸化式を変えるといろんな図形になる様子。

フラクタル図形の解説はここ

シェーダーはUnlit Shaderを生成して、下記のように記述。
2D描画を確認したいときは、
 UI > Panel
を配置してシェーダーを適用したマテリアルをつけると簡単かも。

Shader "Unlit/fractalShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
          //フラクタル図形拡大縮小
        _Scale("Scale", Float) = 1.0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _Scale;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            //漸化式計算回数。高速化のため途中で繰り返し止める
            static const int LIMIT = 256;
            //色付けのため
            static const float PI = 3.14159265f;
            static const float DEG2RAD = PI/180.f;

            //フラグメントシェーダー
            fixed4 frag (v2f i) : SV_Target
            {
                //フラクタル集合であれば黒
                fixed4 col = fixed4(0,0,0,1);

                //テクスチャ座標(x,y)を複素数(x, y)とする
                float2 c = i.uv.xy * _Scale;

                //いい感じに見えるようずらす
                c *= float2(2.0f,2.0f);
                c -= float2(1.0f,1.0f);

                // z1 = z0 + c
                //    =  0 + c
                // z2 = z1 + c
                //    =  c + c
                float2 z = c;

                int itr = 0;
                for(itr = 0; itr < LIMIT; itr++)
                {
                    // z1 = z0^2 + c
                    //    = x^2 - y^2 + 2xyi + c
                    z = float2( z.x * z.x - z.y * z.y, 2 * z.x * z.y);
                    z += c;

                    //自ベクトルとの内積 d = |a||a|cos(0) = |a|^2
                    //絶対値2を超えると発散=フラクタル集合ではない
                    if( dot(z,z) > 4.0f )
                    {
                        break;
                    }
                }

                if( itr < LIMIT )
                {
                    //発散(フラクタル集合でない座標に色をつける
                    col = fixed4(sin(itr*DEG2RAD),
                                 _CosTime.x,
                                 _SinTime.y*0.5+0.5,
                                 1);
                }

                return col;
            }
            ENDCG
        }
    }
}
10
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
12