Quantcast
Channel: historia Inc –株式会社ヒストリア
Viewing all 998 articles
Browse latest View live

[UE4]PerceptionNeuronとの連携について

$
0
0

今回はPerceptionNeuronというモーションキャプチャとUE4との連携について紹介させていただきます。
使用しているUE4のバージョンは4.18.3になります。
(2018/05/28現在、使用するプラグインが対応しているバージョンが4.18.3までのためです。)

PerceptionNeuronとは

中国のNoitom社から出ている、モーションキャプチャ装置のことです。
ジャイロスコープ、加速度計、磁力計のセンサーがついており、USB、もしくはWifiで
キャプチャしたデータをPCに送るようになっています。全身+指+プロップ1つをキャプチャすることが可能です。
キャプチャ時に使用するソフトはAxisNeuronです。
公式ホームページ(日本語)はこちらになります。
https://neuronmocap.com/ja

 

UE4で準備するモデルについて

まず、モーションキャプチャをするにあたって、モデルが必要ですが、HIKやBVHに適した骨構造であれば大丈夫です。
またPerceptionNeuronでは全身をキャプチャする以外に、腕のみ、上半身のみキャプチャするモードもありますし、
必ずしも用意するモデルがヒト型ではなくても大丈夫です。

UE4との連携をする場合はRoot(一番上の階層)に回転値などが入っていると、
移動値の軸がおかしくなってしまうので、Rootの回転値はX,Y,Z=0,0,0にしておきましょう。

また、バインドポーズはTスタンスにしておきましょう。
AxisNeuron側の初期値がTスタンスのため、それに合わせるためです。
以下に例として、グレイマンのデフォルトのAスタンスのままモーションキャプチャを流したものと、
Tスタンスにバインドポーズを修正したものを挙げます。

 
Aスタンスのほうは少し腕をおろした状態を初期値とみなされているため、
モーションキャプチャを流し込むと腕が内側に行き過ぎてしまっています。
また足や指も真っ直ぐではなく角度がついていたため、ポーズが異なっています。

またAxisNeuron側のモデルの特徴としては、以下になります。
まず足の指がありません。そのため、つま先立ちなどで足の指部分だけ接地させたい場合は別途そこだけ動きを付ける必要があります。
InHandがありますが、キャプチャされる部分ではないため、UE4側のモデルにInHanadがなくても大丈夫です。
SpineはSpine~Spine3の4本ありますが、モーションを読み込む側のモデルの背骨の本数を合わせなくても大丈夫です。

 

UE4とのリアルタイム連携について

UE4との連携はこちらのUnreal Pluginを使用します。
https://neuronmocap.com/downloads

公式のPDFはこちらです。

https://support.neuronmocap.com/hc/en-us/articles/218293067-How-can-i-setup-the-Unreal-Plugin-

このプラグインでできるようになることは以下の点になります。
・AxisNeuronの動きをリアルタイムに反映する
(AxisNeuronでリアルタイムに収録中の動きと、収録済みのBVHをAxisNeuronで再生している状態の動きの2パターンを反映できます)
・AxisNeuronから出力したBVHをUE4のモデルのボーンにマッピングする

今回は以下のようにAxisNeuronとUE4を連携し、モーションキャプチャしたものをUE4で同期再生、
おまけで揺れものを含めた状態でFBXを書き出すところまでの手順を説明させていただきます。

ではPluginの導入から順に説明させていただきます。

1.プロジェクトの作成とプラグインの導入
プロジェクトを作成した後、プロジェクトをいったん終了し、作成したプロジェクトフォルダをエクスプローラで開きます。
プロジェクトフォルダの直下にPluginsのフォルダを作成し、そこに上記リンク先でダウンロードしたプラグインをフォルダごと入れます。

2.プラグインの確認
プロジェクトを再起動し、Pluginが有効になっているか確認します。

3.モデルの読み込み
モデルを読み込みます。

4.AnimationBluePrintを作成
読み込んだモデルのスケルトンを右クリックしてCreate>AnimationBluePrintで作成します。

5.AnimationBulePrintを編集
このAnimationBluePrintでAxisNeuronから送られてくるBVHの骨と、読み込んだモデルの骨をマッピングします。
AnimationBluePrintを開いてAnim Graphを表示して、右クリック>NewPoseCalcのノードを出します。
NewPoseCalcとFinalAnimationPoseをつなげます。

NewPoseCalcをクリックしてマッピングを編集します。
左の欄がNeuronのキャプチャーの骨、右が読み込んできたモデルの骨になります。
右の読み込んできたモデルの骨の欄は、すべての骨があらかじめ登録されているので、
それに合わせて左のNeuronの骨を設定していきます。
(すべての骨をマッピングしなくても大丈夫です)

コンパイルしてセーブします。

6.BluePrintActorを作成
Add Newもしくは右クリック>BluePrintClass>Actorを作成します。
作成したActorを開いてAdd Component>SkeletalMeshとPerceptionNeuronを追加します。
DefaultSceneRootの子ではなく、一番上の階層になるようにしておきます。


追加したSkeletalMeshをクリックし、Details>Animation>Anim Classに5で作成したAnimationBluPrintを選択します。
AnimationModeがUse Animation BluePrintになっていることを確認しておきます。
Meshには読み込んだモデルを選択してください。

コンパイルしてセーブします。

7.AxisNeuronが送るBVHの設定
UE4からAxisNeuron(キャプチャソフト)に移り、File>Setting>Broadcastingの設定項目の中の
Tcp/UDPをUDPに、BVHの欄をEnableにチェックを入れて、ClientPortの番号を確認します。(この番号をUE4で使います)
OKを押してダイアログを閉じてキャプチャ装置とAxisNeuronを接続してリアルタイムでキャプチャしている状態か、
もしくは収録済みのBVHをループ再生している状態にします。
(AxisNeuron上で動いているものがないとUE4に情報が送られません。キャプチャ装置との接続が切れていたり、
BVHの再生が止まっているとUE4側は何も反映されません。)

また、デフォルトの状態だと、骨すべてに移動値もいれてデータが送られてくるため、
場合によってはその移動値により変形がおかしくなってしまいます。
その場合は移動値を含まないようにしてデータを送ることができます。
同じウィンドウ内のOutput Formatに移動し、DisplacementのチェックをOFFにします。
回転順はデフォルトのYXZのままで大丈夫です。

8.レベルに必要なものを配置
新規レベル、もしくは既存のレベルを開きます。

ビューポート(レベル)にリアルタイムにモーションが流し込まれているモデルを表示する方法は2タイプあります。
6で作成したBluePrintActorをそのままレベルに置くタイプと、Spawnerを使ってBluePrintActorをスポーンさせるタイプです。

まずBluePrintActorをそのままレベルに置くタイプのものからです。
作成したレベルに6で作成したBluPrintActorと、ModesからPerceptionNeuronManagerをレベルに配置します。


BluePrintActorの置く位置はモーションの位置に関係するので、再生したい場所になるよう位置を調整します。
(収録データが接地している状態であれば、BluePrintActorの場所が接地面になります。)
配置したBluPrintActorを選択し
PerceptionNeuron(Inherited)>Perception Neuron>Avatar Nameに
AxisNeuronと同じ名前を入れます。AxisNeuronの名前は下記画像のところで確認・変更ができます。

 

PerceptionNeuronManagerをクリックして、
Network>Portに7で確認したポート番号7002を入れます。

レベルをプレイ(Simulateが確認しやすいです)するとモーションがリアルタイムに反映されているのが確認できます。

 

次にSpawnerを使ってBluePrintActorをスポーンさせるタイプのものです。

レベルにPerceptionNeuronManagerとPerceptionNeuronSpawnerを配置します。
(上記の方法を試したのち、引き続きこちらの方法を試している場合は、PerceptionNeuronManagerを追加で置く必要はありません。)

PerceptionNeuronSpawnerをクリックして
Actor Binding>Avatar NameをAxisNeuronと同じ名前を入れます。
Dynamic Actor Classには6で作成したBluePrintActorを選択します。

レベルをプレイするとアクターがスポーンされてモーションがリアルタイムに反映されているのが確認できます。

 

9.収録したBVHを直接UE4上で再生したい
UE4とNeuronが上記の手順で連携できていれば、AxisNeuron側で収録したBVHを再生して、
それをUE4で確認することもできますが、それが面倒な場合などは、UE4に直接BVHをインポートして再生することができます。

インポートしたいBVHは特定の場所に置いておく必要があります。
場所は、プロジェクトの”フォルダ\Content”に”BVH”のフォルダを新規作成し、そこに.bvhファイルを置きます。

流し込みたいBVHをUE4にインポートします。
もし上記の場所に置いていないBVHをインポートした場合、
BVHをダブルクリックすると出てくるダイアログのFile>BVH File Pathにオレンジ色のエラーアイコンが出てきます。

6で作成したBluePrintActorをレベルに配置します。

配置したBluePrintActorを選択し、PerceptionNeuron(Inherited)>BVH Assetに
読み込んだBVHを選択、レベルをプレイするとBVHのモーションが再生されます。

 

おまけ:UE4からのモーションの書き出し

以上でUE4とAxisNeuronの連携はできました。
ですが、キャプチャしたモーションを修正するとなると、外部のDCCツールにデータを持っていく必要があるかと思います。
AxisNeuronからはBVH、FBXなどのデータを書き出すことができますが、
書き出される骨の名前はAxisNeuronが定めたもので、骨の名前やサイズ、階層構造を変更することはできません。
そのため、リターゲットなどをしなくてはなりませんが、上記手順でUE4とAxisNeuronを連携しているのであれば、
AnimationBluePrintで骨の名前をマッピングしているので、モデルのボーンの構造のままアニメーションを書き出すことが可能です。
また、フィジックスなど、UE4で設定した揺れものなどのアニメーションも書き出せます。

では書き出し方法の説明です。

Neuronと連携している状態のActor、もしくは収録済みのBVHを流しているActorをレベルに配置します。

レベルをプレイして、モーションが動いている状態にします。

AnimBluePrintを開いてDebugFilterからプレビューするモデルを変更します。

変更するとAnimationBluePrintのプレビューが、Tスタンスの状態からレベルでプレイしているモーションと同じ動きになります。

動きがプレビューできている状態になったら録画ボタンを押して、作成するファイル名と場所を決めます。

録画終了するとアニメーションシーケンスが作られているのが確認できます。

これをFBXで書き出せば、UE4で見ていたモーションと同じものを外部に書き出せます。
(画像は書き出したFBXをMAYAで開いたものになります)

揺れものなどがある場合はそれらもまとめて書き出せます。試しにモデルにマントを付けて、
それをフィジックスで動かしたものを録画、FBXで書き出しすると以下のようになります。
 
問題点としては、いくつか手順を踏むので、収録済みのBVHを上記の方法でUE4内で再収録しようとすると、
BVHの開始(エディタのプレイ)タイミングとAnimBluePrintの録画開始タイミングがずれてしまいます。
BVHはループ再生されるので2週目から録画するか、あらかじめBVHの頭に余分な尺を置いておくと良いかもしれません。
モーションキャプチャーの収録と同時にUE4でもアニメーションを収録しようとすると、AxisNeuronとUE4の2つの録画ボタンを押す必要もあります。
収録のタイムスケジュールが決まっていたり、AxisNeuronで後々修正したい場合は、まずAxisNeuronのみ録画し、UE4でFBXに変換、といった手順にしたほうが良さそうです。
揺れものを手付で調整する場合や、UE4での揺れものを考慮して修正する場合に役立つかもしれません。

長くなりましたが、ご覧いただきありがとうございます。
参考になるものがあれば幸いです。


社員研修旅行に伴う臨時休業のお知らせ

$
0
0

社員研修旅行による臨時休業のお知らせ

平素は格別のお引き立てをいただき、厚く御礼申し上げます。

誠に勝手ながら、弊社では6月25日(月)間、社員研修旅行のため臨時休業とさせていただきます。
皆様にはご迷惑をおかけいたしますが、何卒ご了承いただきますようお願い申し上げます。

