應用噪聲函式製作火焰特效

js0907發表於2020-12-04

1.白噪聲

在這裡插入圖片描述
gridCount = 5,生成的白噪聲紋理是 5行5列的:類似 frac(5x)的結果。
在這裡插入圖片描述白噪聲原始碼:

float WhiteNoise(int seed, int i, int j)
{
    //return (51237 * sin((i * 15367 + j * 66374 + seed * 36275) % 425767) + (seed * 12352 + 24556)) % 1.0f;
    //float r = sin((float(i) * 157.024f + sin(float(j) * 66.525f) * 214.0f + 214.126f * float(seed)) * 21.25f);
    float r = frac(sin(dot(float2(i, cos(j)), float2(float(seed) + 12.9898, float(seed) + 78.233))) * 43758.5453);
    return r;
}

2.柏林噪聲
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
下面是柏林噪聲的原始碼:

float HashGrid(int seed, int i, int j)
{
	//	白噪聲的結果
    float r = WhiteNoise(seed, i, j);
    r = r * 2.0f - 1.0f;
    return r;
}
float2 ComputeGradient(int seed, int gridX, int gridY)
{
    float2 gradient = float2(HashGrid(seed * 123 + 345, gridX, gridY), HashGrid(seed * 456 + 234, gridX, gridY));
    return normalize(gradient);
}


//柏林噪聲
float PerlinNoise(int seed, float2 p, float gridSize)
{
    p /= gridSize;
    int gridX = floor(p.x);// / gridSize);
    int gridY = floor(p.y);// / gridSize);
    float2 gradient00 = ComputeGradient(seed, gridX, gridY);
    float2 gradient01 = ComputeGradient(seed, gridX, gridY + 1);
    float2 gradient10 = ComputeGradient(seed, gridX + 1, gridY);
    float2 gradient11 = ComputeGradient(seed, gridX + 1, gridY + 1);

    float2 v00 = float2(gridX, gridY);// * gridSize;
    float2 v01 = float2(gridX, gridY + 1);// * gridSize;
    float2 v10 = float2(gridX + 1, gridY);// * gridSize;
    float2 v11 = float2(gridX + 1, gridY + 1);// * gridSize;

    float dp00 = dot((p - v00), gradient00);
    float dp01 = dot((p - v01), gradient01);
    float dp10 = dot((p - v10), gradient10);
    float dp11 = dot((p - v11), gradient11);

    // bilinear interpolation
    float tx = (p.x - v00.x);// / gridSize;
    float ty = (p.y - v00.y);// / gridSize;
    float res = SmoothLerp(SmoothLerp(dp00, dp10, tx), SmoothLerp(dp01, dp11, tx), ty);
    // float res = lerp(lerp(dp00, dp10, tx), lerp(dp01, dp11, tx), ty);

    return res;
}

3.分形布朗運動
在這裡插入圖片描述
4.柏林噪聲+分型布朗運動
在這裡插入圖片描述
5.應用噪聲,做一個動態的火焰:
在這裡插入圖片描述

