某ゲームのクリスタルっぽい表現をShaderGraphで作ってみた

# はじめに
この投稿は[グレンジ Advent Calendar 2022](https://qiita.com/advent-calendar/2022/grenge)の最終日(12/25)の記事です。

メリークリスマス！
[株式会社グレンジ](https://www.grenge.co.jp/)でクライアントエンジニアをしているGamu([@AblerBiri](https://twitter.com/ablerbiri))です。

私が今年貯めてきた小ネタを投稿していこうと思います。
今回はその第2弾です。

当記事では、某ゲームに出てくるクリスタルっぽい表現をShaderGraphで作ったので、その中身を紹介します。

当記事で作成できるものはこちらです。
完全再現は出来ませんでしたが、それっぽいものは出来たのではないかと思います。
<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/5ec93acb-9a09-5012-b8ab-2838de98372e.gif">

### 動作環境
- Windows 10 home 64 bit
- Unity 2021.3.10f1
- Universal RP 12.1.7
- Shader Graph 12.1.7

# 事前準備
当記事では、Unity標準のSphereを使います。

まずは、ShaderGraphでシェーダを作成します。
Projectタブでメニューを開き、Create > Shader Graph > URP > Unlit Shader Graphを選択します。
Built-in RPを使っている場合は、Create > Shader Graph > Builtin > Unlit Shader Graphを選択します。
シェーダを作成したら、それを使ったマテリアルを作成します。
シーン上でSphereを新規作成し、そのSphereに作成したマテリアルをアタッチします。
<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/8aacc3d2-4889-2d62-a014-de664e0fc879.png">

次に、発光が映える環境を準備します。
シーン上のディレクショナルライトを削除するか、下から上へ向くように角度を調整します。
シーン上でVolumeを作成し、Bloomを有効にします。
<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/779047a5-eae1-7a6e-a7ae-3fbcf6062208.png">

Built-in RPを使っている場合は、Post Processing Stack v2でBloomを有効にします。
<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/f923a097-752b-987f-289d-0055da3a7a08.png">

# 工程
### Voronoiでカットを作る
Shader Graphの編集画面を開き、Voronoiノードを作成します。
Voronoiノードはセルラーノイズとボロノイ図を同時に作成することができるノードです。
ボロノイ図を使って宝石カットのような見た目を作ります。
<table>
<td>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/45977e1d-64a8-ff73-5d30-bc09722facda.png">
</td>
<td>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/b3d94d18-8a6e-6304-f870-e933fdfac19c.png">
</td>
</table>

### SphereのUVを考慮してボロノイ図を補正する
UnityのSphereは上下に頂点が密集しているため、密集しすぎないようにUVを補正します。
この処理はCorrectSphereUVというSub Graphとして作成しました。
<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/621c1750-c4ee-f202-5866-f515b7fc5224.png">

CorrectSphereUVで補正したUVを使用するとボロノイ図は次の画像のように変形します。
<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/d3954327-4e0d-7a43-35dd-74056045f246.png">

### ボロノイ図から法線ベクトルを作成する
次に、ボロノイ図を使ってSphereの法線ベクトルを作成します。
この処理はCrystalNormalというSub Graphとして作成しました。
<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/86fe0d81-c8e6-d59a-ca1e-bce472a15a7d.png">

CrystalNormalを使ってボロノイ図から法線ベクトルを作成すると次の画像のようになります。
<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/e5912aa5-3093-82ec-a869-dd7c2da19e63.png">

### 拡散反射を計算する
基本的なLambert拡散反射を計算します。
この処理はCrystalDiffuseというSub Graphで作成しました。
<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/cb99dc81-34c6-009f-ca07-22c81cbadb26.png">


Albedoマップ、環境光をプロパティで用意して、拡散反射の値を使って補間します。
<table>
<td>
<img width="100%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/c1a7227e-146f-a8d2-775a-9cdd567581f2.png">
</td>
<td>
<img width="100%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/973dc885-2d93-8ab2-4e10-ea6f8c1c7b47.png">
</td>
</table>

さらに、通常のSphereの法線を使った拡散反射も計算してブレンドします。
<table>
<td>
<img width="100%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/afaeb9b4-5444-9e62-9202-fd6e2c306e3d.png">
</td>
<td>
<img width="100%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/fac8b802-d5f9-1ec2-0262-75f67b5562a2.png">
</td>
</table>

### 鏡面反射を計算する
基本的なPhong鏡面反射を計算します。
この処理はCrystalSpecularというSub Graphで作成しました。
<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/84a83673-73d2-e1ba-01b2-7afaed5f7e86.png">

上下からライトで照らすように鏡面反射の計算を2回行ってブレンドします。
<table>
<td>
<img width="100%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/bdac3366-1e57-b02a-ee86-d65f8f87cc92.png">
</td>
<td>
<img width="100%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/900d4bc3-311b-c718-40d3-163c3db90608.png">
</td>
</table>

### 鏡面反射のエッジを強調する
ここまでの工程だけだとクリスタルっぽい反射というには微妙な感じがします。
鏡面反射の値を使ってエッジを強調します。
<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/a0c3b423-348b-2a7f-1399-f473ce0f27c2.png">

注目すべきなのは、Voronoiノードのセルラーノイズを使うことで鏡面反射のエッジを強調していることです。
セルラーノイズは最初からエッジに近いほど値が大きくなる特徴があるので、これを利用しています。

これを通常の鏡面反射とブレンドして、パラメータを調整することでエッジが効いた鏡面反射になります。
<table>
<td>
<img width="100%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/c1ef18bd-e7c0-fdfb-4e82-0b1f3cdb20c0.png">
</td>
<td>
<img width="100%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/c693dc52-0d20-01c6-5368-ea415345cad6.png">
</td>
</table>

### リムライトを計算する
視線ベクトルと法線ベクトルを使ったリムライトを計算します。
この処理はCrystalRimLightというSub Graphで作成しました。
<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/065e02d9-22a5-c259-238b-332cd2835637.png">

パラメータのRimLightCoefを10等の高めの値にしておくとBloomが掛かって綺麗になります。
<table>
<td>
<img width="100%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/0dca60e4-4a7c-8a99-0439-b324c367bd56.png">
</td>
<td>
<img width="100%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/f0f95578-9ea7-369d-3ca8-beeaf742dd31.png">
</td>
</table>

### 各要素をブレンドする
拡散反射、鏡面反射、リムライトをブレンドします。
鏡面反射とリムライトは発光色を乗算してからブレンドします。
<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/39584109-e4d9-50dc-34b0-4874339b39dc.png">

### 完成
パラメータを調整したら完成です。
<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/bb1b46ae-f46c-5064-c1be-d327843da426.png">

<img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225590/5ec93acb-9a09-5012-b8ab-2838de98372e.gif">

# さいごに
そこまで凝ったことをせずにクリスタルっぽいシェーダを作ってみました。
Shader GraphはVoronoiが1ノードで作れるのが良いですね。

本当は、色収差やグレアを追加してより似せた表現を行いたかったのですが、時間切れとなってしまい断念しました。
一般的なクリスタルシェーダは様々な方がシェーダを公開されているので、そちらを参考にすると良いと思います！

2022年のGrenge Advent Calenderはこれにて終了です！
今年はあまり注力して取り組めなかったので来年は今年より盛り上げていきたいです！

それでは皆さん、良いお年を！