Shader Graph覚書 〜Textureを合成して簡易キャラクリを実装する〜
最近のゲームでは主人公のキャラクタークリエイトが大体実装されてる
自分で作ったキャラを動かせると楽しいもんね
しかし自作で実装しようとすると大体死ぬ
3Dを作るのも大変なのに、パターン増やしたりサイズや配置も調整可能にしたり、あれこれやろうとしたら過労死しそう
なのでTextureを貼り合わせて簡易実装できないか試した
先に言っておくが、2Dで作ったところで決して楽ではない
ShaderGraphでSpriteを合成させる
完成形はこんな
肌の色、目の色、髪型と色、服上下と色をカスタマイズ

Spriteを参照する
歩行グラフィックなど、画像をアニメーションさせたい場合はTexture 2D Arrayを使うと便利
ParameterにTexture 2D Arrayを追加
今回は体、目、髪型、服上下を設定するので5つ追加
ParameterにFloatを追加
Texture 2D Arrayのインデックス番号を指定する
アニメーションさせる時に便利

Sample Texture 2D Arrayノードをパーツの数だけ追加
各ノードのTextureとIndexに追加したParameterを設定
Textureには各パーツのTexture 2D Arrayを繋ぐ
Indexには全て共通のインデックス番号用Floatを繋ぐ

色変更を設定する
パーツの色変更をしたい場合は、パーツを合成する前に色変更を適用する
ParameterにFloatを追加
Colorで直接色を指定してもいいが、ゲーム中のUI側でRGBを指定できるようにするのが面倒くさい
事前にグラデーションを指定しておき、その中から拾う色をFloatで指定した方がシンプル
今回は肌・目・髪の色はFloat1つ、服上下の色はFloat3つで指定
肌・目・髪は薄い〜濃いの固定のグラデを作っておく
もちろんカラフルにしてもいい
服上下は色相+彩度+明度の組み合わせで作るので3つ用意
RGB指定するより直感的にもわかりやすい
ノードを組むならRGB指定が簡単なのでお好みで
計9つのFloatを追加

Gradientノードを追加し、任意のグラデーションを設定
Sample Gradientノードを追加し、Gradientに前述のノードを、TimeにParameterのFloatを設定
MultiplyノードでTextureと抽出した色を乗算する
これで色相変更はできる

同様にグラデ抽出ノードを構成
これは明度調整用
Blendノードを追加し、各パーツのSample Texture 2D ArrayのColorと調整したColorをブレンド
Hard LightかLinear Lightがおすすめ
Saturationノードを追加し、BlendしたColorをParameterのSaturation用Floatで調整させる
Saturationノードのせいでα値の情報が消えるので、SplitノードとCombineノードを介して元に戻す


各Textureを合成していく
各TextureをAddで足していくと、加算なので色が混ざってしまう
重複する部分を塗り潰すには、下のTextureから上のTextureの範囲を
減算して消す必要がある減算する都合上、処理の順番に注意すること

Subtractノードを追加し、Aに色調整したTexture、Bに上に重ねるTextureのSample Texture 2D Arrayノードからα値を設定
RGBAで減算すると色味によって差が出てしまう
Textureにアンチエイリアスがかかっていると繋ぎ目に隙間ができる可能性がある
今回はドット絵でやってるから考慮しないけど、対策考えた方がいいのか
調整したTextureをそれぞれMaximumで合成する
Addだと減算したα値が元に戻ってしまう

同じ要領で各パーツを重ねていく
Textureが未設定の場合は上手く表示されなくなるので注意
アクセサリーパーツのように着脱したい場合は、透明なTextureを使った方がいい

光源の影響を受けさせるなら、Vertex ColorとTextureをMultiplyノードで乗算してからBase Colorに渡す
AlphaはSplitでRGBAからα値だけを取り出してから繋ぐこと

キャラクリシステムを実装する
画像を用意する
キャラクリ用の画像を用意する
今回は歩行グラフィックをキャラクリできるようにしたい
歩行グラフィックなのでアニメーションが必須
SpriteをMultipleモードにして分割、だとMaterialから参照しづらい
のでTexture 2D Arrayに設定する

これを各パーツ用意する
パーツ数(体、目、髪、服上下)5種類
髪と服はそれぞれ4種類
モーション(歩く、走る、スプリント、しゃがむ、登る、落下、倒れる、その他)8種類くらい
それぞれ6〜8枚くらいのアニメーション
向き(前後左右)4種類
左右はx軸の反転で代用できるので実質3種類
単純計算で5000個以上の画像を描く羽目になる
コピペでなんとかなる部分もあるのでキッチリ5000個ではないが、楽ではない
何故手を出してしまったのか
Materialを作る
Materialに作成したShader Graphを設定
各パラメーターに初期値を設定
適当なゲームオブジェクトにSprite Rendererを追加し、作成したMaterialを適用
MainTexを使用してないため、Sprite Rendererに設定されたSpriteは表示されない
サイズは設定したSpriteに依存するので注意
2D Object > Sprite > Square がオススメ
落ち影をつけたい時にはDebugモードでCast ShadowをOnにするのも忘れず
3D Object > Planeでもいいけど、環境光が反映されるせいで色味が変わる
初期値に設定されたTextureが合成されていることを確認

スクリプトを作る
Material ParameterをC#スクリプトで変更できるようにする
MaterialのTexture 2D Arrayに設定された画像を変更すれば、ゲーム中でも合成される画像を変更できる
勿論、色調変更も可
スクリプトの書き方は省略
ググればいっぱい出てくるから

アニメーションを作る
合成した画像をアニメーションさせる場合は、マテリアルのパラメーターを操作すると簡単
全てのTextureがIndexパラメーターを参照しているので、Indexの値を0、1、2、と操作すれば全てのTextureをまとめて操作できる
数値の補完をConstantにするのを忘れないこと


セーブ&ロードシステムを作る?
Materialのパラメーターを直接いじるので、テストプレイ中でも変更が保持される
初期化処理を入れるのを忘れず
ビルド後にどうなるかは未確認
保持されるならセーブシステム作らなくて済むから楽だな