ゲーム制作においてハイライト表現は結構重要な要素です。3D空間内での「触った」「触ってない」という情報がプレイヤーに伝わらなければ、それはストレスの原因になるからです。今回はほぼコーディングなしでハイライト表現を実装します。
#制作物のイメージ
仕上がったハイライトを先に掲載しておきます。こんなハイライトを作ります。
#制作環境
Unity 2019.1.0f2
Shader Graph ver.5.13.0(※デフォルトでver.5.7.2が入っていることがありますが、バージョンをあげないとエラーがでます)
Lightweight Render Pipeline(Assets > Create > Rendering > Lightweight Render Pipeline で辿ってください)
#ShaderGraphでハイライトの縁を作る
Unity2019よりShader Graphというエディターが正式に実装されたことで、ノードベースでシェーダーを組むことができるようになりました。今回はこのエディターを使用することにします。
プロジェクトを立ち上げたばかりではこのエディターは組み込まれていないので、自分でPackage Managerからインストールする必要があります。Package Managerはツールバーより Window > Package Manager で辿れます。バージョンは基本的に最新のものが選択されているはずですが、まれに最新になっていないことがあるので注意してください。
ShaderGraphが導入できたら、Create > Shader > Unlit Graph と辿ってシェーダーを作成します。作成できたらダブルクリック等でシェーダーを開きます。
エディターが開いたら、以下のようにノードを組みます。今回はハイライト部分に特別凝ったことはしていないので、とてもシンプルに仕上がっています。ハイライト部分にもライティングを入れたい、ハイライトを点滅させたい、などといった場合は自分でノードを組みなおしてください。
今回のハイライト表現の基本方針は “二度描き” です。ハイライトを入れたいオブジェクトを一回り大きく描画し、再度従来のマテリアルで描画する、というやりかたです。
ノードはスペースで検索できます。
- Positionノード は Input > Geometry
- Multiplyノード は Math > Basic
なお、ノードが組み終わったら、必ずSave Assetしましょう。しないとマテリアルに反映されません。
シェーダーに関しては以上です。以降さわることはありません。(便利な時代になりました...)
#カスタムなScriptable Render Pipeline(SRP)に変更する
次に“二度描き”を行えるように標準のSRPからカスタムなSRPに変更します。描画順序を変更するためには、Create > Rendering > Lightweight Render Pipeline > Pipeline Asset / Forward Renderer を辿って、SRP用のスクリプタブルオブジェクトを準備します。
ファイルを準備しても、Unity側ではまだこのパイプラインを使用するようには設定されていません。なのでツールバーより Edit > Project Setting... を辿り、Graphics項目のScriptable Render Pipeline Settingを先ほど作成したPipeline Assetに変更します。
次はPipeline Asset側がカスタムなForward Rendererを使用するように設定します。AssetフォルダよりPipeline Assetを選択するとインスペクターに下図のようなパラメータ画面が表示されます。General > Data の項目を先ほど作成したForward Rendererに設定します。
下準備は完了しました。次はカスタムなForward Rendererに描画順序を設定していきます。
#Custom Forward Rendererで描画順序を弄る
AssetフォルダよりカスタムするForward Rendererを選択します。インスペクターよりRenderer Featuresを追加していきます。注意点としては、SRPではレイヤーグループ単位で描画順序を弄るため、ハイライトさせたいオブジェクトだけが属するレイヤーグループを準備する必要があります。そしてOverridesで二度描きでしようするマテリアルをShaderGraphで作成したシェーダーマテリアルに設定します。(※画像ではStencilにチェックが入っていますが、必要ありません)
この時点での描画結果は以下のようになります。元のオブジェクトより一回り大きく、ライティングなしの単色一色で描画されていることがわかります。
さて、ハイライトの縁になる部分は描画できましたが、これでは元のオブジェクトが何なのかわからないので、元のオブジェクトを描き直します。先ほどと同じようにRenderer Featuresを追加し、以下のように設定してください。
今回はオリジナルのマテリアルで再度描画してほしいので、Override用のマテリアルは設定しません。結果は以下の通りです。
これにてハイライトは完成です。あとはハイライトさせたいオブジェクトのレイヤーをハイライト用のレイヤーに変更するだけです。ね、簡単でしょ?
#二度描きの欠点と回避方法
完成と書きましたが、実は二度描きゆえの描画破綻が存在します。この描画破綻は、ハイライトの上(※正確にはハイライトとカメラの間に)に別のオブジェクトが存在する時に生じます。
これを回避するには、ハイライト上に存在する可能性があるオブジェクトの描画を遅らせる必要があります。上図のGIFではプレーヤーオブジェクトがハイライトを遮っているので、それの描画を遅らせます。プレーヤー用のレイヤーを設定し、下図のように設定します。Renderer Featuresは上から描画が優先されるようなので、Playerレイヤーは一番下に設置します。
#まとめ
結構敷居が高かったハイライト表現がいとも簡単に実装できる!!Unityは今日も世界を救う!!
#余談
実は、ハイライト部分をメッシュとして動的に作成してしまうという方法もあります(←めっちゃめんどくさい)。その方法を用いたイメージも一応載せておきます。これは二度描きしていないので、ハイライト部分が距離に忠実に描画されています。ま、こういう方法もあるよ、ということです。
#参考文献
テラシュールブログ, 【Unity】LWRPで、壁で遮られて見えないキャラクターをシルエット表示するのが超簡単にできた, 2019/04/15,
http://tsubakit1.hateblo.jp/entry/2019/04/15/234935