Unity面片实现火焰效果
一、效果说明
大家好,我是阿赵。这是一个火焰的效,不过它不是粒子做的,是用一个面片做的,可以理解成是2D的特效。这个例子很简单,但可以拓展一下思路,原来除了用序列帧和粒子做动画,还可以用Shader来实现。
二、分步制作原理
1、颜色部分
这里主要是使用了一张噪声图作为火焰的模拟
通过控制UV坐标,让噪声图有一个从下到上滚动的效果
float2 noiseUV = i.uv*_NoiseTex_ST.xy + _NoiseTex_ST.zw +_Time.y*_Speed;
half4 noiseCol = tex2D(_NoiseTex, noiseUV);
接下来用一张渐变图实现火焰上下过渡的效果:
可以看到,通过噪声图和渐变图,面片上已经有一点火焰的感觉了。但现在的火焰是黑白的,我们还要乘以一个颜色。
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;
注意到代码里面有一个finalG的变量,用于最终输出颜色的G通道,然后RB通道都是直接使用了一个指定的颜色_Color。其实这里也可以整个_Color和渐变色、噪声图颜色一起做乘法的,效果会是这样
half3 finalRGB = _Color.rgb* genVal*noiseVal;
感觉没有单独用G通道去计算的效果好。
2、透明度部分
这里使用一张黑白的遮罩图,对上面得到的颜色结果进行裁剪,得到只有在遮罩范围内才显示:
现在的形状过于整齐,火焰燃烧时应该是有一定的抖动效果,所以在计算这个遮罩的时候,把噪声图和渐变图也加入进去,让火焰的边缘产生不规则的抖动:
三、完整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
}
}
}