はじめに
アークナイツ・エンドフィールドのベータテストが始まり、グラフィック面でどのような技術が使われているのか話題になっています。
その中でもこちら
自分の知らないディザ抜きがされており、気になったので調べてみました。
Interleaved gradient noiseというノイズらしいです。
ソースコード
記事中のコードはこちらです。
一般的なディザ抜き
// ディザ抜きに必要な4x4の閾値
// https://docs.unity3d.com/ja/Packages/com.unity.shadergraph@10.0/manual/Dither-Node.html
static const float DITHER_THRESHOLDS[16] =
{
1.0 / 17.0, 9.0 / 17.0, 3.0 / 17.0, 11.0 / 17.0,
13.0 / 17.0, 5.0 / 17.0, 15.0 / 17.0, 7.0 / 17.0,
4.0 / 17.0, 12.0 / 17.0, 2.0 / 17.0, 10.0 / 17.0,
16.0 / 17.0, 8.0 / 17.0, 14.0 / 17.0, 6.0 / 17.0
};
// https://docs.unity3d.com/ja/Packages/com.unity.shadergraph@10.0/manual/Dither-Node.html
// value : Ditherの強度
// screenPosition : screenPosition
float dither(float value, float2 screenPosition)
{
float2 uv = screenPosition.xy * _ScreenParams.xy;
uint index = (uint(uv.x) % 4) * 4 + uint(uv.y) % 4;
return value - DITHER_THRESHOLDS[index];
}
BayerMatrixと呼ばれるディザのパターンを用意しそれをディザの強度として取得して網掛けを作成する方法です。
ディザのパターンはテクスチャで用意したり、上記のように配列で用意したりします。
様々なゲームでカメラと3Dモデルが干渉してモデルの内部が見えてしまうのを防いだり、ドット絵では色数が少ないがグラデーションをさせるのに使用されることが多いです。
こんな感じのグラデーションです。
InterleavedGradientNoise
参考は以下のリンクです。
// https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare/
// value : uv
float interleavedGradientNoise(float2 value)
{
float f = 0.06711056 * value.x + 0.00583715 * value.y;
return frac(52.9829189 * frac(f));
}
このメソッドを使用するだけでBayerMatrixとは違う模様でディザ抜きができます。
このディザ抜きにメリットはあるのか?
InterleavedGradientNoiseはTAAで使用するために最適化されたノイズ生成方法らしく、ディザ抜きに関してはメリットはそんなにないと思います。
でもBayerMatrixのディザ抜きに比べて独特な模様は出にくいとは思います。
(https://bartwronski.com/2016/10/30/dithering-part-three-real-world-2d-quantization-dithering/ より)
BayerMatrixを使用するとこのようなハッチング模様が段階的に出てしまいますが
(https://bartwronski.com/2016/10/30/dithering-part-three-real-world-2d-quantization-dithering/ より)
InterleavedGradientNoiseなら段階的な模様が出ません。
そのためディザ抜きで段階的に模様が出るのを控えめにすることができるというメリットはあるかもしれないです。
しかし、ディザ抜き=BayerMatrixを使用する、この模様!という認識がゲームやってる側にある気がするので変えることが絶対的なメリットにつながるとは思えないです。