ゲームの境界

ゲームUXからUI実装まで取り上げます UI/UE/UMG

【UE/UMG】プロシージャル手法で作成したマテリアルで汎用的なボタン部品を作成する(前編)

UMGに関する情報は分散していて、なかなか教科書的な使い方がわからないものです。ここでは9Slice,GetUserInterfaceUVなどを使い、プロシージャルな手法で作成したマテリアルと組み合わせて汎用性の高いボタンを作成することを目指します。

要件

  1. サイズ毎に部品を作る必要を減らすためリサイズ可能であること
  2. 解像度依存を減らすためにテクスチャを減らすこと
  3. ボタンアニメーションを調整しやすい形で実装すること

これらの開発現場での要求に即した作り方をまとめてみました。

作例

今回は角丸あり、枠線ありの矩形ボタンを作成することにします。同様の手法でどのような形状が作れるか・または作れないか、は別途検討します。

マテリアル

要件1と2を満たすことのできるマテリアルはプロシージャルな手法で作成することになります。9Sliceを利用することを想定して正方形を4分割し、それぞれをボタンフレームの4角として割り当てるように見た目を形成します。この際、肝になるのは下記の2点です。

  • 角丸の半径と枠線の太さを設定できるScalarParameterを用意する
    • raduis・・・角丸の半径
    • thickness・・・枠線の太さ
  • UVについてはGetUserInterfaceUVから取得する
    • ピン「9-Slice UV」は9Slice設定を反映したUVが導かれる
    • ピン「NormalizedUV」は9Slice設定を無視したUVが導かれる

WidgetBPデザイナー画面:Imageパネル

ウィジェットブループリントでのImageパネルの設定は下記のように行います。「アピアランス」のDrawAsをBoxとして、Margin値とImageSize値にて9Sliceの設定を行います。各値の設定値に癖があるので図解しました。

ボタンテキストの設定

要件1にあるリサイズ可能性を維持するため、テキストのフォントサイズもボタンサイズに合った形で拡縮するような配置を検討します。フォントサイズ値を随時変更するのはあまり現実的ではないのでScaleBoxパネルを利用してみます。

WBP_Btnと名付けたユーザーウィジェットは下記のような階層と設定を持つようにしました。

上図の設定により、このユーザーウィジェットをCanvasPanel等に配置した親ウィジェットでサイズ指定を行うと、そのサイズに沿ったボタン形状やフォントサイズに変更されます。

【留意点】UEのフォントはサイズが変更されるごとにメモリにそのサイズ用のフォントテクスチャが展開されるらしい?のでメモリ量には気を付ける必要があるかもしれません。

テキストのオーバーライド設定

ボタン関連のワークフローでいうと、ボタン内の可変内容物(テキストやアイコンなど)をどのようにプログラムとやり取りするか、という問題が常に存在します。

UE以外のエンジンではボタン部品の内部オブジェクトを部品を配置した親レイアウトから上書き(オーバーライド)する機能を持たせ、親レイアウトの各ボタンインスタンスでテキストを設定させるのが一般的な様に思います。ただUEではその機能は明示的に紹介されておらず、NamedSlotパネルなどの代替方法を紹介されるのですが、これはテキストアニメーションとは相性が悪くこの場合には向きません。

結局プログラマに直接対象のオブジェクトをスコープしてテキスト代入してもらうことになることが多いのではないかと思いますが、ここでは別の方法を紹介します。(ただパフォーマンスの懸念もあるのでその懸念を併記しておきます)

WBP_Btnボタン内に一つのテキストPanelであるtxt_valueを持つとして、グラフ画面にて新たにText型の変数txtValueを作成します(名称は何でも良い)。インスタンス編集可能設定を行い(もしくは変数の右端の目マークを開かせる)外部から編集可能にします。

Text型変数txtValueの作成と設定

デザイナー画面にもどり、テキストボックスのテキスト設定右の「バインド」プルダウンに先ほど作成したtxtValueが選択肢に追加されるので、これを選択します。

テキストバインドの設定

このボタンを配置した親部品に配置すると、その設定項目「デフォルト」に先ほど設定したtxtValueの項目が表示されるので、ここでボタンインスタンスごとにテキストを設定することが可能になります。

親レイアウトのインスタンス毎にtxtValueを上書き設定できる
実行するとボタンテキストが設定したtxtValueに差し変わっているのがわかる

ただし、この「バインド」を使う方法は毎フレーム処理が走る、ということから基本的に非推奨であるという認識があります。

今回は単にテキスト変数を呼んでいるだけなので、そこまでパフォーマンスに影響を与えるかは調べてみないとわかりませんが、このワークフロー上有意義な仕組みを採用するか、プログラマと相談する価値があるのではないかと思います。

後編はボタンアニメーションなどについて触れていく予定です。

【UE/UMG】射影変換で自由変形を実現するマテリアル(移植編)

UMGの持つトランスフォーム機能は「移動」「回転」「拡大」「シアー」の4つがあり、幾何学的にはアフィン変換と呼ばれる座標変換処理にあたるもので実現されています。

UI実装者はこの機能を使いレイアウトやインタラクション実装を行っていますが、この仕組みだけでは物足らないと感じる場合があります。特に疑似的な立体表現としての台形への変形を行いたい時でしょう。(Photoshopでいうところの「自由変形」のように処理したい)

例えばUBISOFTの『DIVISION2』やプラチナゲームスの『アストラルチェイン』などではプレイヤーのステータス画面の実在感を高めるため、3Dのプレイヤーモデルとの位置関係を空間的にし、若干の傾きを持った板のように表現しています。ただこれらは実装上はレベル内に配置した一枚の板ポリゴンにUIレイヤーを張り付けた、いわゆる3DUIと呼ばれるものではないかと思われます。

『DIVISION2』台形に変換されたプレイヤーメニュー

UEにもアクターにウィジェットBPを張り付けて3DUIとして扱う機能は存在しますが、3DUIは一般的に取り扱いが難しく、特にビューポートにレイアウトを固定したい要素については結局カメラとの位置関係や挙動を構築するのにコストがかかってしまうため、細かいちょっとした要素に使うには向いていません。

(蛇足ですが、サイバーパンク2077やDESTINY2ではHUDにレンズ的湾曲表現を取り入れており、プレイヤー目前にあると思わせるモニター感を生んでいて好きな表現です。ただしこれはHUD全体のポストプロセス処理が必要になるので一般的に重いと言えます)

『DESTINY2』レンズ効果ポストプロセスを含んだHUD

つまり固定的なレイアウトが必要で、さらに要素の前後関係を制御する必要がある場合、できるだけ2DUIで実装する必要が出てきます。

アフィン変換と射影変換(ホモグラフィー)

そこでウィジェット用のマテリアル内でUVを変形させてしまうという手法を考えるわけですが、ここで出てくるのが射影変換(ホモグラフィー)という変換方法です。

射影変換のイメージ

これは幾何学的にも前述したアフィン変換を包括する関係にありますので将来的にはUMGグラフ画面での基本機能としても実装できるのでは…とエピックさんにお願いしたいところですが、現状ではないものねだりなので何とか自前で対応します。

今回の手法では矩形のテクスチャを(0,0)(1,0)(1,1)(0,1)の座標系でとらえ、(x0,y0)(x1,y1)(x2,y2)(x3,y3)の4点を頂点とする座標を結ぶ自由矩形に変形する、という機能に限定します。UEにはRetainerBoxという特殊なUMG部品があり、配下部品をレンダリングしたものを一枚のテクスチャとしてマテリアル内に展開できるという便利な機能があるため、これを組み合わせることを考えると相性が良いやり方のように思います。

射影変換の考え方などは各種ブログエントリなどにありますのでここでは書かず、あくまでUEのマテリアル実装について絞っていきます。いろいろググっていくとUnityでホモグラフィー変換を実装している方がいらっしゃったので、これに乗っかってUEのマテリアルノードに移植してしまいたいと思います。

UEのマテリアルノードへの移植

こちらのエントリにAPIのソースコードへのリンクが記載されています。

入力座標が (0.0, 0.0)、(1.0, 0.0)、(1.0, 1.0)、(0.0, 1.0) と出来るため 8 次元連立一次方程式は割りと綺麗に解くことが出来ます

Unity で画面出力を変形するイメージエフェクトを作ってみた

(僕は投げ出しました…凹みさんありがとうございます!)

このうち、GetInverseHomographyPositionが対応するものになるのでUEのマテリアル関数として移植します。

ソースコードに対応するように下記のノードに分けることにしました。

GetInverseHomographyPosition

CalcInverseMatrix

CalcHomographyMatrix

ホモグラフィー変換用マテリアル関数 MF_Homography

それぞれカスタムノードを使うことでそれぞれの導出式を組み込んでいきます。カスタムノードのinput/outputを複数持てるようになったのはありがたいですね。

[CustomNode]CalcHomographyMatrix(射影変換行列)

4頂点の座標をinputとし、h11~h32までをoutputとします。カスタムノード内のコードは下記になります。

float x00 = P1.x;
float y00 = P1.y;
float x01 = P4.x;
float y01 = P4.y;
float x10 = P2.x;
float y10 = P2.y;
float x11 = P3.x;
float y11 = P3.y;
float a = x10 – x11;
float b = x01 – x11;
float c = x00 – x01 – x10 + x11;
float d = y10 – y11;
float e = y01 – y11;
float f = y00 – y01 – y10 + y11;
h13 = x00;
h23 = y00;
h32 = (c * d – a * f) / (b * d – a * e);
h31 = (c * e – b * f) / (a * e – b * d);
h11 = x10 – x00 + h31 * x10;
h12 = x01 – x00 + h32 * x01;
h21 = y10 – y00 + h31 * y10;
h22 = y01 – y00 + h32 * y01;
return 1;

[CustomNode]CalcInverseMatrix(逆行列変換)

ここでは上述のh11~h32(h33は常に1)をinputとし、o11~o33をoutputとします。どちらも3×3の行列マトリクスです。

float i33 = 1;
float a = 1 / ((i11 * i22 * i33)+ (i12 * i23 * i31)+ (i13 * i21 * i32)- (i13 * i22 * i31)- (i12 * i21 * i33)- (i11 * i23 * i32));
o11 = ( i22 * i33 – i23 * i32) / a;
o12 = (-i12 * i33 + i13 * i32) / a;
o13 = ( i12 * i23 – i13 * i22) / a;
o21 = (-i21 * i33 + i23 * i31) / a;
o22 = ( i11 * i33 – i13 * i31) / a;
o23 = (-i11 * i23 + i13 * i21) / a;
o31 = ( i21 * i32 – i22 * i31) / a;
o32 = (-i11 * i32 + i12 * i31) / a;
o33 = ( i11 * i22 – i12 * i21) / a;
return 1;

[CustomNode]GetInverseHomographyPosition(ホモグラフィー変換先からの元位置取得)

上述のoutputを受けて各ピクセルの変換元のUV値を算出します。

float s = h6 * uv.x + h7 * uv.y + h8;
float x = (h0 * uv.x + h1 * uv.y + h2) / s;
float y = (h3 * uv.x + h4 * uv.y + h5) / s;
return float2(x, y);

[Output]Mask(変換先の領域マスク)

取得される変換用UVは変形後の矩形の外側も計算されます。これ自体は繰り返し表現などにも使えそうなので矩形領域と分けて出力しておきます。出力部分のノードは0~1の判別をifを使えば明快ではあるのですが、パフォーマンスを考えてあえて使いませんでした。

MF_Homographyのサンプル

このマテリアル関数を使って作成したサンプルがこちらになります。

MF_Homographyを利用して台形変形を行うサンプル

MF_Homographyの入力はpointLT:左上, pointRT:右上, pointLB:左下, pointRB:右下の4点の変換先のポイントとUVを接続します。出力は変換されたUV(ResultUV)と4点による矩形の内側マスク用領域(Mask)となります。

今回は簡単にアニメさせるためにマテリアル内でTimeノードを使ってサクッと実現しましたが、4点のベクターをパラメータ化してグラフのシーケンサー上で扱えるのでより意図に合わせた取り扱いができると思います。

(ちなみにサンプル用のテクスチャはmidjourneyで短時間で作成しました、こういったことには非常に便利ですね。)

おわりに

とりあえずの移植とUEに合わせた実装は完了しましたが、下記の点で実用前に検証が必要だと考えています。が、それはまたいずれ、ということにしておきます。

  • 関数のスリム化(逆関数などがそのままなので)
  • マスク領域のアンチエイリアシング追加(エッジが立つので)
  • Insightなどを利用してパフォーマンスを計測し、UMGのトランスフォーム機能との比較

実際のところ、このようなテクスチャの2D自由変形はUIグラフィック以外ではあまり使うことがないでしょう。狭い範囲での内容にはなりますが効果的なUI表現の足しになると良いと思います!

ゲームUX理論の明快な建付け:セリア・ホデント『ゲーマーズブレイン』

セリア・ホデント「ゲーマーズブレイン」は半分ほど読んで積読していたのを、長めの休暇ができたのでようやく読み切りました。かなりカロリーの高い本でした。読み終わってみると、これは今後何年かは日本のゲームUX分野においてのバイブルになりえるのではないかという感想を持ちました。(日本語で読めるという意味で)

いや、もうなっているのかな?

「ゲーマーズブレイン」の網羅性

なんといっても提示するゲームUXの建付けが明快です。

まずフレームワークとして後述する「ユーザビリティ」と「エンゲージアビリティ」をユーザー体験の主要コンポーネントとして定義しています。

これらを人間中心デザイン(HCD)のプロセスにのっとりデザインを進め、ゲーム開発の各フェーズにおいて適切なUX評価手法に沿って改善点を見つけイテレーションを回すことでクオリティを上げることを勧めています。

でもそれを行う体制はチームや会社単位でのUXへの感化が必要で長い時間がかかるため皆頑張って!と最後に締めています。

ゲームUXのフレームワーク

ホデントが定義するゲーム体験のフレームワークは下記のようになります。

ユーザビリティ

  • サインとフィードバック
  • 明確さ
  • 形態は機能に従う
  • 一貫性
  • 最小限の負荷
  • エラー回避/回復

エンゲージアビリティ

  • 動機付け 有能性、自律性、関係性、意義、対価、潜在的動機付け
  • 情動 ゲームの感覚、臨場感、サプライズ
  • ゲームフロー 難易度曲線、ペース、学習曲線

これらはWeb業界からゲーム業界に進んだ自分にとっては割とわかりやすく分けられています。

「ユーザビリティ」に関してはノーマン「誰のためのデザイン?」やワイシェンク「インターフェースデザインの心理学」などで語られてきた人間中心のデザインプロセスにのっとったビジュアルデザインサイドの普遍的テーマです。

「エンゲージアビリティ」は主にゲームメカトロニクスを担うゲームデザイナーが中心的に関与する領域です。ゲームメカトロニクスに関する知見はいろいろな書籍が出ているので今後読み進めたいと考えています。(読み物としては桝田省治「ゲームデザイン脳」が好き)自分にとってはぼんやりしていたゲームの自己目的化に関するこの定義が非常に刺さった部分でした。

これらは過去職種としてはUIデザイナーおよびゲームデザイナーが担っていた領域をUXの文脈で定義しなおし包括したといってよいでしょう。そして、ここで出てくるのは上記のフレームワークのロジックが最適になっているかの評価を行う独立した職種やチームの必要性です。

ゲームUX実践の困難

国内コンシューマ系大手ゲーム開発会社2社のプロジェクトに関わり知った範囲では、独立もしくは専任のUXストラテジストやリサーチャー職が存在したプロジェクトはなく、定義上でのUX評価(QAやユーザーテストのアンケート評価)を行うのは主にゲームのディレクターが担っていました。おそらくWeb開発会社からゲーム開発会社に進んだデベロッパーではUXの認知度の高さから状況は異なるかもしれませんが、UX専任職の求人をほとんど見たことがないことから、なかなかそこにコストを掛けられる状況にはないということでしょう。

著者のホデント自体、UBIやエピックゲームスといった開発会社でUXチームビルディングや運営に携わっていたことから、UXという概念を社内に認知、活用させることの難しさを感じているようです。

個人的には過去UXチームビルディングを志向しようとしてリーン・バレイ「一人から始めるユーザーエクスペリエンス」などを参考に実践するタイミングを探っていた時期もありましたが、コロナ禍でコミュニケーションの壁が高くなりプロジェクトの状況も良くならず断念してしまいました。

ゲームUXへの近視的リアリティ

私がUIデザイナーとしてとあるゲームプロジェクトからの離脱を迎えた3年ほど前、Webデザイナーとして活動していたころに鳴り物入りでやってきたUXという概念がゲーム業界にも広がってきていると知り、状況はどんなものなのかとゲームUXに関するセミナーなどにいくつか参加してみたものの、ゲーム開発当事者が語っているものは少なく「我流ゲームUX」の概念を語るにとどまっているものが多い印象を受けました。(ゲーム好きなUX関係者が語る、という感じ)

そのような若干の落胆を感じるような状況があり、そして同じころバリバリのゲームUXストラテジストが書いた本書が和訳された(2019年春刊行)ということですから、私の知らないところで本書のフレームワークを取り入れた開発が国内のどこかで進んでいるだろうとは思っています。

ただAAAといわれるゲーム開発には数年かかり、UXリサーチはゲームのプロトタイピング時期から関与すべきと本書は言います。そして成果はゲームのリリース後に長期的に判断されるもので、ゲーム開発中は秘匿案件扱いです。そのタイムスパンを考えると、事例や経験則といったものが公に共有されることはゲームの他の要素に比べると少ないだろうと予想できます。(実際CEDECでの該当テーマ発表も数少ないようです)

では国内のゲーム業界の片隅に居るUIデザイナーとしては、このような情報の乏しい中でゲームUXへのアンテナを張る姿勢として、以下のようなことを考えていきたいと思っています。

  1. 【内省的作業】既存ゲームのUXモデル化作業など
  2. 【視野拡大】海外のゲームUXシーンへの追随
  3. 【発露】このブログを含むアウトプット

ゲームUXに関しては、本書のフレームワークとの参照という形でエントリーを積み上げていきたいと考えています。

(2022/9/10 文体などを変更しました)

Powered by WordPress & Theme by Anders Norén