去年末から続いていた余裕のない日々も終息し、仕事以外であれこれ考える時間が持てるようになった。その間にアンリアルエンジンは当たり前に進化、ユーザーもますます増えて共有される情報も豊富になり、取り残されたたような寂しさを感じています。
このブログもほぼ1年間更新していないにもかかわらず、それなりのアクセス数に何となく後ろめたさを覚えつつも、少しでも誰かの役に立てているかと思うと書いてよかったと思っています。
さてさて
ゲージ100本ノック
発端は、チームメンバーの後輩がシェーダーを勉強しようと既存のアセットを睨みながら難しい顔をしているのを見て、いい教材がないことに気づいたことだった。
UI でシェーダーを使う機会は多いと思う。(UEからUIのお仕事を始めた方にはマテリアルと言ったほうがいいかもしれないけど、ひとまず シェーダー と表記して進めます)
使わなくても UI は作れますが、使いこなせばいろいろな場面で調整が簡単になったり、テクスチャが節約できたり、面白い表現を載せることができたりします。
応用力がモノを言うので、ひらめきをすぐに形にできるようにしたいですね。
扱うノードの種類はそれほど多くないので覚えるのはすぐだけど、扱う機会が少ないと応用する以前に扱いを忘れてしまうという といった話をよく耳にします。
また UI で扱うのはテクスチャや画像イメージの操作が主なので、特殊でもなんでもなく、アイデアをネットで見つけるのが難しい。
UIアーティストとしてのキャリアパスを考えたときに、果たしてシェーダーが扱えることのアドバンテージについては、所属組織による判断のウェイト次第なので、オススメ!くらいの温度感にしておきます。
話を戻します。
渋い表情の後輩を前に、教材も充実していないのにも関わらず つい、
ゲージを100本作ったら さすがに覚えられるよ
と言い放ってしまった。
そのときはお互い乾いた笑いでその場は流しました。
言ってしまってから、ほんとに100本も作れるのか?という疑問が重くのしかかり、実際にリストアップしてみることにした。ところが、いざ作り方を分類してみると大して作り方にバリエーションがないことが判明。やばいと思って今度は実際にシェーダーを作り始めてみる。そして気づく。テンプレのバリエーションが少ないことに。
あくまでもシェーダーに慣れてサクサク扱えるようになるため反復練習は大事。 一度うまくいっても忘れてしまうのはもったいない。ということで 何かドリルのようなものを作れないかという発想に至りました。プラスをマイナスにする、というようなちょっとした変更も数に入れています。決して水増しでは・・・けっして・・ゲフンゲフン
X(旧Twitter)にあげたゲージサンプルをこのブログで解説していきます。
Xで見てどうやって作るのか自身で試してもらって、このブログで答え合わせする、といった使い方をしてもらえるとよいのかなと考えています。
ただ見た目は同じでも別の手法で再現可能というのが結構出てきます。一つの方法にこだわらず柔軟な考え方で取り組んでアレンジを楽めるといいですね。ゲームの世界観にあった、素敵なゲージデザインに役立てることを願うばかりです。
ゲージの増減アニメーションについては、サンプル用に大量のマテリアルを同時に動かしたかったので、MaterialParameterCollectionアセットを使用しています。

Timelineノードの中はこんな感じ

Materialのグラフで CollectionParameterノードを使っています


ゲームに組み込む際は ScalarParameterノードを使うことが多いと思います。

今回の記事では、CollectionParameter をつないだサンプルになっています。
そもそも棒ゲージは、スケールアニメーション(拡縮)でも十分機能しますが、デザインの幅が広がらないのと、成長要素など長さが可変だったりすると、いろいろ面倒なので、個人的にシェーダーで作るゲージをお勧めします。
リニアなグラデーションさえあれば、簡単にゲージになります。
ここでいう「リニア」というのは、最小値から最大値への変化、0~1.0 とか 0~255 が歪みなくまっすぐな状態です。1→2→4→5→5→7→8... ではなく 1→2→3→4→5→6→7...
リニアじゃないゲージは信頼度が下がってしまいます。
仕組みとして難しいことはしなくて、グラデーションを2階調化するだけ。

TexCoord ノードからリニアなグラデーションを取り出せるのでよく使います。
テクスチャと違い解像度やピクセルの圧縮を気にする必要がないので、どんなサイズでも精度の高いゲージにできます。

前置きはこの辺にして
まずは、テクスチャを使わないシリーズ16選の解説を書いていきます。