6月26日(火)より通常通りに営業いたします。
何卒よろしくお願い申し上げます。

[UE4] DDCを共有してストレスフリーな開発を!

$
0
0

Derived Data Cache (DDC)?

プロジェクト、エンジンフォルダにいつの間にかDerived Data Cacheというフォルダが作成されています。

このDDCですが、主にアセットのシェーダーコンパイルした情報が格納されます。なのでDDCフォルダを削除した後にエディタを起動するとシェーダーコンパイルが走っちゃいます。エディタ起動時に毎回シェーダコンパイルの必要がなかったのはこのファイルのおかげでした!プロジェクト一式をそのまま渡す際にはDDCも含めてあげると無駄にシェーダーコンパイルが起こらなくなく便利です。

デフォルトの状態だとローカル環境でしか更新されないため、チーム制作などでチームメンバーの誰かがマテリアルを編集したりするとエディタ起動やレベルを開いたときなどそのマテリアルが参照されたタイミングでシェーダーコンパイルが走ってしまいます。小さい規模であれば変更したアセットも多くなくそこまで気にならないのかもしれませんが、開発が大きくなってくるとシェーダーコンパイルを待つ時間が多くなったり、エディタの起動が遅くなったりとストレスがたまってしまいます…。

 

そこで朗報!なんとDDCは共有できました!!

 

DDCの共有

DDCが共有できるとマテリアルなどのアセットファイル編集者がシェーダーコンパイルした結果をそのまま別の人でも使用できます。なんてすばらしいんでしょう!ストレスフリーですね!

では早速方法を見てみましょう。

といっても方法はとっても簡単です。[ProjectPath]/Config/DefaultEngine.iniの最後に以下のコード追加するだけでOKです!

[InstalledDerivedDataBackendGraph]
MinimumDaysToKeepFile=7
Root=(Type=KeyLength, Length=120, Inner=AsyncPut)
AsyncPut=(Type=AsyncPut, Inner=Hierarchy)
Hierarchy=(Type=Hierarchical, Inner=Boot, Inner=Pak, Inner=EnginePak, Inner=Local, Inner=Shared)
Boot=(Type=Boot, Filename=%GAMEDIR%DerivedDataCache/Boot.ddc, MaxCacheSize=256)
Local=(Type=FileSystem, ReadOnly=false, Clean=false, Flush=false, PurgeTransient=true, DeleteUnused=true, UnusedFileAge=17, FoldersToClean=-1, Path=../../../Engine/DerivedDataCache)
Shared=(Type=FileSystem, ReadOnly=false, Clean=false, Flush=false, DeleteUnused=true, UnusedFileAge=19, FoldersToClean=-1, Path=\\mystudio.net\DDC)
Pak=(Type=ReadPak, Filename=%GAMEDIR%DerivedDataCache/DDC.ddp)
EnginePak=(Type=ReadPak, Filename=../../../Engine/DerivedDataCache/DDC.ddp)

色々何か書いてありますが、変更する場所は

(※見やすいように、中間のコマンドは省略しています!)

のみです。=の後に共有先のDDCのパスを設定してください。

これでエディタを起動しなおすと指定したパスにDDCファイルが作成されると思います。

 

まとめ

お手軽に重そうなエレメンタルで起動確認してみましたが、DDCを消した状態でエディタの起動からシェーダーコンパイルが終了するまでに15分以上はかかっていたところ、共有設定をし、あらかじめDDCを共有先に作成して起動したエレメンタルでは1分ほどですぐエディタ起動が行えました!超快適!

コード自体は何しているのか自分もはっきりといえるほど理解はしていないですが(申し訳ないです…)、お手軽に開発の高速化が行えるのでぜひお試しください!

これであなたもストレスフリーな開発を!!

【UE4】SphereMaskでお手軽暗闇表現

$
0
0

今回は【SphereMask】ノードを使用し、暗闇の迷路を作成してみます。

【UE4 4.19.2】 New Project からTop Downを使用します。

ボックスを動かして迷路にしました。

このままプレイすると以下のような感じです。

ここで、プレイヤーの周囲を暗闇にしていきます。

 

まずはレベルに【PostProcessVolume】を迷路全体が収まるように配置します。

 

次に新規マテリアルを作成します。

作成したマテリアルを開き、【SphereMask】ノードを使用します。

このノードでは球状のマスクを作成し、1つの点を指定します。

指定した点が球状の内側にあれば1。外側にあれば0に遷移するものです。

【A】チェックしたいポイントを指定します。

【B】球の中心を指定します。

【Radius】球の半径を指定します。

【Hardness】数値を入力し0に近い程、球の内外の境い目で緩やかにグラデーションします。

 

以下のように組んでみました。

迷路を歩きたいので、【B】には常に付いてくるカメラを球の中心として指定し、プレイヤーが収まる程度の半径を入力しました。

チェックしたいポイントも歩くと常に変わるので【A】に【Absolute World Position】を使用し、絶対ワールド位置からピクセル情報をとってきます。

 

次に、【Material Domain】に【Post Process】を指定します。

設定後、レベルに戻り、【PostProcessVolume】を選択します。

【Rendering Features】の【Post Process Materials】の[+]を押して、先程作成したマテリアルを指定します。

設定はこれで完了です。プレイしてみましょう。

 

周囲は暗くなっていますが、白黒の世界になってしまいました。

なので、作成したマテリアルを再度開き、以下のノードを追加しました。

【Lerp】で色の補間を行います。

Aには黒を指定。Bには【Scene Texture】ノードを使用し、レベルにあるテクスチャー情報をPost Processに適用します。

【SphereMask】をAlphaに繋ぎ、完了です。再度プレイしてみましょう。

 

 

球状の内側に元のテクスチャーが適用されました!

 

このように、お手軽に暗闇表現が出来るので、様々なジャンルのゲームに役立ちそうですね。

[UE4]レベルシーケンサーから任意アクターのカスタムイベントを実行する

$
0
0

今回の記事では、レベルシーケンサーからEvent Receiverを使ってアクターのカスタムイベントを実行してみます(UE4.16以降)。

レベルシーケンサー(やマチネ)ではEvent Trackを使えばレベルブループリントのカスタムイベントを呼ぶことができました。ただ、アクターのカスタムイベントは直接呼ぶことができないため、間接的にレベルブループリントなどを経由する必要があります。

Event Trackでレベルブループリントのカスタムイベントを呼べるのはとても便利ですが、そうなるとレベルブループリントが込み入ってしまいます。そこで、レベルシーケンサーのEvent Receiverという機能を使ってアクターのカスタムイベントを直接実行してみましょう。

まず、新規にレベルを開き、アクターブループリントとレベルシーケンサーをレベルに配置します。

レベルシーケンサーを選択して、ディテールパネルからAdditional Event Receiversの+を押してスロットを追加し、レベルに配置したブループリントを登録します。ここで登録したブループリントのカスタムイベントを実行できるようになります。

また、最後にプレイして確認するために、AutoPlayのチェックを入れておきました。

次にレベルシーケンサーを開き、Event Trackを追加します。

併せて、レベルに配置してReceiverに登録したアクターもトラックとして追加しておきます。

そして、Event Trackを右クリックし、プロパティのTrack Eventにアクターを登録します。シーケンサーに追加したトラックから選択できますので、Event Receiverとして登録したアクターが選択できない場合は、シーケンサーのトラックに正しく追加されているかご確認下さい。

 

では、アクターを開きカスタムイベントを作ります。

シーケンサーからは名前でコールするので、イベント名(ここでは[CustomEvent])をコピーしておきましょう。

 

最後に、シーケンサーに戻りEvent Trackにキーを打ちます。

キーを右クリックしてプロパティからEvent Nameとしてカスタムイベント名を入力します。

プレイやシミュレートしてみましょう。

アクターのカスタムイベントが実行されました。

なお、シミュレートの場合は、シーケンサーのタイムスライダーをスクラブしてキーを通過するだけでイベントが実行されます。ちょっとした確認に使えるかもしれません。

レベルブループリントにいろいろ書かなくて済みますね。便利だねー

社員研修旅行に行ってきました2018in那須

$
0
0

6月23日~6月25日の3日間、社員研修旅行で那須高原に行ってきました!

雄大な自然に触れてリフレッシュすることができました( ◠‿◠ )

思い出を振り返りつつブログにまとめようと思います。

ゲーム・UE4全く関係のない記事ですがお付き合いください!

23日当日は雨予報でしたが、那須塩原駅に着いた時点では曇り空。

みんなでバスに乗ってホテルまで移動します。

 

木!!川!!
癒されますね

ホテルに到着しお昼ご飯を頂いた後は、ホテル主催のフォトロゲイニング!!

チェックポイントを回り写真を撮ってポイントを稼ぐ競技です。

 

日ごろの運動不足を解消するため、歩きます。

結構高いところまで来ました!
温泉が湧き出ている地区なのでほのかに硫黄の香り・・・

みんな頑張りました!!

その後、夕食の宴会の場で結果発表。

優勝チームにはホテル宿泊券・ご当地お菓子などたくさんの景品を獲得!

宴会の後は温泉に入ったり、体育館でスポーツをしたり、ボードゲームで遊んだりして一日目は終了です。

 

2日目は朝からりんどう湖レイクビューに遊びに行きました!

貸し切りバスで移動です。

着きました( ◠‿◠ )

ここでは様々なアトラクションや牧場の動物と触れ合いを楽しみました。

可愛いですねー

普段では体験できない乳しぼりもやりました!

お昼はBBQ♪

その後はトリックアート美術館に移動し、目の錯覚を利用した様々なアートの前で写真を撮りました。

浮かれてます( ◠‿◠ )

ホテルに戻ってからはそれぞれ自由な時間を楽しみ、最後の夕食も美味しくいただきました!
夜はサッカー観戦をしたり、帰るのがさみしくてついつい夜更かしをしてしまったり・・・

 

 

そんな感じで今年の社員研修旅行を終えました。

今回お世話になったホテルはこちらです↓
■ラフォーレ那須

http://www.laforet.co.jp/nasu/

社員旅行を熟知したスタッフさんに付いていただき、楽しく過ごすことができました!ありがとうございました!

今のところ2年に一度の社員研修旅行ですが、毎年行きたいなーと思う広報でした。

 

最後まで読んでくだり、ありがとうございました!

[UE4]アニメーション系アセットの設定項目「MetaData」について

$
0
0

エンジニアの山中です。
今回はUE4を使用する上で気になっていた
アニメーション系アセットのとある設定項目について調べてみました。

 

●はじめに

とある設定項目とはズバリ「MetaData」です。
「AnimationSequence」や「AnimationMontage」等に存在しています。


画像:設定項目「MetaData」の場所。画面左下の赤い枠で囲っている場所。

※ややこしいですが、列挙の定義時に使用する「UMETA()」や
UPROPERTYに付与する「meta =」のことではないので注意!
また、アニメーション系アセットと書いていますが「AnimationBlueprint」には無いので注意!

どういった目的で作成された項目なのか調べてみましょう。

 

●調査(エンジンバージョン「4.19」)

「MetaData」では項目内の「+」から配列の要素を追加でき、その際にクラスの指定を要求されます。
デフォルトでは選択可能なクラスは存在していません。
どういったクラスが指定可能なのか、設定項目が定義されているソースを見てみます。

/** Meta data that can be saved with the asset 
* 
* You can query by GetMetaData function
*/
UPROPERTY(Category=MetaData, instanced, EditAnywhere)
TArray<class UAnimMetaData*> MetaData;

どうやら「UAnimMetaData」というクラスのみ指定可能なようです。
そして、変数定義のコメントには以下のように書かれてあります。

「GetMetaData関数によって取得することができる、アセットに保存されるメタデータです」

 

●結論

用途としては、アニメーション系アセットに情報を持たせたい時に使用するもののようです。
※以下のドキュメントURLに、対応アセット等の詳細が記載されています
アニメーションモンタージュを編集する

 

●補足

ここで揃えて覚えておきたいのが、以前弊社のブログでも紹介していた「AssetUserData」という設定項目です。
※過去の記事:「[UE4] Asset User Data とは?

