Unity patch realizes flame effect
1. Effect Description
Hello everyone, I am Zhao. This is a flame effect, but it is not made of particles, it is made of a patch, which can be understood as a 2D special effect. This example is very simple, but you can expand your thinking. It turns out that in addition to using sequence frames and particles for animation, you can also use Shader to achieve it.
Second, the principle of step-by-step production
1. Color part
Here we mainly use a noise map as a simulation of the flame
By controlling the UV coordinates, the noise map has a scrolling effect from bottom to top
float2 noiseUV = i.uv*_NoiseTex_ST.xy + _NoiseTex_ST.zw +_Time.y*_Speed;
half4 noiseCol = tex2D(_NoiseTex, noiseUV);
Next, use a gradient map to achieve the effect of the flame's up and down transition:
It can be seen that through the noise map and the gradient map, there is already a little flame on the patch. But now the flame is black and white, we have to multiply it by a color.
float2 noiseUV = i.uv*_NoiseTex_ST.xy + _NoiseTex_ST.zw +_Time.y*_Speed;
half4 noiseCol = tex2D(_NoiseTex, noiseUV);
half noiseVal = noiseCol.r;
half4 genCol = tex2D(_GenTex, i.uv);
float genVal = genCol.r;
float finalG = (1 - genVal)*_EndVal*noiseVal*_ColChange + _Color.g;
finalG = clamp(finalG, 0, 1);
half3 finalRGB = half3(_Color.r, finalG, _Color.b);
finalRGB = finalRGB * _Bright;
Note that there is a finalG variable in the code, which is used for the G channel of the final output color, and then the RB channel directly uses a specified color _Color. In fact, the entire _Color can also be multiplied with the gradient color and noise map color, and the effect will be like this
half3 finalRGB = _Color.rgb* genVal*noiseVal;
I feel that the calculation effect is not as good as using the G channel alone.
2. Transparency
Here, a black and white mask image is used to crop the color result obtained above, so that it is displayed only within the mask range:
The current shape is too neat, and there should be a certain jitter effect when the flame burns, so when calculating this mask, the noise map and gradient map are also added to make the edge of the flame jitter irregularly:
3. Complete Shader
Shader "azhao/panelFire"
{
Properties
{
_NoiseTex("NoiseTex", 2D) = "white" {}
_Speed("Speed", Vector) = (0,0,0,0)
_Color("_Color", Color) = (1,0.7981879,0,0)
_GenTex("GenTex", 2D) = "white" {}
_EndVal("EndVal", Float) = 1
_ColChange("ColChange", Float) = 0
_Bright("Bright", Float) = 1
_MaskOffset("MaskOffset", Float) = 1
_MaskTex("MaskTex", 2D) = "white" {}
_NoiseLen("NoiseLen", Float) = 0
}
SubShader
{
Tags { "Queue"="Transparent" }
LOD 100
ZWrite off
Cull off
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
};
sampler2D _NoiseTex;
float4 _NoiseTex_ST;
float2 _Speed;
float4 _Color;
sampler2D _GenTex;
float _EndVal;
float _ColChange;
float _Bright;
float _MaskOffset;
sampler2D _MaskTex;
float _NoiseLen;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
half4 frag (v2f i) : SV_Target
{
// sample the texture
float2 noiseUV = i.uv*_NoiseTex_ST.xy + _NoiseTex_ST.zw +_Time.y*_Speed;
half4 noiseCol = tex2D(_NoiseTex, noiseUV);
half noiseVal = noiseCol.r;
half4 genCol = tex2D(_GenTex, i.uv);
float genVal = genCol.r;
float finalG = (1 - genVal)*_EndVal*noiseVal*_ColChange + _Color.g;
finalG = clamp(finalG, 0, 1);
half3 finalRGB = half3(_Color.r, finalG, _Color.b);
finalRGB = finalRGB * _Bright;
float2 maskUV = i.uv;
maskUV.x = (noiseVal * 2 - 1)*noiseVal*0.1*_MaskOffset + i.uv.x;
half4 maskCol = tex2D(_MaskTex, maskUV);
half alpha = smoothstep(noiseVal - _NoiseLen, noiseVal, genVal)*genVal*maskCol.r;
return half4(finalRGB,alpha);
}
ENDCG
}
}
}