上下左右の反転はシェーダーでやらなくてもよかったりしますが、UVの扱いに慣れておくほうがいいので、あえて数に入れました(決して水増しなどではないゲフゲフ)
ゲージの形については設定していません。テクスチャを使っていないので、長さや縦横のバランスは自由です。
1.左から右へ

シンプルに伸び縮みするタイプ。本体のみなので、別に用意した背景と組み合わせることでデザインに組み込みやすい。

Step ノードを使っています。これは Photoshop で説明するなら 「2階調化」を行っています。TexCoordノードから UV値が取り出せるのですが、リニアなグラデーションになっているので、2階調化で「しきい値」を動かすことでゲージとして利用します。
Opacity につなぐと 0が透明、1が不透明となります。
2. 右から左へ

ゲージの向きを反転するために、1-x ノード(ワンマイナス)を使用。

UVの値はテクスチャを貼るための座標として使用されますが、左上が (0, 0)で、右下が(1, 1)
1 から引くことで 値がひっくり返り、結果 反転します。
3. 4. 上下の動き

ComponentMask ノードで水平と垂直を切り替え。
1 の Mask( R ) を Mask( G ) 変更するだけです。

1-x (ワンマイナス)ノードを入れると逆向きに

このタイプはゲージ本体のみで背景が透過しているので、下敷きのテクスチャデザインと組み合わせやすいのがウリ。

5. ~ 8. 背景をつける

ゲージは今どの辺?あとどれくらい?などを示すために、最小と最大の範囲が視覚的にわかるようにしないといけないので背景をセットにしたタイプ。画面で描画するパーツ数を減らせるのがウリ。ただ枠がないので背景によっては視認性が下がったり、安っぽさは出てしまいます。
ゲージ全体が不透明なので Opacity 外します。

Lerp ノード(LinearInterporate)でゲージ本体と背景に着色しています。よく使う手法なので、覚えておくと大変重宝します。
ComponentMaskを切り替えると、縦と横をスイッチできます。
1-x(OneMinus)ノードを差し込むと向きを逆にできます。
基本は 1. ~ 4. と同じなので参考画像は上の一枚だけにします。
9. 中央から

TexCoordノードから出てくるUV値は何も手を加えないと、 0~1 ですが、ちょっと細工するといろいろな値にできます。
ここでは、

活躍するのが Abs ノード で 絶対値(AbsoluteValue)に変換します。
UV値の U から 0.5を引くと -0.5 ~ +0.5 になって、2を掛けて -1.0 ~ +1.0
これを Abs で正の値にして完成。

10. 円形のやつ

ただ丸を拡大縮小しているだけですが、一応ゲージとして機能するのではないかと背景をつけてみました。実際には拡縮ではなく円形のグラデーションを利用しています。
割合が分かりやすいかといえば、ちょっと難しいかも。ざっくり満タンかどうかの2段階でいいなら、クールタイムやフィーバータイムがあるようなタイプのゲージに向いているかと思います。
ここではゲージというより、円形の作り方に焦点を当てたいと思います。
計算で円を描くためには計算が必要になるのですが
アンリアルエンジンには便利なノードが用意されています。
VectorToRadialValue ノードです。

出力ピン LinearDistance の計算だけを取り出すとこんな感じ。

こんな計算式覚えられんし、ノードが多い!
とお嘆きの方に朗報
関数が一つ増えることにはなりますが、 Length ノードを使うとシンプルになります。

TexCoordノードの Tiling初期値は 1.0 なので戻しました。中にあるのは便利なのですが外から見えにくいので、事故りやすいと思う。展開するのも面倒だし邪魔だし・・・
VectorToRadialValueノードはUEにしかないので、Length ノードで組んでみました。

11. 円グラフなやつ

僕はピクミンに登場する敵の体力ゲージが強く印象に残っています。
角度がゲージになるので、下図のようなグラデーションがあれば実現できます。

VectorToRadialValueノードにはこのグラデーションも出力してくれるので、甘えることにしました。

この段階でいったん完成としておきます
つまり、いい感じのグラデーションさえあれば、なんでもゲージになります。
VectorTo~ノードは、何もせずにつなぐと時計で3時の方向から始まります

出力ピン Vector Convert to Angle の計算だけを取り出すとこんな感じ。

Arctangent2 (アークタンジェント2) ノードを使用して、座標を角度に変換します。それを 2π であるところの 6.2831~ で割ってFrac を使って1以下の小数部分のみにして完成。
なるほど、ナルホド、ふむふむ・・・
ということで、次の 12. で向きを変えてみます。
12. 円グラフなやつ2