「SkeletalMesh」「Texture」等の他、今回挙げているアニメーション系アセットにも存在しています。
機能的には類似しているようですが「MetaData」と「AssetUserData」、どのように使い分けるべきなのでしょうか?

リリースノートを見る限りだと、「MetaData」が追加されたのが「UE4.9」、
「AssetUserData」がアニメーションアセットに追加されたのが「UE4.12」のようです。
元々アニメーションを対象とした、情報を付与できる機能を追加していたが
後に別機能によって他のアセットにも対応するようになり、アニメーション系アセットも共通化するようになったと考えられます。
(違いが明記されている情報が無かった為、憶測になります。)
※「UE4.9リリースノート」「UE4.12リリースノート

使い分けに関してですが、それぞれメリットデメリットがあります。

MetaData AssetUserData
メリット ・設定箇所がアニメーション系アセットに限られる為、
他のアセット内で使用される心配がない
・現状「AssetUserData」が対応していない
「AnimMontageSection」にも使用可能
・アセットの種類に関係無く使用可能なので、
ほとんどのアセットで情報付与の手段が共通化できる
・今後も対応アセットが増えていく可能性がある
デメリット ・情報付与の際はルール決めを行わないと
「MetaData」と「AssetUserData」が
混在する恐れがある
・クラス指定時に、作成した分だけリスト化される為
見づらくなる

それぞれの特徴を踏まえた上で使い勝手の良い方を、
また用途に適した方を選択していくのが良さそうです。

 

●MetaDataを使用した、アセットへの情報の追加方法

大まかな流れはほとんど「AssetUserData」と変わらないのですが、
「UAnimMetaData」クラスはBlueprintableなので
直接Blueprintから継承先を選択可能です。(「AssetUserData」のように、C++に基底クラスを作成する必要がありません)


画像:基底クラスの指定と変数の宣言


画像:アニメーションアセットに情報を付与

しかし、メタデータの取得に関しては「AssetUserData」同様、BPからはアクセス不可なので
C++で定義したBlueprintFunctionLibrary等から、アニメーションアセットを引数に
メタデータを取得するような関数を作成する必要があります。

// Fill out your copyright notice in the Description page of Project Settings.

#include "Kismet/BlueprintFunctionLibrary.h"
#include "MyBlueprintFunctionLibrary.generated.h"

UCLASS()
class UMyBlueprintFunctionLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()

public:
UFUNCTION(BlueprintCallable)
static void GetAllAnimMetaData(class UAnimationAsset* TargetAnimation, TArray<UAnimMetaData*> OutAssetUserData);
};

// Fill out your copyright notice in the Description page of Project Settings.

#include "MyBlueprintFunctionLibrary.h"
#include "Animation/AnimationAsset.h"
#include "MyAnimMetaData.h"

void UMyBlueprintFunctionLibrary::GetAllAnimMetaData(class UAnimationAsset* TargetAnimation, TArray<UAnimMetaData*> OutAssetUserData)
{
if (!TargetAnimation) return;

OutAssetUserData = TargetAnimation->GetMetaData();
}


画像:情報を取得する

 

●さいごに

今回はアニメーションアセット系に存在している設定項目「MetaData」について調べてみました。
「UserAssetData」とセットで覚えておくと、役に立つこともあるかと思います。

[UE4] 実はこんなにある!ブックマーク・お気に入り系機能について

$
0
0

今回は、ブックマーク・お気に入り系機能を複数まとめて紹介したいと思います。

現在の正式リリース版には入っていない新機能も紹介したいので、UE 4.20 preview 5 で検証しています。

Blueprint のブックマーク機能

UE 4.20 に実装予定の新機能です。登録したブックマークを選択することで、特定の Event Graph の特定の位置に飛ぶことができるというものです。

ブックマークの登録を行うには、Blueprint の EventGraph の左上にある星ボタンをクリックします。ブックマーク名を入力し、Add ボタンを押せば登録完了です。登録時点での Event Graph・位置・ズームの値がブックマークに記録されます。

登録したブックマークは、メニュー → Window → Bookmarks を選択することで表示される Bookmarks パネルにて閲覧できます。Bookmarks パネル上のブックマークをダブルクリックすることで、記録された位置に飛ぶことができます。

ブックマークの対象となるのはあくまで Event Graph 上の『位置』であって、『ノード』ではない点に注意してください。近辺にあるノードを移動しても飛ぶ位置が追従したりはしません。

また、Bookmarks パネルには配置されているコメントノードも一覧表示されます。ブックマークと同様に、コメントノード名をダブルクリックすることでその位置に飛ぶことができます。こちらは『ノード』を対象とする機能なので、コメントノードの位置を変更してもノードの位置に飛んでくれます。

Bookmarks パネル右上の目玉アイコンをクリックすると、表示設定を変更することができます。各項目の内容は以下のとおりです。

・Show Comment Blocks
オフにするとコメントノードの一覧が表示されなくなります。

・Show Bookmarks for Current Graph Only
オンにすると、現在アクティブなタブ上で表示している Event Graph に紐付いたブックマークのみが表示されるようになります。

なお、最近配信された Epic Games Japan 様の Unreal Japan Stream でもこの機能が紹介されています (1:08:10 ~)。

Unreal Japan Stream | UE4.20で入る新機能の一部をご紹介! – YouTube

Blueprint Node のお気に入り機能

Blueprint の Node をお気に入り登録して見つけやすくする機能です。

お気に入りの登録は、Blueprint Node の Context Menu にて、ノード名の左側にある星ボタンをクリックすることで行うことができます。

お気に入りの一覧は Context Menu 上部に表示されます。もし表示されない場合は、以下の設定を確認してください。

・Editor Preference → Content Editors → Blueprint Editor → Workflow → Context Menu: Show Favorites Section
オンにしないとお気に入り一覧が表示されません。

・Editor Preference → Content Editors → Blueprint Editor → Workflow → Flatten Favorites Menus
オフだと他のカテゴリと同様に、最初は『Favorites』カテゴリとして折り畳まれた状態で表示されます。
上の画像のように最初から展開された状態で表示したい場合はオンにしてください。

Material Node のお気に入り機能

Material Node にもお気に入り機能があります。

お気に入りを登録するには、Node をクリックして Add to Favorites を選択します。

登録したお気に入りは Favorites カテゴリに表示されます。Blueprint Node のお気に入りのように上部に一覧表示する機能はなさそうなので、あまり使い勝手はよくないかもしれません…。

Level のお気に入り機能

Level Editor の メニュー → File → Favorite Levels にて、Level のお気に入り登録とオープンが可能です。

この機能をよく利用する場合は、登録した Level のオープン処理にショートカットキーを割り当てておくと便利かもしれません。Editor Preferences → General → Keyboard Shortcuts → Level Editor → Open Favorites File 《数字》 にて設定できます。

Viewport の視点位置のブックマーク機能

Level 毎に、Viewport における視点位置をブックマークすることができます。

ブックマークの登録は、Viewport Options (下向き三角形のボタン) → Bookmarks → Set Bookmark → Bookmark 《数字》 を選択して行います。ショートカットキー Ctrl + 《数字》 が標準で割り当てられています。

ブックマークした視点位置に切り替えるには、Viewport Options → Bookmarks → Jump to Bookmark 《数字》 を選択します。こちらにも、ショートカットキー 《数字》 が標準で割り当てられています。

特に広大なマップで作業を行う際に便利な機能です。

Details パネルのお気に入り機能

Details (詳細) パネルの項目をお気に入りとして登録し、パネル上部にまとめて表示する機能があります。

本ブログにて過去に紹介したことがある機能です。詳しくは以下の記事をご覧ください。

[UE4]地味に便利!パラメータの”お気に入り”機能|株式会社ヒストリア

Content Browser のお気に入り機能

Content Browser のフォルダもお気に入り登録することができます。

お気に入りを登録するには、フォルダ右クリック → Add To Favorites を選択します。
Content Browser 右下の View Options → Show Favorites にチェックを入れるとお気に入りフォルダ一覧が表示されるようになるので、そこから各フォルダにアクセスできます。
ファイル単体ではお気に入り登録できません。ファイル単位で登録を行いたい場合は、次に紹介する Content Browser の Collection 機能を利用してください。

Content Browser の Collection 機能

Content Browser にはお気に入り機能の他に Collection という機能も存在します。

所謂タグのような機能で、別の階層にあるファイルをまとめて閲覧することができます。「キャラクターの実装を進めるために Pawn の Blueprint、ActorComponent、AnimBP、DataTable など様々なファイルを編集する必要があるが、それぞれ入っているフォルダが別々で探しにくい」といった場合には、これらのファイルを同じ Collection にまとめておくと便利です。
こちらはお気に入り機能とは逆で、フォルダの登録はできません。

この機能も本ブログにて過去に紹介したことがある機能ですので、詳細は以下の記事をご覧ください。

[UE4]Collectionを活用して作業効率アップ!|株式会社ヒストリア

まとめ

ブックマーク・お気に入り系機能は、上手く活用すると作業効率を向上させることができます。

すべての機能を使いこなす必要はありませんので、便利そうだと思ったものから使ってみてください。


Unreal Engine 4作品コンテスト「第10回UE4ぷちコン」を8月5日(日)より開催決定!

$
0
0

この度、ヒストリアは第10回UE4ぷちコンを「2、3日でサクッと作ってサクッと応募」をコンセプトに開催します!

UE4ぷちコンとは、株式会社ヒストリアが主催するゲームエンジン「UnrealEngine4」の学習を目的とする一般参加型ゲームコンテストです。参加者は短期間(約1か月)でテーマに沿った作品を制作・投稿し、入賞を目指します。

本コンテストは「UE4の学習」を目的に行っています。学習目的なのでプロもアマチュアも関係ありません!気になっている皆さん、ぷちコンに応募してUE4を覚えちゃいましょう!

そして今回もファウンドリ様・MODO JAPAN GROUP様のご協賛により、9月30日まで使える3Dモデリングソフト「MODO」の無償ライセンス発行が決定いたしました!申し込みは本日より開始しておりますので、ぷちコンのテーマ発表がされる前にMODOを触ってぷちコンに備えよう!

MODOとは・・・
MODOは新たな次の段階へと進化した3Dモデリング、ペイント、レンダリングなどの機能を、MacおよびPC双方のプラットフォーム上へと、一つの統合環境としてご提供します。そしてさらに、3Dスカルプティングツール、アニメーション、そしてネットワークレンダリングを備える真に徹底したソリューションとなっています!それぞれがただ機能として存在しているだけではなく、MODOはテクノロジを見事に統合し、すばらしい処理能力、ワークフローの改善が施されています。

MODOお申込みはコチラから↓
http://modogroup.jp/regist/petit_con_10

また、8月4日(土)にはMODO未経験者・超初心者の方を対象に、MODOの基本操作+Unrealとのデータのやり取りなどをお伝えする「MODO無料体験プログラム ~Unrealユーザー向け」を開催致します!(主催:MODO JAPAN GROUP様)

MODO勉強会のお申込みはコチラから↓
http://modogroup.jp/events/16641.html

 

コンテストテーマ・開催概要は8月5日(日)に行われる「出張ヒストリア!ゲーム開発勉強会2018」内で発表いたします!お楽しみに!

※UE4ぷちコンはご協賛いただける企業様を募集しております。
詳細は下記よりお問い合わせください。
株式会社ヒストリア (info@historia.co.jp)

【告知サイト】 http://historia.co.jp/ue4petitcon10 (8月5日公開)
【主催】 株式会社ヒストリア
【共催】 エピック・ゲームズ・ジャパン
【協賛】FOUNDRY
MODO JAPAN GROUP

指定した点の全てを視界に収めるカメラの位置を計算することについて

$
0
0

0.概要

「複数のキャラクター全てをぴったり画面に収める」

個人的な経験から言うと、使いそうであんまり使わない、でも時々欲しくなることもある・・・そんな機能だと思います。

