GameMaker:Studio Shader Wave(波)rev2

 shader   wave   GLSL_ES 

配布されていたシェーダサンプルのコードを整理し、独自に改造を施したもの

Sample Wave

イベントを一つのオブジェクトへまとめ、

    1. Create
    2. DrawGUI

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

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

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

参考:GameMakerStudio Shader Wave(波)

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

キーボードの Q / A 、 W / S 、 E / D キーで値変更可

要 WebGL、Google Chrome/FireFox 等で動作を確認。

HTML5( WebGL ) と Windows PC で微妙に描画結果が異なる場合があります。

このサンプルはテクスチャの UV を使って波のように画面を動かしています。

application surface を対象にしシェーダ使って Draw してるのですが、前回出したサンプルではウィンドウサイズが変更された時にテクスチャサイズも変更される処理を Android に限ったものとしてコードを作っていました。

しかし Windows PC 版でもフルスクリーンあるいはサイズ可変でアスペクト比率維持のウィンドウ設定がありえるので、もう少しこの辺りをスクリプト側できっちり対応できるコードが必要になるかもしれない、この点を踏まえてコードを一部作り直ししました。

主な変更点はテクスチャのサイズ変更を GMS/GML 側で行わず、Vertex Shader 側で拡縮処理をこなすようにした点。

ウィンドウサイズの変更を許可する設定は GlobalGameSettings ( GGS ) から行います。

グローバルゲームセッテイング:画面

シェーダー名:SH_Wave

Vertex Shader

attribute vec3 in_Position;
attribute vec2 in_TextureCoord;

varying vec2 v_texcoord;

uniform float u_ratio;

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

Fragment Shader

precision mediump float;
varying vec2 v_texcoord;

uniform float time;
uniform float wave_amount;
uniform float wave_distortion;
uniform float wave_speed;

float tws = (time * wave_speed);

void main()
{
    vec2 uv = v_texcoord;
    /*
    uv.x   += cos((uv.y * wave_amount) + tws) / wave_distortion;
    uv.y   += sin((uv.x * wave_amount) + tws) / wave_distortion;
    */
    // 以下は、こういう書き方もできるよね的なサンプル、ただし描画結果は上記と微妙に異なります
    uv += (vec2( cos((uv.y * wave_amount) + tws) , sin((uv.x * wave_amount) + tws)) / wave_distortion);
    
    gl_FragColor = texture2D(gm_BaseTexture,uv);
}

ユーザ定義関数 Init_Shader_Wave

///Init_Shader_Wave();
draw_set_font(font0);

    if (!shader_is_compiled(SH_Wave)) {
        show_message("Your hardware doesn't support shader - SH_Wave");
    }
    else{
        /* for Debug */
        shader_enabled = true;
        
        /* for Fragment Shader, uniform variables */
        //                      ~~~~~~~
        var a,b,c,d, e;
        a =  0.0;
        b =  5.0; // higher = more waves | 0.0 == the movement of circling
        c = 25.0; // higher = less distortion
        d =  2.0; // higher = faster
        e =  1.0;
        
        // (a) time
        uni_time            = shader_get_uniform(SH_Wave , "time");
        var_time_var        = a;
        
        // (b) wave_amount
        uni_wave_amount     = shader_get_uniform(SH_Wave , "wave_amount");
        var_wave_amount     = b; // higher = more waves | 0.0 == Circling
        
        // (c) wave_distortion
        uni_wave_distortion = shader_get_uniform(SH_Wave , "wave_distortion");
        var_wave_distortion = c; // higher = less distortion
        
        // (d) wave_speed
        uni_wave_speed      = shader_get_uniform(SH_Wave , "wave_speed");
        var_wave_speed      = d; // higher = faster
        
        /* for Vertex Shader, uniform variables */
        // (e) u_ratio
        uni_ratio           = shader_get_uniform(SH_Wave , "u_ratio");
        var_ratio           = e; // defalut value == 1.0;
    };

ユーザ定義関数 DrawGUI_Wave

///DrawGUI_Wave();
var a;
a = 0.01;// higher = faster | 0.00 == stop;
var_time_var += a;
    if shader_enabled {
        var_ratio = Screen_Scale_Ratio();
        shader_set(SH_Wave);
            shader_set_uniform_f(uni_ratio,           var_ratio);
            shader_set_uniform_f(uni_time,            var_time_var);
            shader_set_uniform_f(uni_wave_amount,     var_wave_amount);
            shader_set_uniform_f(uni_wave_distortion, var_wave_distortion );
            shader_set_uniform_f(uni_wave_speed,      var_wave_speed);
            draw_surface(application_surface,0,0);
        shader_reset();
    };

ユーザ定義関数 Screen_Scale_Ratio

///Screen_Scale_Ratio();
/* room properties から views の設定 →  view 0 を有効にする  */
var b,c;
b = view_wview[0] / window_get_width();
c = view_hview[0] / window_get_height();
    if (b < c) b = c;
return b;

ユーザ定義関数 DrawGUI_Show_Status

///DrawGUI_Show_Status();
if keyboard_check_pressed(ord("R")) room_restart();
/* ================================================ */
if keyboard_check(ord('Q')) var_wave_amount += 1;
if keyboard_check(ord('A')) var_wave_amount -= 1;

if keyboard_check(ord('W')) var_wave_distortion += 1;
if keyboard_check(ord('S')) var_wave_distortion -= 1;

if keyboard_check(ord('E')) var_wave_speed += 1;
if keyboard_check(ord('D')) var_wave_speed -= 1;

draw_set_colour(c_red);
draw_text(0, 0,"Real FPS: "                + string(fps_real));

draw_set_colour(c_yellow);
draw_text(0,30,"Wave amount     (Q & A): " + string(var_wave_amount));
draw_text(0,60,"Wave distortion (W & S): " + string(var_wave_distortion));
draw_text(0,90,"Wave speed      (E & D): " + string(var_wave_speed));
/* ================================================ */
draw_set_colour(c_green);
draw_text(0,room_height-30,"Shader SH_Wave");

実際のイベント処理

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

Create Event

Init_Shader_Wave();

Draw GUI Event

DrawGUI_Wave();
DrawGUI_Show_Status();

application_surface を対象としてシェーダでエフェクトをかけます。

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

テクスチャの UV 情報を扱うシェーダなので、ウィンドウサイズが変更された時の対処を標準で備えるようにしました。

新しく追加された ユーザ定義関数 Screen_Scale_Ratio(); が倍率を計算します。

var b,c;
b = view_wview / window_get_width();
c = view_hview / window_get_height();
    if (b < c) b = c;
return b;

上記抜粋部分が該当します。

このサンプルのルームサイズは 縦横 512px 、あるいはウィンドウモードで動作するアプリケーションの場合には倍率を測る処理が不要なので、倍率は常に 1.0 固定で済む。

しかしモバイルはデフォルトがフルスクリーン動作、ルームサイズがディスプレイの画面サイズよりも小さい場合には解像度に応じた拡縮処理が自動的に行われます。このためテクスチャが等倍のまま UV 情報をフラグメントに送ってしまうと、シェーダは等倍時の UV 情報に応じた処理を実行し、その結果得られたシェーダの描画結果は画面サイズよりも小さく、余白を生じてしまいます。

この他 WindowsPC でもウィンドウサイズを変更するアプリケーションという可能性もあるため、スクリーンの拡縮比率は常に求めるようにし、実際の拡大縮小には GML ではなくシェーダ側に任せることにしました。( Vertex Shader へ倍率を送っています )

このため、前回の処理では

draw_surface_ext(application_surface,0,0,b,c,0,0,0);

を利用していましたが、今回は

draw_surface(application_surface,0,0);

普通に draw_surface を使っています。あとは送信した倍率を利用してシェーダで拡大します。




次へ

前へ