~下の画像をクリックすると、UFOが動くアニメーションが見られます。Demo!!」というデモを公開されています。参考にして、グレアのエフェクトのひとつであるハロを実装してみました。今回のプログラムは、次のものです。(ハロ:DirectX9)まぁ、いつものように適当にファイルが入っています。出力されるフレームワークのファイルは紹介を省かせていただきます。アプリケーションのソースあと、実行ファイル、モデル及び、プロジェクトファイルが入っています。その論文には、目の仕組みを分析し、グレアの種類と原因を分析しています。ハロは、目のレンズである水晶体の構造によって発生します。本来の像の外側に虹色のリングを作りだします。ここで、プログラム的にリングを作り出す方法が今回のみそです。円を作る方法は、ガウスフィルタを使えば可能です。それらの画像の差として、円環状のフィルタを作ります。赤い色は広くぼかし、青い色は小さくしかぼかさないことによって実現します。なにげに今回のパス数は多いです。最初にシーンを描画します。この時に、浮動小数点バッファを利用して、鏡面反射による1.0よりも明るい色をテクスチャに記録します。次に、縮小バッファに輝度を強調してコピーします。小さなテクスチャに一度移しておく方が、ガウスフィルタをかけたときにより大きくかかるので、この操作を行ないます。次に、2パスを2回使って、ガウスフィルタを別の2つのテクスチャにかけます。最後にレンダリングしたシーンの画像に、大きなぼかしと小さなぼかしの差を加算合成して貼り付けます。双線型フィルタを使えないのが以外に痛くて、時間があれば、整数バッファで書き直したほうが、パフォーマンスや、ガウスフィルタのサンプル数の数で有利になるでしょう。これも、最初のパスでハロの強さをアルファ成分に記録しておけば可能でしょう。■シーンの描画こつこつとプログラムを見ていきましょう。最初にシーンの描画をします。描画するモデルは、テクスチャを張っていないただのメッシュです。頂点シェーダでは、座標変換と環境色、拡散光の計算をします。鏡面反射色は、ピクセルシェーダで行なうので、計算に必要な法線ベクトルと視線ベクトルをテクスチャ座標としてピクセルシェーダに流します。ちなみに、これらのベクトルは、モデルのローカル座標系で計算しています。}ピクセルシェーダでは、法線ベクトルと視線ベクトルから反射ベクトルを計算して、適当な色をかけて鏡面反射色に足しこみます。浮動小数点バッファなので、1以上の値もテクスチャに保存されます。次に行なう操作は、縮小バッファへのコピーです。16ボックスサンプリングを使って、4x4のテクセルを1つのピクセルに読みこきます。元のサイズの1/4のサイズのテクスチャにレンダリングしました。縮小バッファへのコピーでは、頂点シェーダは使わずに、ピクセルシェーダだけで全て処理しました。ピクセルシェーダの負荷を軽くすると、少し高速化されるでしょう。暗い部分は色が小さくなるように変換してから出力します。これで、白色とは違う本当に色の強い部分が抽出されます。}■ガウスフィルタ次は、ガウスフィルタです。このフィルタは、縦横2パスを使い、さらに大きくぼかすのと小さくぼかす2回のセットで描画します。ガウスフィルタは、前にやったとおりに頂点シェーダで8つのテクスチャ座標を与えてピクセルシェーダで重みを付けて合成します。テクセルは1つのサンプリングで1つづつ、計16個のテクスチャをサンプリングします。ちなみに、縦方向の頂点シェーダは次のようになります。}ピクセルシェーダでは、前と同じプログラムで重みを付けて足し合わせます。float4の4次元ベクトルです(前はfloatのスカラーでした)。ベクトルにして、それぞれの色で円の広がる半径を調整しました。}重みを求める計算は次のようになります。分散として、成分ごとに規格化などの調整をします。大きく広がる上の段のガウス分布から、より小さい下の段のガウス分布の分散の色を最後に引きます。ちなみに、w成分に1をいれたのは、おまけで、たいした意味はありません。}■最後の合成さて、いよいよ最後のパスです。最後は、大きなぼかしたと小さなぼかしの差分を取って、円を作ります。中心のテクセルと上下左右のテクセルの5点をサンプリングして平均化します。リングの強さの調整もここでできるので、見た目で調整(今回は10倍です)して、出力します。出力した結果は、フレームバッファに加算合成で合成します。}■最後にグラデーションをつけると綺麗ですね。一概に浮動小数点バッファを使うほうが綺麗ではないことを今回痛感しました。masaさんのはきれいだなぁ~もどるimagire@gmail.com。