LoginSignup
25
26

More than 5 years have passed since last update.

GLSLで炎エフェクトを作ってみた

Last updated at Posted at 2015-12-13

WebGL Advent Calendar 2015の13日目の記事です。

GLSLを教わる機会があったので、力試しに炎エフェクト作ってみました(glslsandboxのものを参考にしてます)
形状がいまいちですが、炎のカラーバージョンを2つ作ってみました!
001.gif

002.gif

コードはこちら → GLSL Editor - 炎エフェクトDEMO

プログラムの解説

炎のエフェクトは、メタボールを横揺れ用に8個 x 縦揺れ用に8個を描画しています。
メタボール1つだけ表示するとこんな感じです。
meta.png
始めのコードは以下のようなシンプルなものになります。

メタボール1つの場合
// メタボール生成
float metaball(vec2 pos, vec2 offset, float scale){
    // ポジション修正
    pos = pos - offset;
    float len = length(pos);
    float draw = 0.0;
    // 円を描く範囲
    if(len < scale){
        draw = (1.0 - len / scale);
    }
    return draw;
}

// 各ピクセルの原点からの距離を計測し色として出力する
void main(){
    // gl_FragCoord.xy = 0〜512 → *2.0で0〜1024 → -resoで-512〜512 → /resoで-1.0〜1.0座標
    vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / resolution;
    float ball = 0.0;
    float x = 0.0;  // 後で使う
    float y = 0.0;  // 後で使う
    float moveX = x;
    float moveY = y;
    float scale = 0.56;
    // メタボール生成
    ball += metaball(p, vec2(moveX, moveY), scale);
    // blue color
    gl_FragColor = vec4(vec3(ball*0.25+ball*0.1, ball*0.45+ball*0.1, ball), 1.0);
}

上記コードを修正し、メタボール8個を横揺れで動かすとこんな感じです。
それぞれのメタボールはY軸を固定、X軸は-0.3〜0.3をループ移動しています。
003.gif

メタボール8個で横揺れ炎の場合
void main(){
    // gl_FragCoord.xy = 0〜512 → *2.0で0〜1024 → -resoで-512〜512 → /resoで-1.0〜1.0座標
    vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / resolution;
    float ball = 0.0;
    float speed = 10.0; // 炎のスピード
    float yPos = 0.8;   // Y軸の調整

    // 横揺れの炎8つ
    for(int i = 1; i <= 8; i++){
        float x = float(i) * 1.0;
        float y = float(8-i) * 0.18;
        float moveX = cos(x+time*speed) * 0.31;
        float moveY = y - yPos;
        float scale = 0.56;
        // メタボール生成
        ball += metaball(p, vec2(moveX, moveY), scale);
    }
    // blue color
    gl_FragColor = vec4(vec3(ball*0.25+ball*0.1, ball*0.45+ball*0.1, ball), 1.0);
}

縦揺れの炎も同様に8個のメタボールで動作させています。
004.gif

メタボール8個で縦揺れ炎の場合
void main(){
    // gl_FragCoord.xy = 0〜512 → *2.0で0〜1024 → -resoで-512〜512 → /resoで-1.0〜1.0座標
    vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / resolution;
    float ball = 0.0;
    float speed = 10.0; // 炎のスピード
    float yPos = 0.8;   // Y軸の調整

    // 縦揺れの炎8つ
    for(int i = 1; i <= 8; i++){
        float x = float(i) * 0.0;
        float y = float(8-i) * 0.22;
        float moveX = x;
        float moveY = y - yPos + sin(float(i)+time*speed) * 0.2;
        float scale = 0.4;
        // メタボール生成
        ball += metaball(p, vec2(moveX, moveY), scale);
    }
    // blue color
    gl_FragColor = vec4(vec3(ball*0.25+ball*0.1, ball*0.45+ball*0.1, ball), 1.0);
}

最後に縦揺れと横揺れのコードを結合させます。
ここではballという変数に両方の描画結果を加算するだけで、描画内容がブレンドされます。
こういう部分はシェーダーって素晴らしいですね♪

縦揺れと横揺れ結合の場合
// 横揺れの炎8つ
for(int i = 1; i <= 8; i++){
    float x = float(i) * 1.0;
    float y = float(8-i) * 0.18;
    float moveX = cos(x+time*speed) * 0.31;
    float moveY = y - yPos;
    // moveX = 0.0;
    // moveY = 0.0;
    float scale = 0.56;
    // メタボール生成
    ball += metaball(p, vec2(moveX, moveY), scale);
}
// 縦揺れの炎8つ
for(int i = 1; i <= 8; i++){
    float x = float(i) * 0.0;
    float y = float(8-i) * 0.22;
    float moveX = x;
    float moveY = y - yPos + sin(float(i)+time*speed) * 0.2;
    // moveX = 0.0;
    // moveY = 0.0;
    float scale = 0.4;
    // メタボール生成
    ball += metaball(p, vec2(moveX, moveY), scale);
}

// blue color
gl_FragColor = vec4(vec3(ball*0.25+ball*0.1, ball*0.45+ball*0.1, ball), 1.0);

炎の動きの調整が少し難しいですが、以外と簡単にできたので興味ある方はぜひ試してみて下さい!

明日は、takahito-tejimaさんよろしくです。

25
26
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25
26