【Unity】とあるライトマップと光沢感(スペキュラー)
Unityユーザー助け合い所で少し気になった投稿があったので、調査してみました。
Lightmapを焼くと光沢が出ない
ライトマップを使用する時、事前に光の情報をライトプローブに格納しておく事で、ダイナミックなオブジェクトに対して間接光や直接光の影響を与える事が可能です。
但し、Lightprobeにはライトの位置は格納されていないため、光沢といった表現は表示出来ないみたいです。
ちなみにStaticの場合はDirectional Specularの設定をONにしておくことで、スペキュラー情報も含めてライトマップにベイクしてくれます。ただ、間接光からの反射も光沢と認めるのか、直接光が無くても何故か光沢が表現されると、微妙に過剰に表現されてる節があります。
…なおDirectional Specularの機能は5.6から無くなります。
光沢を表現したい
個人的な考えでは、余りゲームに詳しくない人は「光沢の有無」でゲームのグラフィッククォリティを認識してる節があるので、やはり光沢は欲しいです。ので、光沢を表現する方法を考えてみます。
Directional Lightの場合
Directional Lightを使用している場合はMixedを使用する事で解決しますが、Spot LightやPoint Lightのような計算が面倒なライトの場合、ライトの範囲内でも光沢が出なかったりします。
PointLightやSpot Light
Point LightやSpot Lightでリアルタイムに光沢を表現したい場合、リアルタイムなライトが欲しいので、ポイントライトを、スタティックなライトと同じ位置に用意します。
BakedはBounce Intensityは自由に設定出来ますが、RealtimeはPrecomputed Realtime GIがOFFならばBounce Intensityは0です。
ここで、Lighting>LightprobesのAdd Direct Lightのチェックも外しておきます。そうすると、Lightprobeには間接光からの光のみが反映されるようになるので、二重に光の影響を受ける事を防げます。
ただし、LightのCulling Maskは動的に動くオブジェクトだけを指定しないと、今度はstaticの方が輝度が高くなります。場合によっては、Add Direct Lightのチェックを入れつつ、直接光と間接光を半々くらいにするのも良いアイディアかもしれません。
最終的には、こんな感じになります。
それとReflection Probeを使わないと、なんちゃって光沢付きモデルを表現した何かになるので、Reflection Probeは積極的に使うと良いかと。
Pixel Light Countの限界
今回紹介しているアプローチでは、Pixel Light Countの数によっては妙な挙動になる事があります。
Pixel Light Countはピクセルライトを使用できる制限で、その数以上のライトは頂点カラーベースのライティングに切り替わります。また、同一のオブジェクトが受けるスペキュラーの数も制限するらしく、下のように複数のライトから単一のオブジェクトを照らしている場合、優先度の高いライトの光沢が表現されます。
そのため、この手法では「Point Lightの範囲を被らないように設定する」事が必要になりそうです。範囲がかぶらなければ(モデル一つに対して複数のライトが影響しないのであれば)、Pixel Point Lightが1でも下のように光沢がライト毎に出てます。
ライトの優先度は輝度や距離等、様々です。優先順位戦争で負けたポイントライトは、頂点カラーに流し込まれます。
なお、Render ModeでImportantを選択すると単一のオブジェクトに複数のスペキュラを指定出来るようになりますが、重くなるんじゃないかなと予想してます。
AreaLightやEmissive Objectの場合
Emissiveなマテリアルを持つオブジェクトの場合、ReflectionProbeを用意するとスペキュラーちっくな表現が可能です。
その際、ReflectionProbeのHDRはON、かつEmissiveなオブジェクトがReflectionProbeに映る必要があります。
AreaLightは光沢表現を与える物が無いので光沢が表現されません。
ので、強引ですが光沢用の追加ライトを追加します。もしくはAreaLightと同じ大きさのEmissiveなオブジェクトを用意し、ReflectionProbeに写します。
モバイルでは…
個人的には、Matcapのような「決め打ちで光沢が表現されてるもの」や、専用のシェーダーを用意するのが一番クォリティ高く見えるんじゃないかなって気がしています。
また、Lightprobeで頑張るよりも環境マップで決め打ちで光の反射を与えてしまうのも手かもしれません。
5.6以降では
Shadow Maskを使うのが良さそうです。
mixedを指定してやれば、特に何らかの設定を行わなくとも下のような表現になります。
また、事前に準備した影とリアルタイムに準備した影の境目がわかりづらく、かつスペキュラ等もちゃんと表現されています。 …すきかも
なお、5.6では加算ロード時に「Depth OnlyやDon't Clearを指定したカメラ」が「CameraのDepthの一番奥」にある場合、毎フレーム「GL.End requires material.SetPass before!」のようなエラーが出るみたいです。
一応既にFixedになっているので、その内治るんじゃないかなと予想してます。