プログラミング
スタイライズドGGXシェーディング
Stylized GGX Shading (alexandrelamure.github.io)
要約
本記事では、PBR(Physically Based Rendering)とトゥーンシェーディングを融合させた「スタイライズドGGXシェーディング」というレンダリング手法を紹介しています。従来のトゥーンシェーディングがライティングの閾値処理でフラットな色表現にするのに対し、スタイライズドGGXはPBRの滑らかなグラデーションと、トゥーン調のシャープなハイライトを組み合わせることで、よりモダンな見た目を実現します。GGXの法線分布関数(NDF)を調整する「SpecularSize」パラメータを導入し、特に低いラフネス値でハイライトを拡張しつつ、高いラフネス値では元のGGXの形状を維持する改良版も提案されています。
全文翻訳
グラフィックスに戻る
スタイライズドGGXシェーディング — トゥーンドスペキュラーハイライト
2026年7月19日
3Dレンダリングでトゥーン調の外観を実現する最も一般的な方法は、ライティングに閾値処理を適用することです。これにより、滑らかな色のグラデーションがフラットな色に変換されます。
// レンダリング方程式は次のようになります:
float Threshold = 0.0; // 0から1の間の任意の値を設定
vec3 Radiance = BRDF * LightIntensity * step(Threshold, dot(Normal, LightDirection));
ディフューズの閾値処理
スペキュラーの閾値処理
しかし、2Dと3Dのルックをミックスしたい場合もあります。低いラフネスでは大きくシャープなハイライト、高いラフネスでは滑らかなグラデーションです。これはクラシックなトゥーンシェーディングよりもモダンに感じられ、シェーディングのほとんどでPBRに依存できるため、皆の生活が楽になります(エネルギー保存則に近く、既存のパイプラインへの統合が容易で、物理ベースのマテリアルのキャリブレーションも簡単です...)。このミックスアプローチを「スタイライズドGGXシェーディング」と呼びます。
トゥーンシェーディングのビデオ
トゥーン
スタイライズドGGXシェーディングのビデオ
スタイライズドGGX
GGXシェーディングのビデオ
GGX
多くのゲームがPBRとトゥーンシェーディングの組み合わせを探求してきました。例えば、ゼルダの伝説 ブレス オブ ザ ワイルドでは、キャラクターは純粋なトゥーンシェーディングを使用していますが、環境はより3D/PBRルックに依存しています(草のように完全にそうではありません)。これにより、キャラクターが背景から際立ちます。もう一つの例は、私が開発に携わる機会を得たSpellcasters Chroniclesです。開発中、ここで説明している「スタイライズドGGXシェーディング」を含む多くのことをテストしました。最終的には別のものに着地しましたが、それでも2Dと3Dルックのミックスを使用しています。
ゼルダの伝説 ティアーズ オブ ザ キングダムのスクリーンショット
Spellcasters Chroniclesのスクリーンショット
シンプルなバージョン
最も一般的なPBRモデルは、GGX Cook-Torranceマイクロファセットモデルです。表面の粗さは、ラフネスパラメータによって制御される配向されたマイクロファセットの集まりとして解析的にモデル化されます。これらのマイクロファセットの法線の分布は、法線分布関数(NDF)によって記述されます。リアルタイムエンジンは通常、Trowbridge-Reitz NDFを使用しており、これは次のような見た目です。
// GGX Trowbridge-Reitz NDF
float D(vec3 Normal, vec3 HalfVector, float Roughness) {
float a = Roughness * Roughness;
float a2 = a * a;
float NdotH = max(dot(Normal, HalfVector), 0.0);
float NdotH2 = NdotH * NdotH;
float denom = NdotH2 * (a2 - 1.0) + 1.0;
return a2 / (PI * denom * denom);
}
様々なラフネスでのGGX Trowbridge-Reitz NDF
この方程式をわずかに変更することで、スペキュラーハイライトを拡張できます。
// スタイライズドGGX Trowbridge-Reitz NDF
float D(vec3 Normal, vec3 HalfVector, float Roughness, float SpecularSize) {
float a = Roughness * Roughness;
float a2 = a * a;
float NdotH = max(dot(Normal, HalfVector), 0.0);
float NdotH2 = NdotH * NdotH;
float denom = max(SpecularSize * NdotH2 * (a2 - 1.0) + 1.0, 0.0001);
return a2 / (PI * denom * denom);
}
様々なラフネスでのスタイライズドGGX Trowbridge-Reitz NDF
Desmosグラフを作成して、何が起こっているかを視覚化しました(リンクをたどってパラメータを操作してください)。横軸はサーフェス法線とハーフベクトルのドット積(NdotH)を表し、縦軸はNDFの値(戻り値)を表します。値が高いほど、より多くのエネルギーが反射されます。黒い曲線は元のTrowbridge-Reitz NDF、赤い曲線はスタイライズされたものです。新しい「Specular Size」パラメータにより、NDFの元の形状を維持しながら、高い角度でのエネルギー戻りを増やすことができます。
Specular SizeをアニメーションさせるDesmosグラフ
結果的なハイライト形状
改良版
シンプルなバージョンは、余分なコストがかからない(乗算1回とmax関数1回)という利点がありますが、ラフなマテリアルに過剰に影響を与え、それらを過度に明るく見せてしまいます。ここでは、ラフネスが高い場合に元のNDF形状を維持しつつ、ラフネスが低い場合にハイライトを拡張する、わずかに複雑な方程式を示します。
// スタイライズドGGX Trowbridge-Reitz NDF
float D(vec3 Normal, vec3 HalfVector, float Roughness, float SpecularSize, float GGXMatching) {
float a = Roughness * Roughness;
float a2 = a * a;
float NdotH = max(dot(Normal, HalfVector), 0.0);
float NdotH2 = NdotH * NdotH;
// GGXMatchingパラメータは、スタイライズされたNDFがラフネスが高い場合にGGXのものとどの程度一致するかを制御します。実際には、4または8がうまく機能します。
float denom = max((SpecularSize * pow(1.0 - a, GGXMatching) + 1.0) * NdotH2 * (a2 - 1.0) + 1.0, 0.0001);
return a2 / (PI * denom * denom);
}
改良版スタイライズドGGX Trowbridge-Reitz NDF。最後の3つの列は、元のGGXエネルギー分布によく一致しています。
これはラフネスをアニメーションさせるグラフです(高いラフネスでは曲線が平坦になります)。黒い曲線はTrowbridge-Reitz NDF、赤い曲線はシンプルなスタイライズド、緑の曲線は改良版スタイライズドです。改良版は、高いラフネスでは赤い曲線に、低いラフネスでは黒い曲線に一致します。
ラフネスをアニメーションさせるDesmosグラフ
デモ
様々なラフネス、メタルネス、スペキュラーサイズでの最終的なルックを以下に示します。
スタイライズドGGXシェーディングのビデオ
スタイライズドGGXシェーディング
サイドノート
このスタイライズドGGXルックが十分に「トゥーン」的ではないと感じるかもしれません。Spellcastersでは、このトリックに追加する多くのものをテストしました。
- GIプローブを、通常の9係数ではなく、3つのSH係数(空と地面のグローバル、上、下)のみを計算することで刈り込みます。これにより、方向性が減り、手描きの2Dアートのように感じられます。また、保存する係数が少なくなるため、パフォーマンスも節約できます。Hi-Fi Rushでも同様のアイデアが使用されています。
- 深さベースのKuwaharaフィルター、mipバイアス、シンプルなフォグの組み合わせを使用して、遠くのプロップを単純化します。
- リムライティング。
- アウトラインとインライン。
そしてもちろん、テクスチャとモデリングには多くの作業が行われました。
グラフィックスに戻る