グレースケール( Greyscale with fade)
{{< twitter >}}
YoYoGames から配布されていたシェーダ・サンプルを整理し改造。
画像を 256 階調グレースケール化する。このシェーダ・サンプルにはグレースケールへの適用率を任意変更するロジックが組み込まれている。
画像をグレースケール化する計算手法は複数あり、それぞれ微妙に描画結果は異なる。
- 中間値法( middle value )
- NTSC 係数による加重平均法( NTSC Coef. method )
- HDTV 係数による加重平均と補正( ITU Coef. method )
- 単純平均法( simple mean method )
- G チャンネル法( Y=G method )
- 中央値法( 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
( 値は 0 〜 1 までの範囲で制限してあります )
要 WebGL、Google Chrome/FireFox 等で動作を確認。
HTML5( WebGL ) と Windows PC で描画結果が異なる場合があります。シェーダー名:SH_greyscale
参考動作:Shader-Greyscale (with fade)
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 関数。
参考( opengl.org ) dot - OpenGL4 Reference Pages -
参考( naop.jp ) 内積の意味
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 でシェーダ処理を行っている。
別グレースケール化手法が次ページに掲載されている。
次へ