グレースケール( Greyscale with fade)

 colour   greyscale   dot product   mix 

{{< twitter >}}

YoYoGames から配布されていたシェーダ・サンプルを整理し改造。

画像を 256 階調グレースケール化する。このシェーダ・サンプルにはグレースケールへの適用率を任意変更するロジックが組み込まれている。

GameMaker Studio shader Greyscale with Fade Screenshot

画像をグレースケール化する計算手法は複数あり、それぞれ微妙に描画結果は異なる。

  1. 中間値法( middle value )
  2. NTSC 係数による加重平均法( NTSC Coef. method )
  3. HDTV 係数による加重平均と補正( ITU Coef. method )
  4. 単純平均法( simple mean method )
  5. G チャンネル法( Y=G method )
  6. 中央値法( median value method )

参考( osakana.factory )グレースケールのひみつ - CG know-how & Tips

HDTV 係数による加重平均

この方法は Adobe の Photoshop でも利用されているものであり、OpenGL ES シェーダでもこの計算手法を用いてイメージのグレースケール化ができます。

シェーダで計算に用いられている HTDV 係数は正確な数値でなく近似値( 計算コストを減らすための工夫 )

R → 0.2126 = 0.21

G → 0.7152 = 0.71

B → 0.0722 = 0.72

NTSC 係数による加重平均法は PC 用モニタではなくテレビ用ディスプレイ向けと考えた場合、HDTV 係数による加重平均をシェーダで利用するのがなんとなく良さそうなのですが、各モニタ環境等設定の差による見え方の違いの方が深刻で、計算手法に依る描画結果の差は総じてたいした差を生みません。

動作サンプルについて

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

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

参考( YoYoGames MarketPlace )xygthop3's Shader Resources

キーボードの Q と A キーでグレースケールの適用率を変更可能。

( 値は 0 〜 1 までの範囲で制限してあります )

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

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

シェーダー名:SH_greyscale

参考動作:Shader-Greyscale (with fade)

OpenGL-ES_50px_May16 WebGL_50px_June16

Vertex Shader

 
attribute vec3 in_Position;
attribute vec2 in_TextureCoord;
// 今回、頂点カラーは無視しています、必要な場合は追加
varying vec2 v_texcoord;

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

Fragment Shader

 
varying vec2 v_texcoord;

uniform float fade;

const vec3 val = vec3(0.21, 0.71, 0.07);

void main()
{
    vec4 pcv     = texture2D(gm_BaseTexture, v_texcoord);
    float gs     = dot(pcv.rgb , val);//ベクトル pcv.rgb 、val のドット積(点乗積)
    gl_FragColor = vec4(mix(pcv.rgb, vec3(gs), fade), pcv.a);
}
 

10 行目の dot は GLSL ES のベクトル用・組み込みの dot 関数。

dot 関数は二つのベクトルから内積を求め、これを float 型で返す働きをします。

uniform で渡した値を元に、画像のグレースケール化をどの程度適用するかを決定するために dot product ( 点乗積、scalar product とも ) を用います。uniform の値は 0.0 〜 1.0 間で固定されており、値が小さい程グレースケール化の影響を受け無くなります。

ユーザ定義関数 Init_GreyscaleShader

///Init_GreyscaleShader();
draw_set_font(font0);
var a,b,c;
a = SH_greyscale;
    if ( !shader_is_compiled(a) ) {
       b = "ur hardware ain't support shader - SH_greyscale";
       show_message(b);
    }
    else{
       b             = "fade";
       /* for shader */
       Uni_grey_fade = shader_get_uniform(a , b);
       Var_grey_fade = 1.0;
       /* instance variable for surface */
       Surf          = noone;
    };
 

ユーザ定義関数 DrawEv_SetSurface

///DrawEv_SetSurface();
if !surface_exists(Surf){
    var w,h;
    w    = room_width;
    h    = room_height;
    Surf = surface_create(w,h);
    surface_set_target(Surf);
    {
        draw_clear_alpha(c_yellow,1);
        draw_set_colour(c_green);
        draw_rectangle(0,h-150,w,h,false);      
        draw_set_colour(c_red);
        draw_rectangle(0,h-100,w,h,false);
        draw_set_colour(c_blue);
        draw_rectangle(0,h-50, w,h,false);

        var a,b;
        a = banners;
        b = sprite_get_height(a);
            for (var i=0; i<3; i++) {
                draw_sprite_ext(a,i,0,b*i,1,1,0,-1,1);
            };
    };
    surface_reset_target();
}
else{
    draw_surface(Surf,0,0);
};
 

ユーザ定義関数 DrawGUIDebug_Keys

///DrawGUIDebug_Keys();
var w,z;
w = Var_grey_fade;
z = 0.01;
if (keyboard_check(ord('Q')) and w < 1) w += z;
if (keyboard_check(ord('A')) and w > 0) w -= z;
Var_grey_fade = w;
 

ユーザ定義関数 DrawGUIEv_Greyscale

///DrawGUIEv_Greyscale();
var a,b,c, d,e, f,g,h, j,k;
a = display_get_gui_width() >> 1;
b = display_get_gui_height();
c = c_red;
draw_line_colour(a,0,a,b,c,c);

d = sprite_get_height(banners);
e = ((d << 1) + d);
draw_circle_colour(a,e,40,c,c,0);

/* shader draw */
f = SH_greyscale;
g = Var_grey_fade;
h = application_surface;
shader_set(f);
shader_set_uniform_f(Uni_grey_fade, g);
draw_surface(h,0,0);
shader_reset();

/* debug messages */
j = "press Q | A :: change Fade value"
k = string_format(Var_grey_fade, 3, 2);
draw_set_colour(c_white);
draw_text(0,room_height-118,j);
draw_text(0,room_height-60, k);
 

イベント処理

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

Create Event

///Init
Init_GreyscaleShader();

Draw Event

///Draw
DrawEv_SetSurface();

Draw GUI Event

///Draw gui
DrawGUIDebug_Keys();
DrawGUIEv_Greyscale();

application_surface を対象としてシェーダでエフェクトをかけます。シェーダで application_surface 全体を対象にする場合は DrawGUI のタイミングで描画するのが無難。

ユーザ定義関数である DrawGUIEv_Greyscale でシェーダ処理を行っている。

別グレースケール化手法が次ページに掲載されている。




次へ