これを実現するため、カメラの配置について以下の要件を満たすことを考えます。
・カメラの向き及び視野角は予め決まっている
・空間内で任意の座標を持つポイントが複数与えられる
・画面内の端から指定した割合のエリアを除いた部分(以下”セーフフレーム”)に与えられた全てのポイントを含む
・可能な限り前に寄る(⇒セーフフレームの左右両方、または上下両方に与えられた点のいずれかが接する)

つまりこういうことです↓

明るい枠内に4つの球体がぴったり収まるようカメラの位置を制御しています。

 

ここでは気持ちよく、とか良い感じに、とかいった些末については無視して、
とにかくぴったり収めるためのロジックとその実装についてのみ触れます。

内容は数学・・・というか幾何学ですが、なるべく図を入れているので苦手な方でも雰囲気をつかめるかもしれません。
「ドット積(ベクトルの内積)」あたりを抑えていれば普通に読めると思います。
末尾にサンプルコードを添付していますが、これについてはC++を扱えることが必須です。

では解決していきましょう。

 

あ、演習問題としても悪くない内容だと思いますので、挑戦されたい方は答えを見る前に是非・・・!

 

1.理論編

説明がややこしくなるのでセーフフレームのことは一旦忘れます。

この手の問題の常として、まずは「視界内に全ての点が収まる」とはどういうことかを数式で表現できるように消化する必要があります。
とりあえず点が一つの場合を考えます。

視界内に点が収まる

カメラの位置から前方に広がる四角錐にその点が含まれる

四角錐を構成する全ての面に対して点が表側(ここでは四角錐の内側を面の表としました)に位置する

『全ての面について
dot(カメラの座標, 面の法線ベクトル) ≦ dot(点の座標, 面の法線ベクトル)
が満たされる
(dot(a, b) は ベクトル a, b のドット積)』・・・①

このように置き換えられます。

点が複数存在することを加味すると、

『全ての面について
dot(カメラの座標, 面の法線ベクトル) ≦ min(dot(点1の座標, 面の法線ベクトル), dot(点2の座標, 面の法線ベクトル), …)
が満たされる
(min(a,b,c,…) は スカラー値 a, b, c, … のうち最小の値)』・・・②

こうなります。

数式だけではよく分からないかもしれません。
確認の意味も込めて作図してみます。
視認性のために二次元から始めます(途中から三次元になります)。

カメラの向きと視野角が既知であることより、面の法線ベクトルは確定しています。
しかし、面の位置は分かりません。これから求めようとしているカメラの座標と連動するからです。

Fig. 01. 面の法線ベクトル

この面をAとします。
そこに、カメラに収めたい点を置きます。

Fig. 02. 面Aの法線ベクトルと点

 

ここにカメラを追加することを考えます。
①より
dot(カメラの座標, 面の法線ベクトル) ≦ dot(点の座標, 面の法線ベクトル)
を満たすカメラの座標は下図のように示されます。

Fig. 03. カメラを置けるエリア(水色部分)

点が増えるとどうなるでしょうか。
以下の条件を満たすエリアはどこでしょう。

②より
dot(カメラの座標, 面の法線ベクトル) ≦ min(dot(点1の座標, 面の法線ベクトル), dot(点2の座標, 面の法線ベクトル), …)

Fig. 04. カメラを置けるエリア(点が複数ある場合)

さらに、面Bを追加します。

Fig. 05. 面(B)を追加

面Bについて条件を満たすエリアは下図のようになります。
(この形だと、画像のなんとなく上方がカメラの正面方向ということになります。)

Fig. 06. カメラを置けるエリア(面Bについて・水色部分)

カメラは全ての面について条件を満たす位置に置かれなくてはなりません。
つまり、Fig.05.とFig.06.の水色の重なる部分ということになります。

Fig. 07. カメラを置けるエリア(濃い水色部分)

上記のように、二辺に挟まれたエリアが該当することになります。
三次元的に考えた場合、二辺ではなく二面に挟まれたボリュームとなります。
図示が難しくなってきますが、下のような感じです。
(波線の部分は無限に続くべきところを省略したものとして見て下さい)

Fig. 08. カメラを置けるエリアの形状(面A、面Bを考慮)

Fig.08.の水色部分はFig.07.の濃い水色部分に該当します。
残りの2面をも考慮に入れると下図のようになります。

Fig. 09. カメラを置けるエリアの形状(4面を考慮)

点が画面の左右端に接する場合と上下端に接する場合とで先端の形状に違いが出ます。
やはり先端の辺上が最もカメラを寄せた位置ということになります。
そしてこの辺は、左右および上下の面のみを考慮した場合の最寄り配置(カメラにとって縦と横に伸びる無限直線)のうち、より後方に位置するものの一部です。

点群の画面への収まり方をなるべく偏らせたくないという条件を加味すると、カメラを配置すべき位置を絞り込むことができます。
右や左に点が偏らないように配置すべきと考えると、最も寄った(左右いっぱいに使う)配置を表す辺から真っすぐ後方に引いた位置の集合が一つの候補になるでしょう。
図にすると以下のようになります。

Fig. 10. だいたい左右均等に点群を収められるカメラ位置

上下の面についても同様の手順で平面(こんどは水平になります)が決まり、これらの交わる範囲がカメラの配置先ということになります。

Fig. 11. 最終的なカメラの配置範囲

その交わる範囲はFig.11.に青く示したようにカメラの後方に伸びる半直線になります。
できるだけ被写体に寄せるという条件であれば、前方の端点が解ということになります。

最後にセーフフレームについてですが、
射影後の画面内にて端を除外するということは視野角を狭めるということと同じであるため、特別なロジックを必要としません。
ここまで視野角としていた部分をセーフフレームの分狭めた値に置き換えるのみでOKです。

大雑把な理論についてはここまでで完成です。

2.実装編(ソースコードとコメント)

原理について書いてしまったのでここで語ることはとくにありません。
補助程度にコメントを付けてありますので一助になればと思います。

ノリでいくつか要素を追加していますが、基本的な理屈は1.で説明した通りですので流したり解析したりしてみてください。
UE4向けのコードとして書いてありますが、数学系の補助関数を用いている程度ですので少し改修をすれば任意の環境で通じるはずです。

アプリケーション的な部分は含めず、単に座標を返す関数の定義に留めています。

// Pointsで与えられた座標群をNormal軸へ射影した結果のうち最小のものを取得します(ついでに大きさを考慮したオフセットを行います)。
float GetMinProjection(FVector Normal, const TArray &Points, const TArray &Sizes)
{
	float Retval = MAX_FLT;

	for (int i = 0; i < Points.Num(); ++i)
	{
		Retval = FMath::Min(Retval, FVector::DotProduct(Points[i], Normal) - Sizes[i]);
	}

	return Retval;
}

// ターゲットの位置・大きさおよびカメラの向きから最適なカメラの位置を決定
FVector CalcCameraLocationByTargetPoints(const TArray &Points, const TArray &Sizes, const FRotator CameraRotation, const float FovXDegrees, const float AspectRatio, const float FovLeftMargin, const float FovRightMargin, const float FovBottomMargin, const float FovTopMargin)
{
	const float HalfFov_X = FMath::DegreesToRadians(FovXDegrees*0.5f);

	const float HalfTanX = FMath::Tan(HalfFov_X);
	const float HalfTanY = HalfTanX / AspectRatio;

	// 非対称なセーフフレームをサポート
	// セーフフレームの視野角を上下左右について求めます
	const float HalfFovLeft = FMath::Atan(HalfTanX * (1.0f - FovLeftMargin * 2.0f));
	const float HalfFovRight = FMath::Atan(HalfTanX * (1.0f - FovRightMargin * 2.0f));
	const float HalfFovBottom = FMath::Atan(HalfTanY * (1.0f - FovBottomMargin * 2.0f));
	const float HalfFovTop = FMath::Atan(HalfTanY * (1.0f - FovTopMargin * 2.0f));

	const float HalfFovLeftDeg = FMath::RadiansToDegrees(HalfFovLeft);
	const float HalfFovRightDeg = FMath::RadiansToDegrees(HalfFovRight);
	const float HalfFovBottomDeg = FMath::RadiansToDegrees(HalfFovBottom);
	const float HalfFovTopDeg = FMath::RadiansToDegrees(HalfFovTop);

	// 座標軸をカメラのそれと平行にすることで計算を簡略化できます。
	// 原点はそのまま、回転のみ合わせます
	// カメラの座標が原点ではないことに注意。
	TArray PointsCS;
	PointsCS.SetNum(Points.Num());

	for (int i = 0; i < Points.Num(); ++i)
	{
		PointsCS[i] = CameraRotation.UnrotateVector(Points[i]);
	}

	// ここに計算結果を格納します
	FVector CameraLocationCS;


	// 左右の面による拘束
	float XbyLR;
	float Dydx;
	{
		// カメラと平行な座標系では、XY平面上で計算できます
		const FVector LeftBoundNormalCS = FVector::RightVector.RotateAngleAxis(-HalfFovLeftDeg, FVector::UpVector);
		const float LeftBoundPosCS = GetMinProjection(LeftBoundNormalCS, PointsCS, Sizes);

		const FVector RightBoundNormalCS = -FVector::RightVector.RotateAngleAxis(HalfFovRightDeg, FVector::UpVector);
		const float RightBoundPosCS = GetMinProjection(RightBoundNormalCS, PointsCS, Sizes);

		// 連立方程式を解きます。
		// Q は XY平面上に射影した左右の面の交点です
		// dot(Q, LeftBoundNormalCS) = LeftBoundPosCS
		// dot(Q, RightBoundNormalCS) = RightBoundPosCS
		// 
		// 整理して以下の式を得られます
		const float QX = (RightBoundNormalCS.Y*LeftBoundPosCS - LeftBoundNormalCS.Y*RightBoundPosCS) / (LeftBoundNormalCS.X*RightBoundNormalCS.Y - LeftBoundNormalCS.Y*RightBoundNormalCS.X);
		const float QY = (LeftBoundPosCS - QX * LeftBoundNormalCS.X) / LeftBoundNormalCS.Y;

		// 一時的に解を格納します。
		// Xは一時的な値で、上下の面の条件から得られる値との比較が必要です。
		// Yはこれで決まりです。
		// Zは上下面の条件を調べるまで分かりません。
		XbyLR = QX;
		CameraLocationCS.Y = QY;

		// Xに対するYの変化量(セーフフレーム非対称性への対処)を保存します
		Dydx = HalfTanX * (FovLeftMargin - FovRightMargin);
	}

	// 上下の面による拘束
	float XbyTB;
	float Dzdx;
	{
		// XZ平面上で計算できます
		const FVector BottomBoundNormalCS = FVector::UpVector.RotateAngleAxis(-HalfFovBottomDeg, -FVector::RightVector);
		const float BottomBoundPosCS = GetMinProjection(BottomBoundNormalCS, PointsCS, Sizes);

		const FVector TopBoundNormalCS = -FVector::UpVector.RotateAngleAxis(HalfFovTopDeg, -FVector::RightVector);
		const float TopBoundPosCS = GetMinProjection(TopBoundNormalCS, PointsCS, Sizes);

		// 左右面のときと同様です。
		const float QX = (TopBoundNormalCS.Z*BottomBoundPosCS - BottomBoundNormalCS.Z*TopBoundPosCS) / (BottomBoundNormalCS.X*TopBoundNormalCS.Z - BottomBoundNormalCS.Z*TopBoundNormalCS.X);
		const float QZ = (BottomBoundPosCS - QX * BottomBoundNormalCS.X) / BottomBoundNormalCS.Z;

		// 左右、上下の条件から得たXのうち小さい方(より後ろへ引いた方)が求める値です。
		XbyTB = QX;
		CameraLocationCS.Z = QZ;

		// Xに対するZの変化量(セーフフレーム非対称性への対処)を保存します
		Dzdx = HalfTanY * (FovBottomMargin - FovTopMargin);
	}

	CameraLocationCS.X = FMath::Min(XbyLR, XbyTB);
	CameraLocationCS.Y += (Dydx * (CameraLocationCS.X - XbyLR));
	CameraLocationCS.Z += (Dzdx * (CameraLocationCS.X - XbyTB));

	// World座標に復元して返します
	return CameraRotation.RotateVector(CameraLocationCS);
}

 

