中級Shader教程06 2D火焰粒子


0.本篇主要技術點有:

  1. grid 空間劃分
  2. 2D模擬3D中”分層”的概念
  3. 透視模擬
  4. 基於grid的隨機變化(旋轉,位移,閃爍)
  5. sin 週期變化(閃爍)

1.實現

1.空間劃分

float2 coord = uv*_GridSize;


2.交錯grid

 if (abs(fmod(coord.y,2.0))<1.0) //讓格子交錯
        coord.x += 0.5;


3.基於grid的隨機化

float2 gridIndex = float2(floor(coord));
float rnd = Hash12(gridIndex);//根據ID 獲取hash值


4.整體位移

float2 coord = uv*_GridSize - float2(0.,yOffset);//整體沿y軸上升
float tempY = gridIndex.y + yOffset ;
float life = min(   10.0*(1.0-min((tempY)/(24.0-20.0*rnd)//生命值隨機
                                    ,1.0)),1.0);


5.加點閃爍

float sinval = sin(PI*1.*(0.3+0.7*rnd)*ftime+rnd*10.);//加點亮度的變化實現閃爍  隨週期變化
float period = clamp(pow(pow(sinval,5.),5.),0.,1.);
float blink =(0.8+0.8*abs(period));


6.加點旋轉

float2 rotate = float2(sin(deg),cos(deg));//單位圓旋轉偏移
float radius =  0.5-size*0.2;
float2 cirOffset = radius*rotate;//
float2 part = frac(coord-cirOffset) - 0.5 ;//讓格子自己旋轉起來 位置變 
float len = length(part);


6.最終效果


整體代碼:

float3 _Color;
float _GridSize;
float _RotSpd;
float _YSpd;
float3 ProcessFrag(float2 uv){
    float3 acc = float3(0.0,0.0,0.0);

    float rotDeg = 3.*_RotSpd * ftime;
    float yOffset = 4.*_YSpd* ftime;

    float2 coord = uv*_GridSize - float2(0.,yOffset);//整體沿y軸上升
    if (abs(fmod(coord.y,2.0))<1.0) //讓格子交錯
        coord.x += 0.5;
    float2 gridIndex = float2(floor(coord));
    float rnd = Hash12(gridIndex);//根據ID 獲取hash值
    // 彌補y軸上升的逆差 獲取原來的y值 
    // 同時因爲gridIndex = floor(coord) 的原因  會讓tempY值在鎖定固定的grid的同時越來越大;
    float tempY = gridIndex.y + yOffset ;
    float life = min(   10.0*(1.0-min((tempY)/(24.0-20.0*rnd)//生命值隨機
                                        ,1.0)),1.0);
    if (life>0.0 ) {
        float size = 0.08*rnd;//讓大小隨機化
        float deg = 999.0*rnd*2.0*PI + rotDeg*(0.5+0.5*rnd);//添加旋轉隨機化
        float2 rotate = float2(sin(deg),cos(deg));//單位圓旋轉偏移
        float radius =  0.5-size*0.2;
        float2 cirOffset = radius*rotate;//
        float2 part = frac(coord-cirOffset) - 0.5 ;//讓格子自己旋轉起來 位置變 方向不變
        float len = length(part);
        float sparksGray = max(0.0,1.0 -len/size);//畫圓
        float sinval = sin(PI*1.*(0.3+0.7*rnd)*ftime+rnd*10.);//加點亮度的變化實現閃爍 
        float period = clamp(pow(pow(sinval,5.),5.),0.,1.);
        float blink =(0.8+0.8*abs(period));
        acc = life*sparksGray*_Color*blink;
    }
    return acc;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章