Shader学习笔记 05 - 2d火焰
2D程序式火焰
火焰一般包括焰心、内焰、外焰,至少要有内焰、外焰的区分,另外有烟,火花,热扭曲之类的效果。
基本原理很简单,就是使用梯度值(一般是uv.y)截取不断上移的噪声值来形成火焰效果。
截取方法可以定值截取,也可以插值截取
1. 定值
使用step区分内外焰,效果上类似卡通火焰(toon fire)。
另外使用偏导数也可以实现类似效果,好处是能加一点抗锯齿效果。
效果其实差不多
2. 插值
噪声值减去递增梯度值即可,结果是颜色变化比较平滑。
float gradientValue = 1 - uv.y;
float t = noiseValue + lerp(0, -2, gradientValue);
float3 col = _FireColor.rgb*(1-t);
Mask
使用Mask来约束火焰外形的时候,定值截取效果并不好。应该是需要特制下噪声,让火焰集中。
插值的火焰效果就好很多。
Smoke
烟可以单独制作然后叠加上去,也可以从火焰中截取一部分作为烟雾。
1. 单独制作
与火焰原理相同,一个噪声向上移动,然后需要另加一个噪声与之相差让结果有层次感。
相乘结果:
修改颜色,加上Mask。
最后将结果和合并到火焰上取即可。
2. 截取
既然前面可以截取噪声不同值区分内外焰,那么自然可以截取一部分作为烟。
直接插值截取效果并不好,比较好的实现参考:
火花、热扭曲
火花使用纯粹的shader实现起来比较麻烦,目前没有找到好的方法,还是使用粒子效果或者动画。
热扭曲就是简单的uv扭曲。
其他
在一个贴图上是可以模拟出粒子效果。最简单原理参考:
粒子模拟需要能获取上一渲染结果,在unity中需要创建2个RenderTexture。
private RenderTexture SimTexture;
private RenderTexture buffer;
private Material ParticleSimulationMat;
public Shader ParticleSimulationShader; // 粒子模拟Shader
public Material ObjMat; // 目标Sprite的Material
Start {
ParticleSimulationMat = new Material(ParticleSimulationShader)
SimTexture = new RenderTexture(512, 512, 0, RenderTextureFormat.ARGBFloat);
buffer = new RenderTexture(512, 512, 0, RenderTextureFormat.ARGBFloat);
}
Update {
// Graphics.Blit(SimTexture, SimTexture, ParticleSimulationMat) 无效,2019.4 版本
// 保存渲染结果,ParticleSimulationMat中_MainTex便是上一渲染结果
Graphics.Blit(SimTexture, buffer, ParticleSimulationMat);
Graphics.Blit(buffer, SimTexture);
ObjMat.SetTexture("_SimTexture", SimTexture);
}
shadertoy上有一些不错的火焰模拟,基本上可以通过这个方法移植过来,比如这个:
结论
还是直接使用Unity自带的粒子系统吧。