みつまめ杏仁

アンリアルエンジンでGUIを作るためにゴニョゴニョしてます。UIデザイナーの皆様の助けになれば幸いです。

ゲージ100本ノック 62-65

UIアーティストのためのシェーダを学習するためにゲージを100本作ろうプロジェクトを始めてようやく2/3近くになりました。年内に100本終わりそうにないのは悔しいですがネタを集めつつぼちぼちやっていきます。

今回振動するゲージをネタでいただいたので作ってみました。

 

UIで振動を表現するのは簡単だけど難しい。

振動は、ゲーム内で発生するきっかけによって引き起こされる演出表現。実際にゲージに何かがぶつかっているわけでもないので、物理的なリアクションとして揺らすことができなません。「それっぽい」振動をわざとらしく動かすことになるので、すごくセンスを問われるというか、「いい感じのウソ」を求められるのが難しさだと思うのです。

振動を作るにあたって前提を押さえておくほうがわかりやすくなるかなと思ったので、少し趣向を変えて見出し多めで書いてみようと思います。

 

振れ幅が大事

ゲージを揺らすとき、徐々に揺れがおさまって元の位置に戻ってほしいですよね。ブランコのように、初期位置を起点に往復するように動かすと、折り返し地点はプラスとマイナスの符号が反転するような関係になります。動きながら折り返し地点間の距離がゼロに近づいて動かなくなるイメージ。

 

プラスとマイナスを作る

シェーダーで再現する場合、まず最大の振れ幅を往復させておいて、この振れ幅に少しづつ小さな値を掛け算するとゼロに近づいていきます。

 

 

 

時間で変化するもの

シェーダーは画面に対象が存在していると常に計算され続けます。とくにタイマーを利用していると、開始と終了などというものは存在しないことに気が付くと思います。

エフェクトなど演出的な表現の場合はラジオの音量調節のように、始まりと終わりをコントロールするするための仕組みが必要です。

 

制御したいかどうか

機械的で単純な動きではなくエモい動き、感性に訴えてくるような変形などのたわみ、ひずみなども表現したいし、緩急をコントロールしたい場合があります。その場合は、タイムラインで細かくキーを打ってコントロールするので、シェーダーではオフセット値を受け取ってズラすだけで事足ります。ただ渾身のタイムライン制御で作れたとしても同じ動きで飽きられたり、修正や変更に弱いのが悩みどころ。

 

ランダム感

振動に向きが必要ない、むしろ向きがあると違和感が出る場合などはランダムな動きが向いています。ダメージを受けた際インパクトの方向がゲージに反映されてるとそれなりにリンクしている印象を与えることができます。(プログラマに面倒がられますが)

揺れてること自体が記号(サイン)なので、それほど気にしないしとにかく派手に揺れてほしい場合はランダムな動きが向いています。ただランダムには致命的な欠点があって、同じ値を引いたり変化量が小さい時があります。回避するためにはある程度「ルール」を作ってうまく散らすのが重要になります。

 

向きをどうするか

ランダムではなく揺れの方向を意図的なものにしたい場合、タテとヨコそれぞれの振れ幅を指定して変えられるようにすると、向きを選んで揺らすことになります。

向きがあるということは攻撃エネルギーの向きがわかりやすくなります。たとえばビンタを受けたときの顔は横を向きますよね。また精神的にショックを受けたときは横より縦のほうがエモい印象を与えられそうです。

パラメータとして値をシェーダーに渡すときに、どういった値を渡すかによって運用方法が変わります。

 

画面サイズと見え方

マルチプラットフォームで開発となると解像度が一定じゃないので、デバイスによって見え方が変わってくることがあります。

Widget単体だとうまく差が出ないように補正をかけてくれるようになってます。

今回 WorldPositionノードを利用して揺らしますが、Viewportの解像度を変えてみると振れ幅が同じになりませんでした。

いったんアスペクト比は考慮してなくて16:9 で進めますが下図のような補正を組みました。

エンジンのデフォルト解像度が1920x1080に設定されている(自分の使っているモニタ解像度が 1920x1080 なのを見てくれている?)のでエディタでのレイアウト状況と実際の描画解像度とのギャップを埋めるのが目的です。

今回 16:9 のTVモニタを前提にしていますが、アスペクト比についてもいつも泣かされるので、ターゲットのプラットフォームが見えてきたら早めに検証して対策の準備をしておきたいものです。

 

WorldPositionノードの出力

WorldPositionノードから出てくる値は、XYZ座標なので Vector3(Float3)になってます。

Materialでは、少ない入力に多めに渡す分には問題がないですが、逆はエラーになります。

なので多い側が本数を減らすか、少ない側が本数を増やすかして、できる限り本数を等価にしてエラーを回避します。

増やすときは Append MakeFloat系ノードで。減らすときは ComponentMaskノードを使います。

今回紹介している4パターンは、どれもシレっと増やしてつないでます。

 

 

ゲージ本体

今回紹介する4タイプは、揺らし方についてのバリエーションになります。

ゲージの増減部分は同じ仕様のコピペで以下のようになっています。

 

あとは Screen Positionのピンに どのようなオフセット値を渡すかがポイント。

 

揺らす仕組みとゲージデザインは干渉しあうことはないので、お好きなゲージで試せます。

以下の記事でスクショの面積を節約するために上のゲージ増減部分は見切れますがご容赦いただけると助かります。

 

ではそろそろ各ゲージについて

 

 

62. ノイズテクスチャでランダムな振動

揺らすためのテクスチャ 64x64 を用意しました

のノイズを加算合成したものになります。

チャンネルのRとG をそれぞれ XとY方向の移動量として扱うためです。

テクスチャ圧縮による劣化を抑えるために は 全て 0 です。

テクスチャ設定のフィルタは滑らかな動きを期待していないのでNearestです

 

テクスチャの UVサイズをゼロに潰すことで、ゲージ全体を同じ移動量にします。Pannerノードで移動速度と方向を決定。

TextureSamplerから出てくる値は RGBAそれぞれ 0~1.0 なので、0.5 を引き算してやることで -0.5 ~ +0.5 になります。

調整しやすくするために、 -1 ~ +1 にしたい欲求にかられますが、最終的に揺れ幅を掛け算で調整するので、計算ノードを少しでも減らすためにガマン。なので揺れ幅については倍の値を指定すると丁度よくなります。揺れ幅 を調整するために ScalarParameterノード(Scale と命名)をつないでいます。ゼロにすると揺れは止まります。

 

これを、WorldPosition ノードに加算します。

このとき解像度の補正を掛けてから加算するようにします。

 

Pannerノードの Speed値にいろんな値を入れて試してみると面白いです。

あと、Pannerの前の UVに掛ける値をゼロ以外にすればどうなるか。

単なる振動ではなくなってしまいますね。狂気じみた印象を与えられそう。

これはこれで使いどころはありそうです。

 

ノイズテクスチャを意図的なものにすることで、またちょっと変わった動きを作ることもできそうです。

たとえばこんなテクスチャに差し替えてみると

拍動を感じるようになりました。

 

ネットにはランダム値を生成するシェーダーがたくさん紹介されているので、興味のある方はそちらを試してみてください。UI表示でゲージを揺らすだけと考えるとコスパが悪すぎるので見送りました。

計算だけでどうにかするのも面白いのですが、テクスチャを使うことで表情を変えてくれます。組織で開発している場合は調整担当の職域も変わってきたりします。このあたりのバランス感覚は、属人化を回避するするためにも、日ごろから磨いて対策できるようにしておきたいものです。

 

 

63. 三角関数の回転で振動

三角関数でくるくる回します。

くるくるといっても、高速で回すと角度の変化が大きいので、結果ガクガクするような見た目になります。

 

サインとコサインは角度情報を渡すと 円周上のXY座標が求められるので、角度を限定的に動かすと揺れの向きを制御することもできます。

 

回転速度を1にすると

ちゃんと回っているのがわかります

半経をゼロにすると、位置が中央に戻り揺れが収まります。

見た目に動いていなくても計算はずっと続いています。

 

 

 

64. Stepノードを使ったプラスマイナスの動き

タイマーで流れてくる値を Fractionノードで 0~1.0未満の値にして Stepノードで 0 と 1 にする。そこからSubtractで 0.5 を引いて ±0.5 にしたら、VectorParameterノードで縦と横の振れ幅を指定して掛け算します。

62.でテクスチャに対して Stepノード使いましたが、64.はタイマーの時間に対してStepノードを使います。

イメージしやすそうな状況で例えてみると、

62.は地面に書かれた数字を移動しながら読み取っていく動き。64.は数字の書かれたボードが迫ってくるのでそれに従う動き。

その数字を確定するために Stepノードを使うイメージです。

 

パラメータの内容で揺れる方向と量が指定できます。

上の例では、G(縦方向)に 10 なので、±0.5 とかけて 最終的に -5 と +5 をスイッチするように動きます。R(横方向)はゼロなので縦しか動きません。

R と G の比率で振動する方向が変化します。62.や 63.は「」の動きですが、これは「」の動きになります。

 

 

 

 

65. Lerpノードでプラスマイナスの動き

 

64.と同じ「」の動きですが、Lerpノードを使って移動範囲の指定を柔軟にできるようにします。

2つの地点を 63.の方法でスイッチするのがこの方法。

パラメータの内容は以下のようにしています。

R と G が 横方向、 B と A が 縦方向の指定になります。

2か所を指定して往復するかたちなのでお好みの順番で値をセットし、タテ用とヨコ用の値が交わらないように接続すれば大丈夫。

 

 

いかがでしたか?今回は4本紹介しました。

ほかの方法を思いついたら新しいゲージとしてナンバリングして書こうと思います。

とりあえず揺れはするけど常にガクブルしているので落ち着かせたくなります。

次回はこの振動するゲージを、前回の記事で作ったテストプロジェクトに組み込んでみようと思います。

 

いろいろ締め切りが詰まってたりして慌ただしい毎日を過ごしておりますが、あと一回くらいはアップしたいです。

 

ではでは

素敵なゲージライフを!