左が VectorToRadialValue を使っていて、右が使わなかったバージョンです。
回転させるには、UVをどうにか加工してやります。

まず円形を作るためには、UVのゼロ原点を左上から、中央に移動してやる必要があります。2 倍 して 1 引くだけでOK(上図の右上)
UとVを入れ替えるだけで 逆時計回りに90度回転します。ゲージの増減方向としては時計回りにしたいので上下を反転させています。
VectorToRadialValue ノードの入力ピンに、 Vector or UVs (V2) というピンがあるので、ここに90度回すための計算結果をつなぎます。

これで向きは期待通りになりました。
角度を使ったゲージは、時計の12時から始まったほうが直感的かなと思うのですが、いろいろ試してみてゲームに合った開始角度を見つけるといいと思います。
中身を見てしまうと、なんだか計算に無駄があるような気がしないでもないので、VectorToRadialValue ノードを使わないバージョンを作ってみました。

Arctangent2 ノードは三角関数が使われていてそれなりの計算負荷がかかります。三角関数を使わない方法もあるのですが、今回の趣旨と外れるのでまた別の機会に。
13. 一定量ずつ増減するやつ

これは通常の棒ゲージでもこの表現は可能ですが、このあとのテクスチャを使った表現への布石でもあります。
実際 0~1 を滑らかに値が変化していますが、あえて10段階な見え方にしています。
Countというパラメータ(ScalarParameterValueノード)を変更すると分割数を変更できます。
プログラム処理を変更することなく、シェーダーの工夫だけで見た目を変えることができます。
ここで活躍するのが Floor ノード。これは小数部分をざっくりと切り捨ててくれます。

上は グラデーションもゲージの値 両方を10倍して Stepノードで比較する
下は ゲージの値だけ10倍して 切り捨ててから 10で割ることで 0~1の範囲に戻す

割り算を使うか使わないかの違いです。
14. ゲージに着色する

5.~8. のカラーの部分を改造して作ります。テクスチャを使わなくてもちょっとだけリッチに見えます。
Lerpノードを2重に使うことにはなるけど、テクスチャが不要なのでメモリは節約できます。

15. ゲージ量で色が変わるやつ

ゲージの長さに連動して色も変えることで、アクションゲームなどのじっくりゲージを見ながら遊ぶことができないようなゲームで効果を発揮します。
ここでも Lerpノードが活躍します。


Lerpノードは AとBを線形補間 するので、セットしたカラーの組み合わせによっては微妙な色になるので注意。

これを解消するには、テクスチャを使うのが確実です。
16. 満タンの時に色が変わるやつ

ゲージは割合を表すことが多いので、成長やバフなどで全体量(分母)が大きくなってくると、ゲージは増減幅が微妙になります。また満タンであることに何かしらのボーナスや特別な仕様がある場合に必要な表現です。格ゲーのノーダメージボーナスとか。

今回はここまで。
あえて
テクスチャを使わずに作るゲージでシンプルな仕様のものを並べてみました。
アレンジの素となれば幸いです。
次回はテクスチャを使ったゲージを紹介していきます。
まだ16本。先は長い・・・
シェーダーは、画面に描画したい面積をキッチリ埋めるために、ピクセルのカラーを1ピクセルごとに計算するプログラムです。ピクセル数×計算量がそのまま描画処理への負荷になります。こんなことを書くと、怖くなってプログラマの視線に怯えながらなんて無理!となりそうですが、そもそもゲージってメタ情報です。見せ方がショボいとゲーム画面が安くみえたり、デバッグ表示だよね?と言われたりします。商品価値を下げる恐れもあります。かなりの頻度で画面に表示され続けるので、スクショでも公開され、ある意味ゲームのアイデンティティとなります。プレイヤーの経験によるので絶対はないですが、ゲージの見た目で、何かのタイトルを想像していしまうことってないですか?特に売れたタイトルって長時間プレイされて印象に残っているものです。ゲーム画面のスクショでゲージだけ切り取ってなんのゲームか答えるクイズがあってもよさそうです。
ゲージデザイン侮るなかれ。
ただデザインがあるだけでもダメだし、プログラマとの連携は必至だし、企画仕様も開発中に変更なんてしょっちゅうで、そのたびに構造や表現をメンテナンスすることになります。コンソールゲームが強かった時代は過去になりつつあるのを感じます。スマホやPCのようなマルチ解像度対応に加え、新しい携帯機の出現も考えると、テクスチャの依存度について考えていく必要はありそうです。
ではでは
素敵なゲージライフを