3.まとめ

向きの予め決められたカメラを、複数の任意の点を画面内に収めるよう配置する方法について一つの考え方を示しました。

 

 

以上です。

[UE4] コンテンツブラウザからレベルブループリントを編集する方法

$
0
0

レベルブループリントはレベル全体に渡るグローバルな処理を記述できるブループリントとなっています。
そのため、通常のブループリントとは一部の機能が異なっていたり、ブループリントエディタの開き方も通常のブループリントとは異なります。
公式のレベルブループリントドキュメントはこちら

BPエディタの開き方

通常のブループリントの開き方は
・コンテンツブラウザでアセットをダブルクリック
・右クリックのメニューからEdit
・Toolbar->Blueprints->Open Blueprint Class…で開く
・File->Open Asset…(ctrl+p)で選択
などでブループリントエディタを開くことができますが、レベルブループリントは上記の方法で開くとエディタを開くのではなく、そのレベルを読み込んでレベルの編集を行おうとします。
Open Blueprint Class…には候補としても現れません。

レベルプループリントを開くには、現在開いているレベルなら
Toolbar->Blueprints->Open Level Blueprint
サブレベルに設定していれば、
Toolbar->Blueprints->Sub-Levels
から開けます。

もしくはLevelsウィンドウのコントローラーマークをクリックしても開けます。

この記事ですること

レベルブループリントのエディタを開くためには前述の通りの方法を取りますが、該当のレベルを開いてPersistent Levelに設定する必要があり、ただレベルブループリントを開きたいだけだとしても開発の規模が大きくなってくると読み込みに非常に多くの時間がかかってしまいます。
読み込み時間を最小限にするために、空のマップを開いて、レベルブループリントのみ編集するといった方針は取れません。
そこで今回はPersistentでもSubでもないレベルをコンテンツブラウザのLevelアセットを右クリックしてレベルブループリントを開けるようにしてしまおうという内容です。
C++によるプラグインでの実装になるので、C++はどうでもいいよという方はこちらでプラグインを配布しています。

プラグインの作成準備

Edit->PluginsからPluginsウィンドウを開き、右下のNew Pluginをクリックします。

テンプレートの中のBlankを選択し、プラグインの名称を決めてCreatePluginを行います。説明のためここではHogeと名付けます。
配布プラグインはAddOpenLevelBlueprintMenuPluginと長くなってしまったのでどうかいい名前をつけてください。

CreatePluginをおして、しばらく待つとプラグインのコードがテキストエディタで開きます。

プラグイン作成

プラグイン名.upluginを開いてModuleのTypeを”Developer”から”Editor”に変更します。

{
	"FileVersion": 3,
	"Version": 1,
	"VersionName": "1.0",
	"FriendlyName": "Hoge",
	"Description": "",
	"Category": "Other",
	"CreatedBy": "",
	"CreatedByURL": "",
	"DocsURL": "",
	"MarketplaceURL": "",
	"SupportURL": "",
	"CanContainContent": true,
	"IsBetaVersion": false,
	"Installed": false,
	"Modules": [
		{
			"Name": "Hoge",
			"Type": "Editor",
			"LoadingPhase": "Default"
		}
	]
}

次にBuild.csを開き、PrivateDependencyModuleNamesに”UnrealEd”を追加します。

PrivateDependencyModuleNames.AddRange(
	new string[]
	{
		"CoreUObject",
		"Engine",
		"Slate",
		"SlateCore",
                "UnrealEd",
		// ... add private dependencies that you statically link with here ...	
	}
	);

次にヘッダーを開き関数を追加します。

class FHogeModule : public IModuleInterface
{
public:

	/** IModuleInterface implementation */
	virtual void StartupModule() override;
	virtual void ShutdownModule() override;

private:
	static TSharedRef&lt;FExtender&gt; OnExtendContentBrowserAssetSelectionMenu(const TArray&lt;FAssetData&gt;&amp; SelectedAssets);
	static void CreateAssetMenu(FMenuBuilder&amp; MenuBuilder, TArray&lt;FAssetData&gt; SelectedAssets);
	static void OpenLevelBlueprint(TArray&lt;FAssetData&gt; SelectedAssets);
};

最後にc++の実装です

#include "Hoge.h"

#include "Engine/World.h"
#include "LevelEditor.h"
#include "ContentBrowserModule.h"
#include "IContentBrowserSingleton.h"
#include "Misc/MessageDialog.h"
#include "Engine/LevelScriptBlueprint.h"
#include "Toolkits/AssetEditorManager.h"

#define LOCTEXT_NAMESPACE "FHogeModule"

namespace
{
	FContentBrowserMenuExtender_SelectedAssets ContentBrowserExtenderDelegate;
	FDelegateHandle ContentBrowserExtenderDelegateHandle;
}

void FHogeModule::StartupModule()
{
	if (IsRunningCommandlet()) { return; }

	FContentBrowserModule&amp; ContentBrowserModule =
		FModuleManager::LoadModuleChecked&lt;FContentBrowserModule&gt;(TEXT("ContentBrowser"));

	// アセット右クリックメニューへのExtender登録 
	ContentBrowserExtenderDelegate =
		FContentBrowserMenuExtender_SelectedAssets::CreateStatic(
			&amp;FHogeModule::OnExtendContentBrowserAssetSelectionMenu
		);
	TArray&lt;FContentBrowserMenuExtender_SelectedAssets&gt;&amp; CBMenuExtenderDelegates =
		ContentBrowserModule.GetAllAssetViewContextMenuExtenders();
	CBMenuExtenderDelegates.Add(ContentBrowserExtenderDelegate);
	ContentBrowserExtenderDelegateHandle = CBMenuExtenderDelegates.Last().GetHandle();
}

void FHogeModule::ShutdownModule()
{
	FContentBrowserModule* ContentBrowserModule =
		FModuleManager::GetModulePtr&lt;FContentBrowserModule&gt;(TEXT("ContentBrowser"));
	if (nullptr != ContentBrowserModule)
	{
		TArray&lt;FContentBrowserMenuExtender_SelectedAssets&gt;&amp; CBMenuExtenderDelegates =
			ContentBrowserModule-&gt;GetAllAssetViewContextMenuExtenders();
		CBMenuExtenderDelegates.RemoveAll([](const FContentBrowserMenuExtender_SelectedAssets&amp; Delegate)
		{ return Delegate.GetHandle() == ContentBrowserExtenderDelegateHandle; });
	}
}

TSharedRef&lt;FExtender&gt; FHogeModule::OnExtendContentBrowserAssetSelectionMenu(const TArray&lt;FAssetData&gt;&amp; SelectedAssets)
{
	TSharedRef&lt;FExtender&gt; Extender(new FExtender());

	for (auto ItAsset = SelectedAssets.CreateConstIterator(); ItAsset; ++ItAsset)
	{
		if ((*ItAsset).AssetClass == UWorld::StaticClass()-&gt;GetFName())
		{
			Extender-&gt;AddMenuExtension(
				TEXT("CommonAssetActions"),
				EExtensionHook::First,
				nullptr,
				FMenuExtensionDelegate::CreateStatic(&amp;FHogeModule::CreateAssetMenu, SelectedAssets)
			);
			return Extender;
		}
	}

	return Extender;
}

void FHogeModule::CreateAssetMenu(FMenuBuilder&amp; MenuBuilder, TArray&lt;FAssetData&gt; SelectedAssets)
{
	int count = 0;
	for (auto ItAsset = SelectedAssets.CreateConstIterator(); ItAsset; ++ItAsset)
	{
		if ((*ItAsset).AssetClass == UWorld::StaticClass()-&gt;GetFName())
		{
			count++;
		}
	}

	FText toolTip = count == 1 ? LOCTEXT("Open Level Blueprint", "Open Level Blueprint") : LOCTEXT("Open Level Blueprints", "Open Level Blueprints");

	MenuBuilder.AddMenuEntry(
		toolTip,
		LOCTEXT("OpenLevelBlueprint_Tooltip", "Open Level Blueprint. Note: This is unofficial"),
		FSlateIcon(),
		FUIAction(FExecuteAction::CreateStatic(&amp;FHogeModule::OpenLevelBlueprint, SelectedAssets)),
		NAME_None,
		EUserInterfaceActionType::Button
	);
}

void FHogeModule::OpenLevelBlueprint(TArray&lt;FAssetData&gt; SelectedAssets)
{
	for (auto ItAsset = SelectedAssets.CreateConstIterator(); ItAsset; ++ItAsset)
	{
		UWorld* world = Cast&lt;UWorld&gt;((*ItAsset).GetAsset());
		if (!world)
		{
			continue;
		}

		ULevel* level = world-&gt;GetCurrentLevel();
		if (level == NULL)
		{
			return;
		}

		ULevelScriptBlueprint* LevelScriptBlueprint = level-&gt;GetLevelScriptBlueprint();
		if (LevelScriptBlueprint)
		{
			FAssetEditorManager::Get().OpenEditorForAsset(LevelScriptBlueprint);
		}
		else
		{
			FMessageDialog::Open(EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "UnableToCreateLevelScript", "Unable to find or create a level blueprint for this level."));
		}
	}
}

#undef LOCTEXT_NAMESPACE
	
IMPLEMENT_MODULE(FHogeModule, Hoge)

以上でレベルを右クリックした時にメニューに追加されました。

コードの内容について

エディタ実行時にのみ読み込ませるため、upluginではtypeにEditorを記述しました。
また、UnrealEdモジュールを使用しているため、Build.csにはUnrealEdを追加しています。
コードの流れとしては、アセットを右クリックした時にUWorldクラスのアセットだったら右クリックメニューの中にFHogeModule::OpenLevelBlueprint()を実行するメニューを追加するというものです。
ブループリントエディタを開くのにはFAssetEditorManager::Get().OpenEditorForAsset()を使用しています。
右クリックして選択したアセットはUWorldとなっているのでブループリントの本体ではありません。
FHogeModule::OpenLevelBlueprint()関数内で右クリックして選択したSelectedAssetsから->GetCurrentLevel()->GetLevelScriptBlueprint()としてブループリントを取得し、OpenEditorForAsset()に投げています。

おまけ メニューアイコンの追加

今回実装したOpen Level Blueprintにはアイコンが付いていないのでこのアイコンを付けてみます。

Build.csにEditorStyleを追加します。

PrivateDependencyModuleNames.AddRange(
	new string[]
	{
		"CoreUObject",
		"Engine",
		"Slate",
		"SlateCore",
                "UnrealEd",
                "EditorStyle",
		// ... add private dependencies that you statically link with here ...	
	}
	);

FHogeModule::CreateAssetMenu()内のMenuBuilder.AddMenuEntry()でFSlateIcon()の引数を変更します。

void FHogeModule::CreateAssetMenu(FMenuBuilder&amp; MenuBuilder, TArray&lt;FAssetData&gt; SelectedAssets)
{
	int count = 0;
	for (auto ItAsset = SelectedAssets.CreateConstIterator(); ItAsset; ++ItAsset)
	{
		if ((*ItAsset).AssetClass == UWorld::StaticClass()-&gt;GetFName())
		{
			count++;
		}
	}

	FText toolTip = count == 1 ? LOCTEXT("Open Level Blueprint", "Open Level Blueprint") : LOCTEXT("Open Level Blueprints", "Open Level Blueprints");

	MenuBuilder.AddMenuEntry(
		toolTip,
		LOCTEXT("OpenLevelBlueprint_Tooltip", "Open Level Blueprint. Note: This is unofficial"),
		FSlateIcon(FEditorStyle::GetStyleSetName(), "Level.ScriptIcon16x"),
		FUIAction(FExecuteAction::CreateStatic(&amp;FHogeModule::OpenLevelBlueprint, SelectedAssets)),
		NAME_None,
		EUserInterfaceActionType::Button
	);
}

以上でアイコンが追加されました。

[UE4]レベル上でキューブマップをキャプチャし、テクスチャ化する

