GameMaker:Studio Shader ガウスぼかし

 shader   gaussian   GLSL_ES 

配布されていたシェーダのサンプルを整理したもの

ガウスぼかし効果。

イベントを一つのオブジェクトへまとめるようにし、

    1. Create
    2. Draw
    3. DrawGUI

上記の三つのイベントへ収まるように作った。そして無駄な変数定義を全て排除。

なるべくユーザ定義関数化し、コードの使い回しが簡単。

参考動作:http://prester.org/html5/gms_shader_gaussian/

参考(YoYoGames MarketPlace):xygthop3’s Shader Resources

キーボードの Q と A キーで Blur_amount の値を変更可能。

値クランプ処理無し。要 WebGL、Google Chrome/FireFox 等で動作を確認。

このサンプルはオリジナル版に対して改変を加えて有ります。オリジナル版では Surface を二枚使って、その内一枚の Surface を Views とリンクさせて使っています。改変は主にこの部分で、改変したサンプルでは Surface は一枚のみを使用、あとは application_surface を用いています。具体的な処理は DrawGUIEv_gaussian を見てください。

オリジナル版の処理も DrawGUIEv_gaussian_for_Views というユーザ定義関数に収めて有ります。この関数を利用する場合は、初期化処理で省いてあるもう一枚の surface と views をリンクさせる処理、及び、room の設定から Views に関するオプションを有効にすること。

HTML5( WebGL ) と Windows PC で微妙に描画結果が異なる場合があります。特に引数値が 0 の場合の描画結果に注意。

今回はシェーダを二つ使います。

シェーダー名 1:SH_gaussian_vertical

シェーダー名 2:SH_gaussian_horizontal

SH_gaussian_vertical . Vertex Shader

attribute vec3 in_Position;
attribute vec2 in_TextureCoord;

varying vec2   v_texcoord;

void main()
{
    gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * vec4(in_Position, 1.0);
    v_texcoord  = in_TextureCoord;
}

SH_gaussian_vertical . Fragment Shader

varying vec2 v_texcoord;

uniform vec2  resolution;
uniform float blur_amount;

void main()
{ 
   float blurSize = 1.0/resolution.y * blur_amount;

   vec4 sum = vec4(0.0);
   sum += texture2D(gm_BaseTexture, vec2(v_texcoord.x, v_texcoord.y - 4.0*blurSize)) * 0.05;
   sum += texture2D(gm_BaseTexture, vec2(v_texcoord.x, v_texcoord.y - 3.0*blurSize)) * 0.09;
   sum += texture2D(gm_BaseTexture, vec2(v_texcoord.x, v_texcoord.y - 2.0*blurSize)) * 0.12;
   sum += texture2D(gm_BaseTexture, vec2(v_texcoord.x, v_texcoord.y - blurSize)) * 0.15;
   sum += texture2D(gm_BaseTexture, vec2(v_texcoord.x, v_texcoord.y)) * 0.16;
   sum += texture2D(gm_BaseTexture, vec2(v_texcoord.x, v_texcoord.y + blurSize)) * 0.15;
   sum += texture2D(gm_BaseTexture, vec2(v_texcoord.x, v_texcoord.y + 2.0*blurSize)) * 0.12;
   sum += texture2D(gm_BaseTexture, vec2(v_texcoord.x, v_texcoord.y + 3.0*blurSize)) * 0.09;
   sum += texture2D(gm_BaseTexture, vec2(v_texcoord.x, v_texcoord.y + 4.0*blurSize)) * 0.05;
   gl_FragColor = sum;
}

SH_gaussian_horizontal . Vertex Shader

attribute vec3 in_Position;
attribute vec2 in_TextureCoord;

varying vec2   v_texcoord;

void main()
{
    gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * vec4(in_Position, 1.0);
    v_texcoord  = in_TextureCoord;
}

SH_gaussian_horizontal . Fragment Shader

varying vec2 v_texcoord;

uniform vec2  resolution;
uniform float blur_amount;

void main()
{ 
   float blurSize = 1.0/resolution.x * blur_amount;

   vec4 sum = vec4(0.0);
   sum += texture2D(gm_BaseTexture, vec2(v_texcoord.x - 4.0*blurSize, v_texcoord.y)) * 0.05;
   sum += texture2D(gm_BaseTexture, vec2(v_texcoord.x - 3.0*blurSize, v_texcoord.y)) * 0.09;
   sum += texture2D(gm_BaseTexture, vec2(v_texcoord.x - 2.0*blurSize, v_texcoord.y)) * 0.12;
   sum += texture2D(gm_BaseTexture, vec2(v_texcoord.x - blurSize,     v_texcoord.y)) * 0.15;
   sum += texture2D(gm_BaseTexture, vec2(v_texcoord.x,                v_texcoord.y)) * 0.16;
   sum += texture2D(gm_BaseTexture, vec2(v_texcoord.x + blurSize,     v_texcoord.y)) * 0.15;
   sum += texture2D(gm_BaseTexture, vec2(v_texcoord.x + 2.0*blurSize, v_texcoord.y)) * 0.12;
   sum += texture2D(gm_BaseTexture, vec2(v_texcoord.x + 3.0*blurSize, v_texcoord.y)) * 0.09;
   sum += texture2D(gm_BaseTexture, vec2(v_texcoord.x + 4.0*blurSize, v_texcoord.y)) * 0.05;
   gl_FragColor = sum;
}

ユーザ定義関数 Init_Shader_gaussian

///Init_Shader_gaussian();
    if (!shader_is_compiled(SH_gaussian_vertical) or !shader_is_compiled(SH_gaussian_horizontal)) {
        show_message("Your hardware doesn't support shader - SH_gaussian_Vert or Hori");
    }
    else{
        var a,b,c,d;
        a   = view_wview;
        b   = view_hview;
        c   = "resolution";
        d   = "blur_amount";
        
        /* for Shaders */
        uni_resolution_hoz   = shader_get_uniform(SH_gaussian_horizontal, c);
        uni_resolution_vert  = shader_get_uniform(SH_gaussian_vertical,   c);
        var_resolution_x     = a;
        var_resolution_y     = b;
        
        uni_blur_amount_hoz  = shader_get_uniform(SH_gaussian_vertical,   d);
        uni_blur_amount_vert = shader_get_uniform(SH_gaussian_horizontal, d);
        var_blur_amount      = 1.0;
        
        /* for Surfaces */
        final_surface        = surface_create(a, b);
        /*
        surf                 = surface_create(a, b);// for Enable of Views
        view_surface_id[0]   = surf;
        */
        
        /* for Debug */
        shader_enabled       = true;
    };

ユーザ定義関数 DrawGUIEv_gaussian

///DrawGUIEv_gaussian();
    if shader_enabled {
       //Do horizontal blur first
       if surface_exists(final_surface){
           surface_set_target(final_surface);
           shader_set(SH_gaussian_horizontal);
           shader_set_uniform_f(uni_resolution_hoz,  var_resolution_x, var_resolution_y);
           shader_set_uniform_f(uni_blur_amount_hoz, var_blur_amount);
           draw_surface(application_surface, 0, 0);
           shader_reset();
           surface_reset_target();
    
           //Do vertical blur last
           shader_set(SH_gaussian_vertical);
           shader_set_uniform_f(uni_resolution_vert,  var_resolution_x, var_resolution_y);
           shader_set_uniform_f(uni_blur_amount_vert, var_blur_amount);
           draw_surface(final_surface, 0, 0);
           shader_reset();
       }
       else{
           final_surface = surface_create(view_wview, view_hview);
       };
    };

ユーザ定義関数 DrawGUIEv_gaussian_for_Views

///DrawGUIEv_gaussian_for_Views();
/*
This function must be set Enable of views.
plz check >  room settings 
          >  views tab 
          >> turn ON both checkboxs "Enable the use of Views" & "Visible when room starts" 

    if shader_enabled {
        //Do horizontal blur first
        surface_set_target(final_surface);
        shader_set(SH_gaussian_horizontal);
        shader_set_uniform_f(uni_resolution_hoz,  var_resolution_x, var_resolution_y);
        shader_set_uniform_f(uni_blur_amount_hoz, var_blur_amount);
        draw_surface(surf, 0, 0);
        shader_reset();
        surface_reset_target();

        //Do vertical blur last
        shader_set(SH_gaussian_vertical);
        shader_set_uniform_f(uni_resolution_vert,  var_resolution_x, var_resolution_y);
        shader_set_uniform_f(uni_blur_amount_vert, var_blur_amount);
        draw_surface(final_surface, 0, 0);
        shader_reset();
    };
*/

この関数は未使用です。オリジナル版の処理と同じものなので、もしも利用する場合には Rooms の設定から views 関連のオプションを有効化してください。

ユーザ定義関数 Debug_Keys

///Debug_Keys();
if keyboard_check(ord('Q')) var_blur_amount += 0.01;
if keyboard_check(ord('A')) var_blur_amount -= 0.01;
if keyboard_check_pressed(vk_space) shader_enabled = !shader_enabled;

draw_text(10, 0, "Real FPS: "+string(fps_real));
draw_text(10, 40,"Blur amount(Q & A to adjust): "+string(var_blur_amount));

draw_text(10, room_height-90,"Spacebar to toggle shader");

実際のイベント処理

シェーダと4つのユーザ定義関数を使って簡潔なイベントを作成。

Create Event

draw_set_font(font0);
draw_set_color(c_white);
Init_Shader_gaussian();

Draw Event

draw_background_stretched(background0, 0, 0, room_width, room_height);
draw_self();

Draw GUI Event

DrawGUIEv_gaussian();
Debug_Keys();

application_surface を対象としてシェーダでエフェクトをかけます。( オリジナル版では Views と Surface をリンクさせて描画に利用します )

Draw イベントで描画した画面を DrawGUI へ描画するという手順。シェーダで application_surface 全体を対象にする場合は DrawGUI のタイミングで描画するのが無難。

ユーザ定義関数である DrawGUIEv_gaussian でシェーダ処理を行っている。今回のサンプルはオリジナル版と同じく、gaussian_vertical と gaussian_horizontal という二つのシェーダを使って最終出力結果を得ています。




次へ

前へ