👓

[Unity]URPとShaderGraphで光学迷彩シェーダーを作る

2023/12/02に公開

この記事は、神戸電子専門学校 ゲーム技研部 Advent Calendar 2023の2日目の記事です。
https://qiita.com/advent-calendar/2023/kdgamegiken

光学迷彩

メ〇ルギアのステルス迷彩、攻殻〇動隊の光学迷彩(熱光学式迷彩)みたいなやつです。

Unityで、URPとShaderGraphで作ります。

なお、光学迷彩シェーダのアルゴリズムは、こちらの記事のBRPによる実装を参考にしています。
https://3dcg-school.pro/unity-shader-stealth/

動作確認バージョン

  • 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 SettingsSurface TypeTransparentに設定しておきます。
(このあと画面レンダリング結果のテクスチャを取得するために必要です)

これで準備完了です!!

ShaderGraph上で取得してみる

_CameraOpaqueTextureを取得するには、本来なら_CameraOpaqueTextureと紐づけたテクスチャのプロパティを作ったりと色々やる必要があります。

ですが、なんと1つのノードで全部済ませてくれるScene Color Nodeが用意されています!
(私は一通り頑張って実装してから、これの存在を知りました。。。orz)

https://docs.unity3d.com/ja/Packages/com.unity.shadergraph@10.0/manual/Scene-Color-Node.html

とりあえず、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の全体像

これで完成です!

(見やすいように、前半と後半に分割したスクショも)

おわりに

今回はただテクスチャを取得して歪ませるまででしたが、歪み方にノイズを加えてみたり、僅かにぼかしてみたりすると、もっと良い見た目になりそうな予感がします。

よき光学迷彩ライフを!!

参考記事

https://3dcg-school.pro/unity-shader-stealth/
https://matcha-choco010.net/2018/11/06/unity-lwrp-cameraopaquegexture-grabpass/
https://zenn.dev/fuqunaga/articles/005cb0380d495e

神戸電子専門学校ゲーム技術研究部

Discussion