ブルーム
Bloom別名:グロー、光のにじみ
概要
強い光の周りに、光があふれてにじむ効果を足す後処理。画面は白より明るい色を表示できないので、にじみを描くことで「白よりまぶしい」ことを伝える。
デモ
使われる場面
ゲームの光の表現
ネオン、街灯、太陽、魔法のエフェクトの周りに光のにじみを足し、明るさの差を強調する。夜の場面ほど効果がわかりやすい。
写真や映画に似せたレンダリング
実際のカメラでは、レンズや撮像素子の中で強い光が散って周りに広がる。この現象を再現して、実写らしさを出す。
UI や 2D ゲームの発光
光るボタン、文字、弾、パーティクルを、周りににじませて目立たせる。光らせたい部分だけを別に描いてぼかすことも多い。
判断基準
| こういうとき | こうする |
|---|---|
| 光源や発光体がまぶしいことを伝えたい | ブルームをかける。しきい値は、白い壁や紙のような明るいだけの物体が光らない高さに置く。 |
| 画面全体が白っぽくぼやけ、締まりがない | 強さを下げるか、しきい値を上げる。広い範囲にかけると、画面のコントラストが下がる。 |
| 0〜1 に収めた画像(HDR でない画像)にかける | 明るさ 1 の白い物体と光源を区別できず、白いものがすべて光る。可能ならトーンマッピングの前の、リニアな HDR の値で計算する。 |
| 特定の物体だけを光らせたい(UI の部品、魔法のエフェクト) | その物体の発光を 1 より明るくしてしきい値を超えさせるか、光らせる物体だけを別の画像に描いてぼかす。 |
| 処理の負荷を抑えたい | 縮小する段数を減らす。縮小した小さな画像をぼかすので、同じ広さのにじみを元の解像度で作るより軽い。 |
こう見えたら
指示の例
ネオンや街灯がまぶしく見えない。ブルームを入れて、明るい光の周りににじみを足して
画面全体が白くもやっとしている。ブルームのしきい値を上げて、光源だけがにじむようにして
白い壁まで光ってにじんでいる。ブルームはトーンマッピングの前の HDR の値で計算して、しきい値を 1 より上にして
魔法のエフェクトだけを光らせたい。エフェクトの発光を 1 より明るくして、ブルームのしきい値を超えるようにして
詳細
光のにじみを後から足す理由
強い光を見ると、光源の周りがぼんやり明るく見える。カメラではレンズや撮像素子の中で、目では眼球の中で、光が少し散って周りに広がるためである。画面は白(値 1)より明るい色を表示できないので、明るさ 10 の光源も明るさ 1 の白い壁も、そのままでは同じ白になる。ブルームは、このにじみを描き足すことで、白い壁よりも光源のほうがまぶしいことを見分けられるようにする。
取り出す、ぼかす、足す
ブルームは、描き終えた画像に対する三つの手順でできている。
- しきい値より明るい部分だけを取り出す。
- 取り出した画像をぼかす。
- ぼかした画像を元の画像に足す。
デモでは、輝度 がしきい値 を超えた分だけを、色味を保ったまま取り出している。
ぼかした に強さ を掛けて足したものが結果になる。
広いにじみを元の解像度のままぼかすと、計算量が大きくなる。そこで取り出した画像を半分、4 分の 1、8 分の 1 と縮小しながら小さくぼかし、小さい画像から順に拡大して足し合わせる。縮小した段ほど広くにじむので、段ごとの重みを変えると、にじみの広がり方を調整できる。デモの「広がり」は、この重みを変えている。
// しきい値を超えた分だけを取り出す
vec3 c = texture(sceneColor, uv).rgb; // トーンマッピング前のリニアな値
float l = dot(c, vec3(0.2126, 0.7152, 0.0722)); // 輝度
vec3 bright = c * max(l - threshold, 0.0) / max(l, 1e-4);
見分け方と落とし穴
ブルームは、トーンマッピングの前のリニアな HDR の値で計算する必要がある。値が 1 を超えられる画像なら、明るさ 10 の光源と明るさ 1 の白い壁をしきい値で分けられる。0〜1 に収めた後の画像では両方とも 1 になり、光源だけを選び出せない。しきい値を下げすぎると、同じ理由で白い物体まで光り始める。
足す計算も、光の量として正しくなるようリニアな値で行う。sRGB の値のまま足すと、にじみと明るい部分が重なったところが明るくなりすぎる。デモを「超えた部分」の表示にすると、しきい値を変えたときにどこが光の源として選ばれているかを確認できる。