Wave(波)rev.2

 effect   wave   uv   safari   vivaldi   chrome 

{{< twitter >}}

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

HTML5 で動作させる場合に不具合が多く確認されています。

Sample Wave

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

上記二つのイベントへ収まるように作った。無駄な変数定義を排除、処理をユーザ定義関数化しコードの使い回し簡単。

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

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

このサンプルはテクスチャの UV を使って波のように画面を動かします。 application surface を対象にしシェーダ使って Draw しています。ウィンドウサイズが変更された場合、テクスチャのサイズ変更を GMS/GML 側で行わず、Vertex Shader で拡縮処理をするよう作って有ります。

ウィンドウサイズ変更を許可する設定は GlobalGameSettings ( GGS ) にあります。

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

シェーダー名:SH_Wave

参考動作:Shader - Wave -

OpenGL-ES_50px_May16 WebGL_50px_June16

1.( MacBook Pro OS X El Capitan + Vivaldi 1.4.589.39 stable 64bit で正常に動作せず )

2.( MacBook Pro OS X El Capitan + Safari 11601.7.7 で正常に動作せず )

3.( MacBook Pro OS X El Capitan + Google Chrome 54.0.2840.71(64bit) で正常に動作せず )

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);
var s,m;
s = SH_Wave;
    if !shader_is_compiled(s) {
        m = "ur hardware ain't support shader - SH_Wave";
        show_message(m);
    }
    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(s, "time");
        var_time_var        = a;
        
        // (b) wave_amount
        uni_wave_amount     = shader_get_uniform(s, "wave_amount");
        var_wave_amount     = b; // higher = more waves | 0.0 == Circling
        
        // (c) wave_distortion
        uni_wave_distortion = shader_get_uniform(s, "wave_distortion");
        var_wave_distortion = c; // higher = less distortion
        
        // (d) wave_speed
        uni_wave_speed      = shader_get_uniform(s, "wave_speed");
        var_wave_speed      = d; // higher = faster
        
        /* for Vertex Shader, uniform variables */
        // (e) u_ratio
        uni_ratio           = shader_get_uniform(s, "u_ratio");
        var_ratio           = e; // defalut value == 1.0;
    };
 

ユーザ定義関数 DrawGUI_Wave

///DrawGUI_Wave();
var a;
a = 0.01;// a higher value →  waving faster |  0.00 →  freeze waving;
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 a,b;
a = view_wview[0] / window_get_width();
b = view_hview[0] / window_get_height();
    if (a < b) a = b;
return a;
 

ウィンドウサイズが変更された時の対処としてユーザ定義関数 Screen_Scale_Ratio を備えています。この関数はデフォルトのウィンドウサイズと新しいウィンドウサイズを比較して、変更されたウィンドウサイズの縦横比率は維持されているものして拡縮倍率を計算。

ユーザ定義関数 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
Init_Shader_Wave();

Draw GUI Event

///DrawGUI
DrawGUI_Wave();
DrawGUI_Show_Status();

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

Draw イベントの描画結果を DrawGUI でシェーダを介して再描画する手順。シェーダで application_surface 全体を対象にする場合は DrawGUI のタイミングが無難。

このサンプルのルームサイズは 縦横 512 px。ウィンドウモードで動作するアプリケーションの場合、ディスプレイの解像度よりウィンドウサイズが小さければ倍率を測る処理が不要なので、常に 1.0 倍率固定で開始されます。

モバイルはデフォルトがフルスクリーン動作、GM:S で設定されたルームサイズがディスプレイの画面サイズより小さい場合、解像度に応じた拡縮処理が自動的に行われます。シェーダは等倍時の UV 情報で処理を実行、その結果得られたシェーダの描画結果はディスプレイの画面サイズより小さく表示されたり、縦横比率に応じて余白を生じる場合があります。

ウィンドウサイズを変更された場合に備え、スクリーンの拡縮倍率は常に求めるようにし、実際の拡縮には GML ではなくシェーダ側へ任せることにしました。( Vertex Shader へ倍率を送っています )




次へ

前へ