VRChatの環境内でスターウォーズ劇中のようなライトセーバーの軌道を描画することを目的として開発したシェーダー


開発経緯

映画スターウォーズ内でのライトセーバーのブレードとモーションブラー、トレイルは基本的に1コマずつロトスコープで直接描き込むことにより表現されてきた。
VRChat内でそのような光線剣系のトレイルを表現する手法は大きく分けてDynamicBoneを使用したものとUnityのTrailRendererを使用したものの2種類のものが存在していた。これらはそれぞれ長所と短所を備えていた。

1.DynamicBone

DynamicBone方式によるボーン構造

ブレード部につづら折りのボーン構造を作り、トレイルとなる頂点をDynamicBoneを利用してブレード本体に遅れて追従させることで引き伸ばし残像を表現する。この場合ある程度までの速度での斬撃であればリアルな表現となり、かつ静止状態ではトレイル部はブレード内に完全に隠れることになる。しかしブレードとトレイルの間はあくまで直線であるため、剣戟の上級者がこれを使用して殺陣を行うと剣の回転運動にトレイルがついて来ず、不自然なものとなる場合があった。

2.TrailRenderer

ブレードに複数のTrailRendererをアタッチし残像を表現する。
TrailRendererは特殊なボーンやメッシュの構造を必要としないため、専用にモデルを制作する必要がなく、全体として設定が容易であったため3DCGに造詣が深くないVRChatユーザーにも使いやすかった。そして軌道はUnityによって自動的に計算、生成されているため回転運動も表現しやすいという剣戟の上級者に好まれる特徴があった。しかしTrailRendererにより生成されるメッシュは基本的にカメラに対して正面を向こうとするため、剣が静止している場合や側面以外から見た場合メッシュの断片が不自然にチラついてしまうという大きな欠点がある。

これら欠点を克服しより見栄えの良いトレイルを描画するために開発したのが本シェーダーである。


技術解説

本シェーダーは単体ではなく複数のシェーダー群により構成されており、以下のような流れで動作する。

1.ブレードの根本と先端のワールド座標を取得し小さなポリゴンにfloat4のカラーデータとして出力する
2.そのポリゴンをカメラで撮影し32bit floatのRenderTextureに書き出す
3.書き出されたワールド座標は1フレームが経過するごとに右に1pxずつ移動させていく。これにより横8pxのRenderTextureであれば最大8フレーム過去までのブレードの座標をキャッシュすることが可能になる。
4.このRenderTextureをトレイル本体の頂点シェーダーで読み込み、予めUV展開しておいた頂点を過去のワールド座標へ移動させる
5.これにフラグメントシェーダーでブレードと同じカラーを描画させトレイルとなる


課題点など

このトレイルはフレーム単位での描画であるため、例えば90FPSで描画されるOculusRiftを想定して設定したとして、高負荷によりFPSが低下したり、60FPSであるデスクトップで見た場合に想定よりも間延びしてしまうことになる。これを暫定的に解消するために、想定したFPSよりも低い環境で描画された場合、必要に応じてトレイル後方を透過し間延びを防ぐ機能を実装した。


このシェーダーはモデルとセットでVRChatユーザーに向けて配布することを想定して開発したが、構造が複雑化したことでUnityに明るくないユーザーが使用するのが困難となることが危惧された。
特にユーザーが各々のアバターに合わせて位置やスケールを変更した場合にRenderTextureとカメラの撮影領域にズレが生じることは大きな問題だった。
これを解消するためセットアップをある程度自動化するエディタ拡張を作成、同梱し設定を簡易化することにした。


当初よりかなり滑らかにトレイルを描画することが可能にはなったが、モーションベクトルなどは使用しておらず、フレーム間の補間を行えていないのでそこで滑らかさは頭打ちとなる。これ以上の表現には頂点間を何らかの形で補間する技術の導入が必須である(ジオメトリシェーダーやテッセレーションを利用することが考えられる)