分型布朗運動(Fractal Brownian Motion)模型與shader 後篇

有一種新的生成隨機的方式能替代正弦曲線生成隨機,參考地址:https://www.shadertoy.com/view/4djSRW

刪掉正弦曲線相關的代碼,並替換爲新的隨機代碼,正弦曲線的相關概念在接下來會繼續適用於分型布朗運動模型。

生成的效果如下,與上一篇文章最後生成的效果是類似的:

修改後的代碼如下:

Shader "Unlit/sinFunc"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

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

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            float remap1d(float fromx,float fromy,float tox,float toy,float p)
            {
                return (p-fromx)/(fromy - fromx)*(toy - tox) + tox;
            }
            
            
            v2f vert (appdata v)
            {
                v2f o;

                o.vertex = UnityObjectToClipPos(v.vertex);
                 
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }
            
            float doHashFunc12(float2 p)
            {
                float HASHSCALE1 = 0.1031;
            	float3 p3  = frac(float3(p.xyx) * HASHSCALE1);
                p3 += dot(p3, p3.yzx + 19.19);
                return frac((p3.x + p3.y) * p3.z);
            }
            
            float doRandomFunc(float2 xy)
            {
                return  frac(69250*doHashFunc12(xy));               
            }
            
            float mix1d(float x,float y,float p)
            {
                return x*(1.0-p)+y*p;
            }
            
            float doNoiseFunc(float2 xy)
            {
                float2 id = floor(xy);
                float2 lv = smoothstep(float2(0,0),float2(1.0,1.0),frac(xy));
                
                float orign = doRandomFunc(id);
                float forward = doRandomFunc(id+float2(1.0,0.0));
                float up = doRandomFunc(id+float2(0.0,1.0));
                float upForward = doRandomFunc(id+float2(1.0,1.0));
                
                return mix1d(mix1d(orign,forward,lv.x),mix1d(up,upForward,lv.x),lv.y);
                
            }
            
            float clamp1d(float fromx,float fromy,float tox,float toy,float p)
            {
                return (p-fromx)/(fromy-fromx)*(toy-tox)+tox;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                i.uv+=float2(-0.5,-0.5);
                i.uv*=float2(20,20);
                
                float progress = 0;
                float2 pos = i.uv.xx+float2(_Time.y,_Time.y)*0.5;
                progress += doNoiseFunc(pos)*0.5;
                progress += doNoiseFunc(pos*2.0)*0.25;
                progress += doNoiseFunc(pos*4.0)*0.125;
                progress += doNoiseFunc(pos*8.0)*0.0625;
                progress = clamp1d(0,1,-1,1,progress);
                   
                float2x2 beveling = float2x2(1,0,
                                             progress,1);
                i.uv = mul(beveling,i.uv);
                
                float outOfX = max(step(i.uv.x,0.0),step(1.0,i.uv.x));
                float outOfY = max(step(i.uv.y,0.0),step(1.0,i.uv.y));
                float outOfArea = max(outOfX,outOfY);
                if(outOfArea == 1.0)
                {
                    discard;
                }
                
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
                
            }
            ENDCG
        }
    }
}

爲了更好的觀察分型布朗運動的運動趨勢,將其變化過程繪製爲線路圖

效果如下:

代碼如下:

Shader "Unlit/sinFunc"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

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

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            float remap1d(float fromx,float fromy,float tox,float toy,float p)
            {
                return (p-fromx)/(fromy - fromx)*(toy - tox) + tox;
            }
            
            
            v2f vert (appdata v)
            {
                v2f o;

                o.vertex = UnityObjectToClipPos(v.vertex);
                 
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }
            
            float doHashFunc12(float2 p)
            {
                float HASHSCALE1 = 0.1031;
            	float3 p3  = frac(float3(p.xyx) * HASHSCALE1);
                p3 += dot(p3, p3.yzx + 19.19);
                return frac((p3.x + p3.y) * p3.z);
            }
            
            float doRandomFunc(float2 xy)
            {
                return  frac(69250*doHashFunc12(xy));               
            }
            
            float mix1d(float x,float y,float p)
            {
                return x*(1.0-p)+y*p;
            }
            
            float doNoiseFunc(float2 xy)
            {
                float2 id = floor(xy);
                float2 lv = smoothstep(float2(0,0),float2(1.0,1.0),frac(xy));
                
                float orign = doRandomFunc(id);
                float forward = doRandomFunc(id+float2(1.0,0.0));
                float up = doRandomFunc(id+float2(0.0,1.0));
                float upForward = doRandomFunc(id+float2(1.0,1.0));
                
                return mix1d(mix1d(orign,forward,lv.x),mix1d(up,upForward,lv.x),lv.y);
                
            }
            
            float clamp1d(float fromx,float fromy,float tox,float toy,float p)
            {
                return (p-fromx)/(fromy-fromx)*(toy-tox)+tox;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                i.uv+=float2(-0.5,-0.5);
                i.uv*=float2(20,20);
                
                float progress = 0;
                float2 pos = i.uv.xx+float2(_Time.y,_Time.y)*0.5;
                
                progress += 1.0*0.5*            doNoiseFunc(pos*1.0);
                progress += 1.0*0.5*0.5*        doNoiseFunc(pos*1.0*2.0);
                progress += 1.0*0.5*0.5*0.5*    doNoiseFunc(pos*1.0*2.0*2.0);
                progress += 1.0*0.5*0.5*0.5*0.5*doNoiseFunc(pos*1.0*2.0*2.0*2.0);
                //progress = clamp1d(0,1,-1,1,progress);
                
                //繪製分型布朗運動生成的1D曲線
                float isY = smoothstep(progress-0.1,progress,i.uv.y) - smoothstep(progress,progress+0.1,i.uv.y) ;
                
                return isY;
                
            }
            ENDCG
        }
    }
}

觀察上面的代碼,在progress變量累加的那部分是有規律的。

將規律設定爲progress+= A*doNoiseFunc(B*pos);

其中A代表振幅,B代表頻率。

每次對progress累加,都以同樣的規律對A和B進行變換,這裏對A進行了縮小0.5倍,對B放大2倍。

將相關參數改爲可設置的變量,通過調整變量的值,似乎隨機可控制了,效果如下:

代碼如下:

Shader "Unlit/sinFunc"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        A("振幅",Float) = 1.0
        B("頻率",Float) = 1.0
        gain("拉伸",Float) = 0.5
        lacunarity("不均勻性",Float) = 2.0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

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

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float A;
            float B;
            float gain;
            float lacunarity;
            
            float remap1d(float fromx,float fromy,float tox,float toy,float p)
            {
                return (p-fromx)/(fromy - fromx)*(toy - tox) + tox;
            }
            
            
            v2f vert (appdata v)
            {
                v2f o;

                o.vertex = UnityObjectToClipPos(v.vertex);
                 
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }
            
            float doHashFunc12(float2 p)
            {
                float HASHSCALE1 = 0.1031;
            	float3 p3  = frac(float3(p.xyx) * HASHSCALE1);
                p3 += dot(p3, p3.yzx + 19.19);
                return frac((p3.x + p3.y) * p3.z);
            }
            
            float doRandomFunc(float2 xy)
            {
                return  frac(69250*doHashFunc12(xy));               
            }
            
            float mix1d(float x,float y,float p)
            {
                return x*(1.0-p)+y*p;
            }
            
            float doNoiseFunc(float2 xy)
            {
                float2 id = floor(xy);
                float2 lv = smoothstep(float2(0,0),float2(1.0,1.0),frac(xy));
                
                float orign = doRandomFunc(id);
                float forward = doRandomFunc(id+float2(1.0,0.0));
                float up = doRandomFunc(id+float2(0.0,1.0));
                float upForward = doRandomFunc(id+float2(1.0,1.0));
                
                return mix1d(mix1d(orign,forward,lv.x),mix1d(up,upForward,lv.x),lv.y);
                
            }
            
            float clamp1d(float fromx,float fromy,float tox,float toy,float p)
            {
                return (p-fromx)/(fromy-fromx)*(toy-tox)+tox;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                i.uv+=float2(-0.5,-0.5);
                i.uv*=float2(20,20);
                
                float progress = 0;
                float2 pos = i.uv.xx+float2(_Time.y,_Time.y)*0.5;
                
                
                progress += A*            doNoiseFunc(pos*B);
                progress += A*gain*        doNoiseFunc(pos*B*lacunarity);
                progress += A*gain*gain*    doNoiseFunc(pos*B*lacunarity*lacunarity);
                progress += A*gain*gain*gain*doNoiseFunc(pos*B*lacunarity*lacunarity*lacunarity);
                //progress = clamp1d(0,1,-1,1,progress);
                
                //繪製分型布朗運動生成的1D曲線
                float isY = smoothstep(progress-0.1,progress,i.uv.y) - smoothstep(progress,progress+0.1,i.uv.y) ;
                
                return isY;

            }
            ENDCG
        }
    }
}

