げーむ開発徒然日記~怠惰のために勤勉~ Unreal Engineや3DCG制作について学んだことを記事にしていきます 2024-09-14T13:06:26+09:00 raksul_01 Hatena::Blog hatenablog://blog/26006613777905739 まばたきのポストプロセスマテリアル hatenablog://entry/6802340630906238574 2024-09-14T13:06:26+09:00 2024-09-14T13:14:13+09:00 タイトル通りです。 概要 以下のような、ホラゲー導入シーンでありがちなまばたきのマテリアル(Eye blink material)を作りました。 調べても、メッシュを動かして作る方法など、私がやりたかったものとは異なる実装しか見つからなかったので自前で組みました。 なお今回は、シーケンサーでパラメーターを変更する都合上、Material Parameter Collectionを用いましたが、勿論Scalar ParameterでもOKです。 作り方 新規マテリアルの作成 コンテンツブラウザ右クリック>「マテリアル」>「マテリアル」で新規マテリアルを作成します。 ポストプロセスとして使うので、… <p>タイトル通りです。</p> <p> </p> <h3 id="概要">概要</h3> <p> 以下のような、ホラゲー導入シーンでありがちなまばたきのマテリアル(Eye blink material)を作りました。</p> <p> 調べても、メッシュを動かして作る方法など、私がやりたかったものとは異なる実装しか見つからなかったので自前で組みました。</p> <p> </p> <p> なお今回は、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B7%A1%BC%A5%B1%A5%F3%A5%B5%A1%BC">シーケンサー</a>でパラメーターを変更する都合上、Material Parameter Collectionを用いましたが、勿論Scalar ParameterでもOKです。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20240914/20240914125520.gif" width="516" height="290" loading="lazy" title="" class="hatena-fotolife" itemprop="image" style="float: left;" /></p> <p> </p> <p> </p> <p> </p> <p> </p> <p> </p> <p> </p> <p> </p> <p> </p> <p> </p> <p> </p> <h3 id="作り方">作り方</h3> <h4 id="新規マテリアルの作成">新規マテリアルの作成</h4> <p> コンテンツブラウザ右クリック>「マテリアル」>「マテリアル」で新規マテリアルを作成します。</p> <p> ポストプロセスとして使うので、作成したマテリアルの編集画面にて、下図のようにマテリアルを設定します。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20240914/20240914130132.png" width="638" height="147" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h4 id="マテリアルの組み方">マテリアルの組み方</h4> <p> 細かい説明は無しで、作り方を淡々と説明します。</p> <p> 全体像は下図の通り。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20240914/20240914125751.png" width="1200" height="590" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> </p> <p> マスク部分の中身は下図の通り。Blink <a class="keyword" href="https://d.hatena.ne.jp/keyword/Value">Value</a>というパラメータは、まばたきの度合いを0~1で指定する部分です。冒頭で述べた通り、Scalar ParameterでもOKです。</p> <p> また、SmoothStepではなくStepのほうを使えば、ぼんやりとしたまばたきではなく、カチっとしたまばたきにできます。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20240914/20240914125726.png" width="1200" height="529" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> </p> <p> PostProcessInput0に対して、作成したマスクを使って黒色(瞼に覆われている部分の色)で補間します。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20240914/20240914130348.png" width="908" height="499" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> </p> <p> …以上。お役に立てば幸いです。</p> raksul_01 UIマテリアルでテキストなどをおもしろくする hatenablog://entry/6801883189067868959 2023-12-20T00:00:09+09:00 2023-12-20T00:00:09+09:00 この記事は、Unreal Engine (UE) Advent Calendar 2023の20日目の記事となります。 はじめに フォントマテリアル フォントマテリアルの準備と適用方法 Textureで柄を付ける 基本 文字ごとにテクスチャで柄を付ける スクリーン空間にテクスチャで柄を付ける テキストを動かす・変形する テキスト位置をテキストカラーによって動かせるようにしてみる テキストを変形させる エフェクトマテリアル エフェクトマテリアルの準備と適用方法 波打つような変形効果を与える おわりに 参考 はじめに 今回は、UE5のウィジェットで、テキストにエフェクトを加えたり、UIの部分的また… <p> この記事は、<a href="https://qiita.com/advent-calendar/2023/ue" target="_blank" rel="noopener">Unreal Engine (UE) Advent Calendar 2023</a>の<a class="keyword" href="https://d.hatena.ne.jp/keyword/20%C6%FC">20日</a>目の記事となります。</p> <ul class="table-of-contents"> <li><a href="#はじめに">はじめに</a></li> <li><a href="#フォントマテリアル">フォントマテリアル</a><ul> <li><a href="#フォントマテリアルの準備と適用方法">フォントマテリアルの準備と適用方法</a></li> <li><a href="#Textureで柄を付ける">Textureで柄を付ける</a><ul> <li><a href="#基本">基本</a></li> <li><a href="#文字ごとにテクスチャで柄を付ける">文字ごとにテクスチャで柄を付ける</a></li> <li><a href="#スクリーン空間にテクスチャで柄を付ける">スクリーン空間にテクスチャで柄を付ける</a></li> </ul> </li> <li><a href="#テキストを動かす変形する">テキストを動かす・変形する</a><ul> <li><a href="#テキスト位置をテキストカラーによって動かせるようにしてみる">テキスト位置をテキストカラーによって動かせるようにしてみる</a></li> <li><a href="#テキストを変形させる">テキストを変形させる</a></li> </ul> </li> </ul> </li> <li><a href="#エフェクトマテリアル">エフェクトマテリアル</a><ul> <li><a href="#エフェクトマテリアルの準備と適用方法">エフェクトマテリアルの準備と適用方法</a><ul> <li><a href="#波打つような変形効果を与える">波打つような変形効果を与える</a></li> </ul> </li> </ul> </li> <li><a href="#おわりに">おわりに</a></li> <li><a href="#参考">参考</a></li> </ul> <h3 id="はじめに">はじめに</h3> <p> 今回は、UE5の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a>で、テキストにエフェクトを加えたり、UIの部分的または全体にポストプロセス的にエフェクトを加えたりする方法を紹介します。</p> <p>※使用したUEのバージョン:5.3</p> <h3 id="フォントマテリアル">フォントマテリアル</h3> <p> UE5のUIを作る際に使用する<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a>には、フォントマテリアル(Font Material)というものがあります。これは、UText<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8">コンポーネント</a>などで使用できます。テキストにアウトラインを付けたりするのは、フォントマテリアルを使わなくてもできるようになっておりますが、テキストにテクスチャを適用したり、変形したりといったちょっとしたエフェクト的なものを与えたい場合には、フォントマテリアルを使用することになります。</p> <p>例)アウトラインにフォントマテリアルを割り当ててオーラ的な動きをつけたもの</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20231218/20231218192932.gif" width="1106" height="318" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h4 id="フォントマテリアルの準備と適用方法">フォントマテリアルの準備と適用方法</h4> <p>1)新規マテリアルを作成し、<strong>Material Domain</strong>を<strong>UserInterface</strong>にします。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20231218/20231218193426.png" width="432" height="106" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> <strong>Blend Mode</strong>は通常のマテリアルと同様に<strong>Opaque</strong>や<strong>Masked</strong>, <strong>Translucent</strong>などが使え、出力が異なります。文字の一部を削りたいなどの場合はMaskedを使う必要があります。</p> <p> ↓通常のマテリアルとは出力が異なる(Blend Mode = Translucentにしたもの)</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20231218/20231218194020.png" width="218" height="199" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> </p> <p>2)次に適用方法ですが、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a>にText,Editable Text,Rich Text Blockなどを配置して、詳細パネルから割り当てます。なお、テキスト本体および輪郭のフォントマテリアルは分かれており、それぞれにマテリアルを割り当てられるようになっています。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20231218/20231218192017.png" width="667" height="482" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h4 id="Textureで柄を付ける">Textureで柄を付ける</h4> <h5 id="基本">基本</h5> <p> 以下のようにVertex Color(テキストカラー)にUEロゴのテクスチャを乗算したものを最終カラーに出力してみます。</p> <p> <span style="text-decoration: underline;"><strong><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a>のテキストの詳細パネルには上記画像のように、テキストの色と透明度を設定する項目Color and Opacityがありますが、ここで設定した値がフォントマテリアルのVertex Colorとして使用されます。</strong></span></p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20231218/20231218205615.png" width="663" height="516" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p>[結果]</p> <p> テキストカラーは白にしているので、UEロゴのテクスチャがそのまま乗りました。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20231218/20231218205632.png" width="680" height="183" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h5 id="文字ごとにテクスチャで柄を付ける">文字ごとにテクスチャで柄を付ける</h5> <p> 先ほどの例では、テクスチャがテキスト全体に収まるようにストレッチがかかっていましたが、文字ごとにテクスチャの柄を付けたい場合には、どのようにすべきでしょうか。Texture Sampleに<a class="keyword" href="https://d.hatena.ne.jp/keyword/Tex">Tex</a> Coordを入力してみます。<span style="text-decoration: underline;">Indexを「1」にする</span>ことで、文字ごとの座標が取得できるようです。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20231218/20231218205744.png" width="489" height="283" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p>[結果]</p> <p> 各文字に対してテクスチャの柄が付けられました。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20231218/20231218205806.png" width="683" height="178" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h5 id="スクリーン空間にテクスチャで柄を付ける">スクリーン空間にテクスチャで柄を付ける</h5> <p> 先ほどまでの例ではすべて、テクスチャにストレッチがかかってしまっています。これの回避策としては、<strong>ScreenAlignedPixelToPixelUVs</strong>を使う方法がありますが、名前の通りスクリーン空間にテクスチャが貼られるような形になるため、パターン柄でない限りは使いづらい方法です。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20231218/20231218210730.png" width="877" height="298" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p>[結果]</p> <p> テキストの位置が変わっても、テクスチャの位置は変わりません。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20231218/20231218211010.gif" width="840" height="262" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h4 id="テキストを動かす変形する">テキストを動かす・変形する</h4> <h5 id="テキスト位置をテキストカラーによって動かせるようにしてみる">テキスト位置をテキストカラーによって動かせるようにしてみる</h5> <p> マテリアルの出力にあるスクリーン位置に入力を与えることでテキストを動かしたり、変形したりできます。</p> <p> 試しに以下のようなマテリアルを組んでみました。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20231218/20231218212039.png" width="907" height="420" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> 画像のコメントにある通り、テキストの色が変わるとスクリーン位置も変わると予想できます。</p> <p>[結果]</p> <p> 予想通り、テキストの色によって位置が変わりました。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20231218/20231218212627.gif" width="808" height="228" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h5 id="テキストを変形させる">テキストを変形させる</h5> <p> テキストを変形させるマテリアルを適当に組みました。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20231218/20231218214047.png" width="1200" height="608" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p>[結果]</p> <p> ふにふに動きます。ただし、四隅しか動かせません。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20231218/20231218214126.gif" width="990" height="262" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> ↓動きを横方向に制限したもの</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20231218/20231218213840.gif" width="876" height="232" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h3 id="エフェクトマテリアル">エフェクトマテリアル</h3> <p> フォントマテリアルでは、テキストにエフェクトを与えられますが、RetainerBoxのEffect Materialを使うとUIの部分的または全体にポストプロセス的な加工をできます。これはおもしろくて、今回紹介する基本的なもの以外にもいろいろな活用方法があると思います。</p> <h4 id="エフェクトマテリアルの準備と適用方法">エフェクトマテリアルの準備と適用方法</h4> <p> まずは、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a>にエフェクトを適用したい領域をRetainerBoxで形どります。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20231219/20231219233354.png" width="1200" height="298" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> 次にフォントマテリアルと同様に新規マテリアルを作成し、<strong>Material Domain</strong>を<strong>UserInterface</strong>にします。</p> <p> RetainerBoxの詳細パネルの<strong>Effect Material</strong>に、作成したマテリアルを割り当てます。<strong>Show Effects in Designer</strong>にチェックを入れるとUMGデザイナー上でエフェクトを確認できます。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20231219/20231219233657.png" width="628" height="150" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h5 id="波打つような変形効果を与える">波打つような変形効果を与える</h5> <p> 以下のようにマテリアルを組みました。</p> <p><span style="color: #ff0000;"><strong>(注意)</strong></span>RetainerBoxのEffect設定にある"<strong>Texture Parameter</strong>"と同名のテクスチャパラメータをマテリアル内に用意する必要がありますが、テクスチャは何でも大丈夫です。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20231219/20231219234220.png" width="1200" height="429" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p>[結果]</p> <p> RetainerBox内の領域のみに波打つような効果が与えられました。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20231219/20231219235142.gif" width="980" height="394" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p>※UE5.3のバグだと思うのですが・・・背景部分が黒くなってしまっています。<strong>Blend Mode</strong>を<strong>Additive</strong>にしたら、透過できましたが、加算が入ってテキストカラーも変わってしまいました。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20231219/20231219235650.gif" width="954" height="384" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> もちろん、テキスト以外に画像やボタンなどにどれにでもエフェクトを与えられます。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20231219/20231219235813.gif" width="1028" height="394" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h3 id="おわりに">おわりに</h3> <p> 以上、フォントマテリアルおよびエフェクトマテリアルの紹介でした。個人的に、フォントマテリアルは最初に載せた輪郭に適用したものは汎用性が高そうに感じました。</p> <p> また、エフェクトマテリアルはHUDに使ってBPとの連携でパラメータを動的に変更して…などで使うとおもしろいと思います。</p> <p> プロジェクトにマッチしそうなア<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A4%A5%C7%A5%A2">イデア</a>を見つけ、ぜひ使ってみてください!</p> <h3 id="参考">参考</h3> <p>・<a href="https://historia.co.jp/archives/13337/" target="_blank">[UE4]UI用マテリアルの「Screen Position」で遊ぼう|株式会社ヒストリア</a></p> <p>・<a href="https://limesode.hatenablog.com/entry/2016/08/27/231535" target="_blank">UMGのフォントをアレンジ - みつまめ杏仁</a></p> raksul_01 【Houdini】スプラッシュ画面が表示されるだけで起動しない hatenablog://entry/820878482963298577 2023-08-31T12:38:41+09:00 2023-08-31T12:49:03+09:00 個人的備忘メモ 環境:Windows 11 Houdini 19.5.716(indie版使用) 概要 以前使っていたPCでも、新調したPCでも同様の問題が起きていた。 具体的には、ランチャーからの起動でも、直接houdini.exeを開いての起動でもスプラッシュ画面が表示されて数秒後に、スプラッシュ画面が消えるだけで結局起動しない。 その後、何度か試しても時々スプラッシュ画面が表示されるが同様に起動しない。 スプラッシュ画面が表示されない場合のほうが多く、青い読み込みの表示がマウスカーソルの横に出るだけである。 なお、原因を調べようとイベントビューアーを確認したところ、Windowsのntd… <p>個人的備忘メモ</p> <p>環境:<a class="keyword" href="https://d.hatena.ne.jp/keyword/Windows">Windows</a> 11</p> <p>Houdini 19.5.716(indie版使用)</p> <h3 id="概要">概要</h3> <p>以前使っていたPCでも、新調したPCでも同様の問題が起きていた。</p> <p>具体的には、ランチャーからの起動でも、直接houdini.exeを開いての起動でもスプラッシュ画面が表示されて数秒後に、スプラッシュ画面が消えるだけで結局起動しない。</p> <p>その後、何度か試しても時々スプラッシュ画面が表示されるが同様に起動しない。</p> <p>スプラッシュ画面が表示されない場合のほうが多く、青い読み込みの表示がマウスカーソルの横に出るだけである。</p> <p>なお、原因を調べようとイベントビューアーを確認したところ、<a class="keyword" href="https://d.hatena.ne.jp/keyword/Windows">Windows</a>のntdll.dllというものに障害が発生とのことだったが、なぜなのかよくわからない。</p> <p> </p> <p>調べたところ同様の事例がかなり多く報告されているのに対し、いまだに解決策が明確でない状況である。</p> <p>今回は、調べても出てこなかった対策のひとつのメモとしつつも、同様の症状が出ている方の参考になれば幸いだと思ったので共有する。</p> <p>もしこれで治った方がいれば、記事の下部にある★ボタンを押してくださると嬉しいです。</p> <h3 id="対策として試したこと">対策として試したこと</h3> <p>以下、効果がなかったことリスト。</p> <p>・<a class="keyword" href="https://d.hatena.ne.jp/keyword/Windows">Windows</a>再インストール⇒実際には行っていないが、新調しても発生したので意味がないと思われる</p> <p>・Houdiniや<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%E9%A5%A4%A5%BB%A5%F3%A5%B9%A5%B5%A1%BC%A5%D0%A1%BC">ライセンスサーバー</a>再インストール</p> <p>・Houdiniを管理者として実行</p> <p>・<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%D5%A5%A1%A5%A4%A5%A2%A5%A6%A5%A9%A1%BC%A5%EB">ファイアウォール</a>無効化</p> <p>・DocumentフォルダにあるHoudini19.5のフォルダ削除</p> <p>・<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%E9%A5%A4%A5%BB%A5%F3%A5%B9%A5%B5%A1%BC%A5%D0%A1%BC">ライセンスサーバー</a>をサービスから再起動</p> <h3 id="効果があったもの確実に有効かは不明">効果があったもの(確実に有効かは不明)</h3> <p>・私の場合、どうも<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A6%A5%A4%A5%EB%A5%B9%A5%D0%A5%B9%A5%BF%A1%BC">ウイルスバスター</a>が悪さをしているみたいだったので、以下の<strong>「コンピュータの保護設定」</strong>でhoudini.exeをスキャンの対象外に設定した。</p> <p>※私が使用しているライセンスはIndie版だが、設定するのはhindie.exeではなくhoudini.exeで良いと思う。</p> <p>これだけで、Houdiniが起動しないなんてことはなくなってしまった。<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A6%A5%A4%A5%EB%A5%B9%A5%D0%A5%B9%A5%BF%A1%BC">ウイルスバスター</a>でない方も、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A6%A5%A4%A5%EB%A5%B9%C2%D0%BA%F6">ウイルス対策</a>ソフトを疑ってみるとよいかもしれない。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230831/20230831122847.png" width="738" height="569" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h3 id="注意点">注意点</h3> <p>フォルダシールドの設定画面からも<strong>「許可するプログラムの一覧」</strong>という<span style="text-decoration: underline;">上記と似たような設定画面</span>が出てくる。が、こちらは上記の設定とはまた別の設定であり、こちらにhoudini.exeを設定しても効果がなかった(上記の「コンピュータの保護設定」でhoudini.exeをスキャン対象外としても、以下の「許可するプログラムの一覧」には登録されない)。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230831/20230831123251.png" width="664" height="279" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> </p> raksul_01 【UE5】Proceduralなナンバープレートのマテリアルを組んでみる hatenablog://entry/4207112889982218493 2023-04-29T21:50:26+09:00 2023-04-29T21:50:26+09:00 目次 目次 0.はじめに 1.実装例 1-1.完成形 1-2.用意するもの 1-3.マテリアルの作成 1-3-1.テクスチャの任意の範囲を切り取る 1-3-2.任意のUV座標範囲を切り取る 1-3-3.ナンバーを合成したい場所に合わせてポジショニングとスケーリングする 1-3-4.カラー情報を合成する 1-3-5.法線情報を合成する 1-3-6.4桁ナンバーにする 1-4.ランダム化への対応 1-4-1.Custom Primitive Data 1-4-2.Actorを継承したBPクラスを作成 1-5.手動設定への対応 補足 アトラス化されていないテクスチャを使用する場合 BP Actorに… <h3 id="目次">目次</h3> <ul class="table-of-contents"> <li><a href="#目次">目次</a></li> <li><a href="#0はじめに">0.はじめに</a></li> <li><a href="#1実装例">1.実装例</a><ul> <li><a href="#11完成形">1-1.完成形</a></li> <li><a href="#12用意するもの">1-2.用意するもの</a></li> <li><a href="#13マテリアルの作成">1-3.マテリアルの作成</a><ul> <li><a href="#131テクスチャの任意の範囲を切り取る">1-3-1.テクスチャの任意の範囲を切り取る</a></li> <li><a href="#132任意のUV座標範囲を切り取る">1-3-2.任意のUV座標範囲を切り取る</a></li> <li><a href="#133ナンバーを合成したい場所に合わせてポジショニングとスケーリングする">1-3-3.ナンバーを合成したい場所に合わせてポジショニングとスケーリングする</a></li> <li><a href="#134カラー情報を合成する">1-3-4.カラー情報を合成する</a></li> <li><a href="#135法線情報を合成する">1-3-5.法線情報を合成する</a></li> <li><a href="#1364桁ナンバーにする">1-3-6.4桁ナンバーにする</a></li> </ul> </li> <li><a href="#14ランダム化への対応">1-4.ランダム化への対応</a><ul> <li><a href="#141Custom-Primitive-Data">1-4-1.Custom Primitive Data</a></li> <li><a href="#142Actorを継承したBPクラスを作成">1-4-2.Actorを継承したBPクラスを作成</a></li> </ul> </li> <li><a href="#15手動設定への対応">1-5.手動設定への対応</a></li> </ul> </li> <li><a href="#補足">補足</a><ul> <li><a href="#アトラス化されていないテクスチャを使用する場合">アトラス化されていないテクスチャを使用する場合</a></li> <li><a href="#BP-Actorにせず単なるStaticMeshActorで実現したい">BP Actorにせず、単なるStaticMeshActorで実現したい</a></li> <li><a href="#シェーダーコストを下げたい">シェーダーコストを下げたい</a></li> </ul> </li> </ul> <h3 id="0はじめに">0.はじめに</h3> <p> 今回組んでみたのは、様々な組み合わせの番号や用途表示などに対応可能なナンバープレートのマテリアルです・・・というのはあくまで具体例で、実際のところやっていることを抽象的に言えば、</p> <p><strong> 「あるテクスチャの任意の範囲だけ」</strong>を<strong>「任意のモデルの任意のUV座標範囲」</strong>に<strong>合成する</strong>というものです。</p> <p> イメージはこんな感じ↓</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230429/20230429205317.png" width="449" height="408" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> 今回のナンバープレートの場合で言うと、何も書かれていない"更地"のナンバープレートに、数字や文字を合成していくイメージですね。</p> <p> この方法は、色々なことに使えると思います。例えば、</p> <p><strong>【例1】UV空間のほんの一部にしか発光する部分を持たないオブジェクトで、わざわざ<a class="keyword" href="https://d.hatena.ne.jp/keyword/4K%B2%F2%C1%FC%C5%D9">4K解像度</a>のベー<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B9%A5%AB%A5%E9%A1%BC">スカラー</a>テクスチャの<a class="keyword" href="https://d.hatena.ne.jp/keyword/A%A5%C1%A5%E3%A5%F3%A5%CD%A5%EB">Aチャンネル</a>をエミッシブのマスクに使いたくない場合</strong></p> <p> ⇒今回の手法を使えば必要最低限のサイズ(64x64サイズなど)のエミッシブマスクを用意すればよくなります。</p> <p><strong>【例2】学校の教室のプレートや看板など、ベース部分を使いまわしたい場合</strong></p> <p> ⇒今回紹介するナンバープレートと同じパターンです。</p> <p> </p> <p> きっかけはGhostwire: Tokyoで車が様々なナンバーだったのを見かけたことです。最初はテキストレンダー<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8">コンポーネント</a>でも仕込んであるかと思ったんですが、ちゃんと文字がプレート表面から盛り上がっている=ノーマル情報があるんですよね。ただ、Ghostwire: Tokyoの車で使われている数字は完全にランダムではなく何らかの規則性はありそうな気がします。</p> <h3 id="1実装例">1.実装例</h3> <p> 今回使用したUEはバージョン5.1.1です。</p> <h4 id="11完成形">1-1.完成形</h4> <p> 以下の動画をご覧ください。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230429/20230429214848.gif" width="640" height="360" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> 付与した機能は色々ありますが、本記事で取り上げるのは以下の2つです。</p> <p>①ナンバー(10-00~99-99)が、ランダム変化する</p> <p><strong><span style="color: #ff0000;">⇒<span style="text-decoration: underline;">1~3桁ナンバーには対応させていないのでご了承ください。</span></span></strong>そこまで難しいことではないですが、対応させるには別途改変する必要があります。</p> <p>②手動でも設定可能にする</p> <p>⇒今回は、①②を実現するため最終的にBP Actorにします。</p> <h4 id="12用意するもの">1-2.用意するもの</h4> <p>・<strong><span style="color: #ff0000;">単純なアトラス化が施された</span>テクスチャ</strong>(合成したいもの)</p> <p>※もちろんアトラス化されていないものでも大丈夫です(補足参照)。</p> <p> 今回は、<strong>R+Gチャンネルに法線情報</strong>、<strong>Bチャンネルにマスク情報</strong>を持つテクスチャを用意しました(上から順にR+G+B,R+G,B)。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230429/20230429190417.png" width="640" height="128" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230429/20230429190444.png" width="642" height="130" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230429/20230429190506.png" width="642" height="130" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p><span style="font-size: 80%;">※ブログ用に作ったものなのですごく雑ですし、サイズも圧縮のことも何も考えていません。ナンバーって特殊なフォントだなあ…。</span></p> <p> 単純なアトラス化と言っているのは<strong>「要素が等間隔に分割されているもの」</strong>を指しており、上のテクスチャはどちらも各数字が等間隔に配置されています。</p> <p><span style="color: #00cc00; font-size: 80%;">Tips:</span></p> <p><span style="color: #00cc00; font-size: 80%;">・必要な解像度は使用する自動車モデルに使われているテクスチャの解像度に合うようにすることを推奨します。</span></p> <p><span style="color: #00cc00; font-size: 80%;">・3桁ナンバーなどに対応させる場合は「・」もテクスチャに含めないといけません。</span></p> <h4 id="13マテリアルの作成">1-3.マテリアルの作成</h4> <p><span style="text-decoration: underline; color: #ff0000;"><strong>最初はBチャンネルのマスク情報を使って合成するための準備段階から始めるので留意ください!!</strong></span></p> <h5 id="131テクスチャの任意の範囲を切り取る">1-3-1.テクスチャの任意の範囲を切り取る</h5> <p> まず最初に、冒頭で述べた</p> <p><strong>「あるテクスチャの任意の範囲だけ」</strong>を<strong>「任意のモデルの任意のUV座標範囲」</strong>に<strong>合成する</strong></p> <p>の、「あるテクスチャ(この例では、合成に使うテクスチャ)の任意の範囲」を切り取ることから始めます。</p> <p> エンジンに標準で用意されている<span style="color: #ff0000;"><strong>FlipBook</strong></span>というマテリアル関数を使うだけでこれを実現できます。以下(<span style="color: #b388dd;"><strong>紫色</strong></span>でコメントされた部分)をご覧ください。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230429/20230429190725.png" width="1031" height="520" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> 0123456789から3だけが切り取られています。上の画像では、Numberというパラメータに与えられた数字が切り取られるようにしています。</p> <p><span style="color: #00cc00; font-size: 80%;">Tips:FlipBookは本来的には、エフェクトに使う連番テクスチャを入力して、Animation Phaseの値を変化させることでパラパラ漫画のようにアニメーションさせることに使うことが多いと思います。</span></p> <h5 id="132任意のUV座標範囲を切り取る">1-3-2.任意のUV座標範囲を切り取る</h5> <p> 次は、</p> <p><strong>「あるテクスチャの任意の範囲だけ」</strong>を<strong>「任意のモデルの任意のUV座標範囲」</strong>に<strong>合成する</strong></p> <p>の、「任意のモデルの任意のUV座標範囲」を切り取ることを行います。</p> <p> こちらもエンジンに標準で用意されている<span style="color: #ff0000;"><strong>TextureCropping</strong></span>というマテリアル関数を使うだけでこれを実現できます。以下(<span style="color: #f9ce1d;"><strong>茶色</strong></span>でコメントされた部分)をご覧ください。</p> <p> UpperLeftCorner(V2)およびLowerRightCorner(V2)という入力を与える必要があります。これは切り取りたいUV範囲の正規化座標となります。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230429/20230429193056.png" width="630" height="356" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230429/20230429193011.png" width="334" height="332" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h5 id="133ナンバーを合成したい場所に合わせてポジショニングとスケーリングする">1-3-3.ナンバーを合成したい場所に合わせてポジショニングとスケーリングする</h5> <p> ここまでできたら、先ほどの1-3-1で得られた「切り取られたナンバー」を、合成したい範囲の大きさに合わせてポジショニングおよびスケーリングしていきます。</p> <p> 厳密に言えば、「タイリングをした後に、必要な部分のみを残す」といったことを行います。</p> <p> 以下のように1-3-2で使ったTextureCroppingのCrop UVsという出力を、FlipBookのUVsに与えてやると、FlipBookの出力にタイリングをかけることができます。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230429/20230429193737.png" width="537" height="653" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> 次に、タイリングで作られる不要部分を除去するためには、<strong>Crop Mask</strong>という出力が、切り取られた範囲のマスク情報として使えます。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230429/20230429193441.png" width="570" height="368" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> それでは、以下のようにFlipBook(タイリングされたナンバー)から、不要部分をマスクで除去します。なお、途中でBチャンネルをマスクしているのは、Bチャンネルには文字部分のマスク情報があるため、Crop Maskと乗算することで、CropMaskにある範囲内かつ数字のみのマスク情報というのを作ることができるためです。最終出力はMaskedNumberというNamed Rerouteに格納しました。この情報を後々使いまわします。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230429/20230429194152.png" width="1033" height="590" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h5 id="134カラー情報を合成する">1-3-4.カラー情報を合成する</h5> <p> ようやくカラーや法線を合成する準備が整いましたので、まずはカラーから乗せていきますが、これは簡単です。ナンバープレートのベー<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B9%A5%AB%A5%E9%A1%BC">スカラー</a>テクスチャに対して、先ほどのマスク情報を使ってLerpで合成するだけです。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230429/20230429200716.png" width="722" height="333" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h5 id="135法線情報を合成する">1-3-5.法線情報を合成する</h5> <p> まずは、合成する法線情報を作ります。以下のようにマテリアルを組みます。</p> <p> 1-2で説明したように、今回用意したテクスチャはR+Gチャンネルに法線情報があるだけであってBチャンネルを再構築する必要があるため、<strong>DeriveNormalZ</strong>を使って法線情報を再構築します。その後、ナンバー以外の部分は<strong>FlattenNormal</strong>によって平坦化し、強度調整用の<strong>FlattenNormal</strong>も別途配置します。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230429/20230429200851.png" width="1185" height="428" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> あとは、<strong>BlendAngleCorrectedNormals</strong>を使って、ナンバープレートのベースの法線マップに対して合成をかけます。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230429/20230429201226.png" width="917" height="458" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h5 id="1364桁ナンバーにする">1-3-6.4桁ナンバーにする</h5> <p> 4桁ナンバーにするにあたって、まずはマテリアル関数化し、コンパクトにしました。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230429/20230429203456.png" width="747" height="388" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> マテリアル関数内の、TextureCroppingのところも少し変更しています。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230429/20230429203514.png" width="805" height="394" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> あとは、この関数を4桁分=4つ配置して合成します。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230429/20230429204551.png" width="1186" height="643" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> NumberSizeのパラメータのみ使いまわしています。さすがに若干コストが高くなります。とりあえずこれで一通りは完了です!あとはランダム化に対応していきましょう。</p> <h4 id="14ランダム化への対応">1-4.ランダム化への対応</h4> <h5 id="141Custom-Primitive-Data">1-4-1.Custom Primitive Data</h5> <p> Material Instance Dynamics(MID)を使っても可能なのですが、今回はCustom Primitive Data(CPD)を使います。</p> <p> MIDでは<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B9%A5%AB%A5%E9%A1%BC">スカラー</a>パラメータと<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%D9%A5%AF%A5%BF%A1%BC">ベクター</a>パラメータに加えて各種テクスチャパラメータなどを動的に変更可能なのに対し、CPDでは<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B9%A5%AB%A5%E9%A1%BC">スカラー</a>パラメータと<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%D9%A5%AF%A5%BF%A1%BC">ベクター</a>パラメータしか扱えませんが、今回のケースではCPDで十分に対応できます。</p> <p> また、CPDのほうがドローコールを節約するうえで特に有効な手段ですので、CPDで対応できるものは積極的にCPDを利用したほうがよいです。これについては公式ドキュメントを一読しておくことを推奨します。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fdocs.unrealengine.com%2F5.0%2Fja%2Fstoring-custom-data-in-unreal-engine-materials-per-primitive%2F" title="プリミティブごとにマテリアルにカスタム データを保存する" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <p> マテリアル内のNumber_1~Number_4に、Custom Primitive Dataを使うように設定します。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230429/20230429210045.png" width="598" height="400" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> パラメータを選択した状態で、詳細タブから<strong>Use Custom Primitive Data</strong>にチェックを入れて、<strong>Primitive Data Index</strong>を指定します。</p> <p> 今回は、Number_1~Number_4の順に、Primitive Data Indexに1~4を割り当てました。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230429/20230429210314.png" width="377" height="90" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h5 id="142Actorを継承したBPクラスを作成">1-4-2.Actorを継承したBPクラスを作成</h5> <p> 今回は、Actorクラスを継承したBP_LicensePlateMatTestを作成しました。この中のBP処理にてランダム化対応を実装していきます。</p> <p> あとはConstruction Scriptにて、それぞれのCustom Primitive Dataに0~9のランダムな値を与えてやるだけです。また、4桁の場合、先頭に0はこないので、先頭のみ1~9となるようにしています。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230429/20230429214256.png" width="942" height="319" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> ここまででランダムナンバーは終わりです!お疲れ様でした。次はオプション的なものですが、手動設定にも対応させていきます。</p> <h4 id="15手動設定への対応">1-5.手動設定への対応</h4> <p> すぐにできます。それぞれのナンバーに対応する変数と、手動で設定するかどうかを決めるbool変数を用意します(目玉マークが開いているようにすること)</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230429/20230429211941.png" width="293" height="227" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> あとは以下のように、分岐処理を組んであげるだけです。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230429/20230429214357.png" width="954" height="537" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> レベル上で編集してみると、手動設定が機能していることを確認できます。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230429/20230429212132.png" width="769" height="294" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p><span style="font-size: 200%;"> おしまい!</span></p> <h3 id="補足">補足</h3> <h4 id="アトラス化されていないテクスチャを使用する場合">アトラス化されていないテクスチャを使用する場合</h4> <p> 切り取る必要がないということなので、FlipBookを使わずにTextureSampleを使用するだけです。</p> <h4 id="BP-Actorにせず単なるStaticMeshActorで実現したい">BP Actorにせず、単なるStaticMeshActorで実現したい</h4> <p> ナンバーランダム化の柔軟性が落ち、手動設定機能も失われますが、以下のようにすればできます。この例では、シェーダー内でナンバーを自動で決めることによってBPで数値を変更しなくてもよくなっています。ただし、4桁全てをバラバラにするためには更なる工夫が必要です。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20230418/20230418003516.png" width="1088" height="471" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h4 id="シェーダーコストを下げたい">シェーダーコストを下げたい</h4> <p>以下のような対応で、多少は下がると思います。</p> <p>・標準のFlipBookでは冗長なので、必要な計算だけを残したカスタムのマテリアル関数を作成しましょう。</p> <p>・標準のTextureCroppingでは冗長なので、必要な計算だけを残したカスタムのマテリアル関数を作成しましょう。</p> <p>・合成する部分の数が多いほどTextureSampleが増えたりとそれなりにコストも増加していきます。ナンバープレートの場合は、ナンバー4桁=4つ以上は合成する部分が必要になりますが、それ以外はある程度妥協しましょう。FlipBook内でも、TextureCropping内でもTextureSampleが使われているので注意。</p> raksul_01 【UE5】EQSを使って遮蔽物によるインタラクションアイコンの表示・非表示を実装してみる hatenablog://entry/4207112889945803291 2022-12-17T21:20:19+09:00 2022-12-17T21:20:19+09:00 本記事は、Unreal Engine (UE) Advent Calendar 2022の18日目の記事になります。 目次 はじめに 完成形 ウィジェットコンポーネントについて 実装 準備 環境クエリの作成 プレイヤーキャラクターの作成 インタラクティブなオブジェクトの作成 おわりに はじめに 本記事では、UEのEQS(Environment Query System;環境クエリシステム)を使って、アイテムピックアップ、ドア開閉などのインタラクション可能なオブジェクトのアイコンを遮蔽物の有無によって表示・非表示を切り替える機能を実装していきたいと思います。 ※後述しますが、この方法、正直効果的… <p><span style="font-size: 80%; color: #999999;">本記事は、<a href="https://qiita.com/advent-calendar/2022/ue" style="color: #999999; text-decoration: underline;">Unreal Engine (UE) Advent Calendar 2022</a>の18日目の記事になります。</span></p> <p><span style="font-size: 150%;"><strong>目次</strong></span></p> <ul class="table-of-contents"> <li><a href="#はじめに">はじめに</a><ul> <li><a href="#完成形">完成形</a></li> <li><a href="#ウィジェットコンポーネントについて">ウィジェットコンポーネントについて</a></li> </ul> </li> <li><a href="#実装">実装</a><ul> <li><a href="#準備">準備</a></li> <li><a href="#環境クエリの作成">環境クエリの作成</a></li> <li><a href="#プレイヤーキャラクターの作成">プレイヤーキャラクターの作成</a></li> <li><a href="#インタラクティブなオブジェクトの作成">インタラクティブなオブジェクトの作成</a></li> </ul> </li> <li><a href="#おわりに">おわりに</a></li> </ul> <h3 id="はじめに">はじめに</h3> <p><span style="font-size: 80%;"> 本記事では、UEのEQS(Environment Query System;環境クエリシステム)を使って、アイテムピックアップ、ドア開閉などのインタ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%AF">ラク</a>ション可能なオブジェクトのアイコンを遮蔽物の有無によって表示・非表示を切り替える機能を実装していきたいと思います。</span></p> <p><span style="font-size: 80%;">※後述しますが、この方法、正直効果的ではないです。あくまで「EQSを使ってみた」だけのもので、利点は、実装がシンプルでわかりやすいくらいかなと思ってます(<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A4%A5%F3%A5%BF%A5%E9%A5%AF%A5%C6%A5%A3%A5%D6">インタラクティブ</a>なオブジェクトにトレースなどの処理を書かなくて良いため)。プロトタイプや簡単なプロジェクトに使う分にはいいかもしれません。</span></p> <p><span style="font-size: 80%;"> なお、今回使用したバージョンは5.1です。</span></p> <p><span style="font-size: 80%;"><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fdocs.unrealengine.com%2F4.27%2Fja%2FInteractiveExperiences%2FArtificialIntelligence%2FEQS%2FEQSOverview%2F" title="Environment Query System の概要" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://docs.unrealengine.com/4.27/ja/InteractiveExperiences/ArtificialIntelligence/EQS/EQSOverview/">docs.unrealengine.com</a></cite></span></p> <p><span style="font-size: 80%;"> 上記の公式ドキュメントによれば「<span style="color: #b388dd;"><em><span style="font-family: OpenSans_Regular, Verdana, Arial, 'sans serif'; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; float: none; display: inline !important;">EQS の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E6%A1%BC%A5%B9%A5%B1%A1%BC%A5%B9">ユースケース</a>の例としては、最も近い体力のピックアップや弾薬を探したり、どの敵が最も脅威となっているのかを把握したり、プレイヤーが見える位置を見つけたりすることが挙げられます</span></em></span>」と記載されており、EQSはUE標準のAIビヘイビアツリーなどと組み合わせることで様々な環境に対応可能なAIの作成に活用できるものですが、今回はあえてオブジェクトのアイコン表示に使ってみました。</span></p> <h4 id="完成形">完成形</h4> <p><span style="font-size: 80%;"> 作成したものの完成形は以下のような感じ。</span></p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20221217/20221217211718.gif" width="640" height="360" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p><span style="font-size: 80%;"> インタ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%AF">ラク</a>ション可能な<span style="text-decoration: underline;">オブジェクトが遮蔽物の奥に隠れている場合、アイコンが非表示になります</span>。</span></p> <p><span style="font-size: 80%;"> 厳密に言えば、Querierとなるキャ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%AF">ラク</a>ターのカメラ位置から<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A4%A5%F3%A5%BF%A5%E9%A5%AF%A5%C6%A5%A3%A5%D6">インタラクティブ</a>なオブジェクトの原点位置との間に遮蔽物があるかどうかを見ています。この時点でなんとなく、最初に注意点として述べた理由がわかるかと思います。</span></p> <h4 id="ウィジェットコンポーネントについて"><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8">コンポーネント</a>について</h4> <p><span style="font-size: 80%;"> <a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A4%A5%F3%A5%BF%A5%E9%A5%AF%A5%C6%A5%A3%A5%D6">インタラクティブ</a>なオブジェクトにアイコンを表示しようとした場合、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8">コンポーネント</a>をアクターに取り付けることが多いかと思います。</span></p> <p><span style="font-size: 80%;"> そして<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a>の描画方法としては、</span></p> <p><span style="font-size: 80%;">・<strong><span style="color: #ff0000;">スクリーン空間 </span></strong>⇒ワールド座標をもとにスクリーン座標に2D<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a>を描画</span></p> <p><span style="font-size: 80%;">・<strong><span style="color: #ff0000;">ワールド空間 </span></strong>⇒ワールド座標に3D<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a>を描画</span></p> <p><span style="font-size: 80%;">があります。</span></p> <p><span style="font-size: 80%;"> <span style="color: #ff0000;">ワールド空間</span>であれば特に何もせずとも遮蔽物の奥のアイコンは隠れるのですが、</span></p> <p><span style="font-size: 80%;">「カメラとの距離に応じて表示サイズが変わる」「3D<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a>のため3次元の向きを持つ(後ろから見ると反転して見える)」などといった挙動となります。</span></p> <p><span style="font-size: 80%;"> 反対に、<span style="color: #ff0000;">スクリーン空間</span>であれば上記とは逆で「カメラとの距離によって表示サイズは変わらない」「常に正面を向いている」といった挙動にはなりますが、遮蔽物の奥にあったとしても関係なしに画面に描画されます。</span></p> <p><span style="font-size: 80%;"> このように、どちらの描画方法も一長一短ですが、今回のようなインタ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%AF">ラク</a>ションアイコンや敵のHPバーなどといったものに対しては、一般にスクリーン空間での描画が適しています。</span></p> <p><span style="font-size: 80%;"> しかし、繰り返しにはなりますがスクリーン空間への描画をそのまま使うと冒頭で示した動画のような、<span style="text-decoration: underline;">遮蔽によるアイコンの表示・非表示</span>というのができません。仮にこれをBPのみで実装しようとすると、ちょっと面倒だったりします。</span></p> <p><span style="font-size: 80%;"> このため、今回は上述のEQS機能のひとつである「<span style="color: #b388dd;"><em><span style="font-family: OpenSans_Regular, Verdana, Arial, 'sans serif'; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; float: none; display: inline !important;">プレイヤーが見える位置を見つけたりすること</span></em></span>」を使ってサクッと簡単に実装していきます。</span></p> <h3 id="実装">実装</h3> <h4 id="準備">準備</h4> <p><span style="font-size: 80%;"> <span style="text-decoration: underline;">使用するUEのバージョンによっては</span>、プロジェクト内の<strong>[Editor Preferences (エディタの環境設定)] &gt; [Experimental (実験的)] &gt; [AI]</strong>セクションで、<strong>Environment Querying System</strong>をオンにする必要があります。UE5.1ではそもそも項目が見つからないはずです。</span></p> <p><span style="font-size: 80%;"><img src="https://docs.unrealengine.com/4.27/Images/InteractiveExperiences/ArtificialIntelligence/EQS/EQSQuickStart/EQS_QuickStart_01.jpg" alt="EQS_QuickStart_01.png" /></span></p> <p><span style="font-size: 80%;">※画像は<a href="https://docs.unrealengine.com/4.27/ja/InteractiveExperiences/ArtificialIntelligence/EQS/EQSOverview/">公式ドキュメント</a>から引用</span></p> <h4 id="環境クエリの作成">環境クエリの作成</h4> <p><span style="font-size: 80%;"> まずはコンテンツブラウザの右クリックメニューから環境クエリを作成します。</span></p> <p><span style="font-size: 80%;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20221217/20221217191809.png" width="639" height="259" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></span></p> <p><span style="font-size: 80%;"> 作成されたアセットを開くと、ビヘイビアツリーのようなエディタ(クエリグラフ)が開きます。</span></p> <p><span style="font-size: 80%;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20221217/20221217192033.png" width="369" height="213" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></span></p> <p><span style="font-size: 80%;"> 最初から置いてある、ルートノードからドラッグ操作で出てくる[Actors Of Class]を選択します。</span></p> <p><span style="font-size: 80%;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20221217/20221217192121.png" width="432" height="223" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></span></p> <p><span style="font-size: 80%;"> これは、GetActorsOfClassに近いものであって、詳細パネルから取得したいアクタークラスと、球状のサーチを行うかどうかなどを設定できます。</span></p> <p><span style="font-size: 80%;"> 今回は、BP_Interactableというクラスをサーチするので、先に作成し、以下のように[Searched Actor Class]に設定しておきます。</span></p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20221217/20221217201127.png" width="568" height="257" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p><span style="font-size: 80%;"> Generate Only Actors in <a class="keyword" href="http://d.hatena.ne.jp/keyword/Radius">Radius</a>は、TrueであればSearch <a class="keyword" href="http://d.hatena.ne.jp/keyword/Radius">Radius</a>で設定された半径の球状の範囲内のSearched Actor Classオブジェクトをサーチします。Falseであればワールド全体からサーチします。</span></p> <p><span style="font-size: 80%;"> Search <a class="keyword" href="http://d.hatena.ne.jp/keyword/Radius">Radius</a>は後ほどキャ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%AF">ラク</a>タークラスからクエリにパラメータを与えるため、Query Paramsにしておきます。</span></p> <p><span style="font-size: 80%;"> Search Centerはサーチの中心位置です。デフォルトのEnvQueryContext_Querierのままでも大丈夫ですが、今回はカメラ位置を中心にしたいので、コンテンツブラウザ右クリックから[EnvQueryContext_BrueprintBase]を作成します。これによって、Querierの情報をもとにカスタムの位置情報などを作成できます。</span></p> <p><span style="font-size: 80%;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20221217/20221217192800.png" width="430" height="178" loading="lazy" title="" itemprop="image" /></span></p> <p><span style="font-size: 80%;"> 作成したらアセットを開き、Provide Single Location関数をオーバーライドします。これで、Querierの位置をキャ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%AF">ラク</a>ター原点ではなくてカメラ位置にオーバーライドできます。</span></p> <p><span style="font-size: 80%;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20221217/20221217192929.png" width="881" height="298" loading="lazy" title="" itemprop="image" /></span></p> <p><span style="font-size: 80%;"> これができたら、先ほどのSearch Centerに、作成したEnvQueryContextを設定します。</span></p> <p><span style="font-size: 80%;"> 次に、クエリグラフに戻ってActors Of Classノードを右クリックして[テストを追加]&gt;[Trace]を選びます。</span></p> <p><span style="font-size: 80%;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20221217/20221217193301.png" width="545" height="257" loading="lazy" title="" itemprop="image" /></span></p> <p><span style="font-size: 80%;"> Actors Of ClassノードにTraceという項目が追加されるので選択すると、詳細を設定できます。</span></p> <p><span style="font-size: 80%;"> 設定は以下のようにします。</span></p> <p><span style="font-size: 80%;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20221217/20221217193402.png" width="576" height="499" loading="lazy" title="" itemprop="image" /></span></p> <p><span style="font-size: 80%;"> [Context]に先ほど作成したカメラ位置を使えるようにするEnvQueryContextを設定します。</span></p> <p> </p> <p><span style="font-size: 80%;"> これで、このクエリを実行すると、</span></p> <p><span style="font-size: 80%;">カメラ位置を中心とするSearch <a class="keyword" href="http://d.hatena.ne.jp/keyword/Radius">Radius</a>半径の球内に存在するBP_Interactableオブジェクトを取得⇒取得された全てのBP_Interactableオブジェクトの原点位置からカメラ位置にトレースによって遮蔽物があるオブジェクトについてはクエリ終了後の最終的な出力から弾かれる。といった具合になります。</span></p> <h4 id="プレイヤーキャラクターの作成">プレイヤーキャ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%AF">ラク</a>ターの作成</h4> <p><span style="font-size: 80%;"> まずは、近くにあるBP_Interactableを検出するための<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%EA%A5%B8%A5%E7%A5%F3">コリジョン</a><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8">コンポーネント</a>を追加します。</span></p> <p><span style="font-size: 80%;">※InteractableCollisonは詳細パネルから全チャンネルへの応答をオーバーラップにしていますが、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A4%A5%F3%A5%BF%A5%E9%A5%AF%A5%C6%A5%A3%A5%D6">インタラクティブ</a>なオブジェクトのみをオーバーラップ、他のアクターや<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8">コンポーネント</a>に対しては応答を無視にするとなお良いです。</span></p> <p><span style="font-size: 80%;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20221217/20221217202227.png" width="617" height="280" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></span></p> <p><span style="font-size: 80%;"> BeginPlayイベントで色々とセットアップするので、Enable Interactable Detectionというカスタムイベントを追加します。</span></p> <p><span style="font-size: 80%;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20221217/20221217201258.png" width="525" height="189" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></span></p> <p><span style="font-size: 80%;"> 以下がイベントの中身です。<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%EA%A5%B8%A5%E7%A5%F3">コリジョン</a>の半径を設定したり、オーバーラップイベントなどを作成しています。</span></p> <p><span style="font-size: 80%;"> <a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%EA%A5%B8%A5%E7%A5%F3">コリジョン</a>内のBP_InteractableはInteractable配列内に格納されます。</span></p> <p><span style="font-size: 80%;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20221217/20221217201935.png" width="835" height="205" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></span></p> <p><span style="font-size: 80%;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20221217/20221217202018.png" width="987" height="458" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></span></p> <p><span style="font-size: 80%;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20221217/20221217202032.png" width="893" height="270" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></span></p> <p><span style="font-size: 80%;"> 次はSequenceノードの2つ目からの内容です。先ほど、クエリグラフのActors Of Classノードにてサーチ半径にパラメータを使うことに設定していたので、キャ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%AF">ラク</a>ターのBPから与えてやります。</span></p> <p><span style="font-size: 80%;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20221217/20221217202138.png" width="1122" height="544" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></span></p> <p><span style="font-size: 80%;"> UpdateInteractionIconイベントでは、球体内に存在するBP_Interactableに対して、それぞれの可視・不可視に応じて<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a>の可視性をトグルしています(次項参照)。</span></p> <p><span style="font-size: 80%;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20221217/20221217202432.png" width="962" height="223" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></span></p> <h4 id="インタラクティブなオブジェクトの作成"><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A4%A5%F3%A5%BF%A5%E9%A5%AF%A5%C6%A5%A3%A5%D6">インタラクティブ</a>なオブジェクトの作成</h4> <p><span style="font-size: 80%;"> Actorクラスを継承したBP_Interactableは、スタティックメッシュ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8">コンポーネント</a>と、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8">コンポーネント</a>を追加しただけの単純なものです。</span></p> <p><span style="font-size: 80%;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20221217/20221217202814.png" width="319" height="172" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></span></p> <p><span style="font-size: 80%;"> <a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8">コンポーネント</a>の詳細設定にて描画をScreenにしておき、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a>の可視性(Visibility)はデフォルト値をFalseにしておきます。<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a>クラスには自作のアイコン表示用<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a>を設定してください(作成は割愛)。</span></p> <p><span style="font-size: 80%;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20221217/20221217202924.png" width="428" height="354" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></span></p> <p><span style="font-size: 80%;"> キャ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%AF">ラク</a>タークラスから実行していたToggle Iconイベントは以下の通り。</span><br /><span style="font-size: 80%;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20221217/20221217203044.png" width="413" height="185" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></span></p> <p> </p> <p><span style="font-size: 150%;">⇒実装おしまい</span></p> <h3 id="おわりに">おわりに</h3> <p><span style="font-size: 80%;"> というわけで、今回はEQSを使って遮蔽物の有無によるインタ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%AF">ラク</a>ションアイコンの表示・非表示をできるようにしてみました。</span></p> <p><span style="font-size: 80%;"> 実際にはトレースを飛ばし続けてさらに近づいたときに、あとはボタンを押すだけでインタ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%AF">ラク</a>トできることを示すようにアイコンの見た目を変えたり、もちろんインタ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%AF">ラク</a>ション処理も追加実装する必要があります。</span></p> <p><span style="font-size: 80%;"> そしてかなりデメリットであるのが、プロジェクトによっては複数の引き出しを<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8">コンポーネント</a>として持つタンスなどのアクターを作成する場合です。この場合、今回の方法を用いると、アクター(タンス自体)の原点の位置情報が使われるため、タンスの原点さえ見えていれば全ての引き出しに対してアイコンが表示されてしまうといったことが生じうるため根本から方法を変えるか大幅な変更を行う必要などが出てきますので、それでも良ければ構わないのですが、できれば今回の方法でも十分なプロジェクトやプロトタイプ程度に使うのが良いかと思います。</span></p> <p><span style="font-size: 80%;"> また、タイマーでクエリを実行していますが、For Each Loopによるオブジェクト毎への<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a>情報の更新を行いますし、クエリのActors Of Classも決して処理負荷的に優しいものではないという点にご留意ください。</span></p> <p><span style="font-size: 80%;"> なので、ちゃんと実装する場合は、素直に<a class="keyword" href="http://d.hatena.ne.jp/keyword/C%2B%2B">C++</a>を使うのがいいです。</span></p> <p> </p> raksul_01 対象Actorの速度を監視するAbilityTask hatenablog://entry/4207112889910349216 2022-08-20T15:17:16+09:00 2022-08-20T15:17:16+09:00 概要 GASにてダッシュアビリティ(GA_Run)を実装した際、ダッシュのアクション入力をすると止まっているにも関わらずGA_Runの持つState.RunningのようなGameplayTagが付与されてしまうのが気になっていました。 AbilityTaskですが、どうやらTick動作させることができるみたいなので、それを利用してActorの速度を監視するAbilityTaskを作りました。 AbilityTaskの作り方については、あいす氏の記事でわかりやすく解説されていますのでそちらをご覧ください。 また、公式の詳しい作成手順はAbilityTask.h内に示されています。 [UE] A… <h3 id="概要">概要</h3> <p>GASにて<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C0%A5%C3%A5%B7%A5%E5">ダッシュ</a>アビリティ(GA_Run)を実装した際、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C0%A5%C3%A5%B7%A5%E5">ダッシュ</a>のアクション入力をすると止まっているにも関わらずGA_Runの持つState.RunningのようなGameplayTagが付与されてしまうのが気になっていました。</p> <p>AbilityTaskですが、どうやらTick動作させることができるみたいなので、それを利用してActorの速度を監視するAbilityTaskを作りました。</p> <p>AbilityTaskの作り方については、あいす氏の記事でわかりやすく解説されていますのでそちらをご覧ください。 また、公式の詳しい作成手順はAbilityTask.h内に示されています。</p> <p><a href="https://qiita.com/koorinonaka/items/50b8daed1c4d7f691b62">[UE] AbilityTask &#x306E;&#x3064;&#x304F;&#x308A;&#x304B;&#x305F; - Qiita</a></p> <p>使用UEバージョン:5.0.3</p> <h4 id="作成するAbilityTask">作成するAbilityTask</h4> <p>今回作ったものは以下のようなものです。</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20220820/20220820145145.png" width="740" height="165" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p>AbilityTaskを実行するとTargetに接続したActorの速度(<strong>高さ方向は無視</strong>)を監視し続け、Threshold(<a class="keyword" href="http://d.hatena.ne.jp/keyword/%EF%E7%C3%CD">閾値</a>)を超えるとOnStartMovingデリゲートが発行され、再度Threshold以下となるとOnStopMovingデリゲートが発行されるといった非常にシンプルな構成になっています。</p> <h3 id="実装">実装</h3> <pre class="code AbilityTask_WaitGroundMoving.h" data-lang="AbilityTask_WaitGroundMoving.h" data-unlink> DECLARE_DYNAMIC_MULTICAST_DELEGATE(FWaitGroundMovingDelegate); UCLASS() class YOURPROJECT_API UAbilityTask_WaitGroundMoving : public UAbilityTask { GENERATED_BODY() UPROPERTY(BlueprintAssignable) FWaitGroundMovingDelegate OnStartMoving; UPROPERTY(BlueprintAssignable) FWaitGroundMovingDelegate OnStopMoving; virtual void TickTask(float DeltaTime) override; /** TargetActorのXY速度が閾値Thresholdを上回る、又は、Threshold以下となるのを待つ */ UFUNCTION(BlueprintCallable, Category = &#34;Ability|Custom|Tasks&#34;, meta = (DisplayName= &#34;WaitGroundMoving&#34;, HidePin = &#34;OwningAbility&#34;, DefaultToSelf = &#34;OwningAbility&#34;, BlueprintInternalUseOnly = &#34;TRUE&#34;)) static UAbilityTask_WaitGroundMoving* CreateWaitGroundMoving(UGameplayAbility* OwningAbility, AActor* Target, float Threshold); virtual void Activate() override; protected: UPROPERTY() AActor* TargetActor; float Threshold; private: bool bIsMoving; };</pre> <pre class="code AbilityTask_WaitGroundMoving.cpp" data-lang="AbilityTask_WaitGroundMoving.cpp" data-unlink>#include &#34;Kismet/KismetMathLibrary.h&#34; void UAbilityTask_WaitGroundMoving::TickTask(float DeltaTime) { if (TargetActor) { float GroundSpeed = UKismetMathLibrary::VSizeXY(TargetActor-&gt;GetVelocity()); if (GroundSpeed &gt; Threshold) { if (!bIsMoving) { if (ShouldBroadcastAbilityTaskDelegates()) { OnStartMoving.Broadcast(); } bIsMoving = true; } } else { if (bIsMoving) { if (ShouldBroadcastAbilityTaskDelegates()) { OnStopMoving.Broadcast(); } bIsMoving = false; } } } else { ABILITY_LOG(Warning, TEXT(&#34;UAbilityTask_WaitGroundMoving ticked without a valid Actor. ending.&#34;)); EndTask(); } } UAbilityTask_WaitGroundMoving* UAbilityTask_WaitGroundMoving::CreateWaitGroundMoving( UGameplayAbility* OwningAbility, AActor* InTarget, float InThreshold) { auto* MyObj = NewAbilityTask&lt;ThisClass&gt;(OwningAbility); MyObj-&gt;bTickingTask = true; //Tick動作に必要 MyObj-&gt;TargetActor = InTarget; MyObj-&gt;Threshold = InThreshold; return MyObj; } void UAbilityTask_WaitGroundMoving::Activate() { SetWaitingOnRemotePlayerData(); }</pre> raksul_01 MetaSoundでお手軽ラジオボイス風表現 hatenablog://entry/4207112889899560728 2022-07-16T18:03:39+09:00 2022-07-16T18:03:39+09:00 タイトル通りです。 なんとなく「外部ソフトを使用せずにUE5内でプロシージャルにラジオ風音声に変換したいな」と思ったので紹介します。 ※MetaSoundの基本的な使い方は省略します。使用するにはプラグインをONにしてください。 また、音声サンプルはありません。 使用バージョン:UE5.0.3 フィルタを使ってこもったような音声にする 音質を悪くする 仕上げにノイズを追加する フィルタを使ってこもったような音声にする まだMetaSoundをほとんど触ったことがなく、機能を把握しきれていないので今回は単純にLPF(Low-pass filter)とHPF(High-pass filter)+α… <p>タイトル通りです。</p> <p>なんとなく「外部ソフトを使用せずにUE5内でプロシージャルにラジオ風音声に変換したいな」と思ったので紹介します。</p> <p>※MetaSoundの基本的な使い方は省略します。使用するには<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D7%A5%E9%A5%B0%A5%A4%A5%F3">プラグイン</a>をONにしてください。</p> <p>また、音声サンプルはありません。</p> <p>使用バージョン:UE5.0.3</p> <ul class="table-of-contents"> <li><a href="#フィルタを使ってこもったような音声にする">フィルタを使ってこもったような音声にする</a></li> <li><a href="#音質を悪くする">音質を悪くする</a></li> <li><a href="#仕上げにノイズを追加する">仕上げにノイズを追加する</a></li> </ul> <h4 id="フィルタを使ってこもったような音声にする">フィルタを使ってこもったような音声にする</h4> <p>まだMetaSoundをほとんど触ったことがなく、機能を把握しきれていないので今回は単純にLPF(Low-pass filter)とHPF(High-pass filter)+αを使っていきます。もちろんBPF(Band-pass filter)でもできるはずです。</p> <p>LPFは、所定の周波数以上の成分をカットするフィルターで、HPFはその逆です。</p> <p>手順は以下の通りです。</p> <p>①<strong>入力ノード</strong>の<strong>On Play</strong>ピンから<strong>Wave Playerノード</strong>の<strong>Play</strong>ピンに接続して音声アセットを再生できるようにします。</p> <p>②<strong>Wave Playerノード</strong>の<strong>Out Left</strong>ピンから、<strong>ワンポールハイパスフィルタノード</strong>(HPF)の<strong>In</strong>ピンに接続します。</p> <p>下図の例では、カットオフ周波数を"3000"に設定しているので、3000Hz以上の周波数成分を通します(数値は割と適当なので調節してください)。</p> <p>なお、今回はデフォルト設定のモノラル音声のまま進めるので、Wave PlayerノードのOut Rightピンは使用しません。</p> <p>③<strong>ワンポールハイパスフィルタノード</strong>の<strong>Out</strong>ピンから<strong>ワンポールローパスフィルタノード</strong>(LPF)の<strong>In</strong>ピンに接続します。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20220716/20220716174252.png" width="1200" height="386" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p>再生してみるとわかりますが、元の音声に比べてこもったような感じになっていると思います。</p> <h4 id="音質を悪くする">音質を悪くする</h4> <p>先ほどまでの状態でこもった音声にはなりますが、元の音声の品質が高いとまだまだラジオっぽくなりません。</p> <p>そこで、<strong>Bitcrusherノード</strong>なるものを、フィルタを通した先に接続します。</p> <p>これは、ノードの説明にもあるように「入力オーディオ信号をダウンサンプルし、ビット深度も下げる」ものみたいなので使えそうだなと思いました。</p> <p>サンプルレートとビット深度をお好みに合わせて調節してください。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20220716/20220716175409.png" width="750" height="288" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p>これで再生してみると、音質が低下したことで更にラジオっぽくなっていると思います。</p> <h4 id="仕上げにノイズを追加する">仕上げにノイズを追加する</h4> <p>先ほどまでで声のいじくりは終わったので、最後は仕上げにノイズを乗せることでよりラジオっぽくしていきますが、ノイズを追加するかどうかは必要に応じて選択してください。</p> <p>手順は以下の通りです。</p> <p>①<strong>ノイズノード</strong>を出して、出力をPink NoiseかWhite Noiseかを選択する。</p> <p>②今回はモノラル音声なので<strong>Mono Mixer (2)ノード</strong>で声とノイズをミックスする。</p> <p>③声とノイズのゲインを調節する。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20220716/20220716175831.png" width="879" height="453" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p>いかがでしょうか。</p> <p>元の音声と比べるとだいぶラジオっぽくなっていると思います。</p> <p>これで、わざわざ外部ソフトで加工しなくてもUE5内で完結できちゃいますね。また、パラメータを変数化して元の音声ファイルを残したままプロシージャルに調節可能なのもMetaSoundの大きな利点だと思います。</p> <p>使い方を調べながら検証するつもりが思ったよりも使いやすかったため、一瞬で記事まで書けてしまいました。</p> <p> </p> <p>つまり、MetaSoundは素晴らしい!</p> <p> </p> <p>以上</p> raksul_01 CC3キャラクターの表情シェイプキーとフェイスリグを残し、Blender Auto-Rig Proのボディリグに統合する hatenablog://entry/13574176438043865952 2022-02-09T20:23:35+09:00 2022-02-09T20:23:35+09:00 今回の記事はタイトル通りです。 今回ご紹介させていただく方法は、Reallusion公式のチュートリアル動画やAuto-Rig ProとUE4との連携についての先人様のブログをいくつか参考にまとめたものです。 こちらの方法を使うことによって、下記メリットが得られると考えられます。 ・CC3キャラクターをBlenderにインポートしてもリギングされていないためすぐにアニメーション作成に取り掛かれないが、Auto-Rig Proの自動リグ生成によってこれを解消できる。iCloneなどよりBlenderでのアニメーション制作のほうが慣れている場合は特に推奨。 ・フェイシャルリグはAuto-Rig P… <p> 今回の記事はタイトル通りです。</p> <p> 今回ご紹介させていただく方法は、Reallusion公式の<a href="https://courses.reallusion.com/home/iclone/pipelines/blender?product=Character%2520Creator&amp;keyword=rig&amp;v=blender-pipeline-4-combining-facial-shape-keys-and-armature-animation-in-blender-with-auto-rig-pro">チュートリアル動画</a>やAuto-Rig Proと<a class="keyword" href="http://d.hatena.ne.jp/keyword/UE4">UE4</a>との連携についての先人様のブログをいくつか参考にまとめたものです。</p> <p> こちらの方法を使うことによって、下記メリットが得られると考えられます。</p> <p>・CC3キャ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%AF">ラク</a>ターを<a class="keyword" href="http://d.hatena.ne.jp/keyword/Blender">Blender</a>にインポートしてもリギングされていないためすぐにアニメーション作成に取り掛かれないが、Auto-Rig Proの自動リグ生成によってこれを解消できる。iCloneなどより<a class="keyword" href="http://d.hatena.ne.jp/keyword/Blender">Blender</a>でのアニメーション制作のほうが慣れている場合は特に推奨。</p> <p>・フェイシャルリグはAuto-Rig Proの生成機能を使わず、CC3の表情シェイプキーとフェイシャルリグを統合させるため、Reallusionの強力なLive Faceアプリなどは引き続き使える(はず)。</p> <p>・Auto-Rig Proは<a class="keyword" href="http://d.hatena.ne.jp/keyword/UE4">UE4</a>やUnityなどの<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B2%A1%BC%A5%E0%A5%A8%A5%F3%A5%B8%A5%F3">ゲームエンジン</a>向けのエクスポートに対応しており、これによって<a class="keyword" href="http://d.hatena.ne.jp/keyword/UE4">UE4</a>やUnity標準ス<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B1%A5%EB%A5%C8">ケルト</a>ンとほぼ同様の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%CC%BF%CC%BE">命名</a>に自動変換してくれるので地味に嬉しい。</p> <p> <a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B2%A1%BC%A5%E0%A5%A8%A5%F3%A5%B8%A5%F3">ゲームエンジン</a>側で自動でマテリアルなどを設定してくれる<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D7%A5%E9%A5%B0%A5%A4%A5%F3">プラグイン</a>(Auto-Setup<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D7%A5%E9%A5%B0%A5%A4%A5%F3">プラグイン</a>)はあるが、これを使っても標準ス<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B1%A5%EB%A5%C8">ケルト</a>ンに沿った<a class="keyword" href="http://d.hatena.ne.jp/keyword/%CC%BF%CC%BE">命名</a>はなされない。ただしマテリアル設定に関してはAuto-Setup<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D7%A5%E9%A5%B0%A5%A4%A5%F3">プラグイン</a>を使うのがよいと思われます。今回の手順はあくまでもス<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B1%A5%EB%A5%C8">ケルト</a>ンの入れ替えと、アニメーション作成などのためのみです。</p> <p>・CC3で作成したヒト型キャ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%AF">ラク</a>ターやそれ以外のソフト(<a class="keyword" href="http://d.hatena.ne.jp/keyword/Blender">Blender</a>など)で作成したヒト型キャ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%AF">ラク</a>ターを、Auto-Rig Proで作成したアー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%C1%A5%E5%A5%A2">マチュア</a>に統一することでリターゲティングが不要になったり簡単になる場合が多い。</p> <ul class="table-of-contents"> <li><a href="#CC3でのキャラクター作成Blenderでのインポートと準備">CC3でのキャラクター作成~Blenderでのインポートと準備</a><ul> <li><a href="#CC3からエクスポートしBlenderでインポートする">CC3からエクスポートし、Blenderでインポートする</a></li> <li><a href="#Auto-Rig-Proのための事前準備">Auto-Rig Proのための事前準備</a></li> </ul> </li> <li><a href="#Auto-Rig-Proによるアーマチュアリグ生成とスキニング">Auto-Rig Proによるアーマチュア・リグ生成とスキニング</a><ul> <li><a href="#アーマチュアの自動生成と修正">アーマチュアの自動生成と修正</a></li> <li><a href="#UE4オプションUE4標準スケルトンに合わせる">(UE4オプション)UE4標準スケルトンに合わせる</a></li> <li><a href="#備考Secondary-Controllersについて">(備考)Secondary Controllersについて</a></li> <li><a href="#リグの自動生成">リグの自動生成</a></li> <li><a href="#リグが上手く生成されない場合">リグが上手く生成されない場合</a></li> <li><a href="#自動スキニングする">自動スキニングする</a></li> <li><a href="#Auto-Rig-ProのリグとCC3のフェイシャルリグの統合">Auto-Rig ProのリグとCC3のフェイシャルリグの統合</a></li> <li><a href="#ウェイト修正する">ウェイト修正する</a></li> <li><a href="#備考服のスキニングの別の方法">(備考)服のスキニングの別の方法</a></li> <li><a href="#UE4オプションUE4-Aポーズにする">(UE4オプション)UE4-Aポーズにする</a></li> <li><a href="#オプションrootの子ボーンの追加">(オプション)rootの子ボーンの追加</a></li> </ul> </li> </ul> <h3 id="CC3でのキャラクター作成Blenderでのインポートと準備">CC3でのキャ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%AF">ラク</a>ター作成~<a class="keyword" href="http://d.hatena.ne.jp/keyword/Blender">Blender</a>でのインポートと準備</h3> <h4 id="CC3からエクスポートしBlenderでインポートする">CC3からエクスポートし、<a class="keyword" href="http://d.hatena.ne.jp/keyword/Blender">Blender</a>でインポートする</h4> <p> ここは特に難しいことはしません。以下の設定でCC3からFBXエクスポートします。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211218/20211218142514.png" alt="f:id:raksul_01:20211218142514p:plain" width="325" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> エクスポートされたFBXを<a class="keyword" href="http://d.hatena.ne.jp/keyword/Blender">Blender</a>にインポートします。</p> <p>インポート時の設定はデフォルトのままでOKです。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211218/20211218142837.png" alt="f:id:raksul_01:20211218142837p:plain" width="237" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h4 id="Auto-Rig-Proのための事前準備">Auto-Rig Proのための事前準備</h4> <p> テンキーの1を押して正面から見ると、おそらく足がZ=0の面に設置していないことになっているので、アー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%C1%A5%E5%A5%A2">マチュア</a>を選択した状態で、<strong>足がZ=0にくるように</strong>します</p> <p>(X軸を示す赤色の線に合わせる)。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211218/20211218143046.png" alt="f:id:raksul_01:20211218143046p:plain" width="346" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> その後、Aキーで<strong>アー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%C1%A5%E5%A5%A2">マチュア</a>とすべてのメッシュを選択</strong>した状態でCtrl+A→「<strong>適用:全トランスフォーム</strong>」をします。</p> <p> また、このままだとメッシュ内部に骨があって見えづらいので、以下のように「<strong>最前面」にチェック</strong>を入れます。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211218/20211218143619.png" alt="f:id:raksul_01:20211218143619p:plain" width="329" height="175" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> 次に、後で誤って操作しないようにするために各パーツのメッシュ(身体、服、靴、眼球、口、舌、髪の毛などすべて)それぞれに対して、<strong>頂点グループをすべてロック</strong>します。ちなみに、左クリックした状態でドラッグすると一気にロックできます。あるいは、下向きの「>」を押すと「すべてロック」というボタンがあります。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211218/20211218144950.png" alt="f:id:raksul_01:20211218144950p:plain" width="272" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h3 id="Auto-Rig-Proによるアーマチュアリグ生成とスキニング">Auto-Rig Proによるアー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%C1%A5%E5%A5%A2">マチュア</a>・リグ生成とスキニング</h3> <h4 id="アーマチュアの自動生成と修正">アー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%C1%A5%E5%A5%A2">マチュア</a>の自動生成と修正</h4> <p> キャ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%AF">ラク</a>ターの<strong>メッシュをすべて選択</strong>した状態で、Auto-Rig Proのメニューから<strong>Get Selected Objects</strong>を押します。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211219/20211219114651.png" alt="f:id:raksul_01:20211219114651p:plain" width="771" height="635" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> すると、元のアー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%C1%A5%E5%A5%A2">マチュア</a>が非表示になりますが、後の作業のために<strong>アー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%C1%A5%E5%A5%A2">マチュア</a>を再度表示</strong>します。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211219/20211219115401.png" alt="f:id:raksul_01:20211219115401p:plain" width="326" height="132" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> ここからはAuto-Rig ProのSmart機能を使って、アー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%C1%A5%E5%A5%A2">マチュア</a>を生成します。Smart機能を使う際、首、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A5%B4">アゴ</a>、肩、手首、背骨のルート、足首のアタリをつけていくことになります。</p> <p> 先ほどAuto-Rig Pro:Smart内のGet Selected Objectsボタンを押した後、メニュー内がAdd Neckなどのボタンに変わっていると思うので、そちらを押すとアタリをつけるためのマーカーが追加されるので、再表示した<strong>元のCC3アー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%C1%A5%E5%A5%A2">マチュア</a>をもとにアタリをつけていきます</strong>。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211219/20211219121522.png" alt="f:id:raksul_01:20211219121522p:plain" width="415" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> 配置し終えたら<strong>Goボタン</strong>を押します。Auto-Rig Proのバージョンによってはこのとき、フェイシャルリグを生成するか聞かれますが今回はCC3のフェイシャルリグを統合することが目的なので生成しないようにします。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211219/20211219121803.png" alt="f:id:raksul_01:20211219121803p:plain" width="181" height="338" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> すると、アー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%C1%A5%E5%A5%A2">マチュア</a>が自動生成されますが、元のCC3アー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%C1%A5%E5%A5%A2">マチュア</a>に対してずれているので各<strong>ボーンの位置を修正</strong>していきます。なお、手足などは左右対称に位置が移動されるので、片側のみでOKです。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211219/20211219125709.png" alt="f:id:raksul_01:20211219125709p:plain" width="511" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p>足の3か所(leg_ref.l, foot_ref.l, toes_ref.l)</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211219/20211219130225.png" alt="f:id:raksul_01:20211219130225p:plain" width="314" height="163" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p>ひざ(thigh_ref.l)</p> <p>※<strong><span style="color: #ff0000;">重要!!</span></strong><strong><span style="color: #ff0000;">必ずしもCC3アー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%C1%A5%E5%A5%A2">マチュア</a>の位置に合わせる必要はなく、間違った方向にまがらないようにすること</span></strong>。ひざはCC3アー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%C1%A5%E5%A5%A2">マチュア</a>よりもすこし前に出すような感じにするとよい。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211219/20211219130457.png" alt="f:id:raksul_01:20211219130457p:plain" width="1169" height="300" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p>腕(shoulder_ref.l, arm_ref.l)※正面視でも調整すること。</p> <p> ここも<span style="color: #ff0000;"><strong>ひじ関節に注意</strong></span>。画像よりも後ろ(画像上方向)にずらすとよいかもしれません。ボーン位置が適切でないと後で問題が発生しますが、後述するように修正することもできます。</p> <p> 他のボーンと同様に、指のボーン位置も合わせた方がよいです。</p> <h4 id="UE4オプションUE4標準スケルトンに合わせる">(<a class="keyword" href="http://d.hatena.ne.jp/keyword/UE4">UE4</a>オプション)<a class="keyword" href="http://d.hatena.ne.jp/keyword/UE4">UE4</a>標準ス<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B1%A5%EB%A5%C8">ケルト</a>ンに合わせる</h4> <p> <a class="keyword" href="http://d.hatena.ne.jp/keyword/UE4">UE4</a>に持っていく場合は、標準ス<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B1%A5%EB%A5%C8">ケルト</a>ンの仕様上、背骨の数を4つにしたほうがよいです。これをするには<strong>いずれかの背骨(spine)を選択</strong>した状態で、Auto-Rig Proのメニューから<strong>Limb Optionsボタン</strong>を押して<strong>数を4</strong>にします。これはGoボタンでアー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%C1%A5%E5%A5%A2">マチュア</a>を生成する際にも設定できるのでそこで4つに設定していれば変更する必要はありません。</p> <p> さらに、ツイストボーンも追加した方がよいそうです。これをするには、腕のボーンを選択した状態で、<strong>Limb Optionsボタン</strong>を押して<strong>Twist <a class="keyword" href="http://d.hatena.ne.jp/keyword/Bones">Bones</a>を2~4</strong>にします。脚に関してはよっぽど左右のねじれが激しくなければ増やさなくてもよいそう。</p> <h4 id="備考Secondary-Controllersについて">(備考)Secondary Controllersについて</h4> <p> なん氏によるブログ記事(<a href="https://kanianthi.hateblo.jp/entry/2020/09/13/133459">AutoRigProの解説:その2 Smart編 - 当たったらどうすんだよ</a>)より、Limb Optionsのほかにも<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%BB%A5%AB%A5%F3%A5%C0%A5%EA">セカンダリ</a>コントローラ設定ができますが、Twistコントローラは<a class="keyword" href="http://d.hatena.ne.jp/keyword/Blender">Blender</a>独自仕様であり、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B2%A1%BC%A5%E0%A5%A8%A5%F3%A5%B8%A5%F3">ゲームエンジン</a>にそのままエクスポートはできないため<strong>Additive</strong>のままでもよいそう。</p> <h4 id="リグの自動生成">リグの自動生成</h4> <p> ここまでできたら、<strong>Auto-Rig Proのアー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%C1%A5%E5%A5%A2">マチュア</a>を選択した状態</strong>で、<strong>Match to Rigボタン</strong>を押します。するとリグがアー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%C1%A5%E5%A5%A2">マチュア</a>に従って自動で生成されます。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211219/20211219131307.png" alt="f:id:raksul_01:20211219131307p:plain" width="801" height="602" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h4 id="リグが上手く生成されない場合">リグが上手く生成されない場合</h4> <p> 生成されたリグを見ると、脚は真っすぐですが、上腕や下腕のリグはねじれているように見えます。このようなときは肘関節のボーン位置などが原因のことが多いので、 Match to Rigボタンの上のほうにある<strong>Edit Reference <a class="keyword" href="http://d.hatena.ne.jp/keyword/Bones">Bones</a>ボタン</strong>を押してボーンを再度位置修正し、Match to Rigボタンを押してリグを再生成、という工程を繰り返します。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211219/20211219133209.png" alt="f:id:raksul_01:20211219133209p:plain" width="341" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211219/20211219132759.png" alt="f:id:raksul_01:20211219132759p:plain" width="345" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p>上は修正前(リグのねじれが激しい)、下は修正後。</p> <h4 id="自動スキニングする">自動スキニングする</h4> <p>  所望のリグが生成されたら、オブジェクトモードで<strong><span style="text-decoration: underline;">最初に</span><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A5%A6%A5%C8%A5%E9%A5%A4%A5%CA%A1%BC">アウトライナー</a>からメッシュをすべて選択</strong>し、<strong><span style="text-decoration: underline;">最後に</span>リグをShiftを押しながら3Dビュー上で選択</strong>した状態で、スキンメニューにある<strong>Bindボタン</strong>を押してしばらく待ちます。すると、Auto-Rig Proのリグに従ってメッシュが自動でスキニングされます。なお、Mesh Binding設定にてスキニングのメソッドをHeat MapかVoxelizedから選択することも可能です。</p> <p> <span style="color: #ff0000;">※<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B2%A1%BC%A5%E0%A5%A8%A5%F3%A5%B8%A5%F3">ゲームエンジン</a>に持っていく場合は<strong>「体積を維持」のチェックは外す</strong>方がよい。</span></p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211219/20211219141459.png" alt="f:id:raksul_01:20211219141459p:plain" width="1007" height="377" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> リグを動かしてみるとAuto-Rig Proのリグに従ってスキニングされていることが確認できますが、CC3のフェイシャルリグは動作しなくなっています。なので、これらを統合する作業に入ります。</p> <h4 id="Auto-Rig-ProのリグとCC3のフェイシャルリグの統合">Auto-Rig ProのリグとCC3のフェイシャルリグの統合</h4> <p> まずはCC3のアー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%C1%A5%E5%A5%A2">マチュア</a>から不要なボーンを削除します。オブジェクトモードでCC3のアー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%C1%A5%E5%A5%A2">マチュア</a>を選択し、編集モードに切り替えます。</p> <p> サークル選択などを使って<strong>顔以外のボーンを選択</strong>して、Xキー→<strong>ボーンを削除</strong>します(胸にあるボーンも忘れずに削除)。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211219/20211219142221.png" alt="f:id:raksul_01:20211219142221p:plain" width="352" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> オブジェクトモードに戻り、<strong>CC3の残ったアー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%C1%A5%E5%A5%A2">マチュア</a>(フェイシャルリグ)を選択</strong>し、<strong>Shiftを押しながらAuto-Rig Proのリグを選択</strong>し、<strong>Ctrl+J</strong>でリグを統合します。統合後、フェイシャルリグがメッシュの内部に隠れますが問題ありません。</p> <p> 次に、Auto-Rig Proの頭部のリグにCC3のフェイシャルリグが追従するようにします。<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%EF%A5%A4%A5%E4%A1%BC%A5%D5%A5%EC%A1%BC%A5%E0">ワイヤーフレーム</a>表示に切り替えて<strong>CC_Base_Headボーン(CC_Base_Facialに隠れてます)を選択</strong>し、ボーン設定から<strong>c_head.xをペ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A5%EC%A5%F3%A5%C8">アレント</a>に設定</strong>します。</p> <h4 id="ウェイト修正する">ウェイト修正する</h4> <p> 今回は、髪の毛や服などすべて自動スキニングしたため高確率で修正が必要になります。<strong><span style="color: #ff0000;">そもそも髪の毛や服を自動スキニングしない方法もあります</span></strong>が、今回はすべて自動スキニングしたものとして修正の仕方の例を挙げておきます。</p> <p> 前提として知っておくことは、Auto-Rig Proの<a class="keyword" href="http://d.hatena.ne.jp/keyword/%CC%BF%CC%BE%B5%AC%C2%A7">命名規則</a>として、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D7%A5%EC%A5%D5%A5%A3%A5%C3%A5%AF%A5%B9">プレフィックス</a>のないものは基本、できあがりのス<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B1%A5%EB%A5%C8">ケルト</a>ンのボーンとなるもの、"c_"のつくものはコントローラです。なので、ウェイトは<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D7%A5%EC%A5%D5%A5%A3%A5%C3%A5%AF%A5%B9">プレフィックス</a>のないものにつけていくことになります。</p> <p>・頂点グループhead.xで首以外を選択してウェイト1.0で割り当て</p> <p>・首の頂点グループにまつげが含まれていたりするので首以外の部分をウェイト削除</p> <p>・体メッシュ以外は、それぞれのメッシュに対して頂点グループメニューから「<strong>未ロックグループを削除</strong>」でOK</p> <p>※基本的には、最初にロックしたCC3ですでにスキニングされたものだけを残すイメージです。なのでhead.xもすべてウェイト削除でよいかもしれません。</p> <h4 id="備考服のスキニングの別の方法">(備考)服のスキニングの別の方法</h4> <p> こちらのツイートの方法を使えば、服は自動スキニングせずに身体メッシュから転送して対応できそうです。</p> <blockquote class="twitter-tweet" data-conversation="none" data-lang="ja"> <p dir="ltr" lang="ja">【Auto rig pro・服追随】<br />①服・体の順番にメッシュを選択。<br />②スペース押し、メッシュデータの転送→頂点グループを選択。<br />③左下項目で最接近を選択。補間面をすべてのレイヤー(All Layers)選択。<br />④これで全ての頂点グループが服に転送される。<br />参考(<a href="https://t.co/NB93E8yIZX">https://t.co/NB93E8yIZX</a>)</p> — ahobaka (@ahobaka) <a href="https://twitter.com/ahobaka/status/1086419464843743232?ref_src=twsrc%5Etfw">2019年1月19日</a></blockquote> <p> <script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> </p> <h4 id="UE4オプションUE4-Aポーズにする">(<a class="keyword" href="http://d.hatena.ne.jp/keyword/UE4">UE4</a>オプション)<a class="keyword" href="http://d.hatena.ne.jp/keyword/UE4">UE4</a>-Aポーズにする</h4> <p> CC3でもエクスポート時にAポーズを指定していますが、ここでいうAポーズとは同じAポーズでも<a class="keyword" href="http://d.hatena.ne.jp/keyword/UE4">UE4</a>標準に近いAポーズを指します。</p> <p> 厳密にいえば、<a class="keyword" href="http://d.hatena.ne.jp/keyword/Blender">Blender</a>でのリグ&アー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%C1%A5%E5%A5%A2">マチュア</a>再生成&CC3表情シェイプキー統合(要するに今回の方法)を用いないのであれば、CC3でエクスポートする際に<a class="keyword" href="http://d.hatena.ne.jp/keyword/UE4">UE4</a>-Aposeを指定することができますが、今回の方法は<a class="keyword" href="http://d.hatena.ne.jp/keyword/Blender">Blender</a>で、かつ、AutoRig Proを使うことになるため<a class="keyword" href="http://d.hatena.ne.jp/keyword/UE4">UE4</a>-Aposeでエクスポートは行わず、通常のAポーズでエクスポートしていることになります。そのため、AutoRig Proの機能を使って<a class="keyword" href="http://d.hatena.ne.jp/keyword/UE4">UE4</a>のAポーズに近づける必要があります。<br /> Set PoseでAポーズを選んで<strong>Apply Pose at Rest Poseボタン</strong>を押した後に、<strong>Match to Rigボタン</strong>を押すことで<a class="keyword" href="http://d.hatena.ne.jp/keyword/UE4">UE4</a>のAポーズに近いものとなります(Auto-Rig ProのAポーズは<a class="keyword" href="http://d.hatena.ne.jp/keyword/UE4">UE4</a>のAポーズに非常に近い)。</p> <h4 id="オプションrootの子ボーンの追加">(オプション)rootの子ボーンの追加</h4> <p> rootに子ボーンを追加したい場合は、<strong>c_traj</strong>にペ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A5%EC%A5%F3%A5%C8">アレント</a>すれば上手くいった。</p> <p> </p> raksul_01 GASでダッシュアビリティを実装しよう!(アビリティにキー入力を関連付ける) hatenablog://entry/13574176438049058747 2022-01-04T18:36:32+09:00 2022-01-04T18:36:32+09:00 らくするです。 今回は、いまアツいGameplayAbilitiesプラグインを使ったダッシュアビリティ(ダッシュ以外にも幅広く使える!)の実装について紹介したいと思います。 本記事で紹介する方法はダッシュ以外にも色々と使い道があるため、GASの導入時についでに実装しておくといいかも…なんて思ったり。 ※本記事の実装方法を用いて生じたいかなる問題に対しても責任を負えませんのでご了承ください。 今回の記事を書くに至った経緯としては、GameplayAbilitySystemによるダッシュ(スプリント)を実装しようとしたとき、GameplayAbilityクラスを1つだけ使ってShiftキーのPr… <p> らくするです。<br />  今回は、いまアツいGameplayAbilities<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D7%A5%E9%A5%B0%A5%A4%A5%F3">プラグイン</a>を使った<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C0%A5%C3%A5%B7%A5%E5">ダッシュ</a>アビリティ(<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C0%A5%C3%A5%B7%A5%E5">ダッシュ</a>以外にも幅広く使える!)の実装について紹介したいと思います。<br />  本記事で紹介する方法は<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C0%A5%C3%A5%B7%A5%E5">ダッシュ</a>以外にも色々と使い道があるため、GASの導入時についでに実装しておくといいかも…なんて思ったり。<br /> <span style="font-size: 80%"><span style="color: #666666">※本記事の実装方法を用いて生じたいかなる問題に対しても責任を負えませんのでご了承ください。</span></span></p><p> 今回の記事を書くに至った経緯としては、GameplayAbilitySystemによる<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C0%A5%C3%A5%B7%A5%E5">ダッシュ</a>(スプリント)を実装しようとしたとき、GameplayAbilityクラスを1つだけ使ってShiftキーのPress/Releaseの判定をするように実装するのがブループリンターには少し厄介だったためです。<br />  例えば、GameplayAbilityクラスを「歩行」と「走行」の2つのアビリティを用意して、インプットアクションによるイベントを使ってShiftキーを押したら「走行」アビリティを発動し、離したら「歩行」アビリティが発動するように仕組めば可能ではあるのですが、あまりスマートじゃないように思えます。</p><p> GameplayAbilityごとにキー入力を関連付けるというのはかなり多用しそうな処理であるにも関わらず、紹介や解説の記事・動画はあまりないようでしたので、自分なりにまとめてみようと思います。</p><p> 誤っている部分やよろしくない記述が散見されるかもしれませんので、もしよろしければコメントやDMでご指摘いただけますと幸いです。</p><p> 今回の実装にあたって、GASShooterのコードの一部の他に、<a class="keyword" href="http://d.hatena.ne.jp/keyword/Twitter">Twitter</a>でのあいす氏(@koorinonaka)からの下記リプライを参考にいたしました。ご助言ありがとうございました。<blockquote data-conversation="none" class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr"><a href="https://t.co/AgtR3eV8ST">https://t.co/AgtR3eV8ST</a><br>4.6.2 Binding Input to the ASC にInputPressed/Releasedへの実装が書いてあります。ちょっとこの辺は仕様がややこしいですね。。GiveAbilityで渡すFGameplayAbilitySpecに指定するInputIDが一致してればAbilityTaskのInputPressedでイベントが発行されるって感じです。</p>&mdash; あいす (@koorinonaka) <a href="https://twitter.com/koorinonaka/status/1474013534124384257?ref_src=twsrc%5Etfw">2021年12月23日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> </p> <ul class="table-of-contents"> <li><a href="#GASの導入">GASの導入</a></li> <li><a href="#ダッシュの実装">ダッシュの実装</a><ul> <li><a href="#前置き">前置き</a></li> <li><a href="#GameplayAbilityにキー入力を紐づける">GameplayAbilityにキー入力を紐づける</a><ul> <li><a href="#EnumでインプットIDを定義する">EnumでインプットIDを定義する</a></li> <li><a href="#GameplayAbilityクラスを拡張する">GameplayAbilityクラスを拡張する</a></li> <li><a href="#MyCharacterクラスを改変する">MyCharacterクラスを改変する</a></li> </ul> </li> <li><a href="#ダッシュのGameplayAbilityクラスを作成する">ダッシュのGameplayAbilityクラスを作成する</a></li> </ul> </li> <li><a href="#完了">完了</a></li> </ul> <div class="section"> <h3 id="GASの導入">GASの導入</h3> <p> 今回使用したのはUE5EAです。<br />  GASをプロジェクトに導入するには<a class="keyword" href="http://d.hatena.ne.jp/keyword/C%2B%2B">C++</a>を使った初期セットアップが必要ですが、これについては、他のブログ様などでもよくご紹介されている<br /> おかわりはくまい氏によるセットアップ方法の紹介記事が非常に参考になります。<br />  当該記事についてはタイトルだけ下記しておきます。</p><p>・GameplayAbilitiesの使い方(セットアップ編) - おかわりのアンリアルなメモ</p> </div> <div class="section"> <h3 id="ダッシュの実装"><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C0%A5%C3%A5%B7%A5%E5">ダッシュ</a>の実装</h3> <div class="section"> <h4 id="前置き">前置き</h4> <p> 話を振り出しに戻しますが、なぜGameplayAbilityクラスを1つで<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C0%A5%C3%A5%B7%A5%E5">ダッシュ</a>を実装しようとすると面倒なのかについて少しだけ…。</p><p> 今回、肝要となるのが以下の、WaitInputPress/WaitInputRelease(特に後者)というキー入力のPress/Releaseの監視をしてくれるAbilityTaskになります。<br /> <span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211226/20211226225749.png" alt="f:id:raksul_01:20211226225749p:plain" width="706" height="206" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p><p> え、そいつら使えばすぐできるんじゃ…?</p><p>と思われるかもしれませんが、これらのAbilityTaskはすぐには使えません。<br /> 各GameplayAbilityをキー入力に紐づける必要があり、そのためにはプロジェクト設定のアクション<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%C3%A5%D4%A5%F3%A5%B0">マッピング</a>だけでなく、<a class="keyword" href="http://d.hatena.ne.jp/keyword/C%2B%2B">C++</a>を使って紐づける必要があるためです。</p> </div> <div class="section"> <h4 id="GameplayAbilityにキー入力を紐づける">GameplayAbilityにキー入力を紐づける</h4> <p> 本記事では、おかわりはくまい氏によるセットアップ記事の通りにセットアップしたものを改変して実装していきます。</p> <div class="section"> <h5 id="EnumでインプットIDを定義する"><a class="keyword" href="http://d.hatena.ne.jp/keyword/Enum">Enum</a>でインプットIDを定義する</h5> <p> 定義する場所はどこが最適なのかわからないのでプロジェクトのヘッダーに定義しました。<br />  DisplayNameは適当でも大丈夫ですが、<strong><span style="color: #ff0000">各アクション名はプロジェクトのアクション<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%C3%A5%D4%A5%F3%A5%B0">マッピング</a>と同じ名前にしておきましょう。</span></strong><br />  開発を進むにつれてインプットアクションを増やす場合はその都度、EAbilityInputIDも増やしていけば良いだけです。</p><p>プロジェクト名.h</p> <pre class="code lang-cpp" data-lang="cpp" data-unlink><span class="synPreProc">#pragma once</span> <span class="synPreProc">#include </span><span class="synConstant">&quot;CoreMinimal.h&quot;</span> <span class="synIdentifier">UENUM</span>(BlueprintType) <span class="synType">enum</span> <span class="synType">class</span> EAbilityInputID : uint8 { <span class="synComment">// 0 None</span> None <span class="synIdentifier">UMETA</span>(DisplayName = <span class="synConstant">&quot;None&quot;</span>), <span class="synComment">// 1 Confirm</span> Confirm <span class="synIdentifier">UMETA</span>(DisplayName = <span class="synConstant">&quot;Confirm&quot;</span>), <span class="synComment">// 2 Cancel</span> Cancel <span class="synIdentifier">UMETA</span>(DisplayName = <span class="synConstant">&quot;Cancel&quot;</span>), <span class="synComment">// 3 Sprint</span> Sprint <span class="synIdentifier">UMETA</span>(DisplayName = <span class="synConstant">&quot;Sprint&quot;</span>) }; </pre><p>※今回は参考にしたGASShooterにConfirmやCancelといったInputIDが定義されていたので同様に追加しております。<br /> これはおそらく、WaitForCancelInput / WaitForConfirmInputといったAbilityTaskで用いるものと思われますが、詳しく調べてないためここでは説明無しです。</p> </div> <div class="section"> <h5 id="GameplayAbilityクラスを拡張する">GameplayAbilityクラスを拡張する</h5> <p> BPでアビリティ毎のバインド先の変更が簡単にできるよう、MyGameplayAbilityクラスを作成します。</p><p>MyGameplayAbility.h</p> <pre class="code lang-cpp" data-lang="cpp" data-unlink><span class="synPreProc">#pragma once</span> <span class="synPreProc">#include </span><span class="synConstant">&quot;CoreMinimal.h&quot;</span> <span class="synPreProc">#include </span><span class="synConstant">&quot;プロジェクト名/プロジェクト名.h&quot;</span> <span class="synPreProc">#include </span><span class="synConstant">&quot;Abilities/GameplayAbility.h&quot;</span> <span class="synPreProc">#include </span><span class="synConstant">&quot;MyGameplayAbility.generated.h&quot;</span> <span class="synIdentifier">UCLASS</span>() <span class="synType">class</span> プロジェクト名_API UMyGameplayAbility : <span class="synStatement">public</span> UGameplayAbility { <span class="synIdentifier">GENERATED_BODY</span>() <span class="synStatement">public</span>: <span class="synIdentifier">UPROPERTY</span>(BlueprintReadOnly, EditAnywhere, Category = <span class="synConstant">&quot;Ability&quot;</span>) EAbilityInputID AbilityInputID = EAbilityInputID::None; }; </pre> </div> <div class="section"> <h5 id="MyCharacterクラスを改変する">MyCharacterクラスを改変する</h5> <p>(変更点)<br /> ・インクルード対象にMyGameplayAbilityクラスおよびプロジェクトのヘッダーを追加する。<br /> ・AbilityListをMyGameplayAbilityクラスの配列にする。<br /> ・InputIDに対してキー入力を<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D0%A5%A4%A5%F3%A5%C7%A5%A3%A5%F3%A5%B0">バインディング</a>するためのBindASCInput()を宣言。</p><p>MyCharacter.h</p> <pre class="code lang-cpp" data-lang="cpp" data-unlink><span class="synPreProc">#include </span><span class="synConstant">&quot;CoreMinimal.h&quot;</span> <span class="synPreProc">#include </span><span class="synConstant">&quot;GameFramework/Character.h&quot;</span> <span class="synPreProc">#include </span><span class="synConstant">&quot;プロジェクト名/プロジェクト名.h&quot;</span> <span class="synPreProc">#include </span><span class="synConstant">&quot;AbilitySystemInterface.h&quot;</span> <span class="synPreProc">#include </span><span class="synConstant">&quot;MyGameplayAbility.h&quot;</span> <span class="synPreProc">#include </span><span class="synConstant">&quot;MyCharacter.generated.h&quot;</span> <span class="synIdentifier">UCLASS</span>() <span class="synType">class</span> プロジェクト名_API AMyCharacter : <span class="synStatement">public</span> ACharacter { <span class="synIdentifier">GENERATED_BODY</span>() ・・・ <span class="synStatement">public</span>: <span class="synIdentifier">UPROPERTY</span>(VisibleAnywhere, BlueprintReadOnly, Category = Abilities, meta = (AllowPrivateAccess = <span class="synConstant">&quot;true&quot;</span>)) <span class="synType">class</span> UAbilitySystemComponent* AbilitySystem; UAbilitySystemComponent* <span class="synIdentifier">GetAbilitySystemComponent</span>() <span class="synType">const</span> { <span class="synStatement">return</span> AbilitySystem; }; <span class="synIdentifier">UPROPERTY</span>(EditAnywhere, BlueprintReadWrite, Category = Abilities) TArray&lt;TSubclassOf&lt;<span class="synType">class</span> UMyGameplayAbility&gt;&gt; AbilityList; }; <span class="synStatement">protected</span>: <span class="synType">void</span> <span class="synIdentifier">BindASCInput</span>(); <span class="synType">bool</span> bASCInputBound; </pre><p>(変更点)<br /> ・InputIDを削除。<br /> ・MyGameplayAbilityクラスを継承した各アビリティのBPクラスで設定したAbilityInputID != 0であればその値をInputIDに、それ以外はInputIDに-1が割り当てられるように。<br /> ・BindASCInput()の処理を記述。</p><p>MyCharacter.cpp</p> <pre class="code lang-cpp" data-lang="cpp" data-unlink> ・・・ <span class="synType">void</span> AMyCharacterBase::<span class="synIdentifier">BeginPlay</span>() { Super::<span class="synIdentifier">BeginPlay</span>(); <span class="synStatement">if</span> (AbilitySystem) { <span class="synStatement">if</span> (<span class="synIdentifier">HasAuthority</span>() &amp;&amp; AbilityList.<span class="synIdentifier">Num</span>() &gt; <span class="synConstant">0</span>) { <span class="synStatement">for</span> (<span class="synType">auto</span> Ability : AbilityList) { <span class="synStatement">if</span> (Ability) { <span class="synStatement">if</span> (<span class="synStatement">static_cast</span>&lt;int32&gt;(Ability.<span class="synIdentifier">GetDefaultObject</span>()-&gt;AbilityInputID) != <span class="synConstant">0</span>) { AbilitySystem-&gt;<span class="synIdentifier">GiveAbility</span>(<span class="synIdentifier">FGameplayAbilitySpec</span>(Ability.<span class="synIdentifier">GetDefaultObject</span>(), <span class="synConstant">1</span>, <span class="synStatement">static_cast</span>&lt;int32&gt;(Ability.<span class="synIdentifier">GetDefaultObject</span>()-&gt;AbilityInputID), <span class="synStatement">this</span>)); } <span class="synStatement">else</span> { AbilitySystem-&gt;<span class="synIdentifier">GiveAbility</span>(<span class="synIdentifier">FGameplayAbilitySpec</span>(Ability.<span class="synIdentifier">GetDefaultObject</span>(), <span class="synConstant">1</span>, -<span class="synConstant">1</span>, <span class="synStatement">this</span>)); } } } } AbilitySystem-&gt;<span class="synIdentifier">InitAbilityActorInfo</span>(<span class="synStatement">this</span>, <span class="synStatement">this</span>); } } <span class="synType">void</span> AMyCharacter::<span class="synIdentifier">SetupPlayerInputComponent</span>(UInputComponent* PlayerInputComponent) {     Super::<span class="synIdentifier">SetupPlayerInputComponent</span>(PlayerInputComponent); ・・・     <span class="synIdentifier">BindASCInput</span>(); } <span class="synType">void</span> AMyCharacter::<span class="synIdentifier">BindASCInput</span>() { <span class="synStatement">if</span> (!bASCInputBound &amp;&amp; <span class="synIdentifier">IsValid</span>(AbilitySystem) &amp;&amp; <span class="synIdentifier">IsValid</span>(InputComponent)) { AbilitySystem-&gt;<span class="synIdentifier">BindAbilityActivationToInputComponent</span>(InputComponent, <span class="synIdentifier">FGameplayAbilityInputBinds</span>(<span class="synIdentifier">FString</span>(<span class="synConstant">&quot;ConfirmTarget&quot;</span>), <span class="synIdentifier">FString</span>(<span class="synConstant">&quot;CancelTarget&quot;</span>), <span class="synIdentifier">FString</span>(<span class="synConstant">&quot;EAbilityInputID&quot;</span>), <span class="synStatement">static_cast</span>&lt;int32&gt;(EAbilityInputID::Confirm), <span class="synStatement">static_cast</span>&lt;int32&gt;(EAbilityInputID::Cancel))); bASCInputBound = <span class="synConstant">true</span>; } } </pre><p>①GiveAbilityで渡すFGameplayAbilitySpecにInputIDを指定することで、各GameplayAbilityとInputIDとを紐づけます。<br /> ②BindASCInput()内のAbilitySystem->BindAbilityActivationToInputComponentによって、先ほど<a class="keyword" href="http://d.hatena.ne.jp/keyword/Enum">Enum</a>で定義したInputIDに対応するキーがPress/Releaseされた際にインプットアクションが発行され、さらに①で紐づけられたInputIDに対応するGameplayAbilityがActivateされるようになっています。</p><p> なお、AbilitySystem->BindAbilityActivationToInputComponentの実行タイミングはSetupPlayerInputComponentの後にしていますが、<br />  おそらくネットワーク対応ゲームの場合はOnRep_PlayerStateのときも含めて二回とすることが望ましいです(InputComponentが存在しない可能性があるため)。<br /> ※bASCInputBoundは二重にBindASCInput()が実行されないようにするための値なので、ネットワーク対応でない場合は不要。</p> </div> </div> <div class="section"> <h4 id="ダッシュのGameplayAbilityクラスを作成する"><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C0%A5%C3%A5%B7%A5%E5">ダッシュ</a>のGameplayAbilityクラスを作成する</h4> <p> <strong>MyGameplayAbilityクラスをBP継承</strong>したGA_Sprintを作成します。<br />  作成したら、クラスのデフォルト設定にてAbilityInputIDをSprintにしておきます。<br /> ちなみに、上記②のようにインプットアクションをGameplayAbilityに<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D0%A5%A4%A5%F3%A5%C7%A5%A3%A5%F3%A5%B0">バインディング</a>しているため、キャ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%AF">ラク</a>ターのBP内で「インプットアクション○○」→「TryActivateBy~~」などを記述しておく必要はありません。<br />  つまり、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C0%A5%C3%A5%B7%A5%E5">ダッシュ</a>以外のGameplayAbilityを追加した際は、<br /> ・EAbilityInputIDと、プロジェクトのアクション<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%C3%A5%D4%A5%F3%A5%B0">マッピング</a>に同名のアクションを追加する。<br /> ・追加したアビリティBPの設定から、EAbilityInputIDを選択する。<br /> これだけを行うだけで、キャ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%AF">ラク</a>ターのBP内でアビリティ発動の処理を記述する必要がなくなるというわけです。</p><p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20220104/20220104044647.png" alt="f:id:raksul_01:20220104044647p:plain" width="467" height="112" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p><p> 中身は必要最低限で以下のような感じにしました。<br /> Start/Stop Sprintingの中身はキャ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%AF">ラク</a>ターのMovement Componentを取得してSetMaxWalkSpeedで移動速度を変更しているだけです。</p><p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20220104/20220104044924.png" alt="f:id:raksul_01:20220104044924p:plain" width="929" height="335" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><br /> </p> </div> </div> <div class="section"> <h3 id="完了">完了</h3> <p> うまくいけば、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C0%A5%C3%A5%B7%A5%E5">ダッシュ</a>のキーを押すとアビリティがActivateされてStart Sprintingによってスピードが上がり、キーを離すとWaitInputReleasedのOnReleaseから続くEndAbilityが実行され、Stop Sprintingによってスピードが下がって歩行に戻る といった挙動が実現しているはずです。</p><p> 無駄な部分やより良い方法があればぜひ教えていただけると幸いです。</p> </div> raksul_01 「オーストラリアの自然」アセットで使われている道路マテリアルの中身を見てみる(1) hatenablog://entry/13574176438042273613 2021-12-13T15:54:20+09:00 2021-12-13T15:54:20+09:00 ※この記事は、シェーダーに精通していない私の勉強のための備忘録みたいなものです。そのため、間違った部分がある場合がございます。 こんにちは、らくするです。 すっかりクリスマスシーズンですね。 今回は、永続無料コンテンツである「オーストラリアの自然」で使われている道路マテリアルの中身がどうなっているのか、ざっくりと見ていきたいと思います。 www.unrealengine.com なぜ中身を見ようと思ったのかと言いますと、この道路、単純なマテリアルではなく地面と馴染ませるようにされていたり(馴染ませる部分の詳細についてはまた後日ですが…)、その他いろいろと工夫されている点が多い(らしい?)ので一… <p>※この記事は、シェーダーに精通していない私の勉強のための備忘録みたいなものです。そのため、間違った部分がある場合がございます。</p> <p>こんにちは、らくするです。</p> <p>すっかりクリスマスシーズンですね。</p> <p>今回は、永続無料コンテンツである「オーストラリアの自然」で使われている道路マテリアルの中身がどうなっているのか、ざっくりと見ていきたいと思います。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.unrealengine.com%2Fmarketplace%2Fja%2Fproduct%2Frural-australia%3FsessionInvalidated%3Dtrue" title="オーストラリアの自然:環境 - UE マーケットプレイス" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://www.unrealengine.com/marketplace/ja/product/rural-australia?sessionInvalidated=true">www.unrealengine.com</a></cite></p> <p>なぜ中身を見ようと思ったのかと言いますと、この道路、単純なマテリアルではなく地面と馴染ませるようにされていたり(馴染ませる部分の詳細についてはまた後日ですが…)、その他いろいろと工夫されている点が多い(らしい?)ので一度見てみたかったからです。</p> <ul class="table-of-contents"> <li><a href="#道路のメッシュについて">道路のメッシュについて</a></li> <li><a href="#マテリアルについて">マテリアルについて</a></li> </ul> <h3 id="道路のメッシュについて">道路のメッシュについて</h3> <figure class="figure-image figure-image-fotolife mceNonEditable" title="道路メッシュ"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211213/20211213105242.png" alt="f:id:raksul_01:20211213105242p:plain" width="1200" height="719" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">道路メッシュ</figcaption> </figure> <p>道路のメッシュは画像のように、おおよそ長さ3500cm,幅897cmとなっています。</p> <p>緑色のフレームは単純<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%EA%A5%B8%A5%E7%A5%F3">コリジョン</a>です。</p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="ベースカラーテクスチャ"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211213/20211213110240.png" alt="f:id:raksul_01:20211213110240p:plain" width="914" height="596" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">ベー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B9%A5%AB%A5%E9%A1%BC">スカラー</a>テクスチャ</figcaption> </figure> <p>また、ベー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B9%A5%AB%A5%E9%A1%BC">スカラー</a>テクスチャは上のように4096*1024となっており、メッシュのUVはV座標0→1までぴっちり配置なので長さ方向に対して若干縮められますね。</p> <h3 id="マテリアルについて">マテリアルについて</h3> <p>それでは中身を見ていきます。全体は以下の画像の通りです。</p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="道路マテリアル(全体)"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211213/20211213110644.png" alt="f:id:raksul_01:20211213110644p:plain" width="1195" height="621" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">道路マテリアル(全体)</figcaption> </figure> <p>これでは少しわかりづらいので、一旦下側の部分と最後のContactShadows部分を排除します。ちなみに排除した下側部分は、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%F3%A5%C9%A5%B9%A5%B1%A1%BC%A5%D7">ランドスケープ</a>の地面マテリアルとより馴染ませるための部分、ContactShadowsは陰影の調整部分です(内部でワールドポジションオフセットと<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D4%A5%AF%A5%BB%A5%EB">ピクセル</a>深度オフセットを調整している)。</p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="今回見る部分以外を排除したマテリアル"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211213/20211213152208.png" alt="f:id:raksul_01:20211213152208p:plain" width="1200" height="648" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">今回見る部分以外を排除したマテリアル</figcaption> </figure> <p>大まかな内容は画像中にコメントで入れておきました。</p> <p>以下、備考です。</p> <p>・(ベー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B9%A5%AB%A5%E9%A1%BC">スカラー</a>について)</p> <p> 中央上のオーバーレイについてはみつまめ杏仁さんが以下のツイートで非常にわかりやすく図説されていますが、思った以上に計算コストが高そうです。</p> <blockquote class="twitter-tweet" data-conversation="none" data-lang="ja"> <p dir="ltr" lang="ja">ゲーム画面で<a class="keyword" href="http://d.hatena.ne.jp/keyword/Photoshop">Photoshop</a>のオーバーレイと同じ表現がコスト高なことを説明したくて調べてたら、<a class="keyword" href="http://d.hatena.ne.jp/keyword/UE4">UE4</a>にマテリアル関数が用意されてて、それを調べたらとても解りやすかった件<a href="https://twitter.com/hashtag/UI%E5%88%B6%E4%BD%9C?src=hash&amp;ref_src=twsrc%5Etfw">#UI制作</a> <a href="https://t.co/DhHXlMpkGV">pic.twitter.com/DhHXlMpkGV</a></p> — みつまめ杏仁 (@MMAn_nin) <a href="https://twitter.com/MMAn_nin/status/1252441559808634881?ref_src=twsrc%5Etfw">2020年4月21日</a></blockquote> <p> <script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> </p> <p>・(PDOについて)</p> <p> 道路メッシュは略半円筒形状になっており、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D4%A5%AF%A5%BB%A5%EB">ピクセル</a>深度オフセット(PDO)によって、メッシュのぶっ刺し感を低減しています。PDOが低いほどカメラ奥行方向の深度が深い(奥にある)と見做されるやつで、ディザ抜きと併用した馴染ませ用途なんかでもよく使われてます。</p> <p> このマテリアルではベースのPDOと詳細のPDOとを乗算していますが、実際には今回簡易化のために排除してしまった部分が馴染ませの肝となる部分なので、ここまでではたぶん見栄え…というかぶっ刺し感の低減には大きく影響はしません(大事なところが抜けていてごめんなさい)。</p> <p>・(法線の合成について)</p> <p> 上の画像中ではだいぶ割愛して書きましたが、法線の合成はおそらく慣用的な手法で計算しているものと思われます。合成計算について気になる方は是非調べてみてください。BlendAngleCorrectedNormalsなんかでもいけるのではないでしょうか。</p> <p> また、MF_ReconstructZ中で使われているDeriveNormalZは、二軸の成分から残りの成分を計算するためのものです。わかりやすさのために、FP_GunのノーマルマップからRG成分だけを抜き出して、法線の再構築(B成分の計算)を行いました。</p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="DeriveNormalZによる法線の再構築"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211213/20211213153325.png" alt="f:id:raksul_01:20211213153325p:plain" width="674" height="244" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">DeriveNormalZによる法線の再構築</figcaption> </figure> <p> このように、法線情報は2軸成分があれば残り1軸の成分は計算により求められるので、通常のノーマルマップのBチャンネルに別の情報を入れることもできます。これはメモリ節約術として時々見かけることがあります。<span style="font-size: 80%;">圧縮形式などなどが変わってくるのでテクスチャの品質に影響したりするかも…。</span></p> <p> </p> <p>ストアのコンテンツは本当に教科書ですね。</p> <p>次回、今回排除した部分について見ていけたらと思います。</p> raksul_01 第16回UE4ぷちコン振り返り その③~カーソルを筆に変更する(筆先の動きもつける)~ hatenablog://entry/13574176438019044424 2021-10-05T18:10:23+09:00 2021-10-05T18:10:23+09:00 ぷちコンの審査結果発表会も終わりましたが、ありがたいことに賞をいただくことができたのでこのまま逃亡しようとしていた(嘘です)振り返り記事を再開します。 今回紹介するものはこちら↓ 概要 要約 実装方法 スケルタルメッシュを用意する(blender) アニメーションBPを用意する 筆アクターとシーンキャプチャーをレベルに配置する キャンバスウィジェットに追加処理を組む 最後に 概要 前回の記事で紹介させていただいたペイントシステムでは、カーソルがそのままデフォルトのものなのでそれを自前の筆に置き換えよう!っていう内容です。 また、上の動画をご覧の通り、筆の移動に合わせて筆先も動いていますね。 単… <p>ぷちコンの審査結果発表会も終わりましたが、ありがたいことに賞をいただくことができたので<span style="text-decoration: line-through;">このまま逃亡しようとしていた</span>(嘘です)振り返り記事を再開します。</p> <p>今回紹介するものはこちら↓</p> <div align="center"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211005/20211005011523.gif" alt="f:id:raksul_01:20211005011523g:plain" width="252" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></div> <ul class="table-of-contents"> <li><a href="#概要">概要</a></li> <li><a href="#要約">要約</a></li> <li><a href="#実装方法">実装方法</a><ul> <li><a href="#スケルタルメッシュを用意するblender">スケルタルメッシュを用意する(blender)</a></li> <li><a href="#アニメーションBPを用意する">アニメーションBPを用意する</a></li> <li><a href="#筆アクターとシーンキャプチャーをレベルに配置する">筆アクターとシーンキャプチャーをレベルに配置する</a></li> <li><a href="#キャンバスウィジェットに追加処理を組む">キャンバスウィジェットに追加処理を組む</a></li> </ul> </li> <li><a href="#最後に">最後に</a></li> </ul> <h3 id="概要">概要</h3> <p>前回の記事で紹介させていただいたペイントシステムでは、カーソルがそのままデフォルトのものなのでそれを自前の筆に置き換えよう!っていう内容です。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgame-dev-study.hatenablog.com%2Fentry%2F2021%2F09%2F21%2F212743" title="第16回UE4ぷちコン振り返り その②~画面上にペイントする~ - げーむ開発徒然日記~怠惰のために勤勉~" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"></cite>また、上の動画をご覧の通り、<span style="text-decoration: underline;">筆の移動に合わせて筆先も動いています</span>ね。</p> <p>単純にカーソルを画像に置き換えるだけなら</p> <p><span style="color: #ff0000;"><strong><span style="color: #000000;">・</span>Set Mouse Cursor</strong></span>を使う方法</p> <p>・UIに配置した<span style="color: #ff0000;"><strong>imageをTickでマウス位置に追従</strong></span>させる方法</p> <p>が一般的だと思いますが、これらの方法では筆先の動きをつけることができません。やっていることはかなり後者の方法に近いですが、少し工夫して実装することにしました。</p> <h3 id="要約">要約</h3> <p>実装方法を簡単にまとめると</p> <p>・筆スケルタルメッシュをシーンキャプチャーでテクスチャに描画(常に更新)し、そのテクスチャをUIのimageに設定</p> <p>・筆スケルタルメッシュのアニメーションBPにマウスの移動量を与える</p> <p>です。</p> <p>他にも、筆スケルタルメッシュを直接カメラに映し出すといった方法もあるかもしれませんが個人的には上記の方法のほうが手っ取り早いと感じたのでこちらを採用しました(ほかにも理由はありますが後述します)。</p> <h3 id="実装方法">実装方法</h3> <h4 id="スケルタルメッシュを用意するblender">スケルタルメッシュを用意する(<a class="keyword" href="http://d.hatena.ne.jp/keyword/blender">blender</a>)</h4> <p>今回は、グ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%EC%A5%A4%A5%DE%A5%F3">レイマン</a>を<span style="text-decoration: line-through;">人体改造</span>ロボット改造したものを筆としました。</p> <p><span style="font-size: 80%; color: #666666;">※意外にも審査員の方たちは初見で気づかなかったようですが…。</span><span style="font-size: 80%; color: #666666;">その①の記事でも述べた通り、当初作成予定だったウケ狙いゲームの名残ですw</span></p> <p><a class="keyword" href="http://d.hatena.ne.jp/keyword/blender">blender</a>を使って、インポートしたグ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%EC%A5%A4%A5%DE%A5%F3">レイマン</a>のデフォルトのス<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B1%A5%EB%A5%C8">ケルト</a>ンを削除し、引き延ばした頭に新しいス<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B1%A5%EB%A5%C8">ケルト</a>ンを作成した至極雑な作りです。</p> <div align="center"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211005/20211005001656.png" alt="f:id:raksul_01:20211005001656p:plain" width="322" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></div> <p>これに<a class="keyword" href="http://d.hatena.ne.jp/keyword/Substance">Substance</a> <a class="keyword" href="http://d.hatena.ne.jp/keyword/Painter">Painter</a>でペペっとテクスチャを作りました。</p> <h4 id="アニメーションBPを用意する">アニメーションBPを用意する</h4> <p>筆スケルタルメッシュができたら、<a class="keyword" href="http://d.hatena.ne.jp/keyword/UE4">UE4</a>にインポートします。</p> <p>筆スケルタルメッシュのス<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B1%A5%EB%A5%C8">ケルト</a>ンをベースにアニメーションBPを新規に作成し、AnimGraph内でCCDIKを使用して筆先がいい感じに動くようにしました。</p> <div align="center"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211005/20211005004357.gif" alt="f:id:raksul_01:20211005004357g:plain" width="320" height="240" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></div> <p>アニメーションBPは以下のように組んでいます。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211005/20211005004534.png" alt="f:id:raksul_01:20211005004534p:plain" width="1188" height="284" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p>後述するキャンバス<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a>(前回記事の<strong>WB_TestCanvas</strong>)から<strong>Target Effector Location X/Y</strong>に値が代入され、実際のCCDIKにはTarget Effector Location X/YにFInterp Toで徐々に値が近づいていく<strong>Effector Location X/Y</strong>が入力として与えられています。</p> <p>※BPにいっさい処理を組まず、WB_TestCanvasから直接Effector Location X/Yに値を代入しても大丈夫ですが筆先の動きが固くなってしまいます。</p> <h4 id="筆アクターとシーンキャプチャーをレベルに配置する">筆アクターとシーンキャプチャーをレベルに配置する</h4> <p>Actorクラスを継承した<span style="color: #ff0000;"><strong>BP_GrayBrush</strong></span>を新規作成し、Skeletal Mesh Component(筆スケルタルメッシュ)を追加し、上記で作成したアニメーションBPを設定しておきます。</p> <p>このBP_GrayBrushをレベルに配置し、さらに<span style="color: #ff0000;"><strong>Scene Capture 2D</strong></span>がうまい具合にBP_GrayBrushをテクスチャ内に収めるように配置します。</p> <p>※応募作品ではサブレベルに配置しました。</p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="Scene Capture 2Dの設定"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211005/20211005010135.png" alt="f:id:raksul_01:20211005010135p:plain" width="379" height="304" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">Scene Capture 2Dの設定</figcaption> </figure> <p><span style="text-decoration: line-through;">ここで、投影方法は平行投影にしました。なぜ今回の実装方法を採用したのかという理由の2つ目(要約のところでほかの理由と述べたやつです)は、<span style="text-decoration: underline;">筆の投影を平行投影にしたかったため</span>です。</span></p> <p>→この記事を書いている途中で<span style="text-decoration: underline;"><strong><span style="color: #ff0000; text-decoration: underline;">透視投影に変更してみたら</span>そっちのほうがいい感じになりましたw</strong></span></p> <p>上手くできるとこんな感じでキャプチャしてくれます。テクスチャレンダーターゲット<span style="color: #ff0000;"><strong>TRT2D_Brush</strong></span>のサイズは480*480にしました。</p> <div align="center"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211005/20211005010614.png" alt="f:id:raksul_01:20211005010614p:plain" width="257" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></div> <p>ここまでできたら、新規マテリアル<span style="color: #ff0000;"><strong>M_TRT2D_Brush</strong></span>を作成します。</p> <p>TRT2D_Brushのままでは筆の部分だけがアルファの値が0という情報を持っているので、反転させます。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211005/20211005012716.png" alt="f:id:raksul_01:20211005012716p:plain" width="765" height="295" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h4 id="キャンバスウィジェットに追加処理を組む">キャンバス<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a>に追加処理を組む</h4> <p>最後に、前回記事で作成した<strong>WB_TestCanvas</strong>を若干変更していきます。</p> <p>まず、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a>に新規のイメージ(BrushのImageに<strong>M_TRT2D_Brush</strong>を設定)を追加します。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211005/20211005012136.png" alt="f:id:raksul_01:20211005012136p:plain" width="816" height="393" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p>上の画像のようにAlignmentなども調整しておきます。</p> <p>また、テクスチャサイズが先ほど述べた通り480*480に対して、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a>上では600*600となっていますが、解像度より負荷軽減を優先しました。</p> <p>で、前回記事にてオーバーライド処理を施した関数<strong>On Mouse Move</strong>の途中に以下の処理を追加します。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20211005/20211005175535.png" alt="f:id:raksul_01:20211005175535p:plain" width="1200" height="317" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p>マウスの移動量を筆スケルタルメッシュのアニメーションBPに与える前に<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%CE%A1%BC%A5%DE%A5%E9%A5%A4%A5%BA">ノーマライズ</a>して値をベクトルの大きさが1になるように抑えています。2.0を乗算しているのは調整用です。</p> <p>あ、それとコンスト<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%AF">ラク</a>トイベントなどで<span style="text-decoration: underline;"><strong>筆アクターのAnim Instanceを取得しておくこともお忘れなく</strong></span>。</p> <p>他にも細かい処理(例えば、描いてる時より描いてない時のほうが筆の位置が高くしたり、音を鳴らしたり)を色々追加してますが記事の本題から逸れるので説明は省略します。</p> <p><strong><span style="font-size: 150%;">→完成!</span></strong></p> <h3 id="最後に">最後に</h3> <p>実装方法は簡単ですが、私は思いつくのにだいぶ時間がかかってしまいました…。</p> <p>しかしペイント中に筆が現れるようにするだけで、クオリティや描き心地がずいぶん上がったように感じたのでやりがいがありました!</p> <p><span style="text-decoration: line-through;">次回の記事その④(ラスト)では「描いた線にそって道を生成する方法」について紹介します。</span></p> <p>→力尽きて断念しました。。</p> <p> </p> <p> </p> raksul_01 第16回UE4ぷちコン振り返り その②~画面上にペイントする~ hatenablog://entry/13574176438014172775 2021-09-21T21:27:43+09:00 2021-09-21T21:27:43+09:00 第16回UE4ぷちコンで実装したビューポート上へのペイントシステムの紹介です <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20210921/20210921175136.png" alt="f:id:raksul_01:20210921175136p:plain" width="1200" height="630" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p>今回は、第16回<a class="keyword" href="http://d.hatena.ne.jp/keyword/UE4">UE4</a>ぷちコンで実装した画面上へのペイントシステムをどのように実装したかなどを紹介したいと思います。</p> <p> </p> <p><span style="font-size: 150%;">★目次★</span></p> <ul class="table-of-contents"> <li><a href="#概要">概要</a></li> <li><a href="#要約">要約</a></li> <li><a href="#実装方法">実装方法</a><ul> <li><a href="#ナイアガラシステムの準備">ナイアガラシステムの準備</a></li> <li><a href="#ウィジェットの準備">ウィジェットの準備</a></li> <li><a href="#ポーンの用意">ポーンの用意</a></li> </ul> </li> <li><a href="#最後に">最後に</a></li> </ul> <p> </p> <h3 id="概要">概要</h3> <p>作るもののイメージはこちら↓</p> <blockquote class="twitter-tweet"> <p dir="ltr" lang="ja">大神インスパイアを突如として受け、お絵描きできるようにしてみました。インクが滲んで広がるような表現をしたくてTextureRenderTargetとかで試行錯誤したけど、最終的には<a class="keyword" href="http://d.hatena.ne.jp/keyword/Niagara">Niagara</a>をUIに描画するやり方が一番いい感じに。<br />ぷちコンに使えるかは…知らない。タスケテ。<a href="https://twitter.com/hashtag/UE4?src=hash&amp;ref_src=twsrc%5Etfw">#UE4</a> <a href="https://twitter.com/hashtag/UE4Study?src=hash&amp;ref_src=twsrc%5Etfw">#UE4Study</a> <a href="https://twitter.com/hashtag/UE4%E3%81%B7%E3%81%A1%E3%82%B3%E3%83%B3?src=hash&amp;ref_src=twsrc%5Etfw">#UE4ぷちコン</a> <a href="https://t.co/hWH6dpmnB9">pic.twitter.com/hWH6dpmnB9</a></p> — らくする (@raksul_01) <a href="https://twitter.com/raksul_01/status/1429828127987965952?ref_src=twsrc%5Etfw">August 23, 2021</a></blockquote> <p> <script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> </p> <p>マウスの左ボタンを押している間は黒いインクが塗れるようなものになっています。</p> <p>さて、やり方としては<a class="keyword" href="http://d.hatena.ne.jp/keyword/UE4">UE4</a>を触っている方であれば</p> <p><span style="text-decoration: underline;"><span style="color: #ff0000; text-decoration: underline;">TextureRenderTarget2D</span>(以下、<span style="color: #ff0000; text-decoration: underline;">TRT2D</span>)を用意し、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a>に描画。マウス座標に応じて<span style="color: #ff0000; text-decoration: underline;">Draw Texture</span>あるいは<span style="color: #ff0000; text-decoration: underline;">Draw Material</span>を極短い間隔(Tickなど)で使用することによってTRT2Dに対して疑似的にペイント。</span></p> <p>といった方法が通常は思いつくかなと思います。</p> <p>しかし、今回は少し違ったアプローチで実装してみました。というのも、上記の動画をご覧の通り、<strong>インクが滲んで広がるような表現をしたかったため</strong>です(大神の筆しらべもよく見ると広がっていますね)。</p> <p>※上述したような通常の方法で、DrawTextureを用いて同じ座標にサイズを徐々に上げたテクスチャを描画するような手法を使ってみたところ、TRT2Dの更新頻度が上がって負荷が半端なくなりました(当然そうなるのはわかっていたことですが)。</p> <p>また、以下の前回記事で紹介した、<strong>大神の筆しらべを<span style="text-decoration: underline;">Unityで再現したもの</span></strong>は<a class="keyword" href="http://d.hatena.ne.jp/keyword/UE4">UE4</a>で言うTRT2Dのようなものを使用しており、<strong>インクが広がるような表現までは再現していませんでした</strong>。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgame-dev-study.hatenablog.com%2Fentry%2F2021%2F09%2F20%2F195351" title="第16回UE4ぷちコン振り返り その①~構想について~ - げーむ開発徒然日記~怠惰のために勤勉~" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"></cite></p> <h3 id="要約">要約</h3> <p>使用した<a class="keyword" href="http://d.hatena.ne.jp/keyword/UE4">UE4</a>のバージョンは4.26となります。</p> <p>今回のアプローチを簡単にまとめると、</p> <ul> <li><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a>上に<a class="keyword" href="http://d.hatena.ne.jp/keyword/Niagara">Niagara</a>エミッタをマウス座標にフレーム毎に更新</li> <li>当該<a class="keyword" href="http://d.hatena.ne.jp/keyword/Niagara">Niagara</a>エミッタからスプライトパーティクル(TRT2Dを使用するやり方で描画するTextureの代わり)をスポーン</li> </ul> <p>という手法になります。</p> <p><a class="keyword" href="http://d.hatena.ne.jp/keyword/Niagara">Niagara</a>パーティクルを<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a>に描画するにあたって、下記の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D7%A5%E9%A5%B0%A5%A4%A5%F3">プラグイン</a>を使用しました。<strong>無料</strong>です。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.unrealengine.com%2Fmarketplace%2Fja%2Fproduct%2Fniagara-ui-renderer" title="Niagara UI Renderer:コードプラグイン - UE マーケットプレイス" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://www.unrealengine.com/marketplace/ja/product/niagara-ui-renderer"> </a>使い方は<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D7%A5%E9%A5%B0%A5%A4%A5%F3">プラグイン</a>制作者様の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C1%A5%E5%A1%BC%A5%C8%A5%EA%A5%A2%A5%EB">チュートリアル</a>を見た方が早いので、本記事では割愛します。</cite></p> <h3 id="実装方法">実装方法</h3> <h4 id="ナイアガラシステムの準備">ナイアガラシステムの準備</h4> <p>それでは実装方法に入りますが、<a class="keyword" href="http://d.hatena.ne.jp/keyword/UE4">UE4</a>(特に<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a>ブループリント)の基礎知識があるものとして細かいところは省略しつつ進めます。</p> <p><span style="font-size: 80%;">本記事の真似をするだけではできないかもしれませんのでご容赦ください。また、名付けは適当なので任意でお願いします。</span></p> <p>まずは、ナイアガラシステム<span style="color: #ff0000;"><strong>NS_Brush</strong></span>を作成します。エミッタとしてSimpleSpriteBurstを追加しておくとやりやすいと思います。</p> <div align="center"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20210921/20210921185717.png" alt="f:id:raksul_01:20210921185717p:plain" width="68" height="102" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></div> <p>今回、最低限下記のエミッタ設定を行いました。</p> <ul> <li>Emitter StateのLife Cycle Modeを<strong>Self</strong>, Loop Behaviorを<strong>Infinite<br /></strong>→パーティクルのスポーンが止まらないように</li> <li>Particle StateのKill Particles When Lifetime Has Elapsedの<strong>チェックを外す</strong><br />→パーティクルが消えないように</li> <li>Spawn Rateを<strong>750以上</strong></li> <li>パーティクル更新に<strong>Scale Sprite Size</strong>を追加して、1秒で1.2倍くらいのサイズになるようScale <a class="keyword" href="http://d.hatena.ne.jp/keyword/Vector">Vector</a> 2DBy Curveを設定</li> </ul> <p>あとはスプライトに適用するマテリアルですが、以下のような適当なものを用意しました。</p> <div align="center"> <figure class="figure-image figure-image-fotolife mceNonEditable" title="ナイアガラエディタでのプレビュー用マテリアル(M_BrushParticle)"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20210921/20210921191908.png" alt="f:id:raksul_01:20210921191908p:plain" width="833" height="469" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">ナイアガラエディタでのプレビュー用マテリアル(M_BrushParticle)</figcaption> </figure> </div> <p><strong>これは、あくまでもナイアガラエディタ上でプレビューするためのマテリアルです。</strong></p> <p>使用している<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D7%A5%E9%A5%B0%A5%A4%A5%F3">プラグイン</a><a class="keyword" href="http://d.hatena.ne.jp/keyword/Niagara">Niagara</a> UI Rendererの都合上、<span style="color: #ff0000;"><strong>マテリアル<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C9%A5%E1%A5%A4%A5%F3">ドメイン</a>を<a class="keyword" href="http://d.hatena.ne.jp/keyword/User%20Interface">User Interface</a>にしたマテリアルも別途用意しておいてください。</strong></span></p> <p><span style="text-decoration: line-through;"><span style="color: #000000; text-decoration: line-through;">結局、応募作品もこの雑なマテリアルのままにしてしまいました。</span></span></p> <div align="center"> <figure class="figure-image figure-image-fotolife mceNonEditable" title="後述するNiagara System Widgetで使うマテリアル(M_BrushParticleUI)"> <div align="center"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20210921/20210921192015.png" alt="f:id:raksul_01:20210921192015p:plain" width="947" height="463" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></div> <figcaption class="mceEditable">後述する<a class="keyword" href="http://d.hatena.ne.jp/keyword/Niagara">Niagara</a> System <a class="keyword" href="http://d.hatena.ne.jp/keyword/Widget">Widget</a>で使うマテリアル(M_BrushParticleUI)</figcaption> </figure> </div> <h4 id="ウィジェットの準備"><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a>の準備</h4> <p>キャンバス用に新規<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a><span style="color: #ff0000;"><strong>WB_TestCanvas</strong></span>を作成し、パレットから<a class="keyword" href="http://d.hatena.ne.jp/keyword/Niagara">Niagara</a> System <a class="keyword" href="http://d.hatena.ne.jp/keyword/Widget">Widget</a>を追加します(<span style="color: #ff0000;"><strong>NS_BrushInk</strong></span>と名付けました)。</p> <p>また、Borderを最上層に追加します(試したところ、これがないと後のOn Mouse Button Downなどが動作しないみたいです)。</p> <div align="center"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20210921/20210921184916.png" alt="f:id:raksul_01:20210921184916p:plain" width="301" height="136" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></div> <div align="center"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20210921/20210921210629.png" alt="f:id:raksul_01:20210921210629p:plain" width="285" height="108" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></div> <p>そして、NS_BrushInkを選択した状態で詳細タブから以下のように設定します(マテリアルの名前が誤字ってますが気にしないでください)。</p> <div align="center"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20210921/20210921192728.png" alt="f:id:raksul_01:20210921192728p:plain" width="412" height="238" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></div> <p>Material Remap Listはナイアガラエディタでスプライトに適用していたM_BrushParticle(左)を<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a>への描画用にM_BrushParticleUI(右)に置換する設定です。</p> <p>また、Auto Activateのチェックを外さないとマウスのボタンを押してなくても常に描かれてしまいますので外しておきます。</p> <p>次に、On Mouse Button Down関数をオーバーライドして以下のようにノードを組みます。</p> <div align="center"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20210921/20210921193231.png" alt="f:id:raksul_01:20210921193231p:plain" width="1200" height="229" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></div> <p>変数<span style="color: #0000cc;"><strong>Points</strong></span>は<a class="keyword" href="http://d.hatena.ne.jp/keyword/Vector">Vector</a> 2Dの配列で、今回は使いませんが後に「<strong>描いた線に沿った道の生成</strong>」の紹介記事で使うことになります。</p> <p>ちなみにこの処理は、左ボタンを押したポイント<strong>のみ</strong>にインクを塗るためのものであり、このまま連続して線を描くときには次に説明する処理が必要となります。</p> <p>この処理のために、次はOn Mouse Move関数をオーバーライドして以下のようにノードを組みます。</p> <div align="center"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20210921/20210921194005.png" alt="f:id:raksul_01:20210921194005p:plain" width="1200" height="294" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></div> <p>始めの部分でエミッタの位置をカーソル位置に更新しています。</p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="マウス位置にエミッタ位置を更新"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20210921/20210921194140.png" alt="f:id:raksul_01:20210921194140p:plain" width="540" height="267" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">マウス位置にエミッタ位置を更新</figcaption> </figure> <p>その後のブランチ処理は、<span style="text-decoration: underline;">左ボタン押下状態</span>かつ<span style="text-decoration: underline;">マウスが一定距離移動した場合</span>にのみナイアガラシステムをアクティベートするものです。これがないとエミッタの設定上、カーソルを動かさなくても<strong>同じ場所に永遠にパーティクルがスポーンされ続けてしまい<span style="color: #673ab7;">PCが爆発します</span></strong>。</p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="マウスが一定距離移動したらエミッタをアクティベート"> <div align="center"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20210921/20210921194502.png" alt="f:id:raksul_01:20210921194502p:plain" width="1013" height="392" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></div> <figcaption class="mceEditable">マウスが一定距離移動したらナイアガラシステムをアクティベート</figcaption> </figure> <p>最後の処理(拡大画像無し)は、先ほどと同様、Pointsにアイテムを追加するものです。</p> <h4 id="ポーンの用意">ポーンの用意</h4> <p>適当なポーンを用意して、インプットアクションやキー入力でWB_TestCanvasをビューポートに表示する処理を追加します。</p> <p>また、必要に応じてSet Show Mouse CursorやSet Input Mode Game And UIなども入れる必要もあります。</p> <div align="center"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20210921/20210921211429.png" alt="f:id:raksul_01:20210921211429p:plain" width="1200" height="366" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></div> <p>※上記のようなFlip Flopの使用は<strong>バグの元となりやすいため</strong>推奨しません。真面目に作るならbool値を使いましょう。</p> <p><strong><span style="font-size: 150%;">---セットアップ完了!---</span></strong></p> <p>上手くいけば、Hキーを押せばペイントできるようになり、再びHキーを押すことでキャンバスが排除されるようなシステムができているはずです。</p> <h3 id="最後に">最後に</h3> <ul> <li>実際の応募作品ではBPC_MagicBrushという<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8">コンポーネント</a>に<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A6%A5%A3%A5%B8%A5%A7%A5%C3%A5%C8">ウィジェット</a>作成だとか<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B9%A5%DA%A5%B7%A5%E3">スペシャ</a>ルスキルだとかほとんどの機能を入れて、どのポーンに対してもペイント&道生成&スキルを簡単に実装できるようにしていました。<br /> <figure class="figure-image figure-image-fotolife mceNonEditable" title="絵筆の機能をまとめてコンポーネント化したもの"> <div align="center"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/r/raksul_01/20210921/20210921212107.png" alt="f:id:raksul_01:20210921212107p:plain" width="514" height="627" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></div> <figcaption class="mceEditable">絵筆の機能をまとめて<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8">コンポーネント</a>化したもの</figcaption> </figure> </li> </ul> <p>以上、間違いなどがあればDMやコメント等で教えてください!</p> raksul_01 第16回UE4ぷちコン振り返り その①~構想について~ hatenablog://entry/13574176438013822537 2021-09-20T19:53:51+09:00 2021-09-20T19:53:51+09:00 らくする (@raksul_01)です。今回がブログ初投稿となります。 今回は、株式会社ヒストリア様主催の 「第16回UE4ぷちコン(https://historia.co.jp/ue4petitcon16)」に参加したので、 開設しっぱなしだった本ブログの重い腰を上げて、その振り返りについて書いていきたいと思います(-。-)y-゜゜゜ ちなみにぷちコン参加は今回で3回目でした。 目次 目次 まず初めに 着想について 応募作品について 必要タスクの抽出 その他・感想 まず初めに 今回のぷちコンのテーマは「みち」 「みち」に通ずる何らかの要素(道でも未知でも)が入っているゲームであれば基本的には… <p><a href="https://twitter.com/raksul_01">らくする (@raksul_01)</a>です。今回がブログ初投稿となります。</p> <p>今回は、株式会社ヒストリア様主催の</p> <p>「第16回<a class="keyword" href="http://d.hatena.ne.jp/keyword/UE4">UE4</a>ぷちコン(<a href="https://historia.co.jp/ue4petitcon16">https://historia.co.jp/ue4petitcon16</a>)」に参加したので、</p> <p>開設しっぱなしだった本ブログの重い腰を上げて、その振り返りについて書いていきたいと思います(-。-)y-゜゜゜</p> <p>ちなみにぷちコン参加は今回で3回目でした。</p> <h4 id="目次">目次</h4> <ul class="table-of-contents"> <li><a href="#目次">目次</a></li> <li><a href="#まず初めに">まず初めに</a></li> <li><a href="#着想について">着想について</a></li> <li><a href="#応募作品について">応募作品について</a></li> <li><a href="#必要タスクの抽出">必要タスクの抽出</a></li> <li><a href="#その他感想">その他・感想</a></li> </ul> <h3 id="まず初めに">まず初めに</h3> <p>今回のぷちコンのテーマは「みち」</p> <p>「みち」に通ずる何らかの要素(道でも未知でも)が入っているゲームであれば基本的には何でもOKというルールになっています。</p> <p>いやあ、このテーマは苦戦しました。前回の「かわる」というテーマが如何に何でもできてしまうテーマであったかを痛感しました。<cite class="hatena-citation"></cite></p> <h3 id="着想について">着想について</h3> <p>テーマが発表されたときに漠然と考えていたア<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A4%A5%C7%A5%A2">イデア</a>は</p> <ul> <li>筆で<span style="color: #ff0000;">道</span>を自分で描く2~2.5Dのゲーム</li> <li>MetaSoundと<a class="keyword" href="http://d.hatena.ne.jp/keyword/Niagara">Niagara</a>を組み合わせて音の<span style="color: #ff0000;">道</span>を見立てたオーディオビジュアライザー的なもの</li> <li><span style="color: #ff0000;">未知</span>の筆を持った伝説の書<span style="color: #ff0000;">道</span>家<span style="color: #ff0000;">ミッチー</span>がひたすら<span style="color: #ff0000;">道</span>を爆走する筆アクション<a class="keyword" href="http://d.hatena.ne.jp/keyword/FPS">FPS</a>、名付けて「<em><strong>Shodo-ka Simulator</strong></em>」</li> </ul> <p>です。<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%A4%A5%F3%A5%C9%A5%DE%A5%C3%A5%D7">マインドマップ</a>の作成などは一切行っていません(^O^)</p> <p><span style="text-decoration: line-through;">そして実際にこれらをすべて途中まで作っては、すべてボツとなりました(この時点で約2週間を浪費。MetaSoundの勉強にはなりましたが)。</span></p> <p> </p> <p>で、結局何を作ったの?の前に・・・</p> <p>上述の漠然としたア<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A4%A5%C7%A5%A2">イデア</a>をご覧の通り、当初から謎に「<strong>筆</strong>」というものに頭が捉われていた私は、以下のような動画を見つけました。</p> <p><iframe width="560" height="315" src="https://www.youtube.com/embed/yuQXeaYBuuM?start=177&amp;feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" id="widget4"></iframe><cite class="hatena-citation"><a href="https://www.youtube.com/watch?v=yuQXeaYBuuM&amp;t=177s">www.youtube.com</a></cite></p> <p>そう、「<strong>大神</strong>」です。超有名タイトルですね。私は未プレイですが(ん?)</p> <p>上の動画は、その大神における<strong>筆しらべ</strong>をUnityで再現したものです。</p> <p> </p> <p>私はこの動画に衝撃を受けました。</p> <p><span style="font-size: 150%;">・・・いったいぜんたいWhat happens?</span></p> <p>これはUnityを使用しているけど、<a class="keyword" href="http://d.hatena.ne.jp/keyword/UE4">UE4</a>でも何とかして似たようなものを作ってみたい!そして<strong>真似するのはお絵描きの見た目部分だけに留めて、それを活かして今回のテーマに沿ったゲームを作りたい</strong>!と・・・</p> <p> </p> <p>こうして、”筆しらべの見た目を<a class="keyword" href="http://d.hatena.ne.jp/keyword/UE4">UE4</a>で似せてみる”という険しい道のりへ進む決意をしたのでした。</p> <h3 id="応募作品について">応募作品について</h3> <p>長々とお話しましたが、今回の応募作品はこちら↓</p> <p><iframe width="560" height="315" src="https://www.youtube.com/embed/uS3lUkoye8w?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" id="widget6"></iframe><cite class="hatena-citation"><a href="https://youtu.be/uS3lUkoye8w">youtu.be</a></cite></p> <p>個人的には概ね満足いく結果が得られたと感じます。</p> <p>※完全な真似ではなく、ゲーム内容に合致する見た目に調整しています。</p> <p> </p> <p>裏話的なあれですが本当はストーリー構想もあって、ムービーシーンなども作成していました。</p> <p>ですが、作っているうちに応募要件である動画時間や、提出期限を考えると適切でないと考えて途中で路線変更して、レベル(ページ)選択形式のパズルゲームにしようという流れになりました。</p> <p>そうすれば、基本システムさえできてしまえばそのあとはギミック追加などでボリュームを補えますし(;'∀')</p> <h3 id="必要タスクの抽出">必要タスクの抽出</h3> <p>一番重要である、筆しらべの見た目再現を実行するにあたり、大神の動画を見ながら細かいタスクを書き出しました。</p> <ol> <li>筆しらべ突入時に画面が停止し、ポストプロセス処理&紙面が斜めになる<br />→作品の仕様上、停止&斜めにならないほうが良かったため<span style="color: #2196f3;"><strong>除外</strong></span></li> <li>描いた部分から徐々に墨汁が幅方向に広がる(滲む)<br />→<span style="color: #ff0000;"><strong>実現</strong></span></li> <li>描いている途中、墨汁がかすれる<br />→おそらく私の作ったものにも実装可能と考えるが、時間の都合により<span style="color: #2196f3;"><strong>断念</strong></span></li> <li>描く動きに合わせて筆先が動く、また、柄の部分が傾く<br />→筆先の動きは<span style="color: #ff0000;"><strong>実現</strong></span><br />→<span style="text-decoration: line-through;">柄が傾くこと完全に忘れていた・・・<br /></span></li> </ol> <p>他にも色々あるとは思いますが、このようにして、<strong>プレイヤーが描くときの感覚が気持ちよくなる</strong>ための、様々な工夫がなされていると感じました。</p> <p>そして、これら一つ一つが私の頭を悩ませるものとなったのです。</p> <p>なんせ調べて出てくるようなものではなかったので(いくら調べても一切のヒントも得られませんでした_( _´ω`)_)。</p> <p> </p> <p>なお、今回の作品の「<strong>インクで線を描く方法</strong>」「<strong>描いた線に沿って道を生成する方法</strong>」「<strong>筆先に動きをつける方法</strong>」の実装の仕方については以降の記事で紹介予定ですので、お楽しみに。</p> <h3 id="その他感想">その他・感想</h3> <p>最後に、意識した点、良かった点/反省点などを挙げていきたいと思います。</p> <ul> <li>ある意味、<span style="text-decoration: underline;">見た目再現</span>(どうやってるのかな?という部分を自分なりに考えて再現してみること)<span style="text-decoration: underline;">が一番学習したかったこと</span>だったので、時間の都合上不足した点もあるがほぼ満足。</li> <li>リセット機能も用意していた。<br />非効率なOpen Levelで再読み込みする形式ではなく、GameModeに用意されたReset Level()などを使用するリセット。この場合、アクタごとにリセット時のイベントを用意する必要があり、面倒だった。<br />面倒だった割に、動画では紹介できていない。</li> <li>これまた動画では紹介できていないが、特定範囲の外に出ようとすると「絵本の外には出られないよ!」というメッセージ表示も用意してあった。</li> <li>グ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%EC%A5%A4%A5%DE%A5%F3">レイマン</a>の形をした筆は「Shodo-ka Simulator」という当初作りかけていた<span style="text-decoration: line-through;"><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D0%A5%AB%A5%B2%A1%BC">バカゲー</a></span>の名残だったりする。</li> </ul> <ul> <li>実は見た目再現と道生成を実装した後、<span style="text-decoration: underline;">ゲームにどう落とし込むかで相当苦労した</span>。プロシージャル生成マップをひたすら突き進むゲームにするのか、単発ステージを複数用意したパズルゲームにするのか、など。</li> <li>絵本の世界を題材としており、ドローモード時のアウトライン描画とのギャップが激しく生じるようにしたかったので、<span style="text-decoration: underline;">背景グラフィックはあえてリアリスティックなものに</span>。</li> <li>上記に時間をかけたので、UI等に関してはクオリティを損なわない程度のものに。ただし、<span style="text-decoration: underline;">ちょっと雑すぎたかも</span>。<a class="keyword" href="http://d.hatena.ne.jp/keyword/%BF%E1%A4%AD%BD%D0%A4%B7">吹き出し</a>は頑張った。</li> <li>ゲームって<strong><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E6%A1%BC%A5%B6%A5%D3%A5%EA%A5%C6%A5%A3">ユーザビリティ</a></strong>がすごい大事だと思ってるので、ぷちコンと言えども<span style="text-decoration: underline;"><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C1%A5%E5%A1%BC%A5%C8%A5%EA%A5%A2%A5%EB">チュートリアル</a>を丁寧にすることを心がけた</span>。</li> <li><span style="font-size: 150%;">今回もめちゃめちゃに学びが多かった。開催ありがとうございました。</span></li> </ul> raksul_01