情報は力ではない

UE4 とか Blender とか。

命名規則に従ったアセットの自動リネームとアセットバリデーション

この記事は Unrealn Engine 4 (UE4) Advent Calendar 2020 その1 の7日目の記事です。

qiita.com

6日目の記事は はるべえ haru さんの 「【UE4】Toon + PBRを生き残れ」でした。

qiita.com

今回の内容

先日、命名規則に従ったアセットの自動リネームと、アセットバリデーションをやってみました。今回はその実施したことの簡単な紹介記事となります。

アセットの自動リネームは、はのば さんの記事*1、アセットバリデーションは、おかず さんの記事*2を参考にさせていただきました。命名規則については Allar さんのスタイルガイド*3をもとにしています。

今回作成した .uasset は以下に配置していますので、よければダウンロードしてみてください。解凍して Content 直下に配置すれば中身を確認できるかと思います。

https://drive.google.com/file/d/1di_Z5-YbVvCkHdLm8L-BEWQgbDynPwm3/view?usp=sharing

UE4.25 で作成しています。それ以前のバージョンのプロジェクトだと Content に配置してもアセットを見れない可能性があるかと思います。

アセットの自動リネーム

今回は Editor Utility Widget を使用して、コンテンツブラウザーで選択したアセットをリネームするようにしました。以下の動画は動作イメージです。選択したアセットがリネームされているのが確認できるかと思います。
※キャプチャソフトの問題で Rename ボタン押下後のプログレスダイアログが表示されていません。。。

youtu.be

Editor Utility Widget の作成

コンテンツブラウザで Editor Utility Widget を作成します。

f:id:masahiro8080:20201204221031p:plain

UI の作成

作成した Editor Utility Widget を開き、デザイナータブで UI を作成していきます。今回はアセットの種類に応じてプレフィックスを設定し「Rename」ボタンを押下することで選択したアセットがリネームされるようなイメージにしました。

f:id:masahiro8080:20201206101816p:plain
UI 作成

リネーム処理の作成

グラフタブに移り、リネーム処理を記述していきます。アセットのリネームには Rename Asset 関数を使用します。Rename Asset 関数は2つありますが、今回は画像上側の関数を使用しています。

f:id:masahiro8080:20201204215842p:plain
Rename Asset 関数

No Target 説明
1 Editor Utility Library 上側のノード。Asset ピンに接続したアセットを New Name ピンで設定した名前に変更します。
2 Editor Asset Library 下側のノード。Source Asset Path で指定したアセットを Destination Asset Path で指定したパスに変更します。名前の変更も可能ですが、ディレクトリの移動に使用できます。UNIXmv コマンドに近いかと思います。

選択したアセットが命名規則に従っていない場合 Rename Asset 関数で、そのアセットにプレフィックスを付与するような処理を記述しています。

ボタン押下時の処理の概要。選択したアセット群を変数に保存し、それらに対しリネーム処理を実施しています。 https://cdn-ak.f.st-hatena.com/images/fotolife/m/masahiro8080/20201206/20201206095932_original.png

リネーム処理本体。変数に保存したアセットを UI で表示しているクラス毎に抽出し、各アセットが命名規則に従っているか確認後、従っていなければリネーム処理を行っています。 https://cdn-ak.f.st-hatena.com/images/fotolife/m/masahiro8080/20201206/20201206110009_original.png

以上で、リネーム処理の記述が終わりです。

Editor Utility Widget の表示とリネームの実行

作成した Editor Utility Widget をコンテンツブラウザで右クリック。Run Editor Utility Widget を押下すると Editor Utility Widget の画面が表示されます。 あとはコンテンツブラウザでアセットを選択し Rename ボタンを押下することで自動的にリネームすることが出来ます。

f:id:masahiro8080:20201206123654p:plain

アセットバリデーション

次にアセットのバリデーションです。 Editor Utility Blueprint を使用して、アセット保存時にそのアセットが命名規則に従ってなければ、メッセージログで、エラーメッセージを出すようにしていきます。

以下の動画は動作イメージです。選択したアセットを意図的に命名規則と違う名前でリネームすると、保存時に自動的にバリデーションチェックが走り、エラーメッセージが表示されるのが確認できるかと思います。
※キャプチャソフトの問題でアセット名変更後のプログレスダイアログが表示されていません。。。

youtu.be

Editor Utility Blueprint の作成

まず Editor Utility Blueprint を作成します。parent class には EditorValidatorBase を選択します。

f:id:masahiro8080:20201206124729p:plain
f:id:masahiro8080:20201206124839p:plain

バリデーション対象の決定とバリデーション処理

作成した Editor Utility Blueprint を開きます。 バリデーション対象とバリデーションの処理を行うには CanValidateAsset 関数と ValidateLoadedAsset 関数をオーバーライドします。