$
0
0
執筆バージョン: Unreal Engine 4.20

事前に作成した「キューブマップ」を用いた擬似的なリフレクション表現(=環境マップ)は、UE4になってからはほとんど使われることがなくなりましたが、

メッシュパーティクルに使用するUnlitのマテリアルなど、処理負荷などの都合からリフレクションが適用できないマテリアルに対しては、まだまだ有効なテクニックです。

今回は、レベル上でキューブマップをキャプチャし、テクスチャ化する手順をご紹介します。

 

①モードから、”Scene Capture Cube”をレベルに配置してください

※何もないシーンだとキャプチャ結果がわかりにくいのでカラーマン達で囲んでおきましょう

②コンテントブラウザ上で右クリック→「マテリアル・テクスチャ」→「キューブの描画ターゲット」を押下してください

③作成したRenderTargetを①で配置したScene Capture Cubeの”Texture Target”にアサインしてください

Scene Capture Cubeからキャプチャした光景がRender Targetに反映されています

④このままだとゲーム実行中もRender Targetが更新され続けてしまうので、イマイチ使いにくいです。

スタティックテクスチャ化することでキャプチャ画像を固定する事ができます。

これで通常のキューブマップと同じように取り扱う事ができます。

作成したキューブマップは、↓このようにマテリアル上で環境マップとして利用できます。

また、SkyLightに対してアサインする事で、実行時にSkyLightが自動で再キャプチャされる事でたまに起こる、ビューポートとインゲームでのアンビエント光の差異を無くす事ができます。

 

使いみち色々、ぜひお試しください!

夏季休暇のお知らせ

$
0
0

平素は格別のお引き立てをいただき、厚く御礼申し上げます。

誠に勝手ながら、弊社では8月13日(月)~8月15日(水)の3日間、夏季休暇のため休業とさせていただきます。
皆様にはご迷惑をおかけいたしますが、何卒ご了承いただきますようお願い申し上げます。

8月16日(木)より通常通りに営業いたします。
何卒よろしくお願い申し上げます。

コマンドから自動テストを実行してみる

$
0
0

今回はコマンドから自動テストを動かす方法について書きたいと思います。

UE4での自動テストのおさらい

自動テストツールの使い方・追加方法 については過去記事がありますのでこちらを参考にしてください。
自動テストツールの使い方
http://historia.co.jp/archives/689/
自動テストの追加方法
http://historia.co.jp/archives/698/

Blueprintでの実装

過去記事ではC++からの実装でしたが、Blueprintからもテストを作成することができます。
FunctionalTestを元にBlueprintを作ることにより
StartTestイベントノードからつなげることにより自動テストを開始することができます。


FinishTestノードでテストの結果を返せばテスト終了になります。
作成したBlueprintをレベルに配置→レベルを保存後SessionFrontend上のRefreshTestsボタンを押すとテストが追加されます。

 

コンソールから自動テスト

これらの手順ですとSessionFrontendから実行する必要がありましたが、
これから紹介するコマンドをコンソールから入力すると自動テストができます。
※エディタ上、ゲーム起動中でもコンソールから実行できます。

すべてのテストを実行

Automation RunAll

自動テストのリストアップ

Automation List

自動テスト名を調べるためにはこのコマンドで確認をしてください。

テスト名を指定して実行

Automation RunTests テスト名

テスト名をグループごとにつけておくと、グループごとにまとめてテストを行うことができます。
例として以下のようなテストがあった場合

System.Core.Math.Range
System.Core.Misc.Paths
System.Core.Misc.Algos

Automation RunTests System.Core.Misc
と実行すると

System.Core.Misc.Paths
System.Core.Misc.Algos

の2つのテストが実行されます。

複数指定する場合

;(セミコロン)で区切り追加することで複数のテストを追加可能です。

Automation RunTests Test01;RunTests Test02

テスト終了後にウィンドウを閉じる

テストが終了してもアプリは起動したままですので ;で区切りQuitコマンドを追加するとテスト終了後にアプリが終了します。

Automation RunTest テスト名;Quit

※OutputLogウィンド上で使用するとエディタが閉じるので注意

 

外部ツールから自動テストを実行する

-ExecCmds 引数を使用して起動時にコンソールコマンドを実行することができます。
これを使用するとJenkinsのような外部ツールから自動テストを実行することができます。


スタンドアローンでの実行する場合

UE4Editor.exe Project.uproject -ExecCmds=”Automation RunTests テスト名;Quit” -game

パッケージビルドの場合

Project.exe -ExecCmds=”Automation RunTests テスト名;Quit”

※スタンドアローンとパッケージビルドの違い
パフォーマンスチェックの場合はパッケージビルドを使用したほうが良いですが、パッケージビルドの場合は
必要なアセットのみしかロードできないため、コンテントブラウザで管理しているアセット・Blueprintを
すべてチェックするようなテストの場合はスタンドアローンで実行するほうが良い場合があります。

その他に知っておくと便利な追加コマンド

ログの出力ファイル名の指定

-log=outlog.txt

ウィンドウを表示せずに実行

-NullRHI

処理の単体テストを行う場合はこのコマンドを追加したほうが良いでしょう。

Jenkinsの場合 このコマンドを追加せずに起動するとマスターのジョブで動作させると
ウィンドウが表示されずにエラーが発生する場合があります。
スクリーンキャプチャを行うようなテストの場合はJenkinsのスレーブを作成して
別プロセスとして動作させることで自動テストをすることができます。
※今回、Jenkinsの動作している環境によりスレーブの設定が異なるためスレーブの設定方法については省略します。

自動テストはデフォルトでUE4に用意されてますので、それらを活用するのも良いかと思います。
定期的に自動テストを動作させ、問題の早期発見・早期解決につなげましょう!!

第10回UE4ぷちコン 協賛社ライセンス一覧

$
0
0

 

8月5日より開催しております「第10回UE4ぷちコン」ですが、今回もたくさんのスポンサー企業様にご協力いただいています。

こちらのページでは今回ご協賛いただいている企業様のソフトウェアライセンスをまとめました。

ぜひこの機会にさわってみてください!

 

ソフトウェア 企業名
【ぷちコン専用】
MODOソフトウェア(2018年9月30日まで有効)
MODOは新たな次の段階へと進化した3Dモデリング、ペイント、レンダリングなどの機能を、MacおよびPC双方のプラットフォーム上へと、一つの統合環境としてご提供します。そしてさらに、3Dスカルプティングツール、アニメーション、そしてネットワークレンダリングを備える真に徹底したソリューションとなっています!それぞれがただ機能として存在しているだけではなく、MODOはテクノロジを見事に統合し、すばらしい処理能力、ワークフローの改善が施されています。

【申し込みはこちら】

FOUNDRY
MODO Japan Group
FOUNDRYはエンターテイメント業界向けの高品質なビジュアルエフェクト、3Dコンテンツ制作用のソフトウェア開発を行っています。FOUNDRYのクリエイティブなソフトウェアは、アートとテクノロジーを融合させたビジュアル体験を創造する日本のアーティストの皆様をこれからも支援して参ります!

MODO JAPAN GROUPは、国内ユーザーの皆様にMODOを気持ちよくご利用いただける環境をご提供できるよう、MODO日本語プログラムのローカライズ開発をはじめ、テクニカル・カスタマーサポート、マーケティングおよび販売活動を行っております。

 【ぷちコン専用】
UE4開発用 IncrediBuild無償ライセンス (30名様限定)
IncrediBuild は様々な開発ツールを高速化するテクノロジーです。Unreal Engine 4におけるエンジンのビルドやシェーディングコンパイル、プロジェクトビルドを、社内のネットワークに既に繋がっているPCのCPUのアイドルタイムを利用することで、並列分散実行し、最大90%短縮します。IncrediBuildはUnreal Engine 4にインテグレートされているため、煩わしい設定作業は全く必要ありません。もちろん、高価なHPCを導入する事や、ソースコードの変更も必要ありません。

【申し込みはこちら】

インクレディビルドジャパン株式会社 IncrediBuildは、ソフトウェア・アクセレーション・テクノロジーを牽引するソリューション・プロバイダーです。IncrediBuildは現在20社のフォーチュン100企業を含む2,000社を超える企業や組織の10万を超えるユーザーにご利用いただいています。IncrediBuild の分散コンピューティング技術はコード・ビルド高速化の業界標準のソリューションです。

Wwise Starter License
完全なプラットフォームアクセスと、最大500個のサウンド。
小規模予算の制作にも、Wwiseエクスペリエンスの完全版を利用できます。

【お申込みはこちら】

audiokinetic株式会社 Audiokineticについて
革新的な技術と業界における長年の経験を礎に築き上げられたAudiokineticはゲームやメディア業界におけるインタラクティブオーディオ制作に新基準を打ち立てました。当社は、画期的な技術、卓越したサービス、革新的なワークフローを含めたノウハウを業界と共有することに力を注いでいます。

Wwiseをリリースして以来、Audiokineticはオーディオ制作の統合されたアプローチを提供することにより、従来のオーディオおよびサウンドエンジン開発を革新させて来ました。Wwise®やSoundSeed®を含む弊社の製品は、サウンドデザイナーやオーディオプログラマーに、真に洗練されたオーディオを制作するための包括的なオーディオパイプラインソリューションを提供します。

CRI ADX2 LE 「ADX2 LE」は、ゲームならではのサウンド演出を手軽に実現する、便利な機能を数多く搭載したサウンドミドルウェアです。最先端のゲームサウンド制作現場でのニーズやノウハウが反映されており、高度なサウンド演出から細かい音の調整まで、全てがグラフィカルなツール上で直感的に行えます。

【申し込みはこちら】

 株式会社CRI・ミドルウェア CRI・ミドルウェアは、4,000以上のタイトルに採用されているゲーム開発向けミドルウェア製品群「CRIWARE」を提供しています。
各種ゲーム機、スマートフォン、VRデバイスだけでなく、ブラウザにも対応したサウンドミドルウェア「CRI ADX2」、ムービーミドルウェア「CRI Sofdec2」で、ゲーム開発を強力に支援します。

 


UE4ぷちコン ゲームジャム開催のお知らせ

$
0
0

8月5日(日)~9月17日(月)にUnreal Engine 4作品コンテスト 第10回UE4ぷちコン を開催いたします!

過去9回にわたって開催いたしました「UE4ぷちコン」ですが、おかげさまで回数を重ねるごとに応募作品も増え、UE4ユーザーが着々と増えていることを実感しております。
そして、前回初めて開催をし好評だった「ぷちコンゲームジャム」を今回も開催することとなりました。本イベントでは、即興で数人のチームを組み、2日間かけてぷちコン用ゲームを制作いたします。
コンテストに初めて参加する方、常連の方、どなた様もぜひご参加ください!

参加費無料!夕食付き!

 

お申込みはコチラからどうぞ!※先着20名

【9/1-9/2(土・日)】第10回UE4ぷちコン ゲームジャム

 

スケジュール

9月1日(土)

時間 内容
10:30-11:00 集合(弊社セミナー室)
11:00-11:30 ゲームジャム概要説明・会社設備説明
11:30-18:30 ゲーム制作(休憩は各自自由)
18:30-20:00 夕食(弊社社内) ※弊社でご用意いたします。

9月2日(日)

時間 内容
10:30-11:00 集合(弊社セミナー室)
11:00-17:00 ゲーム制作(休憩は各自自由)
17:00-18:30 ゲーム発表会
18:30-20:00 夕食(弊社社内) ※弊社でご用意いたします。

場所

株式会社ヒストリア 内 セミナールーム
住所: 〒141-0032
東京都品川区大崎5-6-2 都五反田ビル西館8階

持ち物

  • PCは弊社でも用意いたします。(先着12名)ご自身のPCをお持ち込みいただいても構いません。
  • その他ゲーム制作に必要になりそうなもの
    (Oculus Rift/touch、HTC Vive、ゲームパッド等は弊社にもご用意はございますが、数に限りがございます。ご用意いただける方はぜひお持ちください)

