dskjal
広告
広告

Eevee でリアルタイムセルルック

カテゴリ:blender

Eevee に Shader to RGB ノードが追加された(実装は神崎航氏)。このノードはディフューズ・キューブマップの色を取得でき、透明オブジェクトにも対応している。ただしスクリーンエフェクト(Screen Space Reflections やScreen Space Subsurface Scatteringなど)の情報は取得できない。

Shader to RGB で取得した色を強さ(Strength)1の放射(Emission)ノードにつなぐと指定した色をそのままレンダリングできる。

shader to rgb
Shader to RGB

古い内容

そのほかの NPR Shader の実装案

Eevee の実装について

source/blender/source/blender/gpu/shaders/gpu_shader_material.glsl を見てみると、Eevee では BSDF で関数を出力しておらず、ライティングした結果を次のノードへ渡している。具体的には以下のデータを渡している。

実際にライティングする関数は source/blender/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl の eevee_closure_diffuse だ。

NPR Uber Shader

NPR Uber Shader は Blender レンダーをシミュレートする、プリンシプル BSDF のようなノードだ。扱いやすいが出力が BSDF なので加工しづらい。

BSDF を分離する方法

この方法は Blender レンダーのマテリアルのような色・アルファ・法線・残りの BSDF データを出力するノードとそれらを結合して BSDF へ変換するノードとを追加する方法だ。こうすると Blender レンダーのノードを移植できるというメリットがある。Blender レンダーとまったく同じレンダリング結果になるわけではないが。

split imprementation
実装イメージ

Eevee Toon Shaders ノード を使えば Eevee で Blinn や Phong をシミュレートできる。しかしそのノードは最終的に放射ノードとディフューズBSDFノードとで色を付けている。この方法では正確な色を指定できない。

加えて単光源にしか対応していない。複数光源のノードを組むこともできるがとても複雑になる。

Eevee にトーン(Toon)BSDF が実装されれば複数光源の問題は解決するが、正確な色を指定できない問題はどうにもならない。

Blender レンダーと PBR の違い

Blender レンダーのマテリアルノードの最終的な出力は表示される色だ。それに対して PBR(Cycles や Eevee)では双方向拡散率分布関数(BSDF)が最終的なノード出力だ。

Blender レンダーでは一度レンダリングされた結果をさらにマテリアルノードで編集していた。なので影のできる場所が特定できた。それに対して PBR ではそれらの情報は取得できない。PBR では入射光の情報とオブジェクトに関する情報(法線や UV など)から BSDF を作る必要がある。というのも影が落ちている場所は単に光が入ってこないだけなので BSDF を作るうえで考慮する必要がない。

色の問題

PBR で正確な色を指定できないのは、レンダリングに必要なすべてのパラメータにアクセスできないからだ。現状では方程式の赤で囲った部分のみコントロールできる。Leは放射ノードのような発光を表現する項で、frはそれ以外の BSDF で設定する項だ。

rendering equation
PBR のレンダリング方程式

放射ノードのみを使えばほぼ正確に色を指定できる。しかし放射ノードは陰を作らず、影の影響を受けない。

Eevee でリアルタイムセルルックを作るには

ライティングノードを作る

Eevee のレンダリングエンジン本体に手を入れて、光源のシャドウマップを参照するノードを追加する必要がある。光源のシャドウマップを参照するノードは実装するとするなら、ライトを指定してライティングされた色を出力するノードになるだろう。表面の材質を指定する方法はないので、グレーのディフューズだと仮定する。

fake node
光源を指定してシェーディングを出力するノードの実装イメージ
Lamp Shading ノードだけ実装すればリアルタイムセルルックは実現可能
// シェーダの疑似コード
p // 頂点位置
n // 法線
light_pos // 光源の位置
l // ライトの方向
c // ライトの色
s // 光の強さ
env // 環境光
tex_depth // シャドウマップテクスチャ
DepthMapMatrix // 頂点位置をシャドウマップの UV 座標へ変換する行列

float real_depth = distance(p, light_pos);
float2 uv = (p * DepthMapMatrix).xy;
float depth_map = texture2D(tex_depth,  uv);

if( depth_map < real_depth ){
    return env;
}
else{
    return dot(n, l) * s * c + env;
}

BSDFノードを作る

Specular ノードが参考になる。Specular ノードは source/blender/source/blender/gpu/shaders/gpu_shader_material.glsl の node_eevee_specular 関数だ。

Eevee シェーダの基本的なライティングは source/blender/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl で行われていて、光源からの可視性は light_visibility 関数で取得できそう。

specular node
法線を光源方向に向けた Specular ノード

ポストエフェクト

リアルタイムポストエフェクトにセルルックの処理を実装することもできる。しかし半透明オブジェクト(深度バッファの問題)や鏡(法線・深度・UV の問題)の処理が困難だ。

リアルタイムでないセルルック

Cycles でやっていたようにマテリアルオーバーライドを使う。2018年 4 月の時点ではマテリアルオーバーライドはまだ未実装だ。

輪郭抽出は反転ポリゴン法、フリースタイル、コンポジットがそのまま使える。

関連記事

Blender 記事の目次


広告
広告

カテゴリ