KafuuChino 发表于 2024-6-25 19:01:03

Unity Shader 2D 火焰效果

本帖最后由 KafuuChino 于 2024-6-25 19:01 编辑

在存火焰Shader的目录下创建一个Common文件夹,再创建一个CommonShaderMethods.cg,把这些内容复制进去:(实现了gradient noise 和 simple noise)

```
float2 unity_gradientNoise_dir(float2 p) {
    p = p % 289;
    float x = (34 * p.x + 1) * p.x % 289 + p.y;
    x = (34 * x + 1) * x % 289;
    x = frac(x / 41) * 2 - 1;
    return normalize(float2(x - floor(x + 0.5), abs(x) - 0.5));
}

float unity_gradientNoise(float2 p) {
    float2 ip = floor(p);
    float2 fp = frac(p);
    float d00 = dot(unity_gradientNoise_dir(ip), fp);
    float d01 = dot(unity_gradientNoise_dir(ip + float2(0, 1)), fp - float2(0, 1));
    float d10 = dot(unity_gradientNoise_dir(ip + float2(1, 0)), fp - float2(1, 0));
    float d11 = dot(unity_gradientNoise_dir(ip + float2(1, 1)), fp - float2(1, 1));
    fp = fp * fp * fp * (fp * (fp * 6 - 15) + 10);
    return lerp(lerp(d00, d01, fp.y), lerp(d10, d11, fp.y), fp.x);
}

float GradientNoise(float2 UV, float Scale) {
    return unity_gradientNoise(UV * Scale) + 0.5;
}

inline float unity_noise_randomValue(float2 uv) {
    return frac(sin(dot(uv, float2(12.9898, 78.233)))*43758.5453);
}

inline float unity_noise_interpolate(float a, float b, float t) {
    return (1.0-t)*a + (t*b);
}

inline float unity_valueNoise(float2 uv) {
    float2 i = floor(uv);
    float2 f = frac(uv);
    f = f * f * (3.0 - 2.0 * f);
    uv = abs(frac(uv) - 0.5);
    float2 c0 = i + float2(0.0, 0.0);
    float2 c1 = i + float2(1.0, 0.0);
    float2 c2 = i + float2(0.0, 1.0);
    float2 c3 = i + float2(1.0, 1.0);
    float r0 = unity_noise_randomValue(c0);
    float r1 = unity_noise_randomValue(c1);
    float r2 = unity_noise_randomValue(c2);
    float r3 = unity_noise_randomValue(c3);
    float bottomOfGrid = unity_noise_interpolate(r0, r1, f.x);
    float topOfGrid = unity_noise_interpolate(r2, r3, f.x);
    float t = unity_noise_interpolate(bottomOfGrid, topOfGrid, f.y);
    return t;
}

float SimpleNoise(float2 UV, float Scale) {
    float t = 0.0;
    float freq = pow(2.0, float(0));
    float amp = pow(0.5, float(3-0));
    t += unity_valueNoise(float2(UV.x*Scale/freq, UV.y*Scale/freq))*amp;
    freq = pow(2.0, float(1));
    amp = pow(0.5, float(3-1));
    t += unity_valueNoise(float2(UV.x*Scale/freq, UV.y*Scale/freq))*amp;
    freq = pow(2.0, float(2));
    amp = pow(0.5, float(3-2));
    return t + unity_valueNoise(float2(UV.x*Scale/freq, UV.y*Scale/freq))*amp;
}

```



---

以下是火焰Shader的内容

Scale 和 Speed都是二维的

将shader赋值给一个材质,随后将材质赋值给一个Sprite Renderer即可

火焰的透明度会受到sprite透明度影响

```
Shader "Custom/Fire"{
    Properties{
      _MainTex ("MainTex", 2D) = "white" {}
      _Color ("Color", Color) = (1,1,1,1)
      _Emission ("Emission", Float) = 1
      
      _Stencil ("Stencil", Int) = 0
      _Edge ("Edge", Float) = 0.7
      _Scale ("Scale", Vector) = (1,1,0,0)
      _Speed ("Speed", Vector) = (1,1,0,0)
    }

    SubShader{
      Tags{
            "Queue" = "Transparent"
            "RenderType" = "Sprite"
      }
      LOD 100

      ZWrite off
      Cull off
      Blend SrcAlpha OneMinusSrcAlpha

      Stencil{
            Ref
            Comp LEqual
      }

      Pass{
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "Common/CommonShaderMethods.cg"

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

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

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _Emission, _Edge;
            float4 _Color;
            float2 _Scale, _Speed;

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

            float4 frag(v2f i) : SV_Target{
                float h = (1 - pow(i.uv.y, 0.5)) - (1.5 - _Edge);
                float2 uv = (i.uv + _Time * _Speed * -1) * (1 / _Scale);
                float fire = GradientNoise(uv, 10) * SimpleNoise(uv, 10);

                float a = tex2D(_MainTex, i.uv).a * clamp(fire + h, 0, 1);
                float4 color = _Color * (_Emission + 1);
                return float4(color.rgb, a) * i.color;
            }
            ENDCG
      }
    }
}
```
页: [1]
查看完整版本: Unity Shader 2D 火焰效果