注意事項

  • 自動車、自転車でのご来場は出来る限りご遠慮ください。会場は駐輪場・駐車場のご用意はしておりません。ご利用の場合は、公共の施設をご利用ください。
  • 会場内は禁煙となっております。喫煙の際は喫煙所をご利用ください。
  • 休憩・昼食は各自合間を見てお取りください。会場内は飲食可能ですが、会場を汚す可能性のあるもの・刺激臭のあるものの持ち込み、出前の発注はご遠慮ください。
  • 弊社以外のフロアへの立ち入りはご遠慮ください。
  • 開場時間(10:30)より前は会場に立ち入ることができません。
  • 20:00以降の会場への居残りは原則として受け付けておりません。

第10回UE4ぷちコン 開催概要

http://historia.co.jp/ue4petitcon10

運営

株式会社ヒストリア ( Twitter公式アカウント )

 

Seuratで3Dシーンを単純化する

$
0
0
執筆バージョン: Unreal Engine 4.19

こんにちは。アシスタントエンジニアの小倉です。

今回はUE4でも使えるVRシーン単純化ツールの紹介をします。
このツールを使うと、次のような3Dシーンを、1つのメッシュと1つのポストプロセスボリュームだけで実現できます。

Seuratについて

SeuratとはGoogleが4月にオープンソース化した、主にモバイルVRを想定したVRシーン単純化ツールです。

VRシーンではとり得る視点の領域が限られていますが、実際には表示されないメッシュも配置されています。このツールでは、限られた視点の領域から、実際に表示される部分のメッシュを(なるべく見た目を変えずに)再構築することで、表示されないメッシュを減らし、シーンを単純化します。

Seuratの詳細については、公式ブログを参照ください。

Seurat Unreal Pluginを導入する

Seuratによるメッシュの再構築は、複数の視点におけるシーンのキャプチャ画像を用います。UE4ではSeurat Unreal Pluginを用いることで、キャプチャ画像を作成します。

プラグインを使用するために、まずここからプラグインをダウンロードし、Pluginsフォルダをプロジェクトフォルダ内に配置します。

UE4で使用するために、コードを変更します。まず、Seurat.Build.csのコンストラクタに、PCHUsageを追加します。

