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自帶的粒子系統吧。