イラスト、モデリング、Unity、VR関連

unityとかblenderとかvr関連の作業メモ

unity shader 特定部分のみsurfシェーダと同じライティングを使う方法

surfシェーダを使うと用意されているライティングを処理を行うことが出来るが、部分的にライティング処理を行いたい等が出来ない。

これを部分的に行う方法を書く。

 

まずは全体にライティング処理が施された状態で書きたいsurfシェーダを書く。

 

シェーダファイルをクリックすると、インスペクタにshow generated codeというボタンがあるので、それをクリック。これがラッパーであるsurfシェーダが本来のfragシェーダに変換されたコードである。

 

realtimeで検索すると、以下のような部分がヒットする

// realtime lighting: call lighting function
c += LightingStandard (o, worldViewDir, gi);
c.rgb += o.Emission;

ここがライティングを行ってる部分である。

surfIn変数が通常のsurfシェーダのInputに該当するものであるので、

このsurfIn変数の値を使って、ライティング処理したい部分としたくない部分を分岐させればよい。

 

ライティングしたくない部分は、

c += _Color;
c.rgb += _Emission;

のように使用したい色をそのまま加算すればよい。

 

ライティングしたい部分はそのまま

c += LightingStandard (o, worldViewDir, gi);
c.rgb += o.Emission;

と書けばよい。

 

素の状態だと、

c.rgb += o.Emission;

となっているが、LightingStandardで、Emissionの値がライティングに合わせて加工されているようである。

 

これでDirectionalライトの特定部分の無効化が完了した。

次はpoint light等の二個目以降のライトを無効化する処理を書く。

 

コードをForwardAddで検索し、下にスクロールしておくと、surf_frag関数内に

c += LightingStandard (o, worldViewDir, gi);

と再び記述されている部分がある。ここを先と同じように分岐させる。ライトを当てたい場合はこれをそのまま書く。

ただし、ライティングを当てたくない部分は先と違い、clip(-1);と分岐先で書く。

if(ライトを当てる){

  c += LightingStandard (o, worldViewDir, gi);

}else{

 clip(-1);

}

(摩訶不思議なのであるが、返り値として使用しているcの値を0などにしてもclip(-1)としないとライトの影響を受けてしまう。これ以降の関数を全てオフにしても結果は同じであった)

 

また、#ifdef等を使っていると、その分surf=>fragへの変換時に生成されるコードが増えるため変更箇所が多くなるのに注意。コピペするだけでいいといえばいいのだが #ifdefを使うのでなく通常の分岐を使えば変更箇所が少なくてすむ。