テラシュールブログ

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

【Unity】確認までに長い時間を要求するライトのベイクを、素早く確認する Progressive Lightmapper

https://cdn-ak.f.st-hatena.com/images/fotolife/t/tsubaki_t1/20170207/20170207003705.gif

今回は、Unity 5.6の個人的な目玉機能、Progressive Lightmapperについてです。

ライトのベイクには時間がかかる

BakedなライトやAreaLight等、テクスチャに直接焼き込むタイプのライティングは実際の結果を確認するまでに非常に長い時間がかかります
特に広大なステージの場合は顕著で、モノによっては1日とか要求する事があり、しかもライトの一つを変更しただけでその時間を要求します。https://cdn-ak.f.st-hatena.com/images/fotolife/t/tsubaki_t1/20151118/20151118233631.jpg

そういった問題の最も効果的な対策はライトマップの適切なクォリティを設定することですが、もう一つの新しいアプローチが出てきました。

https://cdn-ak.f.st-hatena.com/images/fotolife/t/tsubaki_t1/20151119/20151119003706.jpg

Progressive Lightmapper という機能

Progressive Lightmapperは、Scene Viewが見ている範囲を優先的にベイクする事が可能なシステムみたいです。見えている部分を、最初は粗い感じのライティングから始まり徐々に細かくベイクしていきます。

見てる範囲を素早く確認出来るので、BakedなLightやBakedなEmissive マテリアル、AreaLightやAOを焼く場合等で、かなり有効に見えます。

f:id:tsubaki_t1:20170308022328j:plain

例えば下のgifアニメでは、BakedなDirectional Lightを動かしています。実は下の一番大きなキューブは300m近い大きさで、普通にやったらライトを動かす度に30分ベイク完了を待つコースですが、Progressive Lightmapperを使ってみると、少なくとも大雑把な影は割と短時間で更新されています。

f:id:tsubaki_t1:20170308030131g:plain

ちなみに、シーンビューで見てない部分は露骨に後回しにされるので、影が焼かれてる部分と焼かれてない部分でハッキリと差を確認出来ます。

また、違う角度から見た場合も露骨に焼き残しが見えたりします。

f:id:tsubaki_t1:20170308012008j:plain

Progressive lightmapperはUnity 5のEnlightenベースのライティングシステムではなく、Imagination Technologies社の協力で開発する新機軸のシステムのようです。

そのため、Enlightenが提供するようなRealtime GIの機能は使用出来ず、Baked GI専用になりそうです。要するに、モバイルプラットフォームや、フレームレートを稼ぎたいVR等で利用する事になりそうです。

 

ちなみに、「確認までにかかる時間が短い」だけで「ベイク時間が短くなった」訳では無いので、ベイク時間を短くしたい場合はシーンのライティング周りをちゃんと調整した方が良いかと思われ。

tsubakit1.hateblo.jp

ベイクの残り時間が表示される

自分にとってUnityのライティングで不満だった事の一つに、ベイク中の残り時間が分からない事がありましたが、Progressive Lightmapperでは表示するようになったみたいです。

f:id:tsubaki_t1:20170308011450j:plain

実際には、Bakingが始まるまでに少し停止時間がありますが、今のところの感触としてはそれなりに正確な値を返してくれています。

Emissiveなマテリアルで焼いた影が若干綺麗

UnityのEnlighten設定を使用している際、Emissiveなオブジェクトで影を焼く場合は、影のクォリティはClustering…つまりRealtime GIで設定したクラスタの大きさにとても影響を受けます

例えば下のように期待する影に対して大きなチャートだった場合、影は割と大雑把にベイクされます。

これを回避したい場合はFinal Gatherを使用する訳ですが、Final Gatherは割と時間がかかります。

f:id:tsubaki_t1:20170308013412j:plain

Progressive Lightmapperを使用する場合、Realtime GIに依存せず計算しているらしく、影のエッジそれなりに綺麗になっています。

ただ少し模様が出来てしまっているのは、まぁ。

f:id:tsubaki_t1:20170308013736j:plain

ベイク中にゲームを再生したときの動作と、焼かれる順番

Progressive Lightmapperはシーンビューが見てる範囲を優先的に焼きます。つまり、見えてる範囲が焼き終わっていても、全体が焼かれるまでには時間がかかります。

焼き終わってない状態でゲームを再生すると、「途中まで焼いた状態」でゲームを再生します。再生停止すればベイクを再開するので、ゲームに必要な部分をシーンビューで眺めておいてから実行すれば、毎回ライトのベイク完了まで待たずとも、ある程度の勘所は掴めそうです。

f:id:tsubaki_t1:20170308021735j:plain

ただし、LightprobeとReflection Probeはベイク完了後に焼かれるらしく、この二つが絵作りに密接に関わっている場合には注意が必要です。

もしかしたらPrioritize Viewのチェックを外せば、多少早くベイクが完了するかもしれません。

f:id:tsubaki_t1:20170308022053j:plain

使ってみる

Progressive Lightmapperを使用したい場合、LightingのLightmapping settingsのlightmapperをProgressiveに変更するだけです。

f:id:tsubaki_t1:20170308014247j:plain

