ディザ抜きについて軽く調べたことをまとめておきます。
ディザリングとは?という部分に関しては他の方のブログなどにまとまっていると思いますので省略させていただきます。
ディザリング手法の種類
代表的なディザリングの手法として以下のようなものがあります。
(リンクは貼らず、検索しやすいように名称のみ記載しています)
Bayer Matrix Dither
Void-and-Cluster
Interleaved Gradient Noise(Jimenez SIGGRAPH 2014)
Spatiotemporal Blue Noise
ここではゲーム開発で使用されることが多い
Bayer Matrix DitherとInterleaved Gradient Noiseについて取り上げます。
Bayer Matrix Dither
あらかじめ決められたBayer行列によるディザリングで、とても簡単なものです。
Shader Graphに入っているDitherノードは、4×4(16要素)のBayer行列を基に出力を決定します。
ゲーム開発でも昔から使用されているもので
特徴的な格子が見え、レトロなゲームで目にしたことがある人も多いかと思います。
Interleaved Gradient Noise
Jorge JimenezさんがSIGGRAPH 2014のNext Generation Post Processing in Call of Duty: Advanced Warfareで公開した、ALUだけで計算できる擬似ノイズ関数です。
検索すると詳しいスライドが見つかるのでそちらを見るのをお勧めします。
ピクセル座標から連続値として計算されるため、Bayer行列のように段階数が固定されず、しきい値がピクセルごとに異なります。
処理は以下のようにシンプルです。
最適化されたマジックナンバーが存在しています。
float InterleavedGradientNoise(float2 pixCoord)
{
const float3 magic = float3(0.06711056, 0.00583715, 52.9829189);
return frac(magic.z * frac(dot(pixCoord, magic.xy)));
}
フレーム番号に応じてノイズをオフセットし、時間方向と合わせたものが一般的に使用されており
TAAとの相性が良いのが強みです。
Unity URPでTAAを使用しない場合には、以下のようなhlslファイルを使ってCustom Functionから呼び出すようにすれば
既存のDitherと同じように使えます。
void DitherIGN_float(float In, float4 ScreenPosition, out float Out)
{
const float3 magic = float3(0.06711056, 0.00583715, 52.9829189);
float2 pixCoord = ScreenPosition.xy * _ScreenParams.xy;
Out = In - frac(magic.z * frac(dot(pixCoord, magic.xy)));
}