累加的次數應該也是可以控制的,設置累加的次數可控制,代碼如下:

Shader "Unlit/sinFunc"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        Loops("累加次數",Float) = 10
        A("振幅",Float) = 1.0
        B("頻率",Float) = 1.0
        gain("拉伸",Float) = 0.5
        lacunarity("不均勻性",Float) = 2.0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

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

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float A;
            float B;
            float gain;
            float lacunarity;
            float Loops;
            
            float remap1d(float fromx,float fromy,float tox,float toy,float p)
            {
                return (p-fromx)/(fromy - fromx)*(toy - tox) + tox;
            }
            
            
            v2f vert (appdata v)
            {
                v2f o;

                o.vertex = UnityObjectToClipPos(v.vertex);
                 
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }
            
            float doHashFunc12(float2 p)
            {
                float HASHSCALE1 = 0.1031;
            	float3 p3  = frac(float3(p.xyx) * HASHSCALE1);
                p3 += dot(p3, p3.yzx + 19.19);
                return frac((p3.x + p3.y) * p3.z);
            }
            
            float doRandomFunc(float2 xy)
            {
                return  frac(69250*doHashFunc12(xy));               
            }
            
            float mix1d(float x,float y,float p)
            {
                return x*(1.0-p)+y*p;
            }
            
            float doNoiseFunc(float2 xy)
            {
                float2 id = floor(xy);
                float2 lv = smoothstep(float2(0,0),float2(1.0,1.0),frac(xy));
                
                float orign = doRandomFunc(id);
                float forward = doRandomFunc(id+float2(1.0,0.0));
                float up = doRandomFunc(id+float2(0.0,1.0));
                float upForward = doRandomFunc(id+float2(1.0,1.0));
                
                return mix1d(mix1d(orign,forward,lv.x),mix1d(up,upForward,lv.x),lv.y);
                
            }
            
            float clamp1d(float fromx,float fromy,float tox,float toy,float p)
            {
                return (p-fromx)/(fromy-fromx)*(toy-tox)+tox;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                i.uv+=float2(-0.5,-0.5);
                i.uv*=float2(20,20);
                
                float progress = 0;
                float2 pos = i.uv.xx+float2(_Time.y,_Time.y)*0.5;
                
                
                for(float j =0.0;j<Loops;j+=1.0)
                {
                    progress += A*pow(gain,j)*doNoiseFunc(pos*B*pow(lacunarity,j));
                }
                
                
                //progress = clamp1d(0,1,-1,1,progress);
                
                //繪製分型布朗運動生成的1D曲線
                float isY = smoothstep(progress-0.1,progress,i.uv.y) - smoothstep(progress,progress+0.1,i.uv.y) ;
                
                return isY;
                
                /*   
                float2x2 beveling = float2x2(1,0,
                                             progress,1);
                i.uv = mul(beveling,i.uv);
                
                float outOfX = max(step(i.uv.x,0.0),step(1.0,i.uv.x));
                float outOfY = max(step(i.uv.y,0.0),step(1.0,i.uv.y));
                float outOfArea = max(outOfX,outOfY);
                if(outOfArea == 1.0)
                {
                    discard;
                }
                
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
                */
            }
            ENDCG
        }
    }
}