using UnrealBuildTool;
public class Seurat : ModuleRules
{
    public Seurat(ReadOnlyTargetRules Target) : base(Target)
    {
        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; // <= Add
        PublicIncludePaths.AddRange(new string[] {
            "Seurat/Public"
            // ... add public include paths required here ...
        }
    );
    // ~ 省略 ~

次に、プロジェクトの.uprojectのPluginsにSeuratを追加します。

{
    "FileVersion": 3,
    "EngineAssociation": "4.19",
    "Category": "",
    "Description": "",
    "Modules": [
        {
            "Name": "BlogTest419",
            "Type": "Runtime",
            "LoadingPhase": "Default"
        }
    ],
    "Plugins": [
        {
            "Name": "Seurat",
            "Enabled": true
        }
    ]
}

コード変更後、プロジェクトをビルドして起動するとプラグインが有効になっています。

次に、キャプチャ用に設定を変更します。[Project Settings][Rendering]を開き、以下の項目のチェックを外します。

  • Separate Translucency
  • Bloom
  • Ambient Occlusion
  • AutoExposure

次に、レベルに配置されているDirectional Light選択して次の項目を変更します。

  • Intensityを0に変更
  • Cast Shadowを無効化

次に、Scene Capture Seuratアクターをレベル配置し、Detailsパネルでキャプチャ設定を行います。

プロパティについて紹介します。

プロパティ名 詳細 今回の設定値
Location アクターの座標です。この座標がHeadboxの中心になります。 (10, 40, 170)
Headbox Size VRゴーグルをつけたときのとり得る視点の領域です。Headbox内には、表示するメッシュを含まないようにする必要があります。 (150, 150, 100)
Sample Per Face 1面あたりのキャプチャ画像数です。6面(Top, Front, Left, Right, Back, Bottom)をキャプチャするため、Sample Per Face * 6枚のキャプチャ画像が生成されます。例えば、K16の場合は96枚の画像が生成されます。 K16
Resolution 画像の解像度です。例えばK1024を選択すると、1024 * 1024の画像がキャプチャされます。解像度が高いと、キャプチャに時間がかかります。 K1024

最後に、Detailsパネルにある「Capture」ボタンをクリックします。しばらく待ち「Scene Captured!」 というダイアログが出ればキャプチャは成功です。

Seuratからメッシュを作成する

次に、キャプチャした画像を用いてメッシュを生成します。Seuratのバイナリには、有志が提供するものを用います。ここの「seurat-compiled-msvc2017-x64.zip」をダウンロードします。zipファイル内に「seurat-pipeline-msvc2017-x64.exe」があるので、プロジェクトのIntermediate\SeuratCaptureフォルダ内にコピーします。

seurat-pipeline-msvc2017-x64.exeを実行するために、次のようなbatファイルを作成します。

seurat-pipeline-msvc2017-x64.exe -input_path manifest.json -output_path seurat_mesh -triangle_count 288000 -ray_footprint 0.04 -skybox_radius 768 -texture_width 8192 -texture_height 8192
pause

コマンドラインパラメータの一部について紹介します。

パラメータ名 詳細
input_path 入力するmanifest.jsonへのパス(必須)
output_path 出力するファイルのパス(必須)
cache_path キャッシュのパス。プログラム終了時にジオメトリがキャッシュされる。キャッシュがあると、次の起動時にキャプチャ画像の読み込みとメッシュ生成をスキップできる
single_face ヘッドボックス周囲の、指定した立方体の一面のみを出力する。全面の出力よりも高速なので、メッシュのプレビューに便利
triangle_count 生成する最大Triangle数
ray_footprint ジオメトリの継ぎ目を埋めるための値。小さいとジオメトリの隙間が見えることがある
texture_width 生成するテクスチャの幅
texture_height 生成するテクスチャの高さ
skybox_radius 再構築するメッシュの対象とするジオメトリの範囲。この半径の球外にあるジオメトリはクランプされる
fast_preview 品質を落として処理を高速化させる。プレビューに便利

作成したbatファイルを実行すると、メッシュ再構築が行われます。成功すると次のようになり、output_pathに指定したフォルダに再構築されたメッシュの.objと、そのテクスチャである.exrが生成されます。

メッシュをUE4へインポートする

最後に、生成された.objと.exrをUE4にインポートします。

FBX Import Optionsを次のように変更します。

  • Build Adjacency Bufferを無効化
  • Generate Lightmap UVsを無効化
  • Import RotationのXを90に変更

次に、インポートしたStatic Meshをクリックして、Use Full Precision UVsを有効にします。

次に、スタティックメッシュに設定しているマテリアルを開き、以下のように変更します。

  • マテリアルのBlend ModeをTranslucentに変更
  • マテリアルのShading ModelをUnlitに変更
  • インポートした.exrテクスチャをEmissiveとOpacityに接続

設定が終わったら、スタティックメッシュを空のレベルに配置します。

このレベルに配置されているのは、Seuratによる再構築を行ったメッシュと、色調を調整するためのポストプロセスボリュームの2つだけです。見た目がまったく同じというわけではありませんが、レベルに配置されていたアクター数を354から2に減らすことができました。

おわりに

Seuratを使って、シーンを単純化することができました。シーンの単純化が必ずしもシーンの最適化に繋がるわけではありませんが、手法の1つとしてお役に立てれば幸いです。

 

この記事は次のバージョンで作成されました。
Unreal Editor Version: 4.19.2-4033788+++UE4+Release-4.19
Microsoft Visual Studio Community 2017 Version 15.7.5

[UE4] Paragonのアセットを読む

$
0
0

こんにちは。
テクニカルアーティストの黒澤です。

今回は趣向を変えてParagonのアセットからSerathのデータを読んで、EPICの制作フローに思いを馳せることにします。
まずはこちらのハイクオリティな画像をご覧ください。

 

メッシュについて

ポリゴン数は約83,000ポリゴンで、使用しているマテリアルのエレメント数は15とかなり多めです。
マテリアルは金属部分にはClearCoatシェーダー、眼球はEyeシェーダー、髪の毛はHairシェーダー、肌はSubsurfaceProfileを使用しています。

また、変わったところでは、まぶたの下に影の代わりになるメッシュ、眼球にたまった涙のメッシュがあります。

(右からキャラクター全体のメッシュ、まぶたの下の影の代わりになるメッシュ、眼球にたまった涙のメッシュ)

影の代わりになるメッシュ

まぶたが眼球に落とす影のような微細な表現は、シャドウマップの性質上、リアルタイムグラフィックでは難しいので、フェイクとして半透明の板を眼球にくっつけて影の代わりにしています。
目に表情が出るため、簡単に作れる割に効果はとても大きいので、かなり制作で生きるテクニックです。

涙のハイライトにメッシュ

眼球にたまった涙を表現するために、チューブ状のメッシュを眼球の周辺に配置しています。
こちらも目の表現力がアップするのでおすすめのテクニックです。

マテリアルの構成

M_Serath_HKFHEGR というお尻の部分のマテリアルを見ていきます。

ぱっと見ての通り、このマテリアルは金色のプレート、そのふちの銀色の部分、鎖たかびらの3つのマテリアルで要素で構成されています。
マテリアルを開いてみるとこんな感じです。

金属プレートのサブマテリアルに対するインプットはこのようになっており、RチャンネルとGチャンネルが、それぞれ汚れと傷の出やすさになっています。
(AOとCurvatureに加工したようなテクスチャです)
※ AO(アンビエントオクルージョン) 物体の影だまりを表したテクスチャ
※ Curvature(カーバチュア) 物体の表面がどれくらいの角度で折れ曲がっているかを示したテクスチャ

かなり複雑な部分はありますが、いわゆるレイヤードマテリアルを使用した作りになっています。

レイヤードマテリアルとは?

レイヤードマテリアルについて、UE4のマニュアルから引用します。

レイヤー マテリアルは、「マテリアル内のマテリアル」として考えることができます。レイヤーマテリアルは、一連のサブマテリアル (または レイヤー) を持つ単一マテリアルの作成手段です。サブマテリアルは、マスクなどのピクセル単位の操作でオブジェクトのサーフェス全体へ配置することができます。ユニークなサーフェス タイプ間の複雑なブレンド処理に最適です。上記のロケットの画像は、一番右寄りのロケットに独自のマテリアル レイヤーを使用しています。クロム、アルミニウム、そして銅を使用して、ピクセル単位ベースで各マテリアルをブレンドしています。このエフェクトは、レイヤー マテリアルで簡単に実現できます。

ちょっと説明がややこしいですが、簡単に言ってしまえば「マスク画像を使用して、一つのマテリアル内で複数のマテリアルを合成する」機能です。

合成する前のマテリアルは便宜的にサブマテリアルと呼ばれます。
またここでのマスク画像は、複数の素材感を表すために「この色はこの素材感」と指定するためのマップなので、一般的にIDマップとも呼ばれます。

サブマテリアルはUE4のマテリアル内で一つのノードで扱えるので、可読性に優れ、作成したサブマテリアルは再利用可能なところが特徴です。
ただし、可読性に優れるとはいってもマテリアルを組む必要があるので、マテリアルインスタンスの調整に比べれば、制作と管理の難易度は飛躍的に上がります。

ここまで読んで、Substance等を使用したアセットワークに慣れている方なら、スマートマテリアルの概念に似ていることに気が付いたと思います。
おそらくParagonのワークフローとSubstanceを使用したアセットワークの違いは以下のようなものであるということができると思います。


モデル制作:Wes McDermott

上記の概念図を説明します。
SorceMesh(ハイポリ)とInGameMesh(ローポリ)を用意し、InGameMeshのUVに対し、各種マップを生成するところまでは同じです。

Substanceを使用したワークフローではこれらの各種素材をうまく利用して、例えば「革素材はAOが明るい場所は色落ちしており傷も多い。AOの暗い場所は色落ちしておらず、極端に暗い場所には汚れがたまっている」などの素材感を作り、効率よくPBRに必要な素材を制作します。それらの素材はUE4でほぼ手を加えることなく同じ絵を表示できます。

これに対して、レイヤードマテリアルを使用したワークフローでは、各種マップに加え、UE4のマテリアル内で取得できる要素や、ほかのシームレス素材もマテリアル内で合成し、上記の素材感の特徴をUE4の中で生成するといった違いであるといえます。

 

レイヤードマテリアルについてまとめます。

利点

解像度がテクスチャサイズの制限を受けない

同じメッシュで素材の組み合わせが違うようなものをUE4の中で制作できる

ルックの調整がUE4の中だけで完結する

欠点

マテリアルが重くなる

わかりにくくなる

管理が煩雑になる

 

それぞれの項目についてもう少し詳細に解説します。

解像度がテクスチャサイズの制限を受けない

鎖かたびらの質感がわかりやすいのですが、UVに対して6倍繰り返しているため、テクスチャでは24,576Pixel(4096×6)相当の解像度を持っているともいえます。いわゆるディテールマップ的な表現なのですが、こういった表現を無理なく取り込めるのもレイヤードマテリアルの特徴といえるでしょう。繰り返すような素材感はサブマテリアルに持たせてしまえばいいわけです。

また、シャープな絵ほど解像度不足が目立つものですが、マテリアル内でノイズを合成し、コントラストを上げる処理を行って錆の素材感などを出すのであれば、解像度感はベースのテクスチャに拠るわけではないので、解像度不足な感じはほとんど見えなくなります。

同じメッシュで素材の組み合わせが違うようなものをUE4の中で制作できる

M_Serath_HKFHEGRでは鎧と鎧のふち、鎖かたびらのサブマテリアルの合成でしたが、シルクのような素材が混ざったマテリアルを作りたいとします。その場合でもサブマテリアルとIDマップの接続を変えるだけです。

ルックの調整がUE4の中だけで完結する

レイヤードマテリアルだからそうだというわけでもないのですが、「汚れた場合にはBaseColorはこう変化する」といった情報をほとんどマテリアルの中で行っているため、UE4の中でアセットワークが完結するのがうれしいです。質感を高めたいからSubstanceに戻すといったことを行う必要が少なくなります。

マテリアルが重くなる

多くのパラメーターをマテリアルに持たせて合成するということは、当然マテリアルの処理が重くなります。

わかりにくくなる

極限までシンプルなアセットワークを考えてみます。こちらは購入したアセットの一例ですが、マテリアルインスタンスで必要なマップを接続し、調整用のパラメーターをいじるだけです。

サブマテリアルの組み合わせは見た目はわかりやすくなるとは言え、上記の作業に比べると、レイヤードマテリアルは遥かに難易度が高く、アーティストがそれぞれUE4に精通している必要があります。

管理が煩雑になる

アーティストはマテリアルインスタンスしか触らない状況と比較すると、ベースマテリアルも多数存在することになります。
結果的にサブマテリアルが紛れ込んでいた場合の原因と影響範囲の究明など、管理もかなり難しくなります。

以上のことから、アーティスト全員がテクニカルアーティストという、EPICに向いたワークフローであるといえるでしょう。

 

おまけ

最後に、一つ面白いパラメーターを見つけたのでご紹介します。
MF_GoodEvilMaskというマテリアルファンクションがほとんどのマテリアルに接続されていたのですが、この中のClothBurnというパラメータを0から1に変化させると、キャラクターの見た目が一瞬で変化します。(通常にみることのできない暗い革の素材や、特殊なマテリアル表現はこのために用意されています)

こちらもレイヤードマテリアルをうまく使っており、同じIDマップに対してGoodEvilMaskから出てきた変数に応じて、サブマテリアルが表示される範囲が変わるといった作りになっています。

今回、ご紹介したSerathも含め、Paragonのアセットのいくつかは無料で公開されています(UnrealEngine4も無料で使えます)
12億円以上の予算をかけて作られたゲームのデータを見ることができるというのはなかなかないことですので、ぜひ自分でもデータを見てみることをお勧めします!

 

[UE4]簡単なLatentノードの作り方

$
0
0
執筆バージョン: Unreal Engine 4.20

 

Latentノードといえばよく見かける以下のような

ノードの右上に時計のマークが表示されてるノードのことを言います。

ノード内部で処理が終わり次第、次に進むことができるものです。

これをプロジェクト専用に追加する場合FPendingLatentActionを継承したりFLatentActionInfoを使用して実装することができるのですが(※1

少しめんど……く……さい……

 

なんてことを思ってたんですが実はもっとシンプルに作ることができる方法があったので今回はそれをご紹介したいと思います。

では早速サンプルをご確認ください。

上記のサンプルコードではUBlueprintAsyncActionBaseというクラスを継承して作成したものですがこれだけで

という感じにLatentノードを作成することができます。またコード上の変数「Completed2」のコメントを消すだけで

のようにピンを増やすこともできます。

UBlueprintAsyncActionBaseを使用してLatentノードを作成する場合のポイントは4点です。

 

・UBlueprintAsyncActionBaseを継承したクラスを生成し返すStaticな関数を定義し、メタ情報にBlueprintInternalUseOnly = “true”を指定する

・ノード終了時に通知するためのデリゲートを定義する

・Activateをオーバーライドして処理を実装する

・不要になったらSetReadyToDestroyを呼び出してGC対象に

 

 

短いですが今回は以上になります。少しでも皆様の開発に役立てばと思います。

ここまで読んでいただきありがとうございました。

 

 

 

※1

FLatentActionInfo、FPendingLatentActionを使用しての実装に関しては以下のブログが参考になるかと思います。

http://unwitherer.blogspot.com/2017/06/unrealclatent_11.html

http://unwitherer.blogspot.com/2017/06/unrealclatent.html

[UE4] BehaviorTree: Task、Service、Decoratorのイベント

$
0
0
執筆バージョン: Unreal Engine 4.20

BehaviorTreeノードのイベント

UE4のBehaviorTreeでは、各種ノードを組み合わせてAIのふるまいを作っていきます。
このうち、Task、Service、Decoratorの各ノードは、Blueprintでオリジナルのものを作ることができます。

今回は、Task、Service、DecoratorをBlueprintで作る場合に、利用可能なイベントについて調べてみました。

※以下で記述する全てのイベントには、”AI” のつかないイベントも存在します。
機能はほぼ同等ですが、イベント引数が異なります。また、両方を実装した場合は、”AI” のついたイベントのみが呼ばれます。
本記事では、これらの詳細な比較は省略し、”AI” のついたイベントについてのみ、記述します。

Tickイベント

Receive Tick AI イベント (Task)

  • Task実行中に呼ばれます。
  • Tick間隔を指定することはできません。

Receive Tick AI イベント (Service)

  • アタッチされたノードの実行中に呼ばれます。
  • Interval プロパティで、Tick間隔を指定することができます。

Receive Tick AI イベント (Decorator)

  • Observer Aborts のための監視中に呼ばれます。すなわち、Decoratorが、中止すべきか判断する対象となるノードの、監視中に呼ばれます。
  • Observer Aborts の値が None の場合は、一切呼ばれません。
  • Tick間隔を指定することはできません。

Taskの実行、中止時に呼ばれるイベント

Receive Execute AI イベント (Task)

  • Taskが開始されるときに呼ばれます。
  • Receive Execute AI イベントを記述した場合、Finish Execute 関数を呼ぶか、DecoratorによってAbortされるまで、ノードの実行状態が続きます。

Receive Abort AI イベント (Task)

  • TaskがDecoratorによって中止されたときに呼ばれます。
  • Receive Abort AI イベントを記述した場合、Finish Abort 関数を呼ぶまで、ノードの実行状態が続きます。

Receive Execution Start AI イベント (Decorator)

  • アタッチされたノードが開始されるときに呼ばれます。
  • Observer Aborts設定に関わらず呼ばれます。

Receive Execution Finish AI イベント (Decorator)

  • アタッチされたノードが終了、または中止されたときに呼ばれます。
  • Observer Aborts設定に関わらず呼ばれます。

Compositeの下位ノード決定前に呼ばれるイベント

Receive Search Start AI イベント (Service)

  • アタッチされた Composite ノードの下位ノードの中で、最初に実行すべきノードを決める前に、このイベントが呼ばれます。
  • アタッチされたノードがTaskの場合は、一切呼ばれません。

Decorator、Serviceの有効化、無効化時に呼ばれるイベント

Receive Activation AI イベント (Service)

  • アタッチされたノードが、開始されるときに呼ばれます。
  • アタッチされたノードが終了しても、次に実行されるノードが同じノードであった場合、すなわち、この Service が引き続き動作する場合には、次のノードの Receive Activation AI イベントは呼ばれません。

Receive Deactivation AI イベント (Service)

  • アタッチされたノードが、終了されるときに呼ばれます。
  • アタッチされたノードが終了しても、次に実行されるノードが同じノードであった場合、すなわち、この Service が引き続き動作する場合には、終了するノードの Receive Deactivation AI イベントは呼ばれません。

Receive Observer Activated AI イベント (Decorator)

  • Observer Aborts のための監視を開始するときに呼ばれます。すなわち、Decoratorが中止すべきか判断する対象となるノードの、監視を開始するときに呼ばれます。
  • Observer Aborts の値が None の場合は、一切呼ばれません。
  • 監視対象のノードが終了しても、次に実行されるノードが引き続き監視対象であった場合には、次のノードの Receive Observer Activated AI イベントは呼ばれません。

Receive Observer Deactivated AI イベント (Decorator)

  • Observer Aborts のための監視を終了するときに呼ばれます。すなわち、Decoratorが中止すべきか判断する対象となるノードの、監視を終了するときに呼ばれます。
  • Observer Aborts の値が None の場合は、一切呼ばれません。
  • 監視対象のノードが終了しても、次に実行されるノードが引き続き監視対象であった場合には、終了するノードの Receive Observer Deactivated AI イベントは呼ばれません。

実行するTaskが決定してからのイベント呼び出し順序

実行するTaskが決定してから、実際に実行されるまでの、イベント呼び出し順序については、およそ以下のようになっています。

  • (CompositeやDecoratorを元に、開始すべきTaskが決まる)
  • これから実行される Task や Composite にアタッチされている Decorator の Receive Execution Start AI イベント
  • 直前まで実行されていた Task の Receive Abort AI イベント
  • 直前まで実行されていた Task や Composite にアタッチされている Service の Receive Deactivation AI イベント
  • 直前まで実行されていた Task や Composite を監視していた Decorator の Receive Observer Deactivated AI イベント
  • これから実行される Task や Composite を監視する Decorator の Receive Observer Activated AI イベント
  • これから実行される Task や Composite にアタッチされている Service の Receive Activation AI イベント
  • これから実行される Task や Composite を監視する Decorator の Receive Tick AI イベント
  • これから実行される Task の Receive Execute AI イベント
  • これから実行される Task の Receive Tick AI イベント
  • (Task実行中)
  • (Task実行終了、もしくは Decorator による 中止)
  • 実行していた Task や Composite にアタッチされている Decorator の Receive Execution Finish AI イベント
  • (CompositeやDecoratorを元に、開始すべきTaskが決まる)
  • これから実行される Task や Composite にアタッチされている Decorator の Receive Execution Start AI イベント
  • (以下続く..)

Decoratorの Receive Execuiton Start AI イベントの後に、直前まで実行されていた Task などに関わる終了イベントが呼ばれることに注意してください。
例えば、Receive Execution Start AI と、Receive Deactivation AIとで同じBlackboard変数を読み書きする処理を記述していると、前後関係が混ざってしまうことにより、思わぬバグを生む可能性があります。

まとめ

いかがでしたか?同じ名前や似たような名前のイベントであっても、それぞれ役割やタイミングなどに違いがあることがご覧いただけたかと思います。
この違いを把握することで、AIのふるまいをより的確に作っていくことができます。
BehaviorTreeのノード、そしてイベントを使いこなして、さまざまなAI挙動を作ってみてくださいね!

Viewing all 998 articles
Browse latest View live


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