MeshShadowReceiverは影が落ちる場所のポリゴンを探索するためにMesh Treeオブジェクトを必要とします。Mesh TreeはProjectウィンドウのコンテキストメニューから作成することができます。Projectウィンドウの中のMesh Treeを作成したいフォルダを右クリックして、“Create > FastShadowReceiver > XxxxMeshTree”を選択してください。ここで、XxxxはBinaryかOctかTerrainのいずれかとなります。これらのMesh Treeは以下の説明にあるように、使用前にメッシュオブジェクトからビルドしなければなりません。また、メッシュオブジェクトやメッシュオブジェクトのレイアウトが変更された場合は再ビルドする必要があります。
BinaryMeshTreeとOctMeshTree
BinaryMeshTreeとOctMeshTreeは同じような機能を持ちます。どちらのMesh Treeも単一のメッシュオブジェクトか、複数のMeshRendererオブジェクトを子供に持つルートオブジェクトかに対して使うことができます。両者の違いは基本的にはパフォーマンスの違いしかなく、探索の速度やメモリの使用量、シザリングにかかる時間などが変わってきます。おおざっぱに言うと、OctMeshTreeはメモリの使用量を抑えることができますが、小さなシーンではBinaryMeshTreeに比べて探索の速度は遅くなります。また、探索の結果に含まれる余分なポリゴンの数もOctMeshTreeの方が多くなる傾向にあります。
探索の結果に余分なポリゴンが含まれると描画面積が大きくなるのでパフォーマンス上不利になります。MeshShadowReceiverにはScissorオプションがあり、これを有効にすると余分なポリゴンをシザリングしてGPUのパフォーマンスを向上させることができます。しかし、余分なポリゴンの数が多ければそれだけシザリングにかかるCPUの時間が大きくなります。Scissorオプションと一緒にScissor Marginプロパティを設定することで、シザリングにかかる時間を短縮できるのですが、Scissor MargineはBinaryMeshTreeを使ったときにしか有効になりません。詳細についてはShadow Receiverのセットアップセクションを参照してください。
どちらのMesh Treeを得らんだら良い結果が得られるかわからない場合は、両方とも使ってみてパフォーマンスの良かった方を選びましょう。
BinaryMeshTree
|
OctMeshTree
|
|
探索の速度
|
小さなシーンで速い
|
巨大なシーンで速い
|
メモリ使用量
|
多い
|
少ない
|
探索結果
|
余分なポリゴンが少ない
|
余分なポリゴンが多い
|
シザリング
|
速い
|
遅い
|
Mesh Treeオブジェクトはビルドしないと使用することができません。Inspectorビューでメッシュオブジェクトもしくは環境オブジェクトのルートオブジェクトを‘Root Object’にセットすると‘Build’ボタンが有効になります。環境オブジェクトのルートオブジェクトをセットする場合、プレハブを作成して、そのプレハブをセットすることが推奨されます。シーンのオブジェクトをセットしてしまうと、その参照をMesh Treeのアセットの中に保存することができず、次にMesh Treeをビルドするときに、再度ルートオブジェクトをセットする必要があるからです。
環境オブジェクトのルートオブジェクトをセットした場合は、オプションとして‘Layer Mask’と‘Exclude Render Types’を指定して一部のオブジェクトやメッシュをビルドから除外することができます。またOctMeshTreeをビルドする場合は‘Min Node Size’をビルドの前に指定することができます。この値が小さければ探索結果に含まれる余計なポリゴンの数を減らすことができますが、メモリの使用量が増加します。
‘Scaled Offset’や’Fixed Offset’に0以外の値をセットすると、メッシュの各頂点を法線ベクトルの方向に少し押し出すことができます。これはZファイティングによる影のちらつきの問題を解決するのに有効です。特に環境オブジェクトが巨大な場合はZファイティングが顕著になります。頂点を押し出すオフセット値は次の式で頂点v毎に計算されます。
offset = 0.00000025 x |v| x <Scaled Offset> + <Fixed Offset>
.
‘Scaled Offset’はオフセットの量を調整するのに便利です。なぜなら、Zファイティングは浮動小数点の丸め誤差によって生じるもので、誤差のとりうる最大値は概ね対象となる浮動小数点の値の絶対値に比例するからです。
MeshShadowReceiverでライトマップを使う場合は、Lightmap UV Index に UV2 を指定してください。またその場合、Mesh Tree をビルドする際にはルートオブジェクトかルートオブジェクトプレハブのインスタンスがシーンに存在している必要があります。MeshShadowReceiverが何番目のライトマップのどのエリアを使うのかという情報は、ビルド時に Mesh Tree に記録されます。そのため、ライトマップを再ベイクした時は Mesh Tree も再ビルドするようにしてください。
もし、ライトマップの情報をプレハブに含めて、色々なシーンでライトマップを再利用する場合には注意が必要です。もしシーン毎にライトマップのインデックスが変わる可能性があるならば、FastShadowReceiver.LightmapDataInPrefab コンポーネントをプレハブのルートオブジェクトに追加してください。
FastShadowReceiver.LightmapDataInPrefab コンポーネントを追加した場合は、Mesh Tree をライトマップをベイクしたシーンでビルドします。
もし FastShadowReceiver.LightmapDataInPrefab コンポーネントを使わない場合、Mesh Tree をライトマップを使用するシーン毎にビルドしないと、正しくライトマップを参照できなくなる可能性があります。
TerrainMeshTree
TerrainMeshTreeはテレインオブジェクトに対して使うことができます。InspectorビューでTerrainDataオブジェクトを‘Terrain Data’にセットして、‘Build’ボタンを押せばビルドできます。TerrainMeshTreeには他のオブションはありません。
Building a Mesh Tree at runtime
環境オブジェクトのメッシュの頂点がReadableであればMesh Treeをゲームの実行時に行なうことも可能です。ビルドには時間がかかりますが、ビルドの処理はバックグラウンドで行なわれるので、ゲームが中断してしまうことはありません。ただし、ビルドが終わるまでの間、そのメッシュの上の影が描画されません。
FastShadowReceiver/Demo/SimpleExamples/RandomLevelGenerationシーンは実行時にMesh Treeをビルドするサンプルになっています。C#のソースコードはFastShadowReceiver/Demo/Scripts/RandomLevelGeneration.csです。