Shadow Maskはまだ使えない

5.6b10現在、Shadow Maskはまだ使えないみたいです。

f:id:tsubaki_t1:20170308022752j:plain

関連

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

blogs.unity3d.com

 
 
 
 

【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

 
 

【Unity】Timelineエディタのプレビューリリース版その1がリリース

f:id:tsubaki_t1:20170208224608p:plain

UnityのTimelineエディタのプレビューリリース版その1がリリースされてました。

Timeline Experimental Preview Release 1

https://forum.unity3d.com/threads/timeline-experimental-preview-release-1.455265/

機能

現状の機能は大雑把にこんな感じです。

  • タイムラインでアニメーションを制御する
    アニメーションをタイムラインに仕込んだり出来るし、ブレンドも可能
  • タイムライン上でオーディオを制御出来る
  • タイムライン上でスクリプトを制御出来る
    イベントのような瞬間的な物だけではなく、タイムラインで指定した期間連続して駆動するものも表現出来る
  • アセットベースでありながら、シーンのオブジェクトに紐付け出来る仕組み*1

www.youtube.com

 補足

なお、

  • Unityバージョン間でプロジェクトの下位互換性は保証されません。特にExperimentalなプロジェクトを開く場合、プロジェクトをアップグレードする前に、バックアップする事を強くお薦めします。
  • プレビュー版にはビルド機能は含まれません。
  • バージョンによってAPIが変わったり削除されたりします。

また、見てる感じ、明らかにApplyRootMotoinのような仕組みで移動する事が前提になっているように見えます。うーん

関連

tsubakit1.hateblo.jp

*1:無駄に複雑

【Unity】複数のColliderを結合するComposite Collider 2Dを使って少し遊ぶ

今回はUnity 5.6に追加されたComposite Collider 2Dについてです。

Compound Collidersという機能

Rigidbodyの下にColliderが複数ある時、実はUnityはColliderを一つにまとめて処理してくれます。これで動かす場合、MeshColliderよりも高速で動作します。

f:id:tsubaki_t1:20170222002439g:plain

こういったCompound(複合)コライダーはMeshColliderやPolygonColliderより大体高速で動作し、かつMeshCollider系の制約も殆ど受けないので色々と便利です。

 

例えば、下にMeshColliderとComposite Colliderで作成したモデルを用意してみます。

当たり判定は大体同じように作れますが、MeshColliderはCompositeColliderと比較して、単純に当たり判定の計算負荷が高くアニメーションに非対応*1、かつMeshCollider同士の当たり判定が出来ない問題があります。

そのため、単純な形状のコライダーを動かして当たり判定を作るCompoundColliderという機能があります。

f:id:tsubaki_t1:20170222221956j:plain

ちなみに、CompoundColliderはAColliderBuilderでサクっと作れます。

f:id:tsubaki_t1:20170222225404j:plain

https://www.assetstore.unity3d.com/jp/#!/content/15058

CompositeCollider2Dという機能

さて、5.6でCompoundColliderに微妙に似てますが異なる機能が追加されました。CompositeColliderなるコンポーネントです。

これは複数のCollider2D(MeshColliderとBoxColliderのような頂点ベースのコライダー)を結合し、一つのコライダーに変換する機能みたいです。

 

例えば下のように、複数のBoxColliderが同じ範囲に入ると、一つのColliderのように結合されているのが分かります。

f:id:tsubaki_t1:20170222222833g:plain

Colliderの結合は、同期(動かした時に計算?)、非同期、スクリプトからのアクセスの3タイプがあります。要するに、このメッシュ結合はランタイムで動きます。

f:id:tsubaki_t1:20170222223254j:plain

ちなみに結合コストは結構高いのか、弾幕を作り「一つのRigidbody + 一つのComposite Collider(内部に500個程のCollider)」をやってみた所、バラバラに動かしたほうが早かったです。

また、Geometry typeをOutlineに設定すると、コライダーの形状に沿ってコライダーを作成するみたいです。

f:id:tsubaki_t1:20170222223754j:plain

ダイナミック洞窟生成

この機能で思いついたのが、ダイナミック洞窟生成です。

やってる事は物凄い単純で、Geometry TypeをOutlineに設定し、あとはモノをどんどん増やしていくだけです。

下のようになります。

作り方

  1. 結合するCollider2Dの付いたGameObjectを用意する
  2. CompositeCollider2Dの付いたGameObjectを用意する
  3. 1を2の子オブジェクトとして配置
  4. 1のColliderのUse By Compositeにチェックを入れる

f:id:tsubaki_t1:20170222224642g:plain

 

後はEdge Radiusの値を調整します。小さすぎると当たり判定が貫通する事がありますし、大きすぎると凄い浮きます。

f:id:tsubaki_t1:20170222225021j:plain

後はComposite ColliderにはRigidbodyが付いてくるので、BodyTypeをStaticもしくはkinematicに設定しておきます。

f:id:tsubaki_t1:20170222225605j:plain

なんか、コレだけで何かゲームを作れそうな気がしなくもないですね。穴掘りゲーム的な。

関連

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp

*1:メッシュを作成しMeshBake等でメッシュ情報を更新しなければ当たり判定が付いてこない