[GameMaker: Studio] ラスタースクロールシェーダーのサンプル

ラスタースクロールを行うシェーダーの基本的なサンプルです。

HTML5では画面外が描画されないため、シェーダー側で揺らすとこのように黒い部分ができてしまいます。
直接描画せずに、大きめのsurfaceを作ってそこで描画してからメインのsurfaceにコピーすると大丈夫です。

Windowsでは画面外も描画してくれるのでそういった手間はかかりません。
実際にWindowsで動かしているところはこちらで。
http://www.nicovideo.jp/watch/sm25986872

このシェーダーのコードです。

// Vertex
attribute vec3 in_Position;                  // (x,y,z)
attribute vec4 in_Colour;                    // (r,g,b,a)
attribute vec2 in_TextureCoord;              // (u,v)
varying vec2 v_vTexcoord;
varying vec4 v_vColour;

//==========================
uniform float u_Time;       // 時間(0~360)
uniform float u_Level;      // 揺れの強さ
uniform float u_Deg2Rad;    // deg2rad(pi/180.0) ※命令あったかも
uniform float u_Y2Deg;      // 縦ピクセル数を360度に変換(360.0/256.0)
//==========================

void main()
{
    vec4 object_space_pos = vec4( in_Position.x, in_Position.y, in_Position.z, 1.0);

    //==========================
    // 対象ピクセルのY座標を度に変換して時間を足してラジアンにしてcos値を出して強度をかける。
    float lx = cos((u_Y2Deg * object_space_pos.y + u_Time) * u_Deg2Rad) * u_Level;
    // X座標に足す。
    object_space_pos.x = in_Position.x + lx;
    //==========================

    gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * object_space_pos;
    
    v_vColour = in_Colour;
    v_vTexcoord = in_TextureCoord;
}
// Fragment
varying vec2 v_vTexcoord;
varying vec4 v_vColour;

void main()
{
    gl_FragColor = v_vColour * texture2D( gm_BaseTexture, v_vTexcoord );
}

繰り返し使用する変数はメインループのcreateで初期化しておきます。

global.nowTime = 0.0;
global.nowLevel = 0.0;
global.u_Deg2Rad = pi / 180.0;
global.u_Y2Deg = 360.0 / 256.0;
global.p0 = shader_get_uniform(shader0, "u_Time");
global.p1 = shader_get_uniform(shader0, "u_Level");
global.p2 = shader_get_uniform(shader0, "u_Deg2Rad");
global.p3 = shader_get_uniform(shader0, "u_Y2Deg");

メインループのDraw Beginでシェーダーにパラメータを渡します。

shader_set(shader0);
shader_set_uniform_f(global.p0, global.nowTime - 1.0);  // -1.0は間違いです;;
shader_set_uniform_f(global.p1, global.nowLevel);
shader_set_uniform_f(global.p2, global.u_Deg2Rad);
shader_set_uniform_f(global.p3, global.u_Y2Deg);

ここで各objectDrawイベントによってシェーダーを使用した描画が行われます。
Drawイベントがすべて終了したら、メインループのDraw Endでシェーダーをリセットします。

shader_reset();

この方法では全objectがシェーダー描画になってしまうので、特定のobjectのみに適用したいなら前述のように別surfaceを使うか、特定のobjectDrawのみでshader_setを使うかしてください。