如開篇所看到的一樣,圖片的抖動效果有時是非常突兀的,爲了讓圖片的抖動變得平滑,需要調試這相關的4個參數:

平滑效果爲:

將其應用到圖片,效果爲:

最終收尾代碼爲:

Shader "Unlit/sinFunc"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        Loops("累加次數",Float) = 10
        A("振幅",Float) = 1.0
        B("頻率",Float) = 1.0
        gain("拉伸",Float) = 0.5
        lacunarity("不均勻性",Float) = 2.0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

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

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float A;
            float B;
            float gain;
            float lacunarity;
            float Loops;
            
            float remap1d(float fromx,float fromy,float tox,float toy,float p)
            {
                return (p-fromx)/(fromy - fromx)*(toy - tox) + tox;
            }
            
            
            v2f vert (appdata v)
            {
                v2f o;

                o.vertex = UnityObjectToClipPos(v.vertex);
                 
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }
            
            float doHashFunc12(float2 p)
            {
                float HASHSCALE1 = 0.1031;
            	float3 p3  = frac(float3(p.xyx) * HASHSCALE1);
                p3 += dot(p3, p3.yzx + 19.19);
                return frac((p3.x + p3.y) * p3.z);
            }
            
            float doRandomFunc(float2 xy)
            {
                return  frac(69250*doHashFunc12(xy));               
            }
            
            float mix1d(float x,float y,float p)
            {
                return x*(1.0-p)+y*p;
            }
            
            float doNoiseFunc(float2 xy)
            {
                float2 id = floor(xy);
                float2 lv = smoothstep(float2(0,0),float2(1.0,1.0),frac(xy));
                
                float orign = doRandomFunc(id);
                float forward = doRandomFunc(id+float2(1.0,0.0));
                float up = doRandomFunc(id+float2(0.0,1.0));
                float upForward = doRandomFunc(id+float2(1.0,1.0));
                
                return mix1d(mix1d(orign,forward,lv.x),mix1d(up,upForward,lv.x),lv.y);
                
            }
            
            float clamp1d(float fromx,float fromy,float tox,float toy,float p)
            {
                return (p-fromx)/(fromy-fromx)*(toy-tox)+tox;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                i.uv+=float2(-0.5,-0.5);
                i.uv*=float2(20,20);
                
                float progress = 0;
                float2 pos = i.uv.xx+float2(_Time.y,_Time.y);
                
                
                for(float j =0.0;j<Loops;j+=1.0)
                {
                    progress += A*pow(gain,j)*doNoiseFunc(pos*B*pow(lacunarity,j));
                }
                
                progress = clamp1d(0,1,-0.5,0.5,progress);
                
                //繪製分型布朗運動生成的1D曲線
                //float isY = smoothstep(progress-0.1,progress,i.uv.y) - smoothstep(progress,progress+0.1,i.uv.y) ;
                //return isY;
                
                
                float2x2 beveling = float2x2(1,0,
                                             progress,1);
                i.uv = mul(beveling,i.uv);
                
                float outOfX = max(step(i.uv.x,0.0),step(1.0,i.uv.x));
                float outOfY = max(step(i.uv.y,0.0),step(1.0,i.uv.y));
                float outOfArea = max(outOfX,outOfY);
                if(outOfArea == 1.0)
                {
                    discard;
                }
                
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
                
            }
            ENDCG
        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章