No 関数名 説明
1 CanValidateAsset In Asset ピンに入ってきたアセットがバリデーション対象かどうかを指定します。バリデーション対象であれば true を返すようにします。
2 ValidateLoadedAsset バリデーションチェック本体。In Asset ピンのアセットを確認して、バリデーションエラーかどうかを判断します。

まず CanValidateAsset 関数をオーバーライドしていきます。In Asset ピンのアセットクラスがバリデーション対象のクラスかどうかを判定しています。

https://cdn-ak.f.st-hatena.com/images/fotolife/m/masahiro8080/20201206/20201206130047_original.png

TypeToConvention 変数は、バリデーション対象のクラスをキーにしたマップです。バリューには命名規則プレフィックスを指定しています。

f:id:masahiro8080:20201206130231p:plain

次に ValidateLoadedAsset 関数をオーバーライドします。この関数では、バリデーションを通過した場合は Asset Passes 関数を呼び、Valid を返し、バリデーションエラーの場合は Asset Fails を呼び、Invalid を返すようにしていきます。

In Asset ピンのアセットクラスに対応したプレフィックスになっているかを確認し、命名規則通りであれば Asset Passes 関数を呼び、Valid を返し、 そうでなければエラーメッセージを構築し、Asset Fails 関数にエラーメッセージ渡し、返り値として Invalid を返すようにしています。

https://cdn-ak.f.st-hatena.com/images/fotolife/m/masahiro8080/20201206/20201206130755_original.png

以上で、バリデーションチェック処理が完了です。

あとは Asset Actions > Validate Assets でのバリデーションや、アセット保存時にこのバリデーションチェックが実行されます。

※作成した Editor Utility Blueprint は Editor の起動時に読み込まれるそうなので、作成後は一度 Editor を再起動する必要があるそうです。

おわりに

初めて Editor Utility Widget や Editor Utility Blueprint を使いましたが、便利です。他にもいろいろ使えそう。 アセットの自動リネームに関しては、選択したディレクトリ以下のアセットにもリネーム処理を行ったり、サフィックスについても付与したりしたいですね。 また、今のバリデーションチェックは十分ではないので、そのあたりも修正していきたいです(例えば AI Controller は AICプレフィックスにしたいのですが、AI Controller も Blueprint のため、現状の処理だとプレフィックスを BP_ にしてくださいというエラーメッセージが出てしまう等)

作成したブループリントの関数のキャプチャには Naotsun の GraphPrinter プラグインを使用しました。選択したノードのキャプチャが取れてこちらも便利です。

github.com

VEX でカスタム COP を作成してみる

VEX でカスタム COP 作れるということだったのでやってみた。自分用にまとめておきます。

※ 2020/4/25 追記 下記の「VEX」で記載している処理は自身の理解不足により誤った記載をしており、期待した結果になりませんでした。調査した後、訂正したいと思います。

基本

基本は VEX を .vfl ファイルに記述して vcc でコンパイルし HDA 化する。 今回は COP で使用できる HDA を作るので、メイン関数で指定するコンテキストは cop2 にしておく。演算の結果は RGBA 変数に格納する。

題材

今回練習として作成したのは、4つの画像からそれぞれ指定したチャンネル (RGBA) を取り出して、それぞれを異なるチャンネルに格納し、一つの画像にまとめるような HDA ファイルを作成してみました(一般にこういう処理がどういう名前で呼ばれているのか知りたい)

VEX

今回書いた VEX は以下です。

VEX でカスタム COP 作成

VEX の説明

そこまで難しいことは書いてないので簡単にしか説明は書かないですが Houdini の UI に見える部分はプラグマで設定して、処理は関数で実行という感じ。

ノードの名前とかパラメータとかはプラグマで設定しています。各プラグマの細かい説明は公式ドキュメントがそこそこ詳しいので今回は省きます。今回の題材は4つの画像が必要なので、opmaxinputs でインプットの数を4つに設定しています。choice を使用することで Houdini の UI でパラメータをリストから選択できるようにしています。

sample 関数はインプットの (IX、IY) から指定したチャンネルの値を取り出す関数です。useChannel の 0 ~ 3 がそれぞれ RGBA に対応しています。IX、IY はピクセルの位置を表すグローバル変数です。

sample_merge 関数がメイン関数でコンテキストに cop2 を指定しています。 インプットの4つの画像から指定したチャンネルの値を取り出して、それぞれ RGBA に値を格納しているだけです。

コンパイル

これをコンパイルして HDA にします。

vcc -l sample_merge.hda sample_merge.vfl

作成した HDA をインポートしたら HDA として使えます。下図は使用している図で、4つの画像の B チャンネルを1つの画像にまとめようとしているところです。

f:id:masahiro8080:20200418163605p:plain

今回は簡単ですが、これで終わり。

参考

Packaging についてのメモ

先日、第 13 回 UE4 ぷちコンに作品を応募しました。

historia.co.jp

6回ほど参加していて、今回初めて応募作品を公開しました。itch.io で公開しています。

https://0xuma.itch.io/butterfly-bloosom

