読者です 読者をやめる 読者になる 読者になる

テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

【Unity】とあるライトマップと光沢感(スペキュラー)

Unityユーザー助け合い所で少し気になった投稿があったので、調査してみました。

Lightmapを焼くと光沢が出ない

f:id:tsubaki_t1:20170304214320j:plain

ライトマップを使用する時、事前に光の情報をライトプローブに格納しておく事で、ダイナミックなオブジェクトに対して間接光や直接光の影響を与える事が可能です。

但し、Lightprobeにはライトの位置は格納されていないため、光沢といった表現は表示出来ないみたいです。

 

ちなみにStaticの場合はDirectional Specularの設定をONにしておくことで、スペキュラー情報も含めてライトマップにベイクしてくれます。ただ、間接光からの反射も光沢と認めるのか、直接光が無くても何故か光沢が表現されると、微妙に過剰に表現されてる節があります。

…なおDirectional Specularの機能は5.6から無くなります。

光沢を表現したい

個人的な考えでは、余りゲームに詳しくない人は「光沢の有無」でゲームのグラフィッククォリティを認識してる節があるので、やはり光沢は欲しいです。ので、光沢を表現する方法を考えてみます。

Directional Lightの場合

Directional Lightを使用している場合はMixedを使用する事で解決しますが、Spot LightやPoint Lightのような計算が面倒なライトの場合、ライトの範囲内でも光沢が出なかったりします。

f:id:tsubaki_t1:20170304215041j:plain

PointLightやSpot Light

Point LightやSpot Lightでリアルタイムに光沢を表現したい場合、リアルタイムなライトが欲しいので、ポイントライトを、スタティックなライトと同じ位置に用意します。

f:id:tsubaki_t1:20170304220308j:plain

BakedはBounce Intensityは自由に設定出来ますが、RealtimeはPrecomputed Realtime GIがOFFならばBounce Intensityは0です。

ここで、Lighting>LightprobesのAdd Direct Lightのチェックも外しておきます。そうすると、Lightprobeには間接光からの光のみが反映されるようになるので、二重に光の影響を受ける事を防げます。

ただし、LightのCulling Mask動的に動くオブジェクトだけを指定しないと、今度はstaticの方が輝度が高くなります。場合によっては、Add Direct Lightのチェックを入れつつ、直接光と間接光を半々くらいにするのも良いアイディアかもしれません。

f:id:tsubaki_t1:20170304221239j:plain

最終的には、こんな感じになります。

f:id:tsubaki_t1:20170304225850j:plain

それとReflection Probeを使わないと、なんちゃって光沢付きモデルを表現した何かになるので、Reflection Probeは積極的に使うと良いかと。

Pixel Light Countの限界

今回紹介しているアプローチでは、Pixel Light Countの数によっては妙な挙動になる事があります。
Pixel Light Countはピクセルライトを使用できる制限で、その数以上のライトは頂点カラーベースのライティングに切り替わります。また、同一のオブジェクトが受けるスペキュラーの数も制限するらしく、下のように複数のライトから単一のオブジェクトを照らしている場合、優先度の高いライトの光沢が表現されます。

f:id:tsubaki_t1:20170304222905j:plain

そのため、この手法では「Point Lightの範囲を被らないように設定する」事が必要になりそうです。範囲がかぶらなければ(モデル一つに対して複数のライトが影響しないのであれば)、Pixel Point Lightが1でも下のように光沢がライト毎に出てます。

f:id:tsubaki_t1:20170304223731j:plain

ライトの優先度は輝度や距離等、様々です。優先順位戦争で負けたポイントライトは、頂点カラーに流し込まれます。

f:id:tsubaki_t1:20170304225200j:plain

なお、Render ModeでImportantを選択すると単一のオブジェクトに複数のスペキュラを指定出来るようになりますが、重くなるんじゃないかなと予想してます。

f:id:tsubaki_t1:20170304225646j:plain

AreaLightやEmissive Objectの場合

Emissiveなマテリアルを持つオブジェクトの場合、ReflectionProbeを用意するとスペキュラーちっくな表現が可能です。

その際、ReflectionProbeのHDRはON、かつEmissiveなオブジェクトがReflectionProbeに映る必要があります。

f:id:tsubaki_t1:20170307102420j:plain

f:id:tsubaki_t1:20170307104057j:plain

f:id:tsubaki_t1:20170307102850g:plain

AreaLightは光沢表現を与える物が無いので光沢が表現されません。

ので、強引ですが光沢用の追加ライトを追加します。もしくはAreaLightと同じ大きさのEmissiveなオブジェクトを用意し、ReflectionProbeに写します。

f:id:tsubaki_t1:20170304234655j:plain

モバイルでは…

個人的には、Matcapのような「決め打ちで光沢が表現されてるもの」や、専用のシェーダーを用意するのが一番クォリティ高く見えるんじゃないかなって気がしています。

tsubakit1.hateblo.jp

docs.unity3d.com

また、Lightprobeで頑張るよりも環境マップで決め打ちで光の反射を与えてしまうのも手かもしれません。

5.6以降では

Shadow Maskを使うのが良さそうです。

mixedを指定してやれば、特に何らかの設定を行わなくとも下のような表現になります。

また、事前に準備した影とリアルタイムに準備した影の境目がわかりづらく、かつスペキュラ等もちゃんと表現されています。 …すきかも

f:id:tsubaki_t1:20170304231829j:plain

tsubakit1.hateblo.jp

なお、5.6では加算ロード時に「Depth OnlyやDon't Clearを指定したカメラ」が「CameraのDepthの一番奥」にある場合、毎フレーム「GL.End requires material.SetPass before!」のようなエラーが出るみたいです。

f:id:tsubaki_t1:20170304233415j:plain

一応既にFixedになっているので、その内治るんじゃないかなと予想してます。

関連

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp