Quantcast
Channel: ぼっちプログラマのメモ
Viewing all 159 articles
Browse latest View live

Vive Trackerを一定数繋いだ状態でUE4を起動するとクラッシュする不具合の修正方法について (UE4.21で正式修正予定)

$
0
0

はじめに

Vive Trackerを一定数以上繋いだ状態でUE4を起動するとクラッシュする、という不具合が報告されています… そこそこ本気でVTuberする上でこれは辛いので、修正方法を共有します…修正箇所は凄く少ないので対応コストは少ないです。
正式に入るのはUE4.21を予定しています。

関連issue
https://issues.unrealengine.com/issue/UE-54387
https://issues.unrealengine.com/issue/UE-63579 (申請が通れば公開されます)

修正内容

"\Engine\Plugins\Runtime\Steam\SteamVR\Source\SteamVRController\Private\SteamVRController.cpp"

30行目付近の MAX_TRACKED_DEVICES をコメントアウト

//#define MAX_TRACKED_DEVICES (int32)EControllerHand::Special_9 - (int32)EControllerHand::Left + 1

115行目付近のMaxControllers に入れる値を変更

/** Total number of motion controllers we'll support *///static const int32 MaxControllers = MaxUnrealControllers * CONTROLLERS_PER_PLAYER;// NOTE: This used to be MaxUnrealControllers * CONTROLLERS_PER_PLAYER, but we needed to support many more trackers than thatstaticconst int32 MaxControllers = vr::k_unMaxTrackedDeviceCount;

Github

#jira UE-63579 Assert when having too many VR devices
Increase max controllers to support more.
https://github.com/EpicGames/UnrealEngine/commit/01c783a907cffba11905dc8f15823b29d2b451d7


もしこの対応を入れてもクラッシュする場合はご連絡ください…


UE4 と Ikinema Orionで遊んでみた その1

$
0
0

はじめに

突然ですが、UE4VTuberムーブをキメることになったので、早速Ikinema Orionで遊び始めました!凄く楽しいです!!!

せっかくなので、メモ代わりに記事書いていきます。
今回はIkinema Orionの紹介と、Orionを使う上で必要なVive Trackerの購入、固定方法について説明します。

Ikinema Orionについて

簡単言うと、HTC ViveとVIVE Trackerを使って全身モーションキャプチャできるソフトです。下の動画みたいなことが簡単にできてしまいます!しかも、年間ライセンス62,400円(税別)!超安い!…い、いや…安いんですって!
www.youtube.com

Ikinema Orionの詳細や契約周りはMogura VRさんのページをご確認ください。14日間の無料体験版があるので導入前のテストができて安心です(僕のときはメールを送ってすぐ返信がきました!素晴らしい!)
www.moguravr.com

注意点としては、
HTC Vive:1セット、Vive Tracker:3台以上
が必要になります。(両足、腰 に Vive Trackerを必ず使うため)

f:id:pafuhana1213:20180910232833p:plain:w300
引用:IKINEMA | Motion Capture, VR, Games - Documentation

Vive Tracker購入編

Vive Trackerはご家庭に必ず8台あるものだと思いますが、念の為。

Vive Trackerは2018年9月現在2017版と2018版の2つがありますが、 互換性があるので2018年版を購入して問題ありません。購入するショップに関しては、公式サイトで丁寧にまとめられているので参考になります。
VIVE 正規取扱販売店 一覧

Vive Tracker 固定編

OrionでVive Trackerを使うためには、手・腰・足・肘などに固定する必要があります。
まずは今回セットアップする上で参考にした記事を紹介。
sumoch1.hatenablog.com

足に関しては、上記の記事で紹介されている「クロックス + ネジ」スタイルにしました。

f:id:pafuhana1213:20180911000130p:plain

手(肘)と腰に関しては、Genz( @Genz_3D )さんオススメのセットで組みました!


なお、Track Strap は 以下から購入可能です。ガッツリ固定されて超いい感じです!
Track Strap 《送料無料》 - 自作PC・PCパーツが豊富!PC専門店【TSUKUMO】
f:id:pafuhana1213:20180911000210p:plain

腰固定用のザムストはZW-3 ソフトサポートを選択。穴を開けて足で使ったネジを使って固定しました。ちょっと固定が甘くてブルブル震えてる感があるので、ZW-5以降の硬めのものにした方がいいかもしれません…

f:id:pafuhana1213:20180911000230p:plain
f:id:pafuhana1213:20180911000242p:plain

ひとまずこれでVive Trackerを固定できるようになりました!しばらくはこの構成でいこうと思います!

さいごに

次はUE4とOrionの連携について書こうと思います。
といっても、ビックリする程簡単です!お楽しみに!

Windows + iOS開発で必要な証明書・プロビジョニングファイルを削除する方法

$
0
0

はじめに

Windows上からMacをリモートで使ってiOSパッケージを作成するリモートビルドという機能がUE4にはあります。
そのリモートビルドが急に上手くいかなくなった時とかに試す証明書・プロビジョニングファイルの削除を
何度も何度も忘れるのでメモ。なお、自己責任でお願いします

Windows上での証明書・プロビジョニングファイルの作成手順
Unreal Engine | iOS クイックスタート

リモートビルドについて
Unreal Engine | Windows で iOS をビルドする

プロビジョニングファイルの削除

"C:\Users\\AppData\Local\Apple Computer\MobileDevice\Provisioning Profiles"
のファイルを全削除

証明書の削除

Win+Rを押した後に、certmgr.mscと入力・実行
f:id:pafuhana1213:20181019112922p:plain

Certificates->Personal->Certificates にある iPhone Developer :~ を全削除
f:id:pafuhana1213:20181019113135p:plain

以上

Oculus社のリップシンクライブラリ「Oculus LipSync ( OVRLipSync )」をUE4で使う方法について その1 (サンプル解説編)

$
0
0

はじめに

2018/10/14のアンリアルフェスにて、UE4VTuberをする方法について講演しました。

www.slideshare.net

その中で「Oculus LipSyncはいいぞ!」ムーブをキメました(p94以降)が…具体的にどのように導入・使用するのかについて触れなかったので記事にまとめようと思います。

Oculus LipSyncについて

Oculus LipSync ( 以下、OVRLipSync ) はOculus社が提供しているリップシンク(口パク)ライブラリで、2018/10/5にリリースされた v1.30.0 でUE4に対応しました。そして、2018/11現在(v.1.30.0)ではUE4.20に対応しており、サンプルプロジェクトも用意されています(v.1.30.0、UE4.21でも一応動きました)。

このライブラリを使うことで、マイク音声または事前に収録した音声データ( SoundWavアセット )からリップシンク情報を取得することができます。つまり、セリフに合わせたキャラクタの口パクアニメーションを簡単に作ることができます!
( 表情用のMorph TargetをキャラのSkeletalMeshに用意する必要はありますが… )

サンプルでは、OVRLipSyncが検出した口形素( Viseme )をSkeletal MeshのMorph Targetに渡すBPが用意されています。Visemeは音声から唇の形状を分類したもので、全部で15パターン用意されています。( ただ一般的によく用いられるのは母音(a, i , u, e, o)なので、全てのパターンを使い分ける必要はないかと思います。)
f:id:pafuhana1213:20181116232919g:plain
Visemeに関するドキュメント:Viseme Reference

以降は、サンプルに含まれるBPについて簡単にですが解説します。

OC5におけるOVRLipSyncに関する講演

www.youtube.com

サンプルのセットアップ・動作確認

まずはサンプルを動かしてみましょう。上述のダウンロードページからサンプルプロジェクトをダウンロードできます。
f:id:pafuhana1213:20181116233208p:plain

ダウンロード後、"LipSync\UnrealPlugin\OVRLipSyncDemo"にOVRLipSyncDemo.uproject を実行してみましょう!…以下のようなウィンドウが出てきます(;´∀`)
f:id:pafuhana1213:20181116234327p:plain

残念ながら、OVRLipSync (v1.30.0)を使うためにプラグインをビルドする必要があります。「はい」を選択しビルドを走らせましょう。また、もしVisual Studioが入っていない場合はビルドに必要なのでインストールしましょう。

ビルドが完了すると自動的にサンプルプロジェクトが立ち上がります。やったね!
f:id:pafuhana1213:20181116234711p:plain

サンプルには以下の2つのレベルが用意されています。初回起動時に開かれるのはLiveCaptureレベルです。

  • “Content/Maps/LiveCapture”:マイク音声を使用するサンプル
  • “Content/Maps/CannedPlayback” 音声データを使用するサンプル

具体的な解説に行く前にサンプルが正常に動作するか確認しましょう!Playボタンを実行して、マイクに向かって喋ってみましょう。声に合わせてモデルが口パクしたら正常に動作しています。

もし正常に動作していない場合はOutput Logを確認してみましょう。以下の文字列が出力されていた場合、PCにマイクがデバイスとして認識されていません。「windowsマイク デバイス設定」などで検索して設定して下さい。

LogVoiceCapture: Warning: Failed to create capture device 0x88780078
LogTemp: Error: Can't create voice capture

もし音声データ(SoundWav)を持ってる方は CannedPlaybackレベルも試してみましょう。持ってないけど試したい方はサンプルボイスがプロジェクトにあります
“Content/Audio/vox_lp_01”

まずはSoundWavアセットを右クリックし、Generate LipSyncSequenceを実行すると、同じフォルダに OVRLipSync用のアセットが生成されます。
f:id:pafuhana1213:20181116235707p:plainf:id:pafuhana1213:20181116235739p:plain

そして、このアセットをCannedPlaybackレベルに配置されているPlaybackBlueprint OVRLipSyncPlaybackコンポーネントの Sequenceプロパティに設定すればOKです。
f:id:pafuhana1213:20181116235805p:plain

この状態でPlayを押すと、指定した音声が再生されつつ口パクしてくれます。


サンプルが正常に動作したという前提で、各レベルで使われているBPについて解説します。といっても、結構シンプルな作りになってるのでご安心ください!

LiveCaptureBlueprint について

LiveCaptureレベルの場合は”Content/Blueprints/LiveCaptureBlueprint”が 口パクの検出・適用処理をしています。
f:id:pafuhana1213:20181117000350p:plain

OVRLipSyncコンポーネント

LiveCaptureBlueprintで使われているOVRLipSyncコンポーネントは、その名の通りOVRLipSyncの機能を使うためのコンポーネントです。用意されているプロパティは以下の通り。
f:id:pafuhana1213:20181117000558p:plainf:id:pafuhana1213:20181117000607p:plain
Sample Rate:弄る際は慎重に。適切な値ではない場合は正しく処理されません。基本はデフォルト値でいい気がします。
Provider Kind:OVRLipSyncの検出処理の設定を変えているのですが…詳細な解説が今の所ない(はず)です。おそらく、v 1.30.0 の笑い声検出機能(β)を使いたいなら Enhanced with Laughter、使いたくないなら Enhancedでいい気がします
Enable Hardware Acceleration: …デフォルトの有効のままでいいのかなと(正直な所、どんな効果があるかわからない!たぶんサウンド屋さんが知ってるはず!)

BeginPlay

f:id:pafuhana1213:20181117000835p:plain
StartノードでOVRLip Syncによる検出機能を開始し、その後にWindowsの場合は voice.SilenceDetectionThreshold 0.0コマンドを使ってます。これはWindowsは マイクの無音判定用の閾値である voice.SilenceDetectionThresholdに 0より上の値が設定されているため、OVRLipSyncによる検出の妨げになるからです。ちなみに、なぜ無音判定処理がデフォルトで入っているかというと、OVRLipSyncはUE4ボイスチャット用のマイク入力機能を使用しているからです。

On Visemes Ready

f:id:pafuhana1213:20181117001614p:plain
On Visemes Readyは「OVRLipSync内で一定間隔毎に行われる音声解析処理」の実行後に呼ばれるイベントです。そのため、On Visemes ReadyのタイミングでOvrLipSyncの最新の検出結果を取得・利用できます。ちなみに、デフォルトでは20ms間隔で呼ばれます。間隔変えたい方は、OVRLipSyncLiveActorComponent.cpp UOVRLipSyncActorComponent::VoiceCaptureTimerRateを変更する必要があります(デフォルトは0.2f)。

On Visemes Readyでは、OVRLipSyncが推定した各Visemeの値を Skeletal Meshの各MorphTargetに反映する処理を行っています。
Get Visemes NamesノードはドキュメントにあるVisemeの名前の配列を返します。そして、Get Visimesノードは各Visemeの検出値を返します。これらをForEachLoopを使って順にSkeletal MeshのMorphTargetに渡してます。あと、Get Laughter Scoreノードで笑い声の推定結果の値もSkeletal Meshに渡しています。

以上!
ね?シンプルでしょ?

PlaybackBlueprint について

CannedPlaybackレベルの場合は、”Content/Blueprints/PlaybackBlueprint” が口パクの検出・適用処理をしています。更にシンプルな作りです。
f:id:pafuhana1213:20181117002220p:plain

まずボイスチャットの機能を使わないので、コンソールコマンドを使っていません。加えて、AssignVisemesToMorphTargetsノードというものだけが使われてます。…実はこの関数の中身は LiveCaptureBlueprintにおける各visemeの設定処理と全く同じです(つまり、笑い声の判定処理はありません)。

void UOVRLipSyncActorComponentBase::AssignVisemesToMorphTargets(USkeletalMeshComponent *Mesh, const TArray<FString> &MorphTargetNames)
{
	for (int cnt = 0; cnt < MorphTargetNames.Num(); cnt++)
	{
		Mesh->SetMorphTarget(FName(*MorphTargetNames[cnt]), Visemes[cnt]);
	}
}

じゃあ、AssignVisemesToMorphTargetsノードだけでいいじゃん!と思うかもしれませんが…残念ながらそうはいきません。

サンプルの問題点

f:id:pafuhana1213:20181117002600p:plain
これはサンプルで使用しているメッシュのMorphTargetです。見ての通り、名前と順番がOVRLipSyncが持つVisemesと全く同じです。この状態にしないと、AssignVisemesToMorphTargetsノードは正常に動作しません
更に言うなら、LiveCaptureBlueprintにおける実装も動作しません!!!

つまり、サンプルにあるBPの実装をそのまま別モデルに流用することはできないということです。と言っても、対応は簡単です!

長くなりましたので、一旦ここまで。
次回の記事では自分のプロジェクトでOVRLipSyncを導入する手順やサンプル以外のモデルに適用する際の手順について解説します

つづく

Oculus社のリップシンクライブラリ「Oculus LipSync ( OVRLipSync )」をUE4で使う方法について その2 (Grayちゃんでリップシンク!編)

$
0
0

はじめに

この記事はこちらの記事の続きです
pafuhana1213.hatenablog.com

前回はOVRLipSyncのサンプルについて解説しました。しかし、サンプルに含まれるモデルはOVRLipSyncの仕様に超特化したものなので、そのまま他モデルに適用することはできません。
そこで、他モデルでOVRLipSyncを使うにはどうすればいいのかについて解説します。なお、今回の解説では皆大好きなGrayちゃんのモデル・ボイスをお借りしています。
3Dモデル:Grayちゃんモデルデータ – rarilog
ボイス:Grayちゃんボイスが、より扱いやすくなりました - Grayちゃん OFFICIAL WEBSITE


OVRLipSyncプラグインの導入

まずは公式サンプルプロジェクト( OVRLipSyncDemo )に含まれるOVRLipSyncプラグインを別プロジェクトで移植します。今回はGrayちゃんの3Dモデルに含まれるGrayChanProjectに移植します。

1. OVRLipSyncプラグインをコピペ

OVRLipSyncDemoにある Pluginsフォルダ を GrayChanProjectのルートフォルダ(GrayChanProject.uprojectがあるフォルダ)にコピペします

2. マイクを使うために設定追加

GrayChanProjectのConfigフォルダにある DefaultEngine.ini に 以下の文字列を追加します。これでマイクが使用可能になります。なお、事前に録音した音声しか使わない場合はこの設定追加は不要です。

[Voice]
bEnabled=True

[OnlineSubsystem]
bHasVoiceEnabled=False

3. OVRLipSyncプラグインが有効になっているか確認

GrayChanProjectを開き、PluginsからOVRLipSyncプラグインが有効になっているか確認します。
f:id:pafuhana1213:20181126001832p:plain

なお、OVRLipSyncプラグインは "EnabledByDefault" : true なのでデフォルトで有効になっているはずです。ですので、この確認はあくまで念の為だったりします。
( 気になる方は、OVRLipSync.uplugin をテキストエディタで開いてみましょう! )

Grayちゃんボイスで口パクしてみる

今回はマイク音声ではなく、事前に収録された音声であるGrayちゃんボイスを使ってみます。マイクを使用する場合でもBPによる実装内容は殆ど変わりないからです。準備周りはサンプルからコピペしましょう!

音声データのインポート・変換

まずは使用する音声データをUE4にインポートし、右クリックメニューからOVRLipSync Frame Sequenceを生成します。(詳細は前回の記事で)
f:id:pafuhana1213:20181126002349p:plain

必要なコンポーネントの追加・セットアップ

次に、ThirdPersonCharacterにOVRLipSyncPlaybackActorコンポーネントとAudioコンポーネントを追加します。
f:id:pafuhana1213:20181126002526p:plain

そして、OVRLipSyncPlaybackActorコンポーネントには先程作成したOVRLipSync Frame Sequenceを指定します。
f:id:pafuhana1213:20181126002853p:plain
また、Audioコンポーネントにはインポートした音声データ(SoundWave)を指定し、さらに勝手に自動再生されないように Auto ActivateをOFFにしておきます。
f:id:pafuhana1213:20181126002920p:plain

口パク(モーフターゲット)制御の実装

最後に、OVRLipSyncが解析した口パクをGrayちゃんモデルに渡す処理をBPで実装します。

まずは、ボイスとOVRLipSyncによる解析を開始する処理を書きます。今回は簡単に 1キー を押したら処理を開始するようにします。
f:id:pafuhana1213:20181126004946p:plain

次に、OVRLipSyncによる解析結果が更新される On Visemes Ready イベントにてGrayちゃんのモーフターゲットを制御する処理を実行します。

前回の記事で紹介した通り、OVRLipSyncはVisemsという音声解析を元にした口の形状パラメータの配列を返してくれます。
公式ドキュメント:Viseme Reference

そして、今回使用するGrayちゃんモデルには母音( a, i, u, e, o )用のモーフターゲットが用意されています。
f:id:pafuhana1213:20181126003856p:plain

ですので、Visemsの10番目から15番目のパラメータを各Visemに対応するモーフターゲットに渡す形になります。ちなみに、パラメータの順番はこんな感じ。
f:id:pafuhana1213:20181126004431p:plain

上記のように配列から一つずつ値を取得する感じで実装しても良いのですが、せっかくなのでシンプルに実装してみました!
f:id:pafuhana1213:20181126011400p:plain
コピペ用: https://blueprintue.com/blueprint/p-z2c6ys/

これで準備完了です。実行して 1キー を押すと 「はじめに」で載せた動画のように音声に合わせて口パクします!

最後に

これでサンプル以外のモデルでもOVRLipSyncを用いた口パクができるようになりました。しかし、改良の余地はまだまだまだまだあります。例えば、口をもっと大きく開くように補正処理をかけたり…
f:id:pafuhana1213:20181126010038p:plain

アニメ的な表現を再現するために更新間隔を調整したりなどなど…色々あります!(ググると色々…モニョモニョ…)
是非色々カスタムしてみてください!

補足

シーケンスレコーダーによるベイク処理を使って、OVRLipSyncによる口パクをアニメーションアセット化したい方がそれなりにいるかと思います。

www.slideshare.net
(シーケンスレコーダーについては、126ページ以降)

しかし、Set Morph Targetでモーフターゲットを制御する場合はベイク処理の対象外になります。そのため、ベイク処理の対象にするためには、Animation BPのAnim Graphにて Modify Curveノードを使って各モーフターゲットの値を制御する必要があります。ご注意下さいまし。
f:id:pafuhana1213:20181126011012p:plain

おわり

UE4 & iOS開発時の実機デバッグ・プロファイリング方法 まとめ 2018

$
0
0

はじめに

この記事はUnreal Engine 4 Advent Calender 2018の13日目の記事です。
qiita.com

f:id:pafuhana1213:20181213023820j:plain
おかげさまでUE4モバイル案件が増えてきたということもあり、ネット上にあまり情報がないiOS開発時の実機デバッグ・プロファイリング方法についてまとめてみました。
…社内外含めて情報全然ない!がんばた!

各記事のご案内

…予想以上に内容が膨らんだので記事を分割しました。

  • ログの確認
    • 実行中のログ確認
    • 実行後のログ確認

pafuhana1213.hatenablog.com

pafuhana1213.hatenablog.com

  • CPU, GPUプロファイリング
    • Instrumentsを使って、CPU・GPU処理の負荷を確認

pafuhana1213.hatenablog.com

注意

なお、全て実機上でのデバッグ・プロファイリングについてです。UE4エディタ上で行う際はモバイルプレビュア機能をご活用ください。ただしあくまで疑似再現なので、ちゃんとデバッグ・プロファイリングするときは実機でしましょう!
api.unrealengine.com

また、stat関連とログ取得以外に関しては必ずMacが必要になります


Mac Mini(2018)、少なくとも個人開発レベルでは、リモートビルド・プロファイリングする上で不便に思ったことはないです。オススメです。はい。

Macと仲良くできるかはまた別問題だけどな!

検証環境

開発環境構築について

皆さん大好きな証明書、プロビジョニングファイル、リモートビルドを含む開発環境の構築に関しては、わんちゃん( @WanchanJP )さんの神記事に全てが載っているのでご確認くださいまし…(本当に…本当にありがとうございます!)
soramame-games.com

最後に (各記事をご確認頂いた後にどうぞ)

手探り感が凄いですが、UE4iOS開発をする際のデバッグ・プロファイリング方法について簡単にまとめてみました。
ただ、Macを使った開発をまだ勉強中ということもあり、「もっといい方法があるよ!」と思う方がいるかもしれません…

そういう方は…ぜひ教えてください!
なんでもしますから!

はい

以上です。あとは各記事をご確認ください。
明日は @dgtanakaさんの「なんか書きます」です!
いつも非常に有益な記事を公開して頂いているので今回も楽しみです!

UE4 & iOS開発時の実機デバッグ・プロファイリング方法 まとめ 2018

$
0
0

本内容は複数の記事で構成されています。検索などでこの記事に直接飛んできた方はまず以下の記事をご確認ください。
pafuhana1213.hatenablog.com

はじめに

ゲーム中にPrintStringなどで出力したデバッグ情報の確認やクラッシュ時の原因調査など、ログファイルはすごく便利で得られるものも多いです!
ということで、まずはログの確認、ファイル取得から。


実行中のログ確認(Mac)

Macの場合は、UE4エディタのSessionFrontend 又は XcodeのConsole機能を使うことになります。Session Frontendに関してはWindowsでも同じ手順なので後述します。ここでは後者の方法について紹介します。

Open Console機能

XcodeのConsole機能は2通りの使い方があります。まずは、XcodeWindow->Devices and Simulatorsを選択した後に出るウィンドウの”Open Console”を使用する方法です。この方法の利点は、後述のRunやAttachなどの下準備をしなくてもログ出力を確認できるという所にあります。
f:id:pafuhana1213:20181213021655p:plain

ただし、実行中のUE4製アプリ以外の情報も出力されるため、右上にあるフィルタ機能を活用する必要があります。また、ログが細かい粒度で大量に出力されるため、UE4エディタ上で見れるログ出力と同レベルのものを見たい場合には少し不向きです。
f:id:pafuhana1213:20181213020920p:plain

Console Area機能

次に、Xcode上のConsole Areaでログを確認する方法があります。UE4エディタやVisual Studioで見れるログ内容と同じものが出力されるため、単純にログを確認する際はこちらの方が便利かと思います!
f:id:pafuhana1213:20181213021836p:plain

しかし、後述する「実機でアプリ起動後にXcodeからプロセスにアタッチする」方法ではConsole Areaにログは出力されません。( Xcodeの仕様っぽい?
ios - Xcode attach to process doesn't display NSLog - Stack Overflow

そのため、「Xcodeからアプリを実機上で実行する」必要があります。以前にヒストリアさんが解説していましたが、少し状況変わったりしているので補足を入れつつ手順を説明します。

[UE4] 実機でデバックしてみよう!(iOS編)|株式会社ヒストリア
[UE4] 実機のプロファイリング!(iOS編)|株式会社ヒストリア

Xcodeからアプリを実機上で実行する方法

1: Launchを実行, または パッケージ(.ipa)作成

まずは、Xcode経由で実機上でアプリを実行するためにアプリのバイナリデータである .app ファイルを作成する必要があります。といっても、UE4エディタ上でLaunch, またはパッケージングを実行すれば、”[Project Root]\Binaries\Payload”に .appファイルが自動生成されます。かんたん!

余談 .appファイルに対して圧縮を含む変換処理をかけたものが .ipaファイル。
.app→.ipaへの変換について - ほげぐらまの別館

2: Xcodeから実機上で実行する用のSchemeを追加

XcodeにはSchemeというビルドに関する各設定をまとめたものがあり、用途別に使い分けることが可能です。
Xcodeの概要: アプリケーションを構築する

UE4が生成したXcodeのプロジェクトファイル( .xcodeproj )には2つのSchemeUE4, [Project名] )がデフォルトで用意されています。しかし、どちらもDevelopment Editor設定でMac以外を実行対象にできないため、実機上でアプリを実行することができません。
f:id:pafuhana1213:20181213022336p:plain

そのため、実機実行用にSchemeを新規追加します。といっても簡単です。
f:id:pafuhana1213:20181213022417g:plain

3: Xcodeから実機上でアプリを実行

ここまでで準備は終わりました!さて、アプリを実行しましょう!
この際、Product -> Perform Action -> Run Without Buildingで実行することをおすすめします!何故なら、通常のRunだとBuildが走ってしまうので、ビルド待ち時間が増える上にビルド失敗などトラブルの原因になりやすいからです…
f:id:pafuhana1213:20181213022746p:plain

実機上でアプリが無事立ちあがれば、Xcode右下のConsole Areaにログが流れ始めます!更に、既にプロセスにアタッチしている状態で起動するため、後述のBreakPointによるデバッグも可能です!やったね!

実行中のログ確認 (Win)

Windowsの場合は、少し前に触れたSession Frontendを使用することになります。
api.unrealengine.com

ちなみにAndroid実機とSession Frontendの接続に関しては、以下のスライドで紹介しました(p38以降)。

www.slideshare.net

iOSの場合もほぼ同じなのですが…「Project SettingsにあるUDP MessagingのStatic Endpointsに [iOS端末のIPアドレス:6666] を追加する」作業が必要になる点が唯一異なります。
f:id:pafuhana1213:20181213022944p:plain

この設定を入れておかないと、ケーブルで直繋ぎしてもSession Frontendに認識されません。ちなみに、認識されると以下のように端末が表示されます。
f:id:pafuhana1213:20181213023049p:plain

Session Frontendと接続ができれば、実行中のログ確認だけでなく、コンソールコマンドの送信やCPUプロファイラなどの様々な機能が利用可能になります!ぜひ活用していきましょう!

注意:

UE4.20, UE4.21.0の場合、以下の不具合によりSessionFrontendとの接続が失敗する可能性があります。もし不具合が発生した場合はUE4.21.1以上にアップデートするか、URL先にあるFix Commitを適用するようお願いいたします…
UE-65365 Launching on IOS, sessions do not appear in the Session Frontend

実行後のログ確認(Mac)

次は、アプリ実行後に端末に保存されたログを取得する方法について紹介します。Macの場合は、以下の記事で書かれている方法を使うことになります。
qiita.com

.xcappdataのダウンロード後、右クリックメニューの「パッケージの内容を表示」を選択することで、実行中に出力されたログ、プロファイル系のファイルなどを確認することが可能です。ちなみに、ログファイルは、”AppData\Documents\[Project Name]\Saved\Logs”にあります。
f:id:pafuhana1213:20181213024622p:plain

実行後のログ確認(Win)

Windowsの場合は、”Engine\Binaries\DotNET\IOS” にある IPhonePackager.exeを使って、端末から各ファイルを抽出します。手順は以下の通り。

1 .IPhonePackager実行
2. ログを抽出したいアプリの uproject ファイルを指定
3. Advanced Tools の Other Development Tools を選択
f:id:pafuhana1213:20181213023424p:plain
4. 端末を選択し、Backup documentsを選択
f:id:pafuhana1213:20181213023447p:plain
5. アプリのインストール時に使用した .ipaファイルを選択

端末からの抽出処理が完了すると、“[Project Root]\IOS_backups” 以下に各ファイルが配置されます。ログファイルの場合は、”[Project Root]\[Device Name]\Documents\iOSTest\Saved\Logs” にあります。

(やることが…やることが多い…!!)

最後に

ここまでがログの確認・取得方法についてでした!地味な部分ではありますが、得られる情報は非常に多いです。ただ開発環境によってフローが異なるのでご注意下さい!
次の記事では、デバッグでお馴染みのBreakPointをどうやって使うのかについて。
pafuhana1213.hatenablog.com

UE4 & iOS開発時の実機デバッグ・プロファイリング方法 まとめ 2018 < CPU・GPUデバッグ編 >

$
0
0

本内容は複数の記事で構成されています。検索などでこの記事に直接飛んできた方はまず以下の記事をご確認ください。
pafuhana1213.hatenablog.com

はじめに

ゲームの動作や不具合を調査・デバッグする上でBreakPointは必要不可欠です。ということで、UE4&iOS開発時にどのようにしてBreakPointを使うのかについて紹介します。なお、Xcodeを使用する関係でMacが必須なのでご注意ください ( MacMiniはいいぞ )。
f:id:pafuhana1213:20181213024154g:plain

Mac上で開発する場合

リモートビルドは使わずにMac上で開発を進めている場合は、ゲームコード・エンジンコード共に簡単にデバッグ可能です。ただ、Xcodeと実機上で動作するアプリを接続する必要はあります。

接続する方法は2通りあります。まず1つ目は、前回の記事で紹介したXcodeからアプリを起動する方法」です。この方法ならXcodeとアプリが接続した状態で起動するため、BreakPointがすぐ使えます。
なお、エンジンコードにBreakPointを貼りたい場合は、ランチャー版ではなくビルド版を使用する必要があります。ご注意くださいまし。

もう一つ目の方法は、「既に起動しているアプリのプロセスにアタッチする方法」です。XcodeDebug->Attach to Process からアタッチするとBreakPointが有効になります。ただし、前回の記事で軽く触れたとおり、この方法の場合はXcodeのConsole Areaにログが出力されない点にご注意ください。
f:id:pafuhana1213:20181213024418p:plain

リモートビルドを使う場合

Windowsからのリモートビルドの場合でも、Mac上でゲームコードのデバッグは可能です。

リモートビルド中、UE4プロジェクトとエンジンの各ファイル(全ファイルではない)がMacの以下の場所に転送されます。
Macintosh HD\ユーザ\[User Name]\UE4\Builds\[Windows PC Name]”

例えば Windowsの“D\UnrealProjects\SampleProject”にあるプロジェクトでリモートビルドした場合、Mac
Macintosh HD\ユーザ\[User Name]\UE4\Builds\[Windows PC Name]\D\UnrealProjects\SampleProject” にプロジェクトの各ファイルが配置されます。
f:id:pafuhana1213:20181213024701p:plain

そして、その階層にある “Indermediate\ProfjectFilesIOS” 以下に Xcodeのプロジェクトファイル( .xcodeproj )が配置されています。このプロジェクトファイルを使うことで、上述の「既に起動しているアプリのプロセスにアタッチする方法」が可能です。

しかし、リモートビルドの場合は「Xcodeからアプリを起動する方法」とエンジンコードのデバッグは(おそらく)現状できません…。今後にご期待ください…。

GPUデバッグ

いわゆるGPUフレームキャプチャ機能について。
描画に関する負荷・不具合をより細かく調査する必要が出てくる場合があります。例えば「どのような処理が」「どのような順番で」「どのようなアセットを使って」「どのぐらいの処理負荷で」…などといった感じです。
コンソール専用ツールを除けば、UE4開発者内ではRenderDocが有名所かなと思います。
qiita.com

そして、そのGPUフレームキャプチャ機能がXcodeに用意されています。こんな感じ。
f:id:pafuhana1213:20181213024930p:plain
f:id:pafuhana1213:20181213024946p:plain

GPUフレームキャプチャ機能の使い方

といっても簡単です!

Xcodeからアプリを起動する方法」の実行すると、XcodeのDebugメニューからGPUフレームキャプチャに関する項目(Capture GPU Frameなど)が使用可能になります。そして、それを選択するだけでGPUフレームキャプチャを実行することができます。超簡単!
f:id:pafuhana1213:20181213025034p:plain

…言い換えると、「既に起動しているアプリのプロセスにアタッチする方法」の場合はGPUフレームキャプチャは使えません。さらに言うと、リモートビルドの場合はGPUフレームキャプチャは完全使用不可です。

Mac Miniはいいぞ!

XcodeGPUフレームキャプチャ機能は結構いい感じな印象です。例えば、負荷が目立つ処理にはひと目で分かるようにビックリマークがついていたり…
f:id:pafuhana1213:20181213025106p:plain

GPUフレームキャプチャに期待する情報をちゃんと出してくれますし…
f:id:pafuhana1213:20181213025137p:plain
f:id:pafuhana1213:20181213025150p:plain

この辺りはやはりMetalの恩恵が大きいのかなという所です。

個人的参考まとめ(GPUデバッグ)

qiita.com
booth.pm

最後に

ここまでがCPU,GPUデバッグに関してでした。これらの情報を知ってるか知らないかで制作効率が大きく変わってくると思います。ぜひ一度実際に手を動かして試してみましょう!
あと、Xcodeはまだまだ勉強中なので今後もっと情報を出していければと思います…!

次は、みんな大好きプロファイリングについて。プロファイリングツールであるInstrumentsに触れてます。
pafuhana1213.hatenablog.com


UE4 & iOS開発時の実機デバッグ・プロファイリング方法 まとめ 2018 < CPU・GPUプロファイリング編 >

$
0
0

本内容は複数の記事で構成されています。検索などでこの記事に直接飛んできた方はまず以下の記事をご確認ください。
pafuhana1213.hatenablog.com

はじめに

みんな大好きプロファイリングについての話です。
iOS開発では、Instrumentsというプロファイリング用のツールが用意されています。ここではをUE4で開発をする際にどのようにしてInstrumentsを使うかについて説明します。

…実機上で各statコマンドを活用することもお忘れなく。

www.slideshare.net

Instruments起動前の前準備

dSYMの生成

Instrumentsを使うためには、dSYMと呼ばれるデバッグシンボルが必要です。UE4の場合は、プロジェクト設定のiOS/Buildにある “Generate dSYM file for code debugging and profiling”を有効にする必要があります。
このフラグを有効にするとビルド時にdSYMを生成してくれます。しかし、その分ビルド時間が長くなってしまうため、デフォルトでは無効になっています。ちなみに、dSYMは “[Project Root]\Binaries\IOS”以下に生成されます。
f:id:pafuhana1213:20181213025621p:plain

プロファイリング対象のアプリを実機上で起動

Instruments起動後でもいいのですが、ついつい後述のプロセス設定を忘れがちなので、僕はここでアプリを起動しています。起動方法に関しては制約はありません。iOS端末から直接起動してもいいですし、Xcodeから起動しても問題ありません。ただデバッグすることを考えると、Xcode経由の方がいいかなとは思います。

Instrumentsの起動

まずはXcodeのメニューからInstrumentsを起動します。なお、起動後にInstrumentsをDockに登録しておくと次回以降の起動がXcodeなしで出来るので楽になります。
f:id:pafuhana1213:20181213025728p:plain

Instumentsを起動すると、以下のようなウィンドウが開きます。Instrumentsではプロファイリングする項目を選択できるようになっています。ただその項目の量が結構多いため、それらの項目が用途別にまとめられたテンプレートを選択する形になっています。
f:id:pafuhana1213:20181213025751p:plain

developer.apple.com

そして、UE4を使った開発の場合、主に使うテンプレートは以下の3つかと思います。ただ他にも色々項目があるので、軽く見ておくのも良いかと思います。(ただし、iOSでは非サポートの項目もあるのでご注意を)

  • Time Profiler
    • Game threadのプロファイル
    • オーバヘッド:小
  • Metal System Trace
    • Game, Draw, GPU threadのプロファイル
    • オーバヘッド:中
  • Game Performance
    • Game, Draw, GPU thread + Memory管理 のプロファイル
    • オーバヘッド:大

また、表示されたウィンドウの上部にはプロファイリングを行う端末・プロセス名が表示されます。もし意図する対象とは異なる場合はクリックして変更しましょう。

Instrumentsの実行…前の準備

dSYMの配置場所の指定

テンプレート選択したので早速プロファイリングしたい所ですが、まずはInstrumentsのPreferences->Symbolsに、UE4が生成したdSYMがどこにあるのかを設定する必要があります。この設定をしなかった場合、Time Profilerにおける処理項目名がよく分からない文字列になるのでご注意下さい。
f:id:pafuhana1213:20181213030042p:plain
f:id:pafuhana1213:20181213030057p:plain

一応、あとでdSYMを直接指定することも可能です。具体的には、InstrumentsのFile->SymbolsからdSYMに関する情報を確認・変更可能です。

stat namedevents コマンドを実行

Instrumentsによるプロファイリング結果を正しい形で見るために、アプリ起動後に “stat namedevents”コマンドを実行する必要があります。このコマンドを実行しなかった場合、dSYMを指定しなかった場合と同様に、プロファイリング結果をまともに見ることができなくなるためご注意下さい。

ちなみに、他の外部プロファイリングツールでも同様です。stat namedeventsコマンド、大事です。

Instrumentsの実行

ようやく準備が整いました。これでInstruments左上の録画ボタンを押すことでプロファイリングが開始し、もう一度押すと終了します。ちなみに、下の画像はGame Performanceテンプレートを使用した際のプロファイリング結果です。
f:id:pafuhana1213:20181213030225p:plain
それぞれの項目について細かく解説するといつまで経っても終わらないので、ざっくり説明します。

Time Profiler

今回紹介したテンプレートは全てTime Profilerテンプレートを内包します。で、Time Profilerの結果が見れるのがこの CPU Usageです。指定した範囲における各処理の負荷・呼び出し回数などを確認可能です。GameThreadがボトルネックになっている場合、この情報が役に立つ可能性が高いです。
developer.apple.com
f:id:pafuhana1213:20181213030317p:plain

ただ少し注意しないといけないことが幾つかあります。
まずは、UE4以外の処理も抽出されてしまう点です。フィルタを適用しない場合、以下のようによく分からない処理が大量に並びます。
f:id:pafuhana1213:20181213030338p:plain

これでは調査に支障が出てしまうため、Instrumentの左下にあるInput Filter機能を活用します。ここにある [ IOSAPPDelegate MainAppThread ]を選択することで、UE4関連の処理だけを表示するようになります。
f:id:pafuhana1213:20181213030407p:plain

次に、同じくInstrument左下にあるCall Treeにおける”Hide System Libraries”は必ず有効にしましょう。
f:id:pafuhana1213:20181213030558p:plain

有効にしない場合、以下の画像のように項目名が解読不能になってしまいます。
f:id:pafuhana1213:20181213030619p:plain

Call Treeには他にも調査する上で便利な項目があるので、一度試してみましょう!

Displayed Surfaces

Metal System Trace, またはGame Performanceテンプレートに含まれます。この項目ではVsyncのタイミングを確認する事が可能です。それだけの項目なので、他の項目と併用することになります。例えば、Time Profilerでだいたい1フレームにおける負荷を見たい場合は、このVsyncタイミング情報は非常に有用です。
developer.apple.com
f:id:pafuhana1213:20181213030753p:plain
f:id:pafuhana1213:20181213030812p:plain

Graphics Driver Activity

Metal System Trace, またはGame Performanceテンプレートに含まれます。この項目では、描画に関するCPU側のイベントを確認できます。ただGPUフレームキャプチャのように詳細は見れません。どの処理がどの程度負荷があったのかを確認する程度です。
developer.apple.com
f:id:pafuhana1213:20181213030915p:plain

GPU Hardware

Metal System Trace, またはGame Performanceテンプレートに含まれます。この項目では、描画に関するGPU側のイベントを確認できます。具体的には、頂点・フラグメントシェーダにおける負荷を確認可能です。ただし、先程と同様に詳細(使用されたテクスチャ、どのようなメッシュが描画されたかなど)は全く見れません。
developer.apple.com
f:id:pafuhana1213:20181213030959p:plain
f:id:pafuhana1213:20181213031010p:plain

最後に

ここまでがCPU, GPUプロファイリングについてでした。CPUプロファイリングに関してはUE4エディタのCPUプロファイラでもある程度代用可能ですが、オーバヘッドのことを考えるとInstrumentsを使用した方がより高精度なチェックが出来るかと思います。

またGPUプロファイリングに関しては、説明にあったとおりGPUフレームキャプチャのように各処理の詳細は見れません。しかし、どの項目がボトルネックになっているのかを調査するのには非常に適しているかと思います。Instrumentsでボトルネックを確認してから、GPUフレームキャプチャで詳細確認する流れが良いかと思います。

まとめページに戻る
pafuhana1213.hatenablog.com

UE4の物理アセット・クロスの荒ぶりを何とかする方法について (UE4.21版)

$
0
0

はじめに

この記事はUnreal Engine 4 その2 Advent Calendar 2018の20日目の記事です。
qiita.com

何を書こうか色々悩んだのですが、今年も物理と仲良くする(意味深)方法について書こうと思います。なお、去年の記事は以下の通り。(え、もうアレから一年経ったの!?)

UE4.18で生まれ変わった物理アセットエディタ(Physics Asset Editor)について」 と 「物理と少し仲良くなる方法について」
その1:http://pafuhana1213.hatenablog.com/entry/2017/12/13/000000
その2:http://pafuhana1213.hatenablog.com/entry/2017/12/13/000100
その3:http://pafuhana1213.hatenablog.com/entry/2017/12/13/003018

f:id:pafuhana1213:20181220151928g:plain

実験に付き合ってもらうのはいつものこの方々。左のOwenくんはクロス担当、右のグレイマンは物理アセット担当です。

なお、今回は物理アセット・クロスの設定を極力変えずに既存の機能で何とかすることを目標とします。何故なら去年の内容と被りますし、作業コスト高いですし、職人芸になりがちですし、、説明が大変だからです!(ドン!

物理の荒ぶりに対して、我々はどう立ち向かえばいいのか?

基本方針は以下の3つです!

  • 荒ぶりの原因になる挙動を無視させる
  • 物理をリセットして荒ぶりを消す
  • 荒ぶり前に物理を停止し、その後再開する

これらの対応を入れることで、(色々と許容しないといけない場合あったりしますが)、だいたいの物理の荒ぶりを回避できます。

具体的にどうすればいいのか、これから順に説明します。

荒ぶりの原因になる挙動を無視する方法

物理アセットの場合

まず…AnimGraphのRigid Bodyノードを使いましょう!物理アセットを直接使うのではなくRigidBodyノードを通ることで、処理負荷だけでなく物理挙動の安定化する上でも色々メリットがあります!
api.unrealengine.com

Rigid Bodyノードを仕様・表現的に使えないケースもあるかとは思いますが…今回は物理を抑えることが重要なので、以降の説明ではRigid Bodyノードを使っていることを前提にします。ご了承下さい…

Actorの位置が変化する場合

Actorの位置が大きく変更することで物理が荒ぶる場合は、RigidBodyノードのSimulation Space を Component Space にすることをおすすめします。この設定にすることで、物理アセットに関する処理が Skeletal Mesh Componentのローカル座標系で行われます。そのため、Skeletal Mesh Componentのワールド座標が変化しても物理挙動に影響しません。
f:id:pafuhana1213:20181220152259p:plain

ちなみに、Anim Dynamicsノードでも似たような設定が可能です。
f:id:pafuhana1213:20181220152155p:plain

ただ注意点としては、逆にActorの移動量を物理に反映したい場合はSkeletal Mesh Componentのワールド座標で物理の計算をして貰う必要があります。そのため、RigidBodyノードのSimulation SpaceをWorld Spaceにする必要があります。もしComponent Space にしておきたいけど、Actorの移動を物理に反映させたい場合は…Rigid BodyのExternal Forceを使ってそれっぽく外力をかける必要があるかと思います。
f:id:pafuhana1213:20181220152454p:plain:w300


RigidBodyノードのSimulation Space以外にも、Set Actor(World) Location / Rotation / Transform のTeleportフラグを有効にするという解決方法もあります。このフラグを有効にすることで、このSet Actor Locationノードによる位置(向き)の変化を物理が無視するようになります。そのため、Simulation SpaceをWorld Spaceに設定している場合はこのフラグが非常に有用です。
f:id:pafuhana1213:20181220152649p:plain

また、Reset Dynamicsノードを使って、明示的にそのフレームでの移動はTeleportとみなすこともできます。なお、Reset Dynamicsは物理アセット専用なのでクロスに対しては使えません
f:id:pafuhana1213:20181220152708p:plain

アニメーションによってRoot Boneの位置を変化させる場合

カットシーン用のアニメーションなどの場合、Root Boneを移動・ワープさせたりすることがしばしばあるかと思います。この場合は先程の Simulation Spaceを Component Spaceにしても荒ぶりを回避できません。何故なら、アニメーションによるBoneの移動は Skeletal Mesh Componentのローカル座標系で行われるからです。

更に、先ほど説明したTeleportフラグではこの問題を解決することはできません。例えば、Skeletal Mesh Componentに対して現ワールド座標と同じ座標をSet World Location(Teleportフラグ付き)で設定する処理をTickでしてみました。
f:id:pafuhana1213:20181220152909p:plain
こうなります
f:id:pafuhana1213:20181220152919p:plain
つらい


…正直な所、今回説明する中でこれが一番対応が面倒です。とはいえ、対策は…幾つかあります。

まずは後述する「荒ぶり前の状態に保存した後に物理を止める」方法です。リアルタイムに物理計算を行う場合、現時点ではこれが最も挙動が安定します。ただし問題が発生する場面毎に対応を入れる必要があるため、場合によっては対応コストがネックになる可能性があります。

次に同じく後述の「物理をリセットして荒ぶりを消す」も荒ぶりを抑えるという観点では有用です。ただし、リセットされるため動きの連続性がなくなるため、見た目に違和感が生じるケースが多いかと思います。

物理アセットの調整で荒ぶりを抑えることで解決する場合もあります。特に昨年の記事で紹介した「Inertia Tensor Scale」は効果的に働くはずです。とはいえ、どんな条件でも完全に荒ぶりを抑えられる訳ではないのでケースバイケースといった所です。
pafuhana1213.hatenablog.com

「どうしても荒ぶりを解決できない!でも荒ぶりは絶対回避しないといけない!」というケース、あると思います。そういった場合はUE4シーケンスレコーダーを使って物理挙動をベイクした方が幸せになれるかもしれません。
unrealengine.hatenablog.com

ただ「いや、リアルタイムで物理計算をしないといけないんだ!」というケース、あると思います…。その場合はアニメーションによってRoot Boneの位置を変更するフローを見直した方が幸せになれるかもしれません…

クロスの場合

Skeletal Mesh Component の Teleport Distance (Rotation) Thresholdを 調整しましょう!ここで設定した値以上の移動(回転)が1フレームで行われた場合、クロスはTeleportしたと判断して無視するようになります。
f:id:pafuhana1213:20181220153152p:plain

なお、その上にある Reset After Teleportを有効にすると、さらにクロスのリセット処理が行われるようになります。しかし、リセット処理が働くことで見た目に違和感が発生する場合があります。
f:id:pafuhana1213:20181220153223p:plain
左がReset After Teleportを有効にした場合、右は無効にした場合です。リセット処理がかかるとクロスが働く前の状態に戻るため、左の画像では布の部分がピーンと伸びた状態になってしまっています。一方、右は動きを無視しただけでクロスは継続して働いているため、違和感の無い見た目になっています。

ただ常に無効にするのが正しいというわけではありません。例えば、ワープ前後でポーズが異なるようなケースの場合、リセットした方がクロスの挙動が安定するケースもあります。実際に試してみて、どちらが安定するか?挙動に違和感がないか?を確認することをおすすめします。

なお、これらのパラメータは物理アセットとは一切関係がありません。あくまで、クロス用のパラメータです。少しややこしいのでご注意下さい。


ちなみに、少し前に説明したSet Actor Location / Rotation / Transform のTeleportフラグ は クロスに対しても有効です。更に、クロスの場合は、Force Cloth Next Update Teleportノードを使うことで、明示的にTeleportしたと判断させることも可能です。
f:id:pafuhana1213:20181220153332p:plain

また、「アニメーションによってRoot Boneの位置を変化させる場合」に関しては、物理アセットのときはかなり辛い条件でしたが、クロスの場合は先程説明したTeleportに関するパラメータ・関数、全て有効なので対応が楽です!


物理・クロスの設定を調整したり、Teleportフラグを駆使することで物理の荒ぶりの大半は回避できるかと思います。しかし、あくまで物理なので、フレームレートの急激な低下などの悪条件が重なってくると荒ぶりやすくなってしまいます。とはいえ、ユーザに物理が破綻している様子が見えてしまうのは絶対に回避したい所です。

そこで候補に上がってくるのが、「物理・クロスのリセット」「物理・クロスの一時停止・再開」です。まずは前者について説明します。

物理をリセットして荒ぶりを消す方法

「荒ぶりがユーザに見えないように、物理適用前の状態にリセットしちゃおう!」という方法です。基本的にリセット用の処理を呼び出すだけなので、対応自体は簡単です。しかし、先程のReset After Teleportで説明した通り、場合によっては見た目に違和感が発生する場合があります。とはいえ、物理が荒ぶった際の見た目よりは断然マシなので導入の検討はすべきかと思います。

物理アセットの場合

Reset Dynamicsノードを使うことをおすすめします!先程はIn Teleport TypeをTeleport Physicsにしていましたが、今回はリセットなのでReset Physicsに設定します。このノードをどうしても物理が荒ぶってしまうタイミングに呼べば、最悪の事態は回避する事が可能です。
f:id:pafuhana1213:20181220153645p:plain

また、UE4.21からはReset Dynamicsを呼び出すAnim Notifyが追加されています。移動を伴うアニメーションの場合は、その移動タイミングにこのAnim Notifyを仕込んでおけばリセット処理が働くようになります。
f:id:pafuhana1213:20181220153827p:plain
Animation Notifications (Notifies)

ちなみに、このAnim Notifyの内部処理では Reset Physicsが指定されたReset Dynamics関数が呼ばれています。そのため、Teleport Physicsを指定したReset DynamicsをAnim Notifyで使用したい場合は、そのAnim Notifyを独自に用意する必要があります。

クロスの場合

まずは、Skeletal Mesh ComponentのReset After Teleport フラグを活用する方法があります。これに関しては既に説明済みなので割愛します。
次に、Force Cloth Next Update Teleport and Resetノードを呼び出す方法があります。察してる方も多いかと思いますが、Reset After Teleport が有効な状態で Teleport Distance (Rotation) Threshold 以上の移動・回転が生じた際のリセット処理を明示的に行うことができます。
f:id:pafuhana1213:20181220153936p:plain

ちなみに、このForce Cloth Next Update Teleport and Resetを呼び出すAnimNotifyもUE4.21で追加されています。便利!
f:id:pafuhana1213:20181220153953p:plain

荒ぶり前に物理を停止し、その後再開する方法

「物理の荒ぶりは回避したいけど、リセットするのは見た目的にいや! 物理処理は継続的に行いたい!」と思う方は多いかと思います。そんな方向けの方法がこの「物理を停止・再開」する方法です。

結局の所、荒ぶりが起きやすい状態で物理が有効になっているのが今回の問題の原因です。つまり、その状態の間だけ物理を切れば荒ぶりが発生することはなくなります。しかし、単純に物理を切ってしまうとリセット処理が走ってしまいます。それなら、物理を切るだけでなく、対象のメッシュ・アニメーションも一時停止しておいて、その後どちらも再開すれば荒ぶり回避できるし物理処理が継続して見えるじゃん!というのがこの方法です。

物理アセットの場合

物理を切ることは簡単です。Simulate PhysicsをOFFにしたり、RigidBodyノードのAlphaを0にしたりするだけです。問題は、物理を切る前の状態を保存することです。

結局の所、物理アセットは各ボーンを制御しているため、「アニメーションと物理が適用された状態のスケルトンの状態」を保存する必要があります。そこで便利というか、まさにその機能なのが Animation Pose Snapshotです。
f:id:pafuhana1213:20181220154317g:plain

使い方に関しては公式ドキュメントや動画にて解説されているので割愛します。
api.unrealengine.com
Unreal Japan Stream | ポーズスナップショットでラグドール回避アニメーション - YouTube

少し前に触れた通り、荒ぶりの原因となる物理を切っているので、リアルタイムに物理計算行う方法の中ではこれが最も挙動が安定します。ただし、Animation Pose Shapshotを使うための仕込みが必要なため、他の方法に比べて実装コストは少し高めです。

クロスの場合

クロスの場合は一時停止・再開用の機能が用意されています。一時停止はSuspend Clothing Simulation、再開はResume Clothing Simulationです。ちなみに、UE4.21でこれらをAnim Notifyから使うことも可能になりました!
f:id:pafuhana1213:20181220154424p:plain
f:id:pafuhana1213:20181220154434p:plain

その他

最後に、今回の内容と関連するパラメータやTipsについて少し紹介

Cloth Blend Weight

Skeletal Mesh Componentには、アニメーション結果とクロス処理の結果をどの程度ブレンドするかを制御するためのパラメータであるCloth Blend Weightが用意されています。このパラメータを調整することで、「見栄え的にクロスでひらひらさせたいけど、スカートの中が絶対に見えないようにボーンによる制御も同時に行いたい」といったケースに有用です。ただ、個人的にはパン(以下略

また、説明のため簡略化してますが、アニメーションにCloth Blend Weightを制御するためのカーブを埋め込んでおけば、アニメーション毎にクロスのブレンド率を調整することが可能です。
f:id:pafuhana1213:20181220154638p:plain
f:id:pafuhana1213:20181220154648p:plain

Sequencerで扱える物理・クロスに関するパラメータ

Sequencer上でSkeletal Mesh Componentなどの各コンポーネントが持つ各パラメータを制御することができます。そのため、物理・クロスに関する挙動をSequencer上で制御することは十分に可能です。
f:id:pafuhana1213:20181220154603p:plain

更に、Event Trackでリセット・テレポート用のノードを呼び出すことも可能です。更に更にUE4.20からAnimationBlueprintが持つプロパティも制御可能になったので、RigidBodyノードやPose Snapshot絡みの挙動もSequencer上で調整することが可能です!
www.unrealengine.com

SequencerのCamera Cut切り替えタイミングの取得

カメラカットの切り替わり時に、キャラクタの位置・向きを変えたいケースが多いかと思います。しかし、それは1フレームで急激に動かすことになるので、物理・クロスが荒ぶりがちです。そこで、カメラカット切り替えタイミングにTeleportやリセット処理を呼びたくなるはずです。

そんな方にご紹介したいのが、Sequence PlayerのOnCameraCutイベントです。このイベントはその名の通りカット切り替わり時に呼ばれるため、以下のようにして処理を紐付けることが可能です。ぜひぜひご活用くださいまし。
f:id:pafuhana1213:20181220154919p:plain

最後に

f:id:pafuhana1213:20181220155131j:plain
長くなりましたが、物理・クロスの荒ぶり対策について色々ご紹介しました。これらの方法を使用・併用することで、様々なパターンにおける荒ぶりを回避することができるかと…思い…ます…

ただ、繰り返しになりますが、あくまで物理なので今回紹介した方法でも抑え込めないケースもあるかと思います。その場合は、まず何が荒ぶりの原因になっているかを確認した後に、物理アセット・クロスの調整をしてみたり、そもそも荒ぶりやすい条件にならないよう仕様・設計を変えるなど検討したり、物理挙動をベイクしたりなどの方法を検討する必要があるかと思います。場合によっては、ある程度の割り切りも必要かもしれません…

ネガティブなことばかり並べましたが、物理・クロスを適用することで見栄えがリッチになるのは間違いありません。昨年と今年の記事が少しでも物理と仲良くする助けになれば幸いです。

明日は 紙パレット ( @kamipallet )さんによる 「ジラフとアンニカ」のジャンプアニメーションの解説 です!ジャンプアニメーション、いつも調整に苦労してるので凄く楽しみです!!!

【UE4.21】「The specified Android SDK Build Tools version (26.0.1) is ignored, as it is below the minimum supported version (26.0.2) for Android Gradle Plugin 3.0.1.」 というWarningが出てAndroidパッケージ作成に失敗する問題への対応方法

$
0
0

本題

記事タイトルの通りですが、UE4.21にてGradleを有効にした状態でAndroidパッケージを作成すると、以下のメッセージがログに出力されてパッケージ作成に失敗する場合があります。

 Creating rungradle.bat to work around commandline length limit (using unused drive letter Z:)
 Making .apk with Gradle...
 To honour the JVM settings forthis build a new JVM will be forked. Please consider using the daemon: https://docs.gradle.org/4.1/userguide/gradle_daemon.html.
 Daemon will be stopped at the end of the build stopping after processing
 WARNING: The specified Android SDK Build Tools version (26.0.1) is ignored, as it is below the minimum supported version (26.0.2) for Android Gradle Plugin 3.0.1.
 Android SDK Build Tools 26.0.2 will be used.
 To suppress this warning, remove "buildToolsVersion '26.0.1'" from your build.gradle file, as each version of the Android Gradle Plugin now has a default version of the build tools.
 File C:\Users\awfor\.android\repositories.cfg could not be loaded.
 Checking the license for package Android SDK Build-Tools 26.0.2 in C:\NVPACK\android-sdk-windows\licenses
 Warning: License for package Android SDK Build-Tools 26.0.2not accepted.
 
 FAILURE: Build failed with an exception.

原因は最近Googleがライセンス契約を変更したのですが、UE4.21時点ではその変更に対応できていないからです。 (ライセンス更新は2019/1/16 頃、たぶん)

この問題を解決するには、UE4.22から入る新しいライセンス契約への対応をUE4.21に移植する必要があります。といっても対応は簡単で、UE4.22以降が持つ Engine/Source/ThirdParty/Android/package.xmlUE4.21のpackage.xmlに上書きした後に、再度Project設定のAndroidカテゴリにある "Accept SDK License"ボタンを押すだけです。
f:id:pafuhana1213:20190206005342p:plain

なお、この記事を書いた2019/2/6時点では以下のurlからUE4.22版のpackage.xmlをDL可能です。
https://github.com/EpicGames/UnrealEngine/blob/4.22/Engine/Source/ThirdParty/Android/package.xml

おまけ 1

UE4.21からAndroidのNDKのバージョンが 12b から 14b に上がっています。そのため、UE4.20以前にAndroid開発をしていた場合は、\Engine\Extras\AndroidWorks\Win64\CodeWorksforAndroid-1R7u1-windows.exe を使って開発環境をアップデートする必要があります。アップデート後は、UE4エディタのプロジェクト設定におけるAndroidSDKカテゴリにある各項目を新しいバージョンのものに合わせることをお忘れなく。あと、インストールする前に以前のバージョンをアンインストールした方が安全かと思います。

Android
Android NDK r14b (新しい CodeWorks for Android 1r7u1 インストーラは、Windowsおよび Mac上の、以前の CodeWorks を置き換えます。Linuxは 1r6u1 と修正版を使用します)
https://www.unrealengine.com/ja/blog/unreal-engine-4-21-released?sessionInvalidated=true

おまけ 2

上述の対応後にAndroidパッケージの作成を行うと、以下のエラーが発生する場合があります。

LogPlayLevel: Error: C:\Users\●●●\.gradle\caches\transforms-1\files-1.1\support-compat-27.1.0.aar\36ca67ef4f432d33200b3e8a5af4a755\res\values\values.xml:20:5-70: AAPT: error: resource android:attr/fontStyle not found.
 LogPlayLevel: Error: C:\Users\●●●\.gradle\caches\transforms-1\files-1.1\support-compat-27.1.0.aar\36ca67ef4f432d33200b3e8a5af4a755\res\values\values.xml:20:5-70: AAPT: error: resource android:attr/font not found.
 LogPlayLevel: Error: C:\Users\●●●\.gradle\caches\transforms-1\files-1.1\support-compat-27.1.0.aar\36ca67ef4f432d33200b3e8a5af4a755\res\values\values.xml:20:5-70: AAPT: error: resource android:attr/fontWeight not found.
 LogPlayLevel: Error: Z:\app\build\intermediates\incremental\mergeDebugResources\merged.dir\values\values.xml:95: error: resource android:attr/fontStyle not found.
 LogPlayLevel: Error: Z:\app\build\intermediates\incremental\mergeDebugResources\merged.dir\values\values.xml:95: error: resource android:attr/font not found.
 LogPlayLevel: Error: Z:\app\build\intermediates\incremental\mergeDebugResources\merged.dir\values\values.xml:95: error: resource android:attr/fontWeight not found.
 LogPlayLevel: Error: error: failed linking references.
 LogPlayLevel: Failed to execute aapt

発生した場合は、AndroidSDKAPI Levelをandroid-21に戻してみてください。これで解決することが多いです。

おまけ 3

プロジェクト設定のAndroidカテゴリにある "Enable Gradle Instead of Ant"を無効にすれば、gradleではなく昔のantを使ってパッケージを作成するようになるため、gradle絡みの問題を回避することが可能です。しかし、antは古いシステムなので推奨されていない上に今後削除される予定なのでご注意ください。

また、ARCoreを使う場合は必ずgradleを使用する必要があります。 antを使ってパッケージを作った場合、起動後に即クラッシュします。クラッシュした際のlogcatは以下の通り。

02-0523:37:22.006: E/AndroidRuntime(17685): java.lang.UnsatisfiedLinkError: dlopen failed: library "libarcore_sdk_c.so"not found
02-0523:37:22.006: E/AndroidRuntime(17685): 	at java.lang.Runtime.loadLibrary0(Runtime.java:977)
02-0523:37:22.006: E/AndroidRuntime(17685): 	at java.lang.System.loadLibrary(System.java:1530)
02-0523:37:22.006: E/AndroidRuntime(17685): 	at com.epicgames.ue4.GameActivity.<clinit>(GameActivity.java:5504)
02-0523:37:22.006: E/AndroidRuntime(17685): 	at java.lang.Class.newInstance(Native Method)
02-0523:37:22.006: E/AndroidRuntime(17685): 	at android.app.Instrumentation.newActivity(Instrumentation.java:1079)
02-0523:37:22.006: E/AndroidRuntime(17685): 	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2538)
02-0523:37:22.006: E/AndroidRuntime(17685): 	at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
02-0523:37:22.006: E/AndroidRuntime(17685): 	at android.app.ActivityThread.-wrap12(ActivityThread.java)
02-0523:37:22.006: E/AndroidRuntime(17685): 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460)
02-0523:37:22.006: E/AndroidRuntime(17685): 	at android.os.Handler.dispatchMessage(Handler.java:102)
02-0523:37:22.006: E/AndroidRuntime(17685): 	at android.os.Looper.loop(Looper.java:159)
02-0523:37:22.006: E/AndroidRuntime(17685): 	at android.app.ActivityThread.main(ActivityThread.java:6097)
02-0523:37:22.006: E/AndroidRuntime(17685): 	at java.lang.reflect.Method.invoke(Native Method)
02-0523:37:22.006: E/AndroidRuntime(17685): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
02-0523:37:22.006: E/AndroidRuntime(17685): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
02-0523:37:22.008: W/ActivityManager(2739):   Force finishing activity com.YourCompany.ARTemplateBuild/com.epicgames.ue4.GameActivity

どうやらgradleが持っている libarcore_sdk_c.so が必要なので、antだとクラッシュするようです。こちらもご注意くださいまし。

おわり

【UE4 & Android】実機デバッグ実行中のログ確認方法について

$
0
0

はじめに

突然ですが、Android開発時のデバッグ・プロファイリング方法についてまとめようと思います。検証したUE4のバージョンは4.21.2です。

今回は実機実行のログ確認方法についてです。
UE4エディタ上で確認する方法と、Android Debug Monitorというツールを使う方法の2つを紹介します。

ちなみに、iOS開発版はこちらです。
pafuhana1213.hatenablog.com




Session Frontendを使ってログを確認する方法

UE4エディタ上でAndroid実機上のログを確認するためには、UE4のSession FrontendがそのAndroidを認識するようにする必要があります。認識されたAndroid端末は以下の画像のように「自分のセッション」に表示されます。そして、その項目をクリックするとログを確認できるようになります!  
f:id:pafuhana1213:20190219214907p:plain

これから認識する方法について紹介するのですが、以降の説明は adb devices コマンドの結果に対象のAndroid端末が含まれていることを前提とします。「よく分からん!」「認識されてない!」という方は以下のページを見たり、Google先生に相談してください!
api.unrealengine.com

-messaging オプションについて

Session FrontendがAndroidを認識するためには、-messagingコマンドライン引数に追加した状態で実機上で起動させる必要があります。
api.unrealengine.com

と言っても、エディタ右上にあるLaunchボタンやProject Launcher経由で実機実行する場合は -messaging が自動的に追加されます。そのため、特に気にしなくてもSession Frontendで実機を認識します。(…昔は明示的に追加しないと駄目だったような)
f:id:pafuhana1213:20190220001021p:plain
f:id:pafuhana1213:20190220001008p:plain
●Engine\Source\Developer\LauncherServices\Private\Launcher\LauncherWorker.cpp

// game command line
FString CommandLine = FString::Printf(TEXT(" -cmdline=\"%s -Messaging\""),
	*InitialMap);

しかし、作成したパッケージを実機上で実行する場合はこの手は使えません。何故なら、Android OSはコマンドライン引数を実行可能ファイルに渡すことをサポートしていないからです。
そのため、UE4では UE4CommandLine.txtというファイルを経由してコマンドライン引数を渡す方法が用意されています。

UE4CommandLine.txt について

上述の通り、UE4CommandLine.txtを使うことでパッケージの場合でもコマンドライン引数を渡すことができます。更に、このファイルはパッケージインストール後に生成された「 /AndroidのストレージのRoot/UE4Game/Project名/ 」に配置すれば認識されるため、コマンドライン引数を変える度にパッケージ作成をする必要はありません!
f:id:pafuhana1213:20190220002605p:plain
この機能のおかげで「起動時に開くレベルの変更」や「一部機能を制限」などのデバッグ・プロファイリングで必要となる操作を手軽に行うことができます。

UE4CommandLine.txt の書き方

UE4CommandLine.txt には 渡したいコマンドライン引数を書く必要があります。
例えば 「TestProject」というプロジェクトの「Content/Maps フォルダにある LevelA」というレベルを「-Messaging」付きで開きたい場合は以下のように書くことになります。

../../../TestProject/TestProject.uproject /Game/Maps/LevelA -Messaging

Engine\Build\Android\UE4Game\UE4CommandLine.txt.template にサンプルがありますので、こちらも参考になるかと思います。

UE4CommandLine.txt の送り方

コマンドライン引数を書いたら、UE4CommandLine.txt をAndroid上のパッケージのルートフォルダに転送する必要があります。

転送はadb pushコマンドを使います。このコマンドを用いることで、開発PC上にあるファイルをAndroid端末の指定のパスに転送することができます。で、実はUE4にはこのコマンドを使うためのbatファイルが用意されています。

●Engine\Build\Android\UE4Game\PushCommandLine.bat

%ANDROID_HOME%\platform-tools\adb.exe push UE4CommandLine.txt /mnt/sdcard/UE4Game/UE4Game/UE4CommandLine.txt

注意:
/mnt/sdcard/UE4Game/UE4Game/UE4CommandLine.txt の部分は各プロジェクト名に適したパスに変える必要があります。先程例に挙げた「TestProject」の場合は、/mnt/sdcard/UE4Game/TestProject/UE4CommandLine.txtに変えることになります。

PushCommandLine.batと同じフォルダにUE4CommandLine.txt を配置した状態でこのbatファイルを使うことで、UE4CommandLine.txtがAndroid上のパッケージのルートフォルダに転送できます。

これでAndroidパッケージの場合でもコマンドライン引数を指定できるようになりました!

おまけ 1

ちなみに、LaunchボタンやProject Launcherで起動した場合はUE4CommandLine.txtの作成・転送を自動的に行ってくれます。そして、自動生成されるUE4CommandLine.txtに書き込まれる内容は、Project Launcher の Custom Launch ProfileのAdditional Command Line Parametersで編集することができます。
f:id:pafuhana1213:20190220005354p:plain

おまけ 2

Session Frontendで接続後、以下の部分から実機にコンソールコマンドを送ることができます。
f:id:pafuhana1213:20190220011301p:plain

ここまでの参考

wiki.unrealengine.com



Android Debug Monitorを使ってログを確認する方法

Android開発で使用するSDKに含まれる Android Debug Monitorを使うことで実行中のログを確認する方法もあります。この方法のメリット・デメリットは以下の通り。

メリット

  • 「-messaging」をつける必要がない
  • Session Frontendよりも詳細なログを確認可能
  • 起動即クラッシュのように、Session Frontendではログを確認し辛い場合でも有効

デメリット

  • ログの内容が詳細過ぎて見づらい
  • UE4以外のアプリのログも出力される ( 後述のフィルタ機能で対応可能 )
  • Session Frontendではできた「コンソールコマンドの送信」ができない

良し悪しがありますが、サクッとログを見たいときや即クラッシュ調査時には結構便利なのでオススメです。

Android Debug Monitorの使い方

NVPACK\android-sdk-windows\tools\monitor.batを実行するとAndroid Debug Monitorが起動します。左上に認識されているAndroidバイスのリストがあるので、確認したい端末を選択すると右下にログが流れ始めます。
f:id:pafuhana1213:20190220010227p:plain

しかし、UE4アプリ以外の様々なアプリのログが流れるため、肝心の確認したい情報がすぐ埋もれてしまいます。そこで、UE4アプリに関する情報だけを抽出するためにフィルタ機能を利用します。

(たぶん)左下にあるLog Catタブにある +ボタンを選択するとフィルタの作成画面が表示されます。その画面で以下のように入力してOKを押すと、UE4に関するTagが埋め込まれたログだけを表示するフィルタが出来上がります。
f:id:pafuhana1213:20190220012046p:plain
f:id:pafuhana1213:20190220012118p:plain

これで大分見やすくなったはずです。しかし、フィルタを適用しても追いきれない場合もあります。そんな時は以下の画像にある検索ボックスなどを用いて更に抽出するようにしましょう!
f:id:pafuhana1213:20190220012639p:plain

おまけ Android Debug Monitorでスクショを撮る

f:id:pafuhana1213:20190220012918p:plain
f:id:pafuhana1213:20190220012828p:plain

撮ったスクショはそのままPC上に保存できる!便利!


一旦今回はここまで。次は実行のログ確認方法について書く予定です。

販売・公開されているToonシェーダ系UE4アセット・情報 自分用まとめメモ(仮)

$
0
0

自分用雑まとめ。最新版での動作確認はしていません。
抜けてるものがあったらコメントに頂けるとありがたいです
TODO:順番・カテゴリ整理

最終更新:2019/4/9

SK_Mannequin(グレイマン)のアニメーションをT-Poseのモデルに「いい感じに」リターゲットする方法について(T-Poseアニメーション配布)

$
0
0

はじめに

UE4にはスケルトン(ボーン構造)が異なっていてもアニメーションを流用することができる「アニメーションリターゲット」という機能があります(スケルトンが同じ場合でもアニメーションリターゲットといいますが、今回触れるのはスケルトンが異なる場合のアニメーションリターゲットです)。
api.unrealengine.com

しかし、上記のページでも説明されている通り、ベースポーズが異なるとアニメーションが破綻してしまします。
f:id:pafuhana1213:20190429191008p:plain
f:id:pafuhana1213:20190429190931p:plain

友情出演:千駄ヶ谷渋ちゃん
hub.vroid.com

VRMインポートで使用したライブラリ
github.com


ベースポーズをエディタ上で手動でT-Poseにすることで緩和することができますが…すごく面倒です。そこで、事前に用意したT-Poseのアニメーションをベースポーズにします。

T-Poseのアニメーションファイルはこちら(完全に自由に利用可)。SK_Mannequinのスケルトンをインポート時に指定してください。
drive.google.com
f:id:pafuhana1213:20190429192832p:plain

T-Poseのポーズアセットをベースポーズに

ベースポーズにはアニメーションシーケンスアセットを直接指定することはできず、ポーズアセットにする必要があります。そのため、以下のページを参考に、T-Poseのアニメーションシーケンスアセットをポーズアセットにします。
api.unrealengine.com

作成後、SK_Mannequinのスケルトンを開き、Retarget ManagerタブのModify PoseボタンからT-Poseアセットをベースポーズにします。
f:id:pafuhana1213:20190429195110p:plain
f:id:pafuhana1213:20190429195422p:plain
f:id:pafuhana1213:20190429195450p:plain

設定が完了すると、Retarget ManagerタブのView Poseボタンを押すとSK_Mannequinが以下の画像のようにT-Poseになります。
f:id:pafuhana1213:20190429195620p:plain

ベースポーズをT-Poseに変更できたので、以下のようにT-Poseがベースポーズのモデルに「いい感じに」リターゲットできるようになります。
f:id:pafuhana1213:20190429195752p:plain
f:id:pafuhana1213:20190429200008p:plain

もしベースポーズを元々のAポーズ(っぽい)に戻したい場合は、Modify Poseボタンを押したあとにあるResetから可能です。
f:id:pafuhana1213:20190429200101p:plain

おわり

揺れ骨用自作AnimNode「Kawaii Physics」の内部実装解説的なもの その1

$
0
0

はじめに

疑似物理プラグインであるKawaii Physicsを先日リリースしました。髪、スカート、胸などの揺れものを「かんたんに」「かわいく」揺らすことができます。
f:id:pafuhana1213:20190726145840j:plain
f:id:pafuhana1213:20190726144035g:plain
f:id:pafuhana1213:20190726144050g:plain
github.com

エンジン標準のPhysics AssetやAnim Dynamicsは高性能かつ多機能なのですが…慣れるまでは調整大変といった声を聞こえてきたので、自作AnimNodeの勉強も兼ねて作った感じです。趣味プロジェクトです(ここ大事)。

せっかくなので、AnimNodeの自作やKawaii Pyhscisの内部実装に関して単にですがまとめようと思います(未来の自分用メモという意味合いもあります)。
これで皆さん自由に拡張・不具合修正できますね!

なお、本記事ではKawaii Physicsの使い方に関する説明はしません。そちらに関しては、Githubで公開しているサンプルと簡易ドキュメントをご確認くださいまし…。

参考

www.unrealengine.com
qiita.com
qiita.com
あと、エンジンコード

各クラスに関して

まずは全体像を…ということでプラグインに含まれる各クラスについてざっくり説明します。

AnimNode_KawaiiPhysics

アニメーションの制御に関する実装(主に初期化、更新)は全てこのクラスで行っています。といっても、大部分は EvaluateSkeletalControl_AnyThread関数で行われています。

実際にAnimNodeを自作したり、FAnimNode_AnimDynamicsにおける実装を見ると分かるのですが…AnimNodeのInitialize_AnyThreadでは初期化に関する処理全てを行うのが難しいケースがあるためです。そのため、EvaluateSkeletalControl_AnyThreadの初回実行時にボーン階層情報の収集・構築(InitModifyBones)を行ったりしています。

あとは、物理に関する処理をしているSimulateModfyBones関数、その結果をボーンに反映するApplySimuateResult関数が重要な働きを担っています。

AnimGraphNode_KawaiiPhysics

f:id:pafuhana1213:20190726153125p:plain
AnimGraphに配置されたノードのタイトルや一部デバッグ表示をここで行っています。
実際のランタイム上で使われる処理はここでは書かれていません。

KawaiiPhysicsEditMode

f:id:pafuhana1213:20190726153051g:plain
KawaiiPhysicsはPersonaのプレビュー画面でコリジョンの調整をできるようにしているのですが、その処理をここで行っています。また、左下にデバッグ表示している部分に関してもここで行っています。
AnimGraphNode_KawaiiPhysicsと同じく、実際のランタイム上で使われる処理はここでは書かれていません。

後述しますが、このEditModeに関する情報が世になく…そこそこ難産だった記憶があります。

KawaiiPhysicsEditModeBase

KawaiiPhysicsEditModeの基底クラスです。

FModifyBoneEditModeなどエンジン標準のAnimGraphはFAnimNodeEditModeクラスを継承したクラスでプレビュー画面における制御・デバッグ表示を行っているのですが…FAnimNodeEditModeが外部モジュールで使用することを想定していない作りになっていたので、丸ごとコピペしました。FAnimNodeEditModeの実装が今後大きく変化しない事を祈ります。


以降はそれぞれのクラスに関して深掘りしようと思います。ただ全部解説すると終わらないので、要点に絞って説明しようと思います。コードが仕様書です。

AnimNode_KawaiiPhysics

FAnimNode_SkeletalControlBaseについて

AnimNode_KawaiiPhysicsクラスはボーン制御に関する基本的な処理が用意されているFAnimNode_SkeletalControlBaseを継承しています。ボーン制御に関する流れは以下の通り。

  1. AnimNodeの入力ピンに指定したポーズをEvaluateSkeletalControl_AnyThreadのOutput.Poseから取得
  2. Output.Poseに含まれる各ボーンのTransformをコネコネ
  3. OutBoneTransformsに制御する骨と処理後のTransformを渡す

f:id:pafuhana1213:20190726154622p:plain

見ての通り扱いやすい作りになっているので、ボーンを制御するAnimNodeを実装したいときは、とりあえずFAnimNode_SkeletalControlBaseを継承しておけば問題ないのではないかと思います。

一つ注意すべきなのは、Output.PoseやOutBoneTransformsで扱うTransformの座標系が Component座標系なことです。そのため、ボーンの親子関係を考慮した制御などの処理を行いたい場合は各座標系に変換する必要があります。ただご安心ください。各座標系への変換用の関数が用意されています。

//  Component座標系から引数で指定した座標系への変換
FAnimationRuntime::ConvertCSTransformToBoneSpace
// 引数で指定した座標系からComponent座標系への変換
FAnimationRuntime::ConvertBoneSpaceTransformToCS

例えば、KawaiiPhysicsでは各ボーンに紐づくコリジョンに対してのオフセット計算をボーン座標系でする必要があったため、以下のようなコードを組んでいます。

FAnimationRuntime::ConvertCSTransformToBoneSpace(ComponentTransform, Output.Pose, BoneTransform, CompactPoseIndex, BCS_BoneSpace);
BoneTransform.SetRotation(Capsule.OffsetRotation.Quaternion() * BoneTransform.GetRotation());
BoneTransform.AddToTranslation(Capsule.OffsetLocation);
FAnimationRuntime::ConvertBoneSpaceTransformToCS(ComponentTransform, Output.Pose, BoneTransform, CompactPoseIndex, BCS_BoneSpace);

この辺りに関しては、Transform(Modify)Boneノードの実装を行っているFAnimNode_ModifyBoneクラスが非常に参考になります。
f:id:pafuhana1213:20190726155924p:plain

骨の階層構造の収集に関して

KawaiiPhysicsはRootBoneに指定したボーンとそれ以下の階層にある各ボーンを制御対象するようにしています。そして、その階層構造を収集中にExclude Bonesに指定したボーンに到達した場合はそれ以下は収集しない作りにしてます。
f:id:pafuhana1213:20190726163710g:plain

実際に収集しているのは CollectChildBones関数なのですが…ここで問題になるのが、各ボーンは親のボーンのインデックス情報しか持っていないことです。そのため、FReferenceSkeleton::GetDirectChildBonesの処理を参考、というか丸パクリしてます。

int32 FReferenceSkeleton::GetDirectChildBones(int32 ParentBoneIndex, TArray<int32> & Children) const
{
	Children.Reset();

	const int32 NumBones = GetNum();
	for (int32 ChildIndex = ParentBoneIndex + 1; ChildIndex < NumBones; ChildIndex++)
	{
		if (ParentBoneIndex == GetParentIndex(ChildIndex))
		{
			Children.Add(ChildIndex);
		}
	}
	return Children.Num();
}

全探索なので場合によっては結構重たい処理になるかと思います。しかも、現状AnimNode1個毎にこの処理が1回が走るので…(;´∀`)
ちゃんと実装するなら、AnimInstance側で収集して各AnimGraphはそれを参照する形がいいのかなと思います。が、Kawaii Physicsは手軽さも重視してるので先送りしてます。

物理処理について

SimulateModfyBonesで行ってます。で、Adjust~という名前の関数でコリジョンとの当たり判定や角度制限などを行っています。

コリジョン以外の物理アルゴリズムgithubに記載している通り、以下のCEDEC講演で解説されている内容をほぼそのまま使ってます。20行ぐらいの超シンプルな作りです。もし物理挙動をカスタマイズしたい場合はこの辺りを編集することになります。
cedil.cesa.or.jp

物理周りで特に他に説明することはないのですが…強いて言うなら、Adjust~関数にて使用している以下の関数が便利でした。FMathやFVectorには良い機能沢山あるので見るのおすすめです。

点Aから線分B上の最も近い点までの距離の2乗を取得。
FMath::PointDistToSegmentSquared | Unreal Engine
点Aから線分B上の最も近い点を取得
FMath::ClosestPointOnSegment | Unreal Engine
線分Aが平面Bと交差しているかを取得
FMath::SegmentPlaneIntersection | Unreal Engine
点Aを平面Bに投影した際の座標を取得
FVector::PointPlaneProject | Unreal Engine

STATコマンドで負荷を計測できるように

stat animで各負荷を確認したかったので、調査したい処理の部分に SCOPE_CYCLE_COUNTERを埋め込んでます。画像の通り、KawaiiPhysicsの処理が何回呼ばれて合計処理時間はどの程度かをエディタ・実機上で確認できます。
f:id:pafuhana1213:20190726170333p:plain

DECLARE_CYCLE_STAT, SCOPE_CYCLE_COUNTERを使うだけで簡単にstat対応できるのでおすすめです。実際、Kawaii Physicsの最適化においてとても役に立ちました。

実際にあった話。デフォルト設定の場合、カーブアセットが指定されていると毎回値を読みに行くのですが…その負荷が全体の約1/3を占めてました。

// Damiping
Bone.PhysicsSettings.Damping = PhysicsSettings.Damping;
if (TotalBoneLength > 0&& DampingCurve && DampingCurve->GetCurves().Num() > 0)
{
	Bone.PhysicsSettings.Damping *= DampingCurve->GetFloatValue(LengthRate);
}
Bone.PhysicsSettings.Damping = FMath::Clamp<float>(Bone.PhysicsSettings.Damping, 0.0f, 1.0f);

アセットにアクセスしに行くのである程度オーバーヘッドが発生した結果かと思います。とはいえ、動的に値を反映したいケースもあるかと思うので、フラグで動的更新するかをON・OFFできるようにしときました( Update Physics Settings in Game)。
f:id:pafuhana1213:20190726170825p:plain

こういった気付きがあるので、システムを自作する際はSTAT系のスコープを仕込んでおくことを強くおすすめします!


長くなってきたので一旦ここまで。続きはまた後日


UE4エディタ上で、Googleスプレッドシートの内容をDataTableに反映してみた

$
0
0

はじめに

UE4にはDataTableという機能があり、この機能を活用することで大量のデータを効率よく管理することができます。そして、csvjsonとの連携機能を持っているため、
「みんな大好きExcelで編集」
→ 「UE4エディタが変更を検出して自動インポート( Auto-Import )」
→ 「DataTableに反映」
というフローが一般的になっています。
データ駆動型のゲームプレイエレメント | Unreal Engine ドキュメント
[UE4] CSVデータを扱う方法 DataTable編|株式会社ヒストリア
【UE4】DataTableの使い方-その① ~基本編~【★~★★】 - キンアジのブログ

ただExcelを毎回開くのが少し面倒です(環境によってはExcelがそもそもインストールされてないことも)。
また、Excelをインポート → DataTableに反映という流れの都合上、パッケージで動作中にExcelを使ったパラメータ編集をするのは難しいです。そのため、Excelを編集するたびにパッケージを作成し…という手間がありました。

なんか良い手はないかなぁと思っていた時に…

「うちはGoogleスプレッドシートからデータ抽出してるよ。そのおかげでパッケージでもデータをガンガン編集できるよ」

という講演をどこかで聞き、おお!これは実装してみよう!…と思ったのが約2年前。やっと実装してみました。

www.youtube.com
Googleスプレッドシートの内容がDataTableに無事反映されています。素晴らしい。

ということで、やってみたことを自分用メモを兼ねて書いていきます。なお、この辺りに関しては完全に初心者なのでもっといい方法があるかもしれません。ご存知の方はこそっと教えて下さい!

Googleスプレッドシートからデータを抽出する方法を調べてみた

まずはWeb上にあるGoogleスプレッドシートから各データを引っ張ってくる処理について検索してみると、特定のURLから取得する方法、又はGoogle Sheets APIを使う方法のどちらかになるようです。

公式ドキュメント
Reading & Writing Cell Values  |  Sheets API  |  Google Developers
Method: spreadsheets.values.get  |  Sheets API  |  Google Developers
参考ブログ記事
Google Sheets API v4を適当に叩いて適当にデータをJSONで取得する - taiki-t's diary
[PHP] Google Sheets API を使ってスプレッドシートに値を書き込む | AgoHack

厳密にするのなら後者の方法が良いみたいですが、今回はサクッと実装したかったので前者の方法を試してみました。

やったことは以下の通り。詳細は上記の参考ブログを見てくださいまし。

  1. Google Cloud Platform に登録・プロジェクトを作成し、APIキーを作成 https://console.developers.google.com/apis/credentials
  2. Google Sheets APIを ↑ で作成したプロジェクトに登録 https://console.developers.google.com/flows/enableapi?apiid=sheets.googleapis.com
  3. 使用するスプレッドシートを公開 ( リンクを知っている全員が閲覧可能 という設定でOK )

これでWebブラウザで以下の形式のURLにアクセスすると、Json形式でデータを取得できるようになります。
https://sheets.googleapis.com/v4/spreadsheets//values/?key=

f:id:pafuhana1213:20191012210740p:plain

f:id:pafuhana1213:20191012210800p:plain

UE4エディタ上で、HTTP経由でGoogleスプレッドシートからデータを抽出してみた

次は、UE4エディタ上で先程試したことを同じことをします。なお、使用するノードの関係で、Editor Utility Widget上で実装を行います。
[UE4]エディタ上で動作するツール・エディタ拡張をUMGで簡単に作れる Editor Utility Widget について - Qiita


UE4にはFHttpModule というHTTP通信をするための機能が用意されています。
UE4.10 How To Make HTTP GET Request in C++ - Epic Wiki
[UE4] HTTP通信 その1 ~基本編~|株式会社ヒストリア
UE4 で http 通信を行う - お茶漬けびより
UE4: FHttpModule 系の HTTP リクエスト機構を使い "同期処理" する方法 - C++ ときどき ごはん、わりとてぃーぶれいく☆
UE4/C++: http(s) リクエストに FHttpModule 系を使う場合の OnProcessRequestComplete/FHttpRequestCompleteDelegate の成否フラグの注意どころ - C++ ときどき ごはん、わりとてぃーぶれいく☆

しかし、残念ながらBPでは用意されていません。また、これを試していた時の僕は C++ を書く気分ではありませんでした。

なので、金で解決しました。Money is Powerです
f:id:pafuhana1213:20191012211703p:plain
LE Http Request:Low Entry:Code Plugins - UE4 マーケットプレイス

そんなこんなでサクッと実装し…
f:id:pafuhana1213:20191012213642p:plain


Get GoogleSparedSheet Data using HTTP > BlueprintUE.com | PasteBin For Unreal Engine 4


サクッと取得できました。大人って汚いですね。f:id:pafuhana1213:20191012214126p:plain
f:id:pafuhana1213:20191012212052p:plain

Googleスプレッドシートから抽出したJsonデータから更に必要な箇所だけ抽出してみた

あとは抽出したデータをDataTableに反映するだけなのですが、そのためにはまずJsonデータから必要なデータ(values)だけを抽出する必要があります。

UE4にはJsonデータを扱うための機能が用意されています。
[UE4][C++]FJsonSerializebleマクロを使ってみる|株式会社ヒストリア
Unreal Engine4 でローカルにあるJsonをパースする。 - LIFULL Creators Blog
Unreal Engine4でJsonデータをパースしてみた | SystemTelescope

しかし、残念ながらBPでは用意されていません。また、これを試していた時の僕は C++ を書く気分ではありませんでした。

なので、金で解決しました。金は力です

f:id:pafuhana1213:20191012213458p:plain
LE Json:Low Entry:Code Plugins - UE4 マーケットプレイス

そんなこんなでサクッと実装し…
f:id:pafuhana1213:20191012214126p:plain

サクッと取得できました。大人はこういうことを平気でする
f:id:pafuhana1213:20191012214312p:plain

抽出したデータ(values)をDataTableに反映する

最後は抽出したデータをDataTableに反映します。軽く調べた所、DataTableにまとまったデータを反映するには UE4.23 時点ですと Fill Data Table from CSV / JSON Stringノードが役に立ちそうです。
f:id:pafuhana1213:20191012214753p:plain

今回の場合、Fill Data Table from CSV Stringを使う場合は

---,MaxWalkSpeed,GravityScale,Jump Z Velocity,Air Control
Default,"550.000000","3.000000","800.000000","1.000000"
Boost,"550.000000","3.000000","800.000000","1.000000"

Fill Data Table from JSON Stringを使う場合は

[
	{"Name": "Default",
		"MaxWalkSpeed": 550,
		"GravityScale": 3,
		"Jump Z Velocity": 800,
		"Air Control": 1},
	{"Name": "Boost",
		"MaxWalkSpeed": 550,
		"GravityScale": 3,
		"Jump Z Velocity": 800,
		"Air Control": 1}
]

という感じの形式に整形する必要がありそうです。(DataTableアセットの右クリックメニューからCSV, Jsonを出力すればどういう形式のデータにするべきか確認できます。)
f:id:pafuhana1213:20191012215311p:plain

今後の拡張性を考慮するならJson形式に整形すべきかと思うのですが、今回はとにかく楽に実装したかったのでCSV形式にしました。
以下の順番で各文字列が来るので、改行と","を挟むだけなので超ラクです。

---
MaxWalkSpeed
GravityScale
Jump Z Velocity
Air Control
Default
55038002
Boost
55038001

で、実際にはこんな感じのノードになりました。
f:id:pafuhana1213:20191012215926p:plain


Pickup Json data f and convert to DataTable > BlueprintUE.com | PasteBin For Unreal Engine 4

最後に

これでGoogleスプレッドシートの内容をDataTableに反映することができました。あとは、反映されたタイミングでその結果を各キャラ・システムなどに反映すればOKです。または一定時間毎にDataTableを見に行くという開発用機能を各キャラ・システムに組み込むのも良いかと思います。

ただし、Fill Data Table from CSV / JSON Stringノードはエディタ専用の機能なので、PIEでは動作しますがパッケージでは動作しません。そのため、パッケージの場合でもGoogleスプレッドシートの内容を反映させたい場合はDataTableを経由せずに直接対象のパラメータを変更する処理にする必要があるかと思います。また試してませんが、DataAssetを活用するといい感じになる予感がギュンギュンします
[UE4][C++] ユーザー定義オブジェクトのアセット化で楽をする|株式会社ヒストリア
UE4 c++を用いたデータテーブルを使った独自データアセットの作成 - Qiita
【UE4】手軽に独自のデータアセットを作成する 【★★】 - キンアジのブログ



おしまい

2019年内でリリースされたUE4の各バージョンを復習してみる - UE4.22編 - (順次更新)

$
0
0

はじめに

年末年始で思ってたよりも時間が取れたので、
2019年内にリリースされたUE4の各バージョン(UE4.22, 23, 24)を復習。
全部はしない上にメモ代わりなので雑な文章になると思います。ご了承くださいましまし
docs.unrealengine.com


順次更新

UE4標準のTimeSynth機能を使ってイントロループを実装してみた

$
0
0

ガチ勢の皆様へ

少し長くなるかもなので先に結論から

  • ループマーカー対応の話ではありません。イントロ用・ループ用のサウンドアセットを個別に用意する必要があります
    • ゴメンナサイ
  • BPMと小節・伯単位による管理が可能になったという話です
  • アセット側で再生する小節・拍数などの設定ができますが、BPを使った実装も『少し』必要です
  • UE4.24現在でもベータ機能です
  • 処理負荷が増えるのでご注意ください
  • ○DXか○MODか○wise使えばいいじゃん…という言葉は聞こえません。…聞こえないって言ってるだろ!!!

はじめに

ステージ開始時にBGMのイントロ部分を再生し、その後はループ部分を流す『イントロ付きループ』はゲームでよく見ます(聞きます?)。…が、UE4の標準機能で実装すると様々な工夫・妥協をする必要がありました。

詳細は上記の記事を見ていただくとして…問題を簡単にまとめると以下の通りです。

  • BP, SoundCueにおけるDelayノードでは精度が足りず、イントロとループは自然にならない・安定しない
    • シームレスな音楽の連続再生を実現するにはサンプリングレートでのタイミング精度が求められる
      • 原理的に48kHzの音声ファイルなら、1秒間に48000フレーム
    • Fade In/Outによるクロスフェードでごまかす手もあるが使えないケースがある上に実装コストが少し高い

UE4初期からこの問題を抱えており、個人的にもずっとモヤモヤしていたのですが…
UE4.22で入ったTimeSynth機能を使うことで
高精度かつ(比較的)簡単にイントロループを実現可能になりました!

www.youtube.com
ということで実装してみました。素人耳ですが…たぶんいい感じかと思います!!!(音飛びは録画の問題
以降は↑の作業手順について自分用メモも兼ねて書いていきます。

TimeSynthについて

TimeSynth (ベータ)
TimeSynth は、サウンドデザイナーへ音声クリップのサンプルベースの正確な開始、停止、連結を提供することに重点を置いた、新しいオーディオ コンポーネントです。TimeSynth で、インタラクティブな音楽アプリケーションに不可欠な、正確で同期的なイベント オーディオとイベント キューが可能になります。
https://www.unrealengine.com/ja/blog/unreal-engine-4-22-released

f:id:pafuhana1213:20191228145414p:plain
f:id:pafuhana1213:20191228145439p:plain
従来の方法はGame Threadに依存しているため、上図のようなズレが生じたりフェード処理で誤魔化す必要がありました。

f:id:pafuhana1213:20191228145650p:plain
TimeSynth機能はこの問題を解決するため、Game Threadには依存しない上により細かい間隔でサウンドを管理します。具体的には 小節・拍単位での管理を可能にします。その結果、イントロ付きループやインタラクティブミュージックなどの従来の仕組みでは難しかった表現を可能にしています。(注:簡単にとは言ってない。特にインタラクティブミュージックに関して)

インタラクティブミュージックについて非常に参考になる記事


導入手順・詳細に関しては以下の記事をご確認ください。

また、Epic本社のライブストリームが非常に参考になります。動画・スライドに加えて、なんとイントロループデモ付きのサンプルプロジェクトも!

で、上記の情報を見た人間が「やってみよう->できた!」のでその流れを書こうと思ったのが本記事です。なので、以降は少なくともヒストリア様の記事を見た前提で書いていきます。また、私はサウンドに関してもド素人なので、「使用する素材は公開されているものをお借りする」「ソフトはプロ向けではないフリーのものを使用する」というゆるふわな内容になっています。ご理解くださいましまし

今回お借りした素材はこちらです。「ループのみ」と「イントロ+ループ+フェードアウト」の2種類が公開されています。
フリーBGM素材「弾丸」試聴ページ|フリーBGM DOVA-SYNDROME

使用するBGMのBPM、イントロ・ループの切り替わりタイミングを確認する

まずはTimeSynthClipを設定するために、使用するサウンドBPM、切り替わりタイミング(小節・拍数)を知る必要があります。

BPMに関しては『BPM Analyzer』というソフトが簡単でした!D&Dで放り込むだけでBPMをすぐ計測してくれます!便利!
【徹底解説】BPM(テンポ)を自動で測定する「BPM Analyzer 」が超オススメ!曲のテンポを調べるには計測ツール(無料ソフト)で便利です! | のり部屋

小節・拍数に関しては、『Audacity』のリズムトラックという機能を使いました(もっといいやり方がある気がする…
【Audacity】メトロノーム音を追加する方法

f:id:pafuhana1213:20191228154224g:plain
f:id:pafuhana1213:20191228155656p:plain
こんな感じで小節・拍を可視化してくれるので、イントロ・ループ部分の小節・拍数を手動で数えます(もっといいやり方がある気がする…

TimeSynthClipの設定

BPM Analyzer』と『Audacity』を使って分かった情報は以下の通り。これらの情報をTimeSynthClipに反映していきます。

  • BPM:110
  • イントロ部分:8小節
  • ループ部分:25小節

f:id:pafuhana1213:20191228160554p:plain
今回お借りした素材はキレイに小節で区切られたいたので設定もシンプルです。

再生用BPの実装

f:id:pafuhana1213:20191228161010p:plain
BPMの設定、1小節毎のイベント発行、TimeSynth開始、イントロ用TimeSynthClipの再生を行っています。ここで注意すべきことは、PlayClipノードを実行したタイミングでサウンドが再生されるわけではないことです。TimeSynthClipのClipQuantizationで設定した値を元に再生を開始するので、1Barに設定されている場合は最大1小節分待った後に再生されます(で、ですよね…?少し自信ない)。

f:id:pafuhana1213:20191228161847p:plain
1小節毎に発行されるイベントの処理です。イントロまたはループ部分の再生が完了したタイミングでループ部分を再生する必要があるため、このような実装になっています。なお、Num Barsの初期値は0です。

これで準備完了です!再生開始すると初めに紹介した動画のようにイントロ付きループが再生されます!やったね!

最後に

今回はTimeSynth機能を使ってイントロ付きループを実装してみました。これまでのDelayやFade処理が頑張ってた頃に比べると大分楽になったかと思います!

TimeSynthはイントロ付きループだけでなくこの他にも様々な表現が可能です。ヒストリア様の記事にあるようにサウンドに合わせた演出を入れてみたり、Epic本社のライブストリームのように異なるサウンドをいい感じに切り替えたり…。是非色々試してみてください!

おしまい

UE4.24から入った「Editor Validator Subsystem」を使って、アセット保存時などで走るチェック処理(Validate Assets)を拡張しよう!

$
0
0

はじめに

SubSystemって何?という方はまず以下のページをご確認ください。
Programming Subsystems | Unreal Engine ドキュメント

UE4.24でEdiorSubSystem継承のSubSystemが幾つか追加されています。そして、その中のEditor Validator Subsystemはアセット保存時などで走るチェック処理(Validate Assets)を簡単に拡張できるという非常に強力な仕組みです!例えば「対象のStatic MeshアセットがLODを持っていない場合はエラーを出す」というチェック・通知処理をBPでサクッと作ることができます

このような仕組みを用意することで「不適切な設定なアセットが混じることで余分な負荷・エラーが発生する」ことを防止できます。特に中規模・大規模プロジェクトでは致命的になりがちなので早めの段階で用意しておきましょう!

Editor Validator Subsystemの使い方

「対象のStatic MeshアセットがLODを持っていない場合はエラーを出す」を例にどのようにしてEditor Validator Subsystemを使うのかを説明します。

Editor Utility Blueprintを作成

f:id:pafuhana1213:20191231221303p:plain
f:id:pafuhana1213:20191231221737p:plain
はじめに、EditorValidatorBaseクラスをベースにしてEditor Utility Blueprintを作成します。この作成したBPにて「チェック対象にするクラスの指定」と「対象のアセットに対して行うチェック処理」を実装していきます。

チェック対象にするクラスを指定

f:id:pafuhana1213:20191231221942p:plain
f:id:pafuhana1213:20191231222034p:plain
まずはCan Validate Asset関数をオーバーライドし、どのアセットクラスを対象とするか指定します。今回はStatic Meshアセットを対象とするので上図のようにします。

対象のアセットに対して行うチェック処理を実装

f:id:pafuhana1213:20191231223442p:plain
f:id:pafuhana1213:20191231224247p:plain
次にValidate Loaded Asset関数をオーバーライドし、チェック処理の内容を書いていきます。

チェック処理を通過した場合は、Asset Passesノードを呼び、ReturnノードでValidを返します。
チェック処理に引っかかった場合は、Asset Failsノードを呼び、ReturnノードでInvalidを返します。このAsset Failsノードの各引数ピンで指定する内容はエラー画面にて表示されるのでちゃんと設定しましょう!

Editor Validator SubsystemにEditor Utility Blueprintを登録(新規作成時のみ)

f:id:pafuhana1213:20191231230854p:plain
次に、Add Validatorノードを使うことで実装したチェック処理をEditor Validator Subsystemに登録します。
(BPの場合、Editor Validator SubsystemはEditor Scripting系のBPからしかアクセスできないため、EditorUtilityWidgetなどで実装する必要があります)

なお、エディタ起動時に各EditorValidatorBase継承のBPは自動的にEditor Validator Subsystemに登録されます。そのため、上記の処理はEditorValidatorBase継承のBPの作成した後にエディタを再起動すれば不要です。(UEditorValidatorSubsystem::Initialize参照)

アセットのチェック処理を走らせてみよう

f:id:pafuhana1213:20191231232314p:plain
これで準備完了です!試しにLODを持っていないStatic Meshアセットを保存するか、右クリックメニューからチェック処理(Validate Assets)を走らせてみましょう!

f:id:pafuhana1213:20191231232401p:plain
こんな感じにエラーが出ます!最前面にウィンドウが出てくるので、ログに出力する場合と違って無視される可能性が低い…かと思います!

f:id:pafuhana1213:20191231232522p:plain
また、EditorUtilityWidgetなどから明示的にチェック処理を走らせることもできます。そのため、AssetRegistryを使って自動抽出したアセットに対してチェック処理を走らせたりすることができます。

最後に

簡単ではありましたが、Editor Validator Subsystemを使ってアセットのチェック処理を拡張する方法について紹介しました!実装が簡単な上に、エンジン標準のチェック処理に追加する形になるのでワークフローも組みやすいかとと思います。また、ログ出力と違って最前面にエラー文を出せるというのは大きな強みかと思います!是非試してみてください!

おまけ

具体的にどういう仕組みになっているのか知りたい方は UEditorValidatorSubsystem::ValidateAssets の実装をご確認ください。

おしまい

【UE4 Android】アプリのバージョン情報(VersionCode, VersionName)を設定・取得する方法について

$
0
0

記事作成のリハビリを兼ねて、先日調べた内容をサクッと書いてみる
検証バージョンは UE4.25.0

はじめに

Androidアプリのバージョン情報には、整数のVersionCode と 文字列の VersionNameの2つで管理があります。
VersionCodeはストア上での管理で用いられるものです。そして、過去にストアにアップロードしたVersionCodeとの重複が許されないため、ストアにアップするたびに値を追加する必要があります。
VersionNameはユーザへの表示のみを目的としたもので自由に設定することが可能です(例:1.2.3-beta)

参考:
アプリのバージョニング  |  Android デベロッパー  |  Android Developers
versionCodeとversionNameの 違い | アプリ開発のお勉強! アプリリ

バージョン情報の設定方法について

一般的なAndroid開発の場合は build.gradle という名前のファイルにVersionCode, VersionNameを記述するのですが、UE4を使ったAndroid開発の場合はプロジェクト設定で記述することになります。
f:id:pafuhana1213:20200509161407p:plain

上の赤枠のStore Version が Version Code、下の赤枠のVersion Displayが Version Name にあたります。
(名前合わせたほうが混乱しなかったのでは…)

Store Version Offsetで設定した値は、横にある( )内のCPUをサポートするアプリのStore Version に加算されます。そのため、例えばプロジェクト設定のPlatform - AndroidにあるBuildカテゴリの設定を以下のようにすると、作成したパッケージ( APK )のVersionCodeは10+1=11になります。
f:id:pafuhana1213:20200509162156p:plain

ここでカンの良い人は ↑↑図のStore Version Offsetの設定は破綻する可能性があることに気づきます!いったい何が問題なのでしょうか…?






はじめに設定した通り、Version Codeは重複が許されません。そのため、armv7 対応版と arm64対応版をそれぞれストアにアップするプロジェクトの場合、 Store Versionを「11」に設定してアップしようとすると armv7 版は VersionCodeの重複が原因で失敗するはずです。

そのため、実際にStore Version Offsetを運用する際は以下のように重複を回避することを考慮する必要があります。ちなみに、 パッケージが1種類だけプロジェクトの場合は Store Version Offsetを 初期値の0から変更する必要はありません。
f:id:pafuhana1213:20200509163248p:plain

バージョン情報の取得方法について

アプリを更新するかしないかの判定など、 アプリ起動中にStoreVersionを知りたいケースが時々あるかと思います。ということで取得方法についてもご紹介。

プロジェクト設定で設定したStoreVersion や VersionNameなどは UAndroidRuntimeSettings で保持されています。そのため、

.h ファイル

#pragma once#include "CoreMinimal.h"#include "Kismet/BlueprintFunctionLibrary.h"#include "AndroidRuntimeSettings.h"#include "MyBlueprintFunctionLibrary.generated.h"/** *  */
UCLASS()
class BUILD0425_API UMyBlueprintFunctionLibrary : public UBlueprintFunctionLibrary
{
	GENERATED_BODY()

	UFUNCTION(BlueprintCallable)
	staticint GetStoreVersion();

};

.cpp ファイル

#include "MyBlueprintFunctionLibrary.h"int UMyBlueprintFunctionLibrary::GetStoreVersion()
{
	return GetAndroidRuntimeSettings()->StoreVersion;
}

.build.cs 以下の内容を追加

PrivateDependencyModuleNames.AddRange(new string[] {"AndroidRuntimeSettings" } );

とすることで、StoreVersionを取得することが可能です。
f:id:pafuhana1213:20200509164548p:plain


VersionCode ではなく、StoreVersionであることに注意です! 繰り返しになりますが、VersionCode は StoreVersion とStore Version Offset を足したものです。そのため、VersionCodeの値が欲しい場合は UAndroidRuntimeSettingsが持つ以下のプロパティの値も取得する必要があります。

// Offset to add to store version for APKs generated for armv7
UPROPERTY(GlobalConfig, EditAnywhere, Category = "APK Packaging", meta = (DisplayName = "Store Version offset (armv7)"))
int32 StoreVersionOffsetArmV7;

// Offset to add to store version for APKs generated for arm64
UPROPERTY(GlobalConfig, EditAnywhere, Category = "APK Packaging", meta = (DisplayName = "Store Version offset (arm64)"))
int32 StoreVersionOffsetArm64;

// Offset to add to store version for APKs generated for x86_64
UPROPERTY(GlobalConfig, EditAnywhere, Category = "APK Packaging", meta = (DisplayName = "Store Version offset (x86_64)"))
int32 StoreVersionOffsetX8664;

おしまい

余談:
In-app updates for games のベータが最近公開されたけども今後はこれが主流になっていくのかしら…?
developers-jp.googleblog.com

Viewing all 159 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>