【ゲーム制作】グレースケール変換とは?|輝度計算とセピア調ポストエフェクトの作り方

grayscale postfx thumbnail ゲーム制作

「ゲームのリザルト画面や回想シーンでよく見る白黒表現、どうやって作るの?」「輝度ってどう計算するの?単純にRGBを平均すればいいの?」「グレースケールのつもりが茶色っぽくなるのはなぜ?」

こんな疑問はありませんか?

今回は、ゲーム画面を白黒にするグレースケール変換のポストエフェクトについて、実際にDirectXのシェーダーを書いて動かしながら解説していきます。実装しながら気づいた、意外な仕様も紹介します。

グレースケール変換とは?

グレースケール変換とは、

・カラー画像の各ピクセルを、人間の目に感じる明るさ(輝度)1本の値に変換するポストエフェクト

です。回想シーンやゲームオーバー演出、モノクロ写真風のフィルターなど、色情報を落として印象を変えたいときに使われます。ポイントは、単純にR・G・Bを平均すればいいわけではないところです。

シェーダーの中身

// 入力されてきたピクセル色をそのまま出力
outDiffuse = In.Diffuse;

// テクセルの色を乗算して出力
outDiffuse *= g_Texture.Sample(g_SamplerState, In.TexCoord);

// グレースケール変換
float y = 0.299 * outDiffuse.r + 0.587 * outDiffuse.g + 0.114 * outDiffuse.b;
outDiffuse = float4(y, y, y, outDiffuse.a);

// セピア変換
float4 sepia = float4(0.96f, 0.784f, 0.580f, 1.0f);
outDiffuse.rgba *= sepia.rgba;

輝度yを求めている行に注目してください。0.299 * R + 0.587 * G + 0.114 * Bという、一見中途半端な係数を使っています。これは人間の目が緑を最も明るく感じ、青を最も暗く感じるという特性に基づいた重み付けで、映像業界で古くから使われている(ITU-R BT.601という規格に基づく)係数です。単純平均(0.333ずつ)にすると、実際の見た目の明るさとズレた仕上がりになります。

【重要】実装していて気づいたこと:これは「グレースケール」ではなかった

コードを読んで「輝度変換のシェーダーだな」と思って実際に描画してみたところ、予想していた真っ白黒とは違う、茶色がかった仕上がりになりました。もう一度ソースを読み直して気づいたのですが、輝度変換の直後にセピア色を掛け算する処理が最初から書かれていたのです。

実際にレンガのテクスチャを、通常カラーとこのシェーダーで並べて描画した結果です。

左が通常カラーのレンガ、右が輝度変換+セピア掛けをしたレンガ。右は白黒ではなく茶色っぽい仕上がりになっている
左:通常カラー / 右:輝度変換+セピア掛け(単純な白黒にはなっていない)

右側は、白黒ではなくセピア調(古い写真のような茶色がかった色合い)になっています。float4 sepia = float4(0.96f, 0.784f, 0.580f, 1.0f);という行で、輝度変換した結果にさらに暖色系の色を掛けているためです。関数名や見た目の印象だけで「これは単純白黒処理だ」と思い込まず、コードの最後まで読んで初めて正確な仕様が分かった、という実例です。

もし本当に純粋なグレースケール(白黒)が欲しい場合は、セピア変換の2行を削除してyを求めるところまでで止めればOKです。

グレースケール変換のよくある失敗例と対処法

①単純平均(R+G+B)/3を使ってしまう

実装は簡単ですが、緑が沈みがちな不自然な明るさになります。0.299 / 0.587 / 0.114の重み付け(または近い係数)を使いましょう。

②他人のシェーダーを「名前」だけで判断してしまう

上で実演した通りです。ファイル名がGrayScalePSだからといって、中身が純粋なグレースケールとは限りません。流用するときは必ず最後まで目を通しましょう。

③アルファ値まで色と一緒に乗算してしまう

outDiffuse.rgba *= sepia.rgbaのようにa成分まで含めて乗算すると、セピア色のアルファ設定によっては透明度が意図せず変わることがあります。RGBだけ乗算し、アルファは元の値をそのまま使う設計の方が安全な場面もあります。

注意点

  • 輝度は単純平均ではなく重み付き平均(0.299 / 0.587 / 0.114など)で求める
  • シェーダー名だけで中身を判断せず、最後まで読む
  • 純粋な白黒が欲しいときは、セピアなど追加の色味処理が混ざっていないか確認する

まとめ

  • グレースケール変換は重み付き輝度(0.299R + 0.587G + 0.114B)で作る
  • 単純平均だと実際の明るさ感とズレる
  • 「GrayScale」という名前でも、実は追加でセピア変換まで含んでいた(実際に気づいた)
  • 流用するシェーダーは、名前で判断せず中身を最後まで確認する

グレースケール変換自体はよく知られた式ですが、既存のシェーダーを流用するときは名前だけで中身を決めつけてはいけない、という当たり前だけど見落としがちな教訓を実際に得られました。

ここまで読んでくださりありがとうございました。

関連記事