初めてちゃんと Packaging したので、その際に実施したことを自分用のメモとして記載しておきます。間違いやこうしたほうがよい等があれば知りたいです。

基本的には以下を参照しました。

プロジェクトのパッケージ化 | Unreal Engine ドキュメント How to package the right way - reduce .pak size - Unreal Tournament Forums

Packaging の実施について

Packaging の実施自体は簡単で File > Package Project でどのプラットフォーム用に Packaging するかを選択します。画像は Windows 64-bit を選択している場面です。 f:id:masahiro8080:20200405153637p:plain

パッケージサイズの削減について

Packaging 自体は簡単にできるのですが、最初に作成したパッケージのサイズが 3 GiB 弱あり、配布するには大きすぎるので、パッケージサイズを削減していくことにしました(最終的には 700 MiB 程になりましたが、それでも大きい...)。

Project Settings での設定について

Project Settings で Project > Packaging を選択し、パッケージに関する設定を行います。

Project カテゴリ

  • Build Configuration は Shipping にしておく
  • Packaging 実施ごとにビルドを走らせるために Full Rebuild をチェックしておく
  • Include Debug Files にチェックが入ってないことを確認する

f:id:masahiro8080:20200405134933p:plain

Packaging カテゴリ

  • Use Pak File にチェックしてることを確認する

f:id:masahiro8080:20200405135354p:plain

Packaging カテゴリの▼を押下して、設定を開いて、さらに設定していく。

  • 指定したレベルのみ Packaging するために Cook only maps にチェックする。Packaging 対象のマップは Lists of maps to include in a packaged build で指定する
  • パッケージサイズを減らすために Create compressed cooked package にもチェックしておく
  • 削減の作業とは違うが、アセット以外のテキストファイル等を package 対象にしたい場合は Additional Non-Asset Directories to Package でディレクトリを指定する

f:id:masahiro8080:20200405135510p:plain

アセット関連

今回の場合、基本的にテクスチャが容量を食っていたので、テクスチャサイズの削減を実施しました。

テクスチャグループの設定

<Project Directory>/Config に DefaultDeviceProfiles.ini を作成し、テクスチャグループの設定を上書きする。今回はマーケットプレイスのテクスチャで 4K のものが多かったので World、World Normal Map の LODBias の設定を 1 に設定し、1段階テクスチャのサイズを下げました。その上でテクスチャアセット側の設定でよりサイズを下げていくという方法にしました。

[/Script/Engine.TextureLODSettings]
@TextureLODGroups=Group
+TextureLODGroups=(Group=TEXTUREGROUP_World,MinLODSize=1,MaxLODSize=8192,LODBias=1,MinMagFilter=aniso,MipFilter=point,MipGenSettings=TMGS_SimpleAverage)
+TextureLODGroups=(Group=TEXTUREGROUP_WorldNormalMap,MinLODSize=1,MaxLODSize=8192,LODBias=1,MinMagFilter=aniso,MipFilter=point,MipGenSettings=TMGS_SimpleAverage)

テクスチャアセットの設定

Maximum Texture Size で最大サイズを設定します。 f:id:masahiro8080:20200405140849p:plain

ゲーム内で使用されるテクスチャのサイズは Details タブ上部の Max In-Game でわかります。Resource Size はおそらく pak 内でのサイズだと思います。 f:id:masahiro8080:20200405150318p:plain

ライトマップ関連

ライトマップの容量の減らし方はよくわかってないけど以下を実施しました。

  • Static Mesh 等の Light Map Resolution を調整する
  • World Settings で Packed Light and Shadow Map Texture Size を調整する(パッケージサイズの削減とは違う気がする)

その他

コンテンツブラウザでアセットを右クリック > Size Map... で、選択したアセットの容量を確認できます。画像はレベルの Size Map です。 f:id:masahiro8080:20200405151508p:plain

プラグイン関連

不要なプラグインは Enabled にチェックを入れないようにする

最後に

<project directory>/Saved/Cooked の下に pak に含まれる Cook 後の各アセットが配置されるので各アセットサイズを見ることができる。ls -l とかで容量を食ってるアセットを見つける。

GameplayEffect の Stacking と Overflow を使ってみる

この記事は、Unreal Engine 4 (UE4) Advent Calendar 2019 - Qiita 15 日目の記事です。

qiita.com

前日は @ka-s さんの「【UE4】ランドスケープをスタティックメッシュに変換する方法とハマったところの紹介 - Qiita」でした。ランドスケープもスタティックメッシュに変換できるんですね。知らなかったです。

今回は、Gameplay Ability System の要素の一つである GameplayEffect の Stacking と Overflow を使用して何か作っていきたいと思います。

前提

今回は UE4.23.1 で確認しています。 また AttributeSet には Health という Attribute が定義されている前提で話を進めます。

GameplayEffect とは

GameplayEffect は Gameplay Ability System の要素の一つで Attribute を変更するために使用するクラスです。