Shader "Unlit/nosie"
{
    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;
            };

       


            float WhiteNoise(int seed, int i, int j)
            {
                //return (51237 * sin((i * 15367 + j * 66374 + seed * 36275) % 425767) + (seed * 12352 + 24556)) % 1.0f;
                //float r = sin((float(i) * 157.024f + sin(float(j) * 66.525f) * 214.0f + 214.126f * float(seed)) * 21.25f);
                float r = frac(sin(dot(float2(i, cos(j)), float2(float(seed) + 12.9898, float(seed) + 78.233))) * 43758.5453);
                return r;
            }
            // smooth interpolation for perlin noise
            float SmoothLerp(float min, float max, float t)
            {
                t = t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
                return min + t * (max - min);
            }

            float HashGrid(int seed, int i, int j)
            {
                float r = WhiteNoise(seed, i, j);
                r = r * 2.0f - 1.0f;
                return r;
            }


            float2 ComputeGradient(int seed, int gridX, int gridY)
            {
                float2 gradient = float2(HashGrid(seed * 123 + 345, gridX, gridY), HashGrid(seed * 456 + 234, gridX, gridY));
                return normalize(gradient);
            }


            float PerlinNoiseTiling(int seed, float2 p, float gridSize, int tilingSize)
            {
                // tilingSize = 8;
                p /= gridSize;
                int gridX = floor(p.x);// / gridSize);
                int gridY = floor(p.y);// / gridSize);  
                int gridXP1 = (gridX + 1);
                int gridYP1 = (gridY + 1);
                
                float2 gradient00 = ComputeGradient(seed, gridX % tilingSize, gridY % tilingSize);
                float2 gradient01 = ComputeGradient(seed, gridX % tilingSize, gridYP1 % tilingSize );
                float2 gradient10 = ComputeGradient(seed, gridXP1 % tilingSize, gridY % tilingSize);
                float2 gradient11 = ComputeGradient(seed, gridXP1 % tilingSize , gridYP1 % tilingSize);

                float2 v00 = float2(gridX, gridY);// * gridSize;
                float2 v01 = float2(gridX, gridYP1);// * gridSize;
                float2 v10 = float2(gridXP1, gridY);// * gridSize;
                float2 v11 = float2(gridXP1, gridYP1);// * gridSize;

                float dp00 = dot((p - v00), gradient00);
                float dp01 = dot((p - v01), gradient01);
                float dp10 = dot((p - v10), gradient10);
                float dp11 = dot((p - v11), gradient11);

                // bilinear interpolation
                float tx = (p.x - v00.x);// / gridSize;
                float ty = (p.y - v00.y);// / gridSize;
                float res = SmoothLerp(SmoothLerp(dp00, dp10, tx), SmoothLerp(dp01, dp11, tx), ty);
                // float res = lerp(lerp(dp00, dp10, tx), lerp(dp01, dp11, tx), ty);

                return res;
            }
            // perlin noise with Fractal Brownian Motion (add some self-similarity?)
            float PerlinNoiseTilingFBM6(int seed, float2 p, float gridSize)
            {
                // const float aspect = 2.0f;
                // p.x *= aspect;
                // fBM : https://www.iquilezles.org/www/articles/fbm/fbm.htm
                // https://www.shadertoy.com/view/lsl3RH
                // https://www.shadertoy.com/view/XslGRr
                //Vector4 deltaVec = new Vector4(Random.Range(-1.0f, 1.0f), Random.Range(-1.0f, 1.0f), 0.0f, 0.0f); ;// new Vector4(Random.Range(-1.0f, 1.0f), Random.Range(-1.0f, 1.0f), 0.0f, 0.0f);
                float2x2 mat = { //some rotation matrix
                    0.8f, 0.6f,
                    -0.6f, 0.8f
                };

                float f = 0.0f;
                int numFbmSteps = 6;
                float multiplier[6] = { 2.02f, 2.03f, 2.01f, 2.04f, 2.01f, 2.02f };
                // float multiplier[6] = { 1.02f, 2.03f, 3.01f, 2.04f, 3.01f, 3.02f };
                float amp = 1.0f;
                for (int i = 0; i < numFbmSteps; ++i)
                {
                    f += amp * PerlinNoiseTiling(seed, p, gridSize, 10);
                    p = mul(mat, p) * multiplier[i];//(2.0f + Random.Range(0.0f, 0.05f));//brownian motion applied to sample coord
                    // p *= multiplier[i];
                    amp *= 0.5f;
                }
                return f / 0.96875f;
            }
            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;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // 生成遮罩
                // float mask = 1.0f - i.uv.y;
                // mask -= abs(2 * (i.uv.x -0.5f));
                // return fixed4(mask,mask,mask,1);

                float fireheight = 0.5f;
                float flameFadeFactor = 2.0f;
                float mask = fireheight - flameFadeFactor * pow(i.uv.y,2);
                mask -= 3 * pow((abs(2 * (i.uv.x-0.5))),2);
                //return fixed4(mask,mask,mask,1);

                float noise = PerlinNoiseTilingFBM6(96,(i.uv + float2(0,-_Time.y)),0.12f);
                mask += saturate(i.uv.y + 0.3f) * noise;
                //return fixed4(mask,mask,mask,1);


                mask *= 1.8f;
                float detailMask = mask;
                float3 albedo = float3(1.8f,1.5f,1.0f) * float3(detailMask,pow(detailMask,2),pow(detailMask,3));
                float3 res = saturate(albedo) * saturate(mask * 5);
                return fixed4(res,1);
            }
            ENDCG
        }
    }
}

相關文章