应用噪声函数制作火焰特效

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
        }
    }
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Shader 火焰特效是一种使用计算机编程语言创建的图形效果,用于模拟和渲染逼真的火焰效果。 在火焰特效的实现中,常用的算法是基于渲染器的片段着色器来实现的。片段着色器是一种运行在GPU上的小型程序,用于在3D场景中为每个像素计算颜色。为了创建火焰特效,首先需要确定火焰的外观和表现。这通常包括火焰的形状、颜色、透明度、移动方式等。 接下来,通过在片段着色器中编写代码来模拟火焰特性。为了实现逼真的火焰效果,通常使用了一些技术,如噪声函数、渐变颜色、纹理映射等。其中,噪声函数用于产生随机性,使火焰看起来更加真实。渐变颜色可用于模拟火焰的温度和亮度变化,以及火焰的内部和外部区域。纹理映射技术可以将纹理图像应用火焰效果,使其更加有质感。 在实现火焰特效时,还需要考虑火焰的运动方式。可以通过改变火焰的位置、大小、形状和颜色来模拟火焰的燃烧过程。通常使用的方法包括控制火焰的粒子系统、粘滞性和湍流效应等。 最后,通过调整参数和优化代码,可以改进火焰特效的性能和实时渲染效果。这包括调整渲染器的设置、使用快速数学运算方法和适当的近似算法等。 总之,Shader 火焰特效是通过编程语言在GPU上计算出每个像素的颜色,来模拟和渲染逼真的火焰效果。通过使用噪声函数、渐变颜色、纹理映射等技术,结合火焰的运动方式,可以创建出更加逼真和有趣的火焰特效

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值