Gameplay Ability System については、おかずさんの ActionRPG についての資料がわかりやすいかと思います。

実際に試してみたい方はおかわりはくまいさんの記事を参考にするとよいと思います。

okawari-hakumai.hatenablog.com

Stacking と Overflow

GameplayEffect のパラメータには Stacking と Overflow というセクションがあります。
Stacking は同じ GameplayEffect のスタックに関する設定ができます。Overflow は GameplayEffect のスタックが上限に到達した際の設定ができます。

今回はこの機能を用いて、1度目の攻撃はエフェクトが生じるだけでダメージはないが、2度目の攻撃はダメージを受けるというような機能を作成していきたいと思います。

下の動画は完成イメージです。1度目はグレイマンの周りにエフェクトが発生するだけですが、2度目はダメージを受けるようになっています(敵の攻撃を作るのをサボったため、Q キーの押下で敵からの攻撃とみなしています。。

GameplayEffect の作成

今回は GameplayEffect を2つ作成します。1つは Stack させるための GameplayEffect。もう1つは Overflow した際に発動する GameplayEffect です。 まず作るのが簡単な Overflow した際に発動する GameplayEffect を作成していきます。

Content Browser で右クリックし Blueprint Class を選択し GameplayEffect を作成します。今回は GE_Frostbyte としておきました。

f:id:masahiro8080:20191208162306p:plain
GameplayEffect の作成

作成した GE_Frostbyte を開き Modifires セクションを設定していきます。
この GameplayEffect が発動したら対象にダメージを与えるように設定します。Modifiers セクションから Attribute に Health を設定し、Scalable Float Magnitude でダメージ量を設定します。
GE_Frostbyte はこれで終わりです。

f:id:masahiro8080:20191208162701p:plain
Modifiers セクションの設定

次に Stack する方の GameplayEffect を作成していきます。
同様に GameplayEffect を作成します。名前は GE_StackingFrostbyte にしておきます。作成した GE_StackingFrostbyte のパラメータを設定していきます。
Overflow セクションには Overflow Effects として先ほど作成した GE_Frostbyte を追加します。この Overflow セクションは Stack の最大量を超えた際に発動する GamepleyEffect を設定します。Stack の最大量を超えた際には再び Stack を空にしておきたいので Deny Overflow Application、Clear Stack on Overflow ともにチェックを入れます。

次に Display セクションですがここでは GameplayEffect が発動した際のエフェクトに関わる設定をします。後で氷っぽいエフェクトを追加したいのでそのための設定として Gameplay Cues を一つ追加し Gameplay Cue Tags に Effect.Frostbyte を追加します。追加するには Edit から Add New Gameplay Tag から追加します。

f:id:masahiro8080:20191208164628p:plain
Overflow セクションと Display セクション

次は Stacking セクションです。Stacking セクションでは Stack に関する設定を行っていきます。
Stacking Type は Aggregate by Source に設定します(この設定は Ability System Component が持つこの GameplayEffect のスタックカウントの追加の仕方を設定する項目だと思っているのですが、Aggregate by Target との違いが、正直なところよくわかっていません(すみません))。Stack Limit Count を 1 に設定しました。Stack Limit Count は Stack に積める最大個数です。この設定によりこの GameplayEffect が 2 つ Stack されると Overflow を起こします。

最後に Gameplay Effect セクションです。ここではこの GameplayEffect の期間に対する設定を行います。GameplayEffect の Stack 機能を使用するには、Duration Policy を Has Duration か Infinite に設定する必要があります。ここでは Duration Policy を Has Duration に設定し、Scalable Float Magnitute を 10.0 に設定しました。これによりこの GameplayEffect は 10 秒間 Stack に残ることになります。なので 10 秒間の間に敵の攻撃を受けてしまうとダメージということになります。10 秒を過ぎると Stack から削除されます。

f:id:masahiro8080:20191208165215p:plain
Stacking セクションと Gameplay Effect セクション

GE_StackingFrostbyte の設定は以上です。

次に先ほど Display セクションで設定したエフェクトに関する設定を行っていきます。

GameplayCue の作成

GameplayEffect が発動した際や削除された際の GameplayCue はエフェクトやサウンドに関する処理を司るクラスです。

Content Browser から Blueprint Class を選択し GameplayCueNotify_Actor を作成します。名前を GCN_Frostbyte としておきます。

f:id:masahiro8080:20191208165826p:plain
GameplayCueNotify_Actor の作成

GCN_Frostbyte を開き処理を記述していきます。 まず Functions の Override から On Active を選択し次のような処理を記載します。 My Target から Mesh を取り出し Mesh に Emitter を Spawn しています。Emitter Template には InfinityBlade のアセットで氷属性っぽいエフェクトを使用しています。Spawn Emitter Attached の戻り値を保持しているのは GameplayEffect が削除されたときに Emitter を削除するためです。

f:id:masahiro8080:20191208170055p:plain
On Active 関数

次に On Remove の処理を記述していきます。 GameplayEffect が削除された際に Emitter を消すだけの処理を記載しています。

f:id:masahiro8080:20191208170400p:plain
On Remove 関数

最後に Class Defaults の設定を行っていきます。 変更したのは Auto Destroy on Remove と Gameplay Cue Tag の2つです。 GameplayEffect が削除された際にこの GameplayCue も削除してほしいので Auto Destroy on Remove にチェックを入れています。Gameplay Cue Tag には Effect.Frostbyte を設定しています。これは GE_StackingFrostbyte の Display セクションで設定した値です。これを設定することにより GE_StackingFrostbyte が発動した際に GCN_Frostbyte も発動することになります。

f:id:masahiro8080:20191208170552p:plain
Class Defaults

以上ですべての設定は終わりです。

確認のためにレベルブループリントでプレイヤーに GE_StacingFrostbyte を Stack させる処理を記述していきます。 Player Pawn から Ability System Component を取得し ApplyGameplayEffectSpecToSelf で自分自身に GE_StackingFrostbyte を適用しています。

f:id:masahiro8080:20191208171014p:plain
GE_StackingFrostbyte の動作確認

以上により、この記事の最初に表示した動画のようになります。

おわりに

駆け足でしたが Stacking と Overflow の使い方の紹介でした。これを機に GameplayAbilitySystem に興味を持つ人が増えればよいなと思います。

以上です。

明日はがっちょ( ¨̮ )さんの「地形で遊ぼう!」です。地形の内容ということで楽しみです!

参考

Gameplay Attributes and Gameplay Effects | Unreal Engine Documentation GitHub - Pantong51/GASContent: Repo to gather all Gameplay Ability System content for UE4 GitHub - tranek/GASDocumentation: My understanding of Unreal Engine 4's GameplayAbilitySystem plugin with a simple multiplayer sample project. UE4 GameplayAbility Pluginについてのメモ - Qiita

Procedural Foliage について

この記事は Unreal Engine 4 (UE4) #2 Advent Calendar 2019 の 9日目の記事です。

qiita.com

前日は、なんさんアーティストのためのマテリアル式にゅうもんでした。マテリアルで使用するベクターや Multiply、Add の意味がわかりやすく丁寧に書かれていて良い記事でした!

今回は Procedural Foliage について簡単に紹介しようと思います。 公式のクイックスタートもあるのでそちらも参照してみてください。

docs.unrealengine.com

この記事で使用している UE4 のバージョンは古いですが、4.22 です。
内容は次のような感じで進めていきます。

Procedural Foliage とは

設定したパラメータに基づいてプロシージャルに Static Mesh を配置できる機能です。
Modes パネルから選択できる Foliage ツールは手作業でレベルに Static Mesh を配置できる機能ですが、Procedural Foliage はボタン一つでプロシージャルに Static Mesh を配置できるので、サクッと森などの環境を作りたい場合に使用できるかと思います。

以下では Procedural Foliage の使い方を説明しながら森を作っていきたいと思います。

f:id:masahiro8080:20191207145817p:plain
今回作成した森

Procedural Foliage を使用する準備

Procedural Foliage は Experimental の機能なので Editor Preferences から Procedural Foliage を有効にする必要があります。
Editor Preferences を開き General から Experimental を選択し Procedural Foliage にチェックボックスにチェックを入れます。 Editor Preferences は Edit タブから開きます。

f:id:masahiro8080:20191130125026p:plain
Editor Preferences で Procedural Foliage を有効にする

以上で Procedural Foliage が使用可能になります。

Procedural Foliage 機能を使用した森の作成

Foliage Type の作成

まずはじめに Foliage ツールと同様に Foliage Type を作成します。Foliage Type は Foliage 機能で配置する Static Mesh に関する設定を行うクラスです。
Content Browser で右クリックし Miscellaneous から Foliage Type を選択します。森を作るために木の Static Mesh を配置したいので、名前は FT_Tree01 としておきます。

f:id:masahiro8080:20191130144132p:plain
Foliage Type の作成

作成した Foliage Type を開きます。一番上にある Mesh の項目に Procedural Foliage で配置したい Static Mesh を設定します。ここでは木の Static Mesh を設定しておきます。

f:id:masahiro8080:20191130183300p:plain
Mesh の項目に木の Static Mesh を設定

以上で Foliage Type に関する最低限の設定は終わりです。
他の項目は配置する Static Mesh の密度等の項目なのですが、先に Static Mesh の配置をし、その後で項目を設定していきたいと思います。

Procedural Foliage Spawner の作成

次は Procedural Foliage Spawner を作成します。Procedural Foliage Spawner は、設定したパラメータに基づいてプロシージャルに StaticMesh を配置してくれるクラスです。
Content Browser で右クリックし Miscellaneous から Procedural Foliage Spawner を選択します。森を作りたいので、名前は PFS_Forest としておきます。

f:id:masahiro8080:20191130140142p:plain
Procedural Foliage Spawner の作成

作成した Procedural Foliage Spawner を開きます。Foliage Types の + ボタンを押下し Foliage Type Object に先ほど作成した FT_Tree01 を設定します。Foliage Types は Procedural Foliage Spawner で配置する Static Mesh に関する設定です。

f:id:masahiro8080:20191130183551p:plain
Foliage Type Object に FT_Tree01 を設定

以上で Procedural Foliage Spawner の設定は終わりです。
他のパラメータについては公式リファレンス を参照してください。

Procedural Foliage による Static Mesh の配置

先ほど作成した Procedural Foliage Spawner をレベルに配置し、Static Mesh を配置します。

ちゃっと広いレベルを作成したかったのでランドスケープを使用しています。

f:id:masahiro8080:20191130183946p:plain
Landscape モードでランドスケープを作成

PFS_Forest をレベルに配置します。そのままでは小さいのでスケールを変更して大きな領域にしておきます。

f:id:masahiro8080:20191130184849p:plain
レベルに PFS_Forest を配置する

Static Mesh の配置には、PFS_Forest の Detail タブ内 Procedural Foliage カテゴリにある Resimulate ボタンを押下します。

f:id:masahiro8080:20191130185044p:plain
PFS_Forest の Procedural Foliage カテゴリ

すると Procedural Foliage Spawner の Foliage Types に設定した Static Mesh がレベル上に配置されます。

f:id:masahiro8080:20191130185204p:plain
Resimulate した結果

以上で Foliage Type に設定した Static Mesh を配置し、森を作成することが出来ました。

基本的な使い方は以上です。あとは求める背景に近づけるために、パラメータの調整や新しく Foliage Type を作成していきます。

Foliage Type の調整

配置した木の密集具合や木の大きさ等の調整は Foliage Type で行います。
Foliage Type のパラメータを変えて Procedural Foliage Spawner で Resimulate を繰り返し、求める背景に近づけていきます。

ここでは今回設定したパラメータの一部をざっくりと説明していきます。各パラメータに関しては Procedural Foliage Spawner 同様、公式リファレンス を参照してください。

Placement セクション

Placement セクションでは配置に関するパラメータを設定します。
垂直位置のばらつきや地面に対して垂直に Static Mesh を配置するか、ピッチの角度のばらつきを設定できます。今回は Z Offset で少し垂直位置が下がっている木があるようにしてみたり Random Pitch Angle で少し傾いた木があるように設定しました。

f:id:masahiro8080:20191207155626p:plain
Placement セクション

Collision セクション

Collision セクションでは配置する Foliage Type 同士の重なりに関するパラメータを設定します。
今から配置しようとしている Foliage Type の半径内と他の Foliage Type の半径内が重なった際、ルールや優先度によりどちらかが削除されることになりますが、その半径をここでは設定できます。半径は Collision Radius と Shade Radius の2つを設定できます。今回は Collision Radius を少し変更している程度であまり意味があって変更したわけではないです。

f:id:masahiro8080:20191207160241p:plain
Collision セクション

Clustering セクション

Clustering セクションでは密度や年齢に関するパラメータを設定します。
何世代まで配置するかや配置しようとする Static Mesh の密度、そのばらつきを設定できます。Num Steps は 0 だと最初の世代のみが配置されます。Initial Seed Density は種の密度を設定します。密にしたい場合は大きめの値を設定します。Spread Variance は種のばらつきを設定します。今回は、Num Steps を 5 に設定し、6世代まで配置できるようにしています。また Spread Variance を少し大きめに設定しています。

f:id:masahiro8080:20191207164817p:plain
Clustering セクション

Growth セクション

Growth セクションは年齢による成長に関するパラメータを設定します。
Collision セクション で設定した Shade Radius を無視できるようにしたり、最大の年齢を設定できます。Can Grow in Shade と Spawns in Shade をともに true にすることにより Shade Radius を無視できます。今回は、Max Age や Procedural Scale を変更してみています。

f:id:masahiro8080:20191207170259p:plain
Growth セクション

Instance Settings セクション

Instance Settings セクションでは配置された Static Mesh に関するパラメータを設定します。
Mesh を配置する際のおなじみの設定がほとんどかと思います。今回は Collision Presets を No Collision にしていますが、コリジョンが必要な場合はここで適切なコリジョンに設定します。

f:id:masahiro8080:20191207170730p:plain
Instance Settings セクション

複数の Foliage Type の設定と配置

木の Foliage Type を調整した結果、このような感じになりました(途中で Exponential Height Fog を配置しました)。

f:id:masahiro8080:20191207185605p:plain
途中結果

今は木だけですので、地面に草や石も生やしてみます。

今回は草用と石用の Procedural Foliage Spawner を新しく作成しました。草や石の Foliage Type を作成し、それぞれに Procedural Foliage Spawner に設定しています。これらも木の場合と同様にレベルに配置し、Resimulate します。

f:id:masahiro8080:20191207185150p:plain
草の Procedural Foliage Spawner

もしかしたら、一つの Procedural Foliage Spawner に木や草、石をまとめてもよいのかもしれないのですが納得のいく配置が出来なかったので今回は Procedural Foliage Spawner を複数に分けています。

Static Mesh の配置の抑制

ここまでで次のような感じになりました。
ここで画像の手前から真ん中の辺りに向かって道のようにしたいと思いました。その部分に配置されている花や草が邪魔なので、その部分には配置されないように設定します。

f:id:masahiro8080:20191207171800p:plain
ここまでで作成した森

Procedural Foliage Spawner を配置した範囲の中で Static Mesh を配置したくないという領域がある場合には Procedural Foliage Blocking Volume を使用します。Modes パネルで Procedural Foliage Blocking Volume を検索し Procedural Foliage Spawner の中で Static Mesh を配置したくない場所に配置します。

f:id:masahiro8080:20191201140706p:plain
Procedural Foliage Blocking Volume の配置

あとは Procedural Foliage Spawner 側で Resimulate を押下するだけです。押下すると Procedural Foliage Blocking Volume を配置した部分は Static Mesh が配置されなくなります。

f:id:masahiro8080:20191201140946p:plain
Procedural Foliage Blocking Volume 配置後の Resimulate 結果

この機能を使用し、道のような部分を作成しました。

f:id:masahiro8080:20191207172432p:plain
Procedural Foliage Blocking Volume を配置し、Resimulate

どことなく物足りなさを感じたので、倒れた木を一つ配置して(これは手作業)完成としました。

f:id:masahiro8080:20191207145817p:plain
完成

おわりに

以上で Procedural Foliage についての説明は終わりになります。
Procedural Foliage は、まだ Experimental の機能ということで今後どうなっていくのか楽しみです。 ここまでお読みいただいてありがとうございました。

明日は、@suihanki さんの「VRネタで何か一発」です。

参考

How To Create And Use Procedural Foliage Volumes - UE4 Tutorial Open World ツールのプロパティ リファレンス

GameplayAbility を最初に使用した際にゲームが止まるのを修正する方法

GameplayAbility を使っているプロジェクトで開発していると、エディタの起動後、ゲームをプレイして初めて GameplayAbility を使用した場合に一瞬から数秒ゲームが固まることがあります。

多分、GameplayAbility の使用時に何かを探索しているのかなとか考えてたのですが、解決方法が、AnswerHub に書いてました。

https://answers.unrealengine.com/questions/820453/gameplay-ability-long-lag-on-first-use.html

DefaultGame.ini に GameplayCue のあるフォルダを指定してあげると解決できるみたいです。

 [/Script/GameplayAbilities.AbilitySystemGlobals]
+GameplayCueNotifyPaths="GameplayCue があるフォルダのパス"

GameplayAbility を最初に使用する際に、CueManager が作成されるらしく、その処理の中でプロジェクト内の GameplayCue を探し出し、Cue をプールする処理があるそうです。 上記の GameplayCueNotifyPaths は、どこのフォルダを探索するかを指定する設定のようです。 GameplayCueNotifyPaths のデフォルトは /Game/ なので、指定しないとプロジェクト全体を探索してしまうため、ゲームが固まることがあるみたいです。 なので、上記のように GameplayCueNotifyPaths を指定してあげることで解決します。

ちなみに、親切にもログにちゃんと書いてました。

LogAbilitySystem: Warning: No GameplayCueNotifyPaths were specified in DefaultGame.ini under [/Script/GameplayAbilities.AbilitySystemGlobals]. Falling back to using all of /Game/. This may be slow on large projects. Consider specifying which paths are to be searched.

ちゃんとログは読まなきゃですね。

今回は以上です。

GameplayEffect で継続ダメージ処理をやってみる。

最近、GameplayEffect について調べてます。少しわかってきたので、簡単なサンプルを作ってみたいと思います。今回は毒状態みたいな継続ダメージ処理を GameplayEffect で実装してみたいと思います。

前提

  • Unreal Engine 4.22.3 を使用しています。
  • AttributeSet の実装や AbilitySystemComponent の実装については記述しません。
  • AttributeSet には Health という HP を表す Attribute で設定されていると仮定します。

やりたいこと

今回実装してみるものの仕様はざっくり以下になります。 * 毒状態のような継続ダメージ処理 * 継続する期間は 15 秒間 * 5 秒おきにダメージを喰らう * 継続ダメージが有効中は、パーティクルを発生させる * ダメージ時は、パーティクルを発生させる

下2つの仕様は GameplayEffect が有効かどうかを視覚的に確認したいがために追加しました。

それでは、実装していきます。

GameplayEffect の作成

まず、GameplayEffect のブループリントを作成します。

Blueprint Class から GameplayEffect クラスを選択し、GameplayEffect のブループリントを作成します。

f:id:masahiro8080:20190707132044p:plain

作成した GameplayEffect の Class Defaults で設定をしていきます。 今回は GameplayEffectPeriodDisplay を使用します。

Gameplay Effect カテゴリの設定

まず、Gameplay Effect カテゴリの設定をしていきます。 以下、Gameplay Effect は GE と省略します。

f:id:masahiro8080:20190707131851p:plain

GE の有効時間を一定期間に設定するために、Duration PolicyHas Duration にします。

次に、有効時間を設定するために、Duration Magnitude の項目を設定していきます。 Magnitude Calculation Type は値をどのように設定するかに関する項目です。 今回はそのまま float 値で 15 秒と設定したいので、Scalable Float に設定し、 Scalable Float Magnitude に 15.0 と設定します。 これにより、この GE を起動してから 15 秒間の間、この GE は有効状態になります。

次にダメージ処理のための設定を行います。 Modifiers は、指定した Attribute をどのように更新するかを設定します。 今回は GE が適用される毎に Health を 50.0 ずつ減らすようにしてみました。 そのため、Attribute には AttributeSet の Health、Modifier Op には Add を設定しています (DefaultAttributeSet はこのサンプル用に作成しておいた AttributeSet クラスの名前です)。 これにより GE の実行時に Health の値に -50.0 を追加してくれます。

Period カテゴリの設定

次に Period カテゴリの設定を行います。 ここでは、何秒おきにこの GE を実行するかを設定できます。

f:id:masahiro8080:20190707133055p:plain

今回は 5 秒おきに GE を実行するので、Period に 5.0 を設定しました。 また、GE を起動直後はダメージを発生させたくないので、Execute Periodic Effect on Application のチェックを外しておきました。 この項目を有効にしておくと、GE が起動した際にもダメージが発生することになります。

Display カテゴリの設定

最後に Display カテゴリを設定していきます。 Display カテゴリはエフェクトやサウンドのようなものを設定するために存在する項目のようです。 といっても実際に設定するのは、主にタグかと思います。

f:id:masahiro8080:20190707133418p:plain

Gameplay CuesGameplay Cue TagsEffect.Poison というタグを作成し、設定しました。 これを設定しておくことで、この GE が起動または実行されたときに、このタグに紐づいた Gameplay Cue が処理します。

以上で、GE の設定は終わりです。次に Gameply Cue の実装をしていきます。 Gameplay Cue では、GE が起動したときやダメージ処理が実行されたときのエフェクト処理を記述していきます。

Gameplay Cue の作成

Blueprint Class から GameplayEffect クラスを選択し、GameplayCueNotify_Actor のブループリントを作成します。

f:id:masahiro8080:20190707133708p:plain

作成した Cue の Class Defaults の Gameplay Cue カテゴリの Gameplay Cue TagDisplay で設定したタグを設定します。 これで先ほどの GE が起動された場合にこの Cue が紐づくようになります。

f:id:masahiro8080:20190707133748p:plain

次にエフェクトの発生処理を記述していきます。

まず初めに、OnActive 関数をオーバーライドし、次のように実装します。 OnActivate 関数は、この Cue に紐づいた GE が起動した場合に呼ばれます。 ここでは、GE が有効中であることがわかるように GE が有効中の間常にエフェクトが発生するように P_Smoke を発生させるようにしました。あとで消せるように Emitter Smoke 変数でパーティクルを保持しています。

f:id:masahiro8080:20190707134020p:plain

次に OnExecute 関数をオーバーライドし、次のように実装します。 OnExecute 関数は GE が実行されるたびに呼ばれます。今回のサンプルの場合は ダメージ処理が発生するたびに呼ばれることになります。 ここでは、GE が実行されるたびに P_Explosion を発生するようにしました。

f:id:masahiro8080:20190707134232p:plain

最後に OnRemove 関数をオーバーライドし、次のように実装します。 OnRemove 関数は GE が削除される際に呼ばれる関数です。 ここで GE が削除されるときの後処理を記述しています。

準備は以上です。最後に動作確認をしていきます。

動作確認

レベルブループリントで、キャラクターに GE を付与し、GE を実行するようにします。

f:id:masahiro8080:20190707134612p:plain

キャラクターの Health が減っているかどうかを確認するために TIck イベントを次のように実装しました。 GetHealth 関数や GetMaxHealth 関数は、今回説明しませんが、 キャラクターが持つ AttributeSet から Health と MaxHealth の値を取り出すような処理を C++ 側で記述しています。

f:id:masahiro8080:20190707134811p:plain

実行すると次のような感じです。 GE が起動すると煙が上がり、約5秒おきに爆発エフェクトが発生することがわかると思います。 また、非常に見づらいですが、左上の Debug String から Health が 50 ずつ減っていることも確認できるかと思います。

youtu.be

駆け足で説明してきましたが、このような感じです。 まだまだ GameplayEffect について調べているので、ほかに使い方がわかれば新しく記事を書くつもりです。

今回は以上です。