[Unity]URPとShaderGraphで光学迷彩シェーダーを作る
この記事は、神戸電子専門学校 ゲーム技研部 Advent Calendar 2023の2日目の記事です。
光学迷彩
メ〇ルギアのステルス迷彩、攻殻〇動隊の光学迷彩(熱光学式迷彩)みたいなやつです。
Unityで、URPとShaderGraphで作ります。
なお、光学迷彩シェーダのアルゴリズムは、こちらの記事のBRPによる実装を参考にしています。
動作確認バージョン
- Unity 2022.3.12f1
- Universal RP 14.0.9
ShaderGraphを作成する
URPのUnlit Shader Graph
を作成します。
名前はOpticalCamouflageShader
とでもしておきます。
画面のテクスチャを取得してずらす
光学迷彩特有の透明で歪んだ見た目は、画面レンダリング結果のテクスチャを歪ませることで擬似的に表現します。
BRPではGrabPass
を使うだけで、簡単にレンダリング結果をテクスチャとしてシェーダー内で使うことができました。
しかし、URPにはこの機能がありません。
そこで、代替機能として_CameraOpaqueTexture
を使います。
画面のテクスチャを取得できるようにする
さっそく_CameraOpaqueTexture
を使いたいところなのですが、その前に適切に設定をしておく必要があります。
まずは、使用しているURPの設定でCameraOpaqueTextureを有効化しておきます。
(ここではテンプレートそのままを使っているので、Assets/Settings/URP-HighFidelity.asset
を編集しました。)
つづいて、作成したShader Graphを開いて、
必ず、Graph Settings
のSurface Type
をTransparent
に設定しておきます。
(このあと画面レンダリング結果のテクスチャを取得するために必要です)
これで準備完了です!!
ShaderGraph上で取得してみる
_CameraOpaqueTexture
を取得するには、本来なら_CameraOpaqueTexture
と紐づけたテクスチャのプロパティを作ったりと色々やる必要があります。
ですが、なんと1つのノードで全部済ませてくれるScene Color Node
が用意されています!
(私は一通り頑張って実装してから、これの存在を知りました。。。orz)
とりあえず、Scene Color
ノードを作って、FragmentのBaseColorに接続してみます。
それでは、早速使ってみます。
いったんSaveAssetしてから、
新しいマテリアルを作成して、マテリアルが作ったシェーダーを使用するように設定します。
(ここでは特にカテゴリ設定していないので、Shader Graphs/OpticalCamouflageShader
にありました)
そして、早速マテリアルを適用してみます…消えた?!
まぁ当然といえば当然です。
シーンの描画結果をそのまま取ってきて描画したので、背景に完全に溶け込んだ、カンペキな光学迷彩の状態ということになります。
UVをずらす
これではキャラクターがどこにいるか分からないので、とりあえずUVをずらしてみます。
ずらし度合いの値を設定するため、Vector2のプロパティUVScale
を追加します。
デフォルト値は、(1,1)に設定しておきます。
あとは、Screen Position
ノードで取得した画面のUV座標と、さっき作成したUVScale
を掛け合わせて、ずらし度合いを計算し、Scene Color
ノードの入力UV
に接続します。
とりあえずここでSavaAssetして、マテリアルのUVScale
を弄ってみると…
ずれてる!!!良い感じ!
色味を弄る
〇タルギアのステルス迷彩は特に、ゲーム的に見やすくするために色味が調整されています。
というわけでやってみます。
Vector2のプロパティMixColor
を追加します。
デフォルト値は、完全な白(255,255,255,255)にしておきます。
あとは、Scene Color
で取得している色と掛け合わせて、FragmentのBaseColor
に接続します。
ここで再び、SaveAssetして、マテリアルのMixColor
を弄ってみると…
めっちゃメタ〇ギア!!
歪みを付ける
既にここまでだけでも充分にそれっぽいですが、まだ形状を把握しづらいですし、歪みを付けていきます。
歪み度合いを計算
カメラに対して面が斜めであるほど、歪みを強くしてみるといい感じになりそうです。
「面の法線」と「面からカメラに向かうベクトル」の内積を求めることで、斜め度合いを計算します。
まずは、カメラに向かうベクトルを求めます。
カメラ位置から、ワールド座標を引いて、それを正規化するだけです。
つづいて、「法線」と「面からカメラに向かうベクトル」の内積を求めます。
この値のままでは、カメラに対して面が斜めであるほど0に近づく(歪みが小さくなる)ので、これをOne Minus
ノードで逆にしてあげます。
これで歪み度合いが算出できたので、Screen Positionで取得してきた座標に加算します。
(下図で青い枠になってる箇所が、ここでの追記箇所です。)
ここで、SaveAssetして仕上がりを確認してみます。
とりあえず歪みました!
面の向きを使って算出したので、凹凸感もちゃんと分かるようになりました。
なんかガラスっぽいので歪み方を変える
確かに歪んではいますが、どこかガラスっぽくなってしまいました。
(凹レンズとか凸レンズの違いっぽい感じ…)
内積して求めた歪み具合いの値に、-1
を掛けて正負反転してみます。
良い感じの歪み方になりました。
歪み方を調整できるようにする
歪みすぎなので、歪み方をマテリアルで調整できるようにします。
FloatのプロパティRimLevel
を追加します
RimLevel
の分だけべき乗してあげます。
良い感じに弄れるようになりました!
最終的なShaderGraphの全体像
これで完成です!
(見やすいように、前半と後半に分割したスクショも)
おわりに
今回はただテクスチャを取得して歪ませるまででしたが、歪み方にノイズを加えてみたり、僅かにぼかしてみたりすると、もっと良い見た目になりそうな予感がします。
よき光学迷彩ライフを!!
参考記事
Discussion