本帖最后由 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
[HideInInspector]
_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 [_StencilRef]
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
}
}
}