UE4の勉強記録

UE4の勉強の記録です。個人用です。

「Unreal Engine 4.xを使用してRPGを作成する」の足りない部分を作成する 村人用のAIの開発 Part4

f:id:kazuhironagai77:20211128232703p:plain

<前文>

<英語はテニス、日本語はボーリングは間違いか?>

英語喉®︎カズ先生 (シカゴ大学Ph.D.) の木村ここみさんの英語をシカゴ大学Ph.D.が評価してみた [1] を見てたら日本人の会話はキャッチボールと解説されています。

f:id:kazuhironagai77:20211128232744p:plain

私は常々、英語の会話はテニス、日本語の会話はボーリングと言っています。

この事自体は私が発見したアイデアではないですが、これほど日本語と英語の会話の違いを端的に表した言葉はないと思っています。それと全く違う、それも180度違う意見を言う人、しかも私より英語が上手な日本人が言っているのを聞いてびっくりしたんです。

で、全部、この動画を見たんですが、英語は喉を使うとか、英語はアコーディオンのように発音するとか、かなり英語と日本語の違いの本質を突いた発言をしていました。

英語はアコーディオンのように発音する部分では、私が昔、英語はバイオリンのよう、日本語はピアノのようだ。と感じた事を思い出しました。これは英語の発音は日本語のように単語毎に音が切れない事から感じたんですが、兎に角、音の出し方が根本から違うんです。

英語は喉を使うに関してもかなり同感です。日本に帰って来てから日本人からよく小馬鹿にしているように感じると言われて、何で?と思ったら、私が相槌を打つときに喉に響かせていたんです。それがどうも他の日本人には小馬鹿にされていると感じたみたいなんです。それから喉に響かせて音を出すのを止めたら以後一切、小馬鹿にしているように感じると言われなくなって、ふーん。日本では喉に響かせて音を出すと小馬鹿にしているように感じるんだ。と思ったのも覚えているからです。

つまり完全とは言わないですが英語と日本語の違いについてほとんどの意見が一致しているんですが、英語の会話と日本語の会話の違いは全く真逆な意見を言っています。

それで一番最初に思い出したのが、話の粒度(Granularity)の違いと山本義隆氏の「熱学思想の史的展開」に書かれていた熱力学第一法則の発見に関わる話です。

山本義隆氏の「熱学思想の史的展開」に書かれていた熱力学第一法則の発見の話は、熱力学を勉強した事のない人には馴染みがない話なのでここに簡便にまとめておきます。ただしこの本が手元にないんで細かい点では間違いがあるかもしれません。

フランス人のカルノー熱力学第二法則を発見します。その後でドイツ人のメイヤーが熱力学第一法則を見つけるですが、実はイギリス人のジュールの方が先に発見していたんです。

しかし当時のイギリスの学会のボスであるケルビンは、ジュールの発見がカルノー熱力学第二法則に一見反する結果を示しているので、どっちかが間違っているはずとの考えから逃げられなかったんです。のでジュールの実験結果が間違っているだろうと思って相手にしなかったんです。

ところが、ドイツではあるアマチュアの論文でジュールの発見はカルノー熱力学第二法則に反しない形で存在出来る、つまり両方が正解の可能性もある。との認識が既に広まっていたので、ドイツ人であるメイヤーはケルビンと違って、カルノー熱力学第二法則に惑わされる事なく、熱力学第一法則を見つける事が出来たんです。

うろ覚え過ぎて、かなり間違っている部分があるかもしれませんが、言いたい事は、科学の世界では一見相反して見える結果が両方正しい事はありえる。です。

つまり、どっちも正しいんじゃないのかな。と思ったんです。

もう一つは、先週の勉強で出て来た粒度(granularity)の違いについてです。

私が、英語はテニスのようだ。という理由は単純に、英語でHow Are You?と言われたら必ず返事を返さなければならない会話のルールが、必ずボールを打ち返さないといけないテニスに似ているから言っています。

粒度に例えると非常に荒いレベルの話をしています。この動画の話は、ほとんど完璧に英語がしゃべれる日本人がアメリカ人との会話で本当に微妙なニュアンスの違いで誤解している、粒度に例えると非常に細かいレベルの話をしているので粒度(granularity)が違っているのではないのかと思いました。

正し、私自身は、この動画のような粒度(granularity)が非常に細かいレベルの英語の会話でも積極的に、今ここで自分の意見を打ち返さないと。とテニスをPlayしているように感じて会話していました。後、アメリカ人に自分の発言が無視されていると感じた事はあんまりないです。

兎に角、アメリカ人は会話中の無音状態を恐れるんです。だから何があっても会話中は無音状態にしないようにしないといけないんです。それで英語での会話は私にとってはテニスのラリーのように感じます。それに対して日本語の会話は、どちらかと言えば会話中の無音状態も音が発している時と同じぐらい大切です。私にとっては日本語の会話はまるでボーリングをやっているようです。

ところで、回りの英語がしゃべれない日本人にこの話をしたら、全員が日本語の会話がキャッチボールなわけねーだろ。って言われました。上司との会話でお前は、一々、コメント返すのか。と。それで気が付いたのですが、粒度だけじゃなくて、会話の相手が上司の場合とかの場合も関係してるのかもしれません。

後、関東と関西の違いもあるのかもしれません。一回だけ日本人の友達と大阪に遊びに言った時に、自販機にコーラがなかったので「コーラないぞ。」とその友達に言ったら、50m位離れた所にいる全く知らないおばさんが「こっちにあるよ。」って大声で怒鳴ってきたんです。ホントにびっくりしました。

だから私は日本全体が、東京のように会話していると思っていたんですが、実は関西圏では会話はキャッチボールのようにやっているのかもしれません。東京文化圏で育った私には、英語の会話はテニス、日本語の会話はボーリングに感じます。しかし関西文化圏で育った人には逆に感じるのかもしれません。

これを書いていて思い出したんですが、Learn Japanese From Zero!とMatt vs. Japanが日本語のPitchについて議論してた時に、英語喉®︎カズ先生も議論に参加してました。その参加の仕方が私にはとてもテニス的だったです。日本人で他にこの議論に参加した人は他にはいなかった気がします。それは他の日本人はボーリングをPlayしている時のように二人の議論を見てたからだと思っています。

と言う訳で私は自説である英語の会話はテニス、日本語の会話はボーリングを保持していきますが、それは違うと言う人の意見も良く聞くようにします。

今週書こうと思っていたKyle Rittenhouse Trialの感想については来週以降に回します。

それでは今週の勉強を始めます。

<本文>

1.今週の予定

今週は以下の内容をやっていきます。

  • Niagara: Convertible Floor in UE5 Niagara Tutorialについて
  • Material : Content Exampleをみる
  • NPCのAIを作成するためのAIの復習の続き(Environment Query System
  • Game Designポケモン+HxHの念能力 Part 2
  • Landscape4にLoad Stream Levelノードを使用する
  • UE5におけるWorld Partitionの勉強の続き

2.Niagara

2.1 Convertible Floor in UE5 Niagara Tutorial [2]の復習

先週使用したModuleやDynamic Inputなどで機能が分からないものや、始めて使用したものを調査します。

<Spawn Particles in Grid Module

まずは当然ですがこのModuleです。

f:id:kazuhironagai77:20211128232905p:plain

こんなModuleあるの知らなかったと先週も言っていますがホントですね。

試しにParticle をSpawn Particles in Grid Moduleを使用してGrid状に配置してみます。

f:id:kazuhironagai77:20211128232930p:plain

これ、先週のBlogでもやっていましたね。

CGHOW氏もこの辺はTutorialできちんと解説していました。

でもこれでSpawn Particles in Grid Moduleの機能を理解する事が出来ました。

<Grid Location Module

f:id:kazuhironagai77:20211128233137p:plain

Grid Location ModuleはSpawn Particles in Grid Moduleと対で使用するModuleです。Spawn Particles in Grid ModuleがEmitter Update Sectionに配置するのに対して、Grid Location ModuleはParticle Spawn Sectionに配置します。

<Mesh Renderer

Convertible Floor in UE5 Niagara TutorialではMesh Renderer Moduleを使用しています。

f:id:kazuhironagai77:20211128233208p:plain

私はVFXにおけるSpriteの手法って何か詐欺っぽくて嫌いなんです。のでMesh RenderingのでもっとMesh Renderingを勉強しようとは思っています。

でも中々出来ていないです。

<Lerp Linear Colors

f:id:kazuhironagai77:20211128233237p:plain

Lerp Linear ColorsはDynamic Inputの一種で二つの色をLerp で表示します。

Materialでいう所の以下の実装と同じ事をしていますね。

f:id:kazuhironagai77:20211128233302p:plain

上記の実装だと0は赤、1は青、その中間は二つの色をそれぞれの割合で混ぜた色で表現されています。

f:id:kazuhironagai77:20211128233324p:plain

でもそうするとoutput Xの値が0から1の間である必要がありますね。

調べます。

output Xの値は結構複雑な計算で求められていました。

f:id:kazuhironagai77:20211128233346p:plain

ただ最後にSaturate Floatを使用しているので値が0と1の間で示されてるのは間違いないです。

f:id:kazuhironagai77:20211128233359p:plain

Codeを読んだら分かりました。Pointは以下に示した2つのInputです。

f:id:kazuhironagai77:20211128233420p:plain

任意の位置であるPosition Xを適切なOutput Xに変換するためには、全てのGridの最初の位置と最後の位置が分からないと求められません。のでどうやってそれを求めているのかと推測しながらコードを読んでいきますが、実際は最初の位置と最後の位置は最後まで分からないんです。

ではどうしてるかと言うと、上の二つのInputの値を変えてOutput Xが適切な結果になった(この場合、以下に示した様に色が綺麗に表示されたら)時が正解としているんです。

f:id:kazuhironagai77:20211128233445p:plain

これで大体理解したんですが、先週のBlogを読み直すともう少し細かい話、粒度(Granularity)を下げた調査が欲しい気がしてきました。

のでもう少し細かく調査し直します。

私はこの話の粒度(Granularity)をそろえるのがかなり苦手です。大学4年、大学院生一年レベルの人が対象の粒度(Granularity)の話をまとめていても、途中で一般人向けの粒度(Granularity)になってしまったり、またその逆になったりしてしまいます。

先週のBlogで何でFadeの値を追加すると実際の色がFadeするのか分からないと言っていますが、

f:id:kazuhironagai77:20211128233523p:plain

今週の粒度(Granularity)ではこの理由を説明する事は出来ません。

この辺は来年、1年間の課題にします。

<Lerp Linear Colorsの解説やり直し>

まず先程示したこのScreenshotですが

f:id:kazuhironagai77:20211128233555p:plain

正確に言うとこれに使用したOutput Xの実装は

f:id:kazuhironagai77:20211128233620p:plain

これだけです。こっちの結果は

f:id:kazuhironagai77:20211128233643p:plain

これです。

f:id:kazuhironagai77:20211128233704p:plain

言っている内容は正しいのですが、

f:id:kazuhironagai77:20211128233725p:plain

こっちを使用して説明する為にはもう一回、この実装を書く必要があり、それが面倒なので先程の説明で終わらせてしまいました。

それだとFadeの機能の調査が出来ないのでTutorial自体の解説より私が調査した内容の方が薄くなってしまいます。

私の話の粒度(granularity)がコロコロ変わる理由の一つが分かりました。実装し直すのが面倒なので粒度(Granularity)を変えて対応していたんですね。

仕方ない。もう一回、此処までの実装をします。

しました。

Scratch Moduleの中身が以下の状態で

f:id:kazuhironagai77:20211128233804p:plain

結果が以下の様になっています。

f:id:kazuhironagai77:20211128233826p:plain

<<Saturate Floatについて>>

この粒度で考えるとこの時点で良く分からない部分があります。

今使用しているCubeの大きさは1m^3です。UE4のUnitは1㎝ですのでxの値は、110、220、330、440が返ってくるはずです。それをSaturate Float Moduleを使用して0から1にSaturateしているので全部1になるはずです。なのに0にあたる緑が表示されています。

はい。

実際のMap上に配置して上から見ると分かります。

f:id:kazuhironagai77:20211128233855p:plain

Xの位置の値は-110、-220、-330..のCubeが緑色になっていました。

これはこのEffectの位置を原点からずらすと良く分かります。

原点よりー側にずらしました。

f:id:kazuhironagai77:20211128234011p:plain

原点より+側にずらしました。

f:id:kazuhironagai77:20211128234034p:plain

Tutorialでもそのように解説していました。

f:id:kazuhironagai77:20211128234059p:plain

CGHOW氏のTutorialって全部World Coordinateの原点を中心にして作成しているんですね。

これだとそのままGameのEffectには使用出来ないですよね。

うーん。もしかして前にどっかのGame 会社に丸コピされたりしたんでしょうか?

でも丸コピされないためには良いアイデアですね。全部Local Coordinateに直さないと実際のGameには使用出来ない訳ですから。

<<Fade とWipe>>

ここでFadeとWipeの機能を解析します。

まずWipeについてです。

Wipeの実装は以下に示します。

f:id:kazuhironagai77:20211128234128p:plain

もう単純にGridの原点からの位置の値を減らしているだけですね。

Wipe=0です。

f:id:kazuhironagai77:20211128234148p:plain

一個のCubeが100cmで隙間が10cmだから110cmずらすとヒトマス分の色が変わるはずです。

Wipe=110です。

f:id:kazuhironagai77:20211128234211p:plain

ヒトマス分赤が増えています。

赤が6個あるので‐660を引いてみます。

f:id:kazuhironagai77:20211128234252p:plain

‐550にしてみます。

f:id:kazuhironagai77:20211128234643p:plain

はい。Wipeの機能についてはこれだけですね。

次はFadeです。実装部を以下に示します。

f:id:kazuhironagai77:20211128234707p:plain

割っているだけですね。

110cmでGridされているんで110以上で割れば、0と1の間の値0.5とかがでてきてそのGridは黄色系になります。

試しにFade = 220にしてみました。

f:id:kazuhironagai77:20211128234725p:plain

黄色が出来ました。

<<Fade とWipeの結論>>

結論から言えばFadeやWipeは単なる引き算、割り算でした。ただし、

  • Lerpの機能を理解する事。
  • Grid 1m^3Cubeを並べている事。
  • Gridの隙間が10cmである事。
  • UE4の単位、UU1㎝である事。

を知っていないと何をしているのか分からなくなります。それだけです。

<Girdがオレンジと黄色に成る点について>

f:id:kazuhironagai77:20211128234814p:plain

これは(1-同じ計算)を掛けているだけです。

f:id:kazuhironagai77:20211128234837p:plain

それがどうなるのか良く分からないので計算してみました。

f:id:kazuhironagai77:20211128234903p:plain

X*(1-x)を計算すると0と1の間以外の値は全てNegative になりました。この習性を利用して計算したんですね。

因みにオレンジの線はSaturateした後です。

<Scale Mesh Size Moduleについて>

Scale Mesh Size Moduleを使用するためには以下に示したようにParticle Spawn SectionのInitialize Particle ModuleのMesh Scale ModeをUnsetから変更する必要があります。

f:id:kazuhironagai77:20211128234941p:plain

これは覚えておく以外の解決方法はないですね。

<Cubeの下側の伸びを消す>

f:id:kazuhironagai77:20211128235011p:plain

Cubeの下側の伸びを消すために50を足しています。

f:id:kazuhironagai77:20211128235119p:plain

これはCubeの大きさが100cmだからでしょう。

でも一応試してみます。粒度(Granularity)は揃える必要がありますから。

f:id:kazuhironagai77:20211128235142p:plain

ここまで作り直しました。

そしたら説明で

f:id:kazuhironagai77:20211128235203p:plain

f:id:kazuhironagai77:20211128235209p:plain

とはっきり言っていました。

一応確認のためにCubeのサイズを0.5m、Pivot Offsetを0に変更してみます。

f:id:kazuhironagai77:20211128235255p:plain

f:id:kazuhironagai77:20211128235303p:plain

こんな感じで真ん中でz軸に膨張しています。

f:id:kazuhironagai77:20211128235327p:plain

サイズが半分になったのでPivot Offsetを25ずらしたら、上方向にのみ膨張するはずです。試してみます。

f:id:kazuhironagai77:20211128235401p:plain

結果です。

f:id:kazuhironagai77:20211128235419p:plain

今度はCellのサイズを2倍にしてみます。

f:id:kazuhironagai77:20211128235437p:plain

セルの隙間を作るためにParticle Spawn SectionのGrid Locationの

f:id:kazuhironagai77:20211128235503p:plain

XYZ Dimensionsの値を110から220に変更します。

f:id:kazuhironagai77:20211128235524p:plain

こんな感じです。

f:id:kazuhironagai77:20211128235549p:plain

サイズが2倍になったのでPivotを100ずらします。

f:id:kazuhironagai77:20211128235610p:plain

結果です。

f:id:kazuhironagai77:20211128235627p:plain

はい。

Pivotで50ずらしているのはCubeのサイズが1mだからです。Cubeのサイズが50cmならばz軸のPivotを25cmずらせば上方向にのみ伸長します。Cubeのサイズが2mの時はz軸のPivotを1mずらす必要があります。

<回転が途中で止まってしまう>

f:id:kazuhironagai77:20211128235651p:plain

Tutorialの回転も途中で止まっていまいした。

f:id:kazuhironagai77:20211128235711p:plain

<<Update Mesh Orientation Moduleについて>>

Update Mesh Orientation ModuleはMeshを回転させるModuleなのは分かっていますが、これもPivotを中心に回転しているんでしょうかね。

f:id:kazuhironagai77:20211128235737p:plain

以下の青い点を中心にして回っています。

f:id:kazuhironagai77:20211128235803p:plain

Pivotの位置を変えてみます。

Pivot Offsetの値を0に戻しました。

f:id:kazuhironagai77:20211128235822p:plain

Cubeの中心で回り始めました。

f:id:kazuhironagai77:20211128235840p:plain

やっぱりpivotを中心にして回っていますね。

一応解説も載せておきます。

f:id:kazuhironagai77:20211128235902p:plain

<波が最後まで行かない>

f:id:kazuhironagai77:20211128235921p:plain

これはPreviewから見ていたからでした。

Previewは10秒間表示します。

そしてEmitter Update SectionのEmitter State ModuleのLoop Durationは4秒です。

f:id:kazuhironagai77:20211128235944p:plain

f:id:kazuhironagai77:20211128235950p:plain

更にParticle Spawn SectionのInitialize Particle ModuleのLife timeは4秒に指定しています。

f:id:kazuhironagai77:20211129000013p:plain

f:id:kazuhironagai77:20211129000020p:plain

つまり最後の2秒は途中で終わっていたんです。

Level状に配置したら普通に最後まで回転していました。

f:id:kazuhironagai77:20211129000105p:plain

Convertible Floor in UE5 Niagara Tutorial [2]の復習のまとめ

もう今週は粒度(Granularity)をそろえる事だけを考えてやりました。

粒度(Granularity)が突然荒くなる時は、その箇所を検証するためには、実装を一からやり直す必要があってそれが面倒だったのでやらなかったのが原因の一つでした。

もう一つ、先週やった内容もきちんと復習しておかないとTutorialの粒度(Granularity)と揃わないです。

だたその点に関しては最初の粒度(Granularity)は荒くても段々細かくなっていってもいいのかも知れないとも思いました。

今週の最初の部分ですが、

f:id:kazuhironagai77:20211129000144p:plain

結果的には先週のTutorialの内容と同じですが、その過程を解説していてその結果、先週のTutorialはこの事を解説するためにわざわざSpriteで最初は作成していたんだと言う事も分かりました。

楽しくやるのがもっと大切なのかもしれませんね。

楽しかったら自然と粒度(Granularity) も揃いそうです。

2.1 Convertible Floor in UE5 Niagara Tutorial [2]の残りをやる

先週やらなかった個所がちょっとだけ残っています。でもやるほどの内容はないかもしれません。

一応見てみます。

特に記録しなければならない事はなかったです。

今週は、CGHOW氏のHLSL Triangle code to UE4 Material nodes Tutorial [3]をやってみたかったんですが、時間がなくなってしまいました。来週やります。

3.Material

3.1 Content Exampleをみる

先週の続きをやります。

<先週の復習>

先週のBlogを読み直しました。先週は、Content ExampleのMaterial NodesのTessellation Multiplierについてまで勉強したら、公式のDocumentにそのものずばりMaterial Nodes [4] がある事を発見しました。そこにはそれぞれのNodeの詳しい解説が載っていました。結局、これやり直す必要があるのかとなりBase ColorとMetallicはやり直したんですが、疲れてそこで一端中断となりました。

思い出して来ました。

Material Nodes [4]の解説がそんなに期待した内容じゃなかったんです。

Page半分とかParagraph一個の解説しかなかったんです。粒度(Granularity)で言えばとても荒い解説です。今更読む必要がある内容じゃないです。

それで一端これは一端中止にします。

そもそもContent Exampleを見直した目的は、先週のBlogで述べたように

f:id:kazuhironagai77:20211129000237p:plain

を調査するためでした。

パラッと見てこれは知っている。これはやった事がある。これは全く知らない。位の区別がつけばOKだったんです。つまり粒度(Granularity)は非常に荒いレベルで良かったんです。

例えるなら、博物館でも見に行ってその感想をまとめるレベルで良かったんです。

それを忘れてしまった。しかも楽しく見ると言う事も忘れてしまったんです。

3.2 Material Propertiesを見る

今週はMaterial Propertiesを見ます。

f:id:kazuhironagai77:20211129000304p:plain

先週の反省を活かして、

  • 楽しく見る
  • 軽く見る

を心がけてやります。

公式のDocumentも最初にチェックしておきます。まずそのものずばりのMaterial Properties [5] があります。しかし内容を見るとContent ExampleのMaterial Propertiesとは一致していませんね。

これはMaterialのResult NodeのPropertiesを一個ずつ簡潔に解説してます。以下に示したものです。

f:id:kazuhironagai77:20211129000342p:plain

Content ExampleのMaterial Propertiesはその中の一部の機能に注目してExampleを作っているみたいですね。中には一致しているモノもあるみたいです。

公式のDocumentではその次のShading Models [6]に解説されている内容をやっている箇所もあるみたいです。

まあ、焦らず軽く見て行く事にします。

<Blend Mode

f:id:kazuhironagai77:20211129000413p:plain

Blend Modeは以下に示したようにMaterialのBlend Modeについてのそれぞれの特徴を示した展示です。

f:id:kazuhironagai77:20211129000513p:plain

この中で私が使用した事があるのはOpaque、Masked、Translucentの3つですね。

AdditiveとModulatedは使用した事はないです。Translucentとどう違うんでしょうか?

公式のDocumentであるMaterial Blend Modes [7]にはそれぞれの特徴について詳しい解説が載っています。これを読みながらそれぞれの展示を観察していきましょう。

<<Opaque>>

f:id:kazuhironagai77:20211129000532p:plain

普段使用しているヤツですね。

Material Blend Modes [7]では、後ろの物体が透けて見えない所を解説しています。

<<Masked>>

f:id:kazuhironagai77:20211129000600p:plain

透明な部分がある奴です。

設定方法は以下の様にします。

f:id:kazuhironagai77:20211129000631p:plain

Material Blend Modes [7]では、Maskedは物体の一部が透明でその他は透明でない物に対して使用すると解説されていました。

更にお得な豆知識が一つ紹介されていました。Maskedの透明な部分とTranslucentの違いについてです。Translucentは透明ですがRenderingはしています。何故かと言うと、光の干渉は計算する必要があるからです。それに対してMaskedで透明な部分は最初から描いていません。Renderingしてないそうです。

<<Translucent>>

f:id:kazuhironagai77:20211129000656p:plain

Translucent。つまり半透明です。

Transparentが透明ですが、似ていてよく勘違いします。先程のMaskedの解説でReflectionが出て来ていますが、Reflectionは反射で屈曲であるRefractionと似ていてこれもよく勘違いして使ってしまいます。

Material Blend Modes [7]に以下の解説が載っていますが

f:id:kazuhironagai77:20211129000722p:plain

TranslucentとTransparentをそれぞれ正しく認識しておかないと意味が分からなくなります。

この解説によると黒が完全な透明、白が完全な不透明、グレイは半透明としてRenderingされるそうです。

Content Exampleに展示されている例はOpacityに0.5が設定されていました。

f:id:kazuhironagai77:20211129000737p:plain

Material Blend Modes [7]に、またお得な豆知識がのっていました。

Translucentは現状ではSpecular lightは計算されていないそうです。しかしCube mapの機能を利用して似た効果を追加する事は出来るそうです。

<<Additive>>

f:id:kazuhironagai77:20211129000800p:plain

これは全く知らないです。

一見、Translucentと同じに見えますがどう違うんでしょうか?

Material Blend Modes [7]を読んでみます。

f:id:kazuhironagai77:20211129000824p:plain

と書かれていました。

ああ。

2021-09-19のblogに詳しく解説していますが、Dither Temporal AA ノードと同じ働きをするんですね。

f:id:kazuhironagai77:20211129000841p:plain

後、ここでも黒がTransparentとして扱われるそうです。

当たり前ですが、この方法もlightの影響は計算されません。

先程の2021-09-19のblogを読むとDither Temporal AA ノードはBlend ModeはTranslucentを使用するみたいなんです。このAdditive Blend Modeと色々比較したいですね。

Content ExampleのサンプルのMaterialを見ると

f:id:kazuhironagai77:20211129000940p:plain

f:id:kazuhironagai77:20211129000950p:plain

これしか設定していません。

粒度(Granularity)を保つのが大切です。これ以上細かくすると全体の主旨から外れてしまうのでこれ以上の調査はここでは止めましょう。

<<Modulate>>

f:id:kazuhironagai77:20211129001017p:plain

f:id:kazuhironagai77:20211129001032p:plain

これも全く知らないBlend Modeです。

Material Blend Modes [7]を読んでみます。

f:id:kazuhironagai77:20211129001104p:plain

と書かれていました。

単に掛けているだけならLightの影響は計算されているの。と思ったらされていないそうです。

<Lighting Model

次はLighting Modelについてです。

f:id:kazuhironagai77:20211129001144p:plain

Lighting Modelと紹介されていますが、実際はShading Modelの項についてです。

f:id:kazuhironagai77:20211129001204p:plain

先程も述べましたが公式のDocumentではShading Models [6]に解説されています。

f:id:kazuhironagai77:20211129001227p:plain

<<Default Lit>>

f:id:kazuhironagai77:20211129001248p:plain

f:id:kazuhironagai77:20211129001259p:plain

Default Litについてです。

いつも使っているヤツです。

Shading Models [6]によると、Default Lit ではDirect lighting、Indirect Lighting、そしてSpecular Lightingが適用されるとあります。

でも先週のBlogでも述べましたが、以下に示した陰の無い瓶のMaterialをみると

f:id:kazuhironagai77:20211129001321p:plain

Default Litが使用されているんです。

f:id:kazuhironagai77:20211129001339p:plain

これは本当に謎です。

<<Unlit (Emissive)>>

f:id:kazuhironagai77:20211129001403p:plain

f:id:kazuhironagai77:20211129001413p:plain

f:id:kazuhironagai77:20211129001422p:plain

Shading Models [6]を見てみます。

Unlitの特徴について以下の事が述べられていました。

  • Emissive LightもしくはColorを発する。
  • 火や発光体に使用する
  • LightCastするのではなくGlow 効果を発する。
  • この光から影が作成される事はない。

だそうです。

ここに述べられている事は大体知っていますね。

<<Subsurface>>

f:id:kazuhironagai77:20211129001502p:plain

f:id:kazuhironagai77:20211129001510p:plain

これは知ってはいますが使用した事はないと思います。

これもShading Models [6]を見てみます。

簡単に説明すると表面の下に別な色があってそれが光の錯乱によって浮き出てくるMaterialです。

以下にSample ContentのExampleのMaterialを示しましたがSubsurface Colorに表面下の色を指定しています。

f:id:kazuhironagai77:20211129001602p:plain

更に詳しい解説は、Subsurface Shading Model [8] にあるそうです。

<Translucent Lighting Mode

f:id:kazuhironagai77:20211129001630p:plain

これは全く知らない機能ですね。

TranslucencyのLighting Modeについての例を展示しています。

f:id:kazuhironagai77:20211129001648p:plain

公式のDocumentがないのか探したらありました。Materials Content Examples [9]です。

f:id:kazuhironagai77:20211129001712p:plain

先週の反省を活かしてまず公式のDocumentを探して見ました。

ないと思っていたんですが全く違う箇所にありました。

このPageのMaterial Properties Mapの所に

f:id:kazuhironagai77:20211129001744p:plain

全部の解説場所がしるされています。

f:id:kazuhironagai77:20211129001757p:plain

これのTranslucent Lighting Mode [10] をみます。

f:id:kazuhironagai77:20211129001823p:plain

これを参考にして展示されているサンプルを見てみましょう。

<<Volumetric Non Directional>>

f:id:kazuhironagai77:20211129002020p:plain

f:id:kazuhironagai77:20211129002029p:plain

Translucent Lighting Mode [10]によると

f:id:kazuhironagai77:20211129002056p:plain

と解説されています。

ふーん。

成程。VolumetricとしてMeshをRenderingしているんですね。このやり方ではDiffuse lightingのみ表示されてNormalは使用されない。そうです。

因みにCursorをVolumetric Non Directionalに合わせた時に表示される解説では

f:id:kazuhironagai77:20211129002114p:plain

Lightは計算されるけどLightの方向性までは計算しません。と言う事とLighting Modeの中でもっとも安価なやり方であるとあります。

ああ。分かった。

先程のBlend ModeのTranslucentの更に先の選択についてここで解説していたんです。

はー。やっとわかった。

f:id:kazuhironagai77:20211129002130p:plain

つまり、この展示されているサンプルはBlend ModeのTranslucentで展示されているサンプルと同じ物って事です。

前の節の<Lighting Model>は

f:id:kazuhironagai77:20211129002144p:plain

Blend ModeのOpaqueの場合のその先の選択について解説していたんです。

やっと繋がりました。

分かってくると楽しくなって来ますね。

うーん。でもTranslucentでもShading ModelでDefault Lit以外も選択出来はしますね。

f:id:kazuhironagai77:20211129002158p:plain

Blend ModeがTranslucentの時のShading Modelの違いについては自分で調べろと言うみたいですね。

<<Volumetric Directional >>

f:id:kazuhironagai77:20211129002221p:plain

f:id:kazuhironagai77:20211129002232p:plain

まず公式の解説、Translucent Lighting Mode [10]を見ます。

f:id:kazuhironagai77:20211129002257p:plain

こっちはNormalの影響も計算するみたいです。Diffuse lightingのみ表示されるそうです。

Cursorを合わせた時に表示される解説です。

f:id:kazuhironagai77:20211129002311p:plain

こっちの解説を見るとLightの計算で方向を考慮するので結果的にNormalの値も考慮されるとあります。

おお。

役立つ豆知識がここに書かれています。

ParticleのTangent Spaceはdefaultではカメラに向いているので、b Generate Spherical Particle Normalを使用可能にしてもっと役立つTangent Spaceを使用しましょう。と

b Generate Spherical Particle NormalはMaterialの項にあるこれの事でしょうか?

f:id:kazuhironagai77:20211129002345p:plain

Particleの作成にTranslucentかつVolumetric DirectionalなMaterialを使用する時は、この事を気を付けておきましょう。

<<Surface(Metallic Material to show reflections)>>

f:id:kazuhironagai77:20211129002412p:plain

Translucent Lighting Mode [10]をみます。

f:id:kazuhironagai77:20211129002432p:plain

これはReflectionつまり反射が写っているんですね。

確かに透明な部分に床か反射して写っています。

単純に凄いです。

私、この解説を読むまでこの反射して床が写っている事に全く気が付きませんでした。これと前節で解説されていたCube mapを使用してSpecularを追加する方法って同じ事をやっているんでしょうか?ちょっと気になります。

Cursorをおいた時に表示される解説です。

f:id:kazuhironagai77:20211129002446p:plain

表面のLightingが計算されると書かれています。これはReflectionについて述べているんでしょうか?

あんまりCostはかからないみたいな事も書かれていますね。

機会があったらぜひ使ってみたいです。

3.2 Shader Performance Measurement - Shader Graph Basics - Episode 21 [11]について

Ben Cloward氏のShader Performance Measurement - Shader Graph Basics - Episode 21 [11]を勉強します。

まずパラっと見ました。

今回は題の通りShaderの計算コストの測り方についてです。

簡単に結論から述べるとMaterialのStatsに表示されるInstructionの数からでは本当のShaderの計算コストを推測する事は出来ないと言う事です。

f:id:kazuhironagai77:20211129002526p:plain

その理由は

  • InstructionではLoopはすべての可能性についてCountされている。
  • InstructionはDataが大きくなる事による余計なCostについてもCountされていない。
  • 幾つかのInstructionは他のInstructionより極めて高いCostがかかる。

だからだそうです。

途中で、Shader Playground(https://shader-playground.timjones.io/)を使用して本当のコストを計算します。

f:id:kazuhironagai77:20211129002557p:plain

これの使い方を覚えるのが今回のTutorialの肝ですかね。

<Weather_Rainノードを使用したInstruction数の変化の確認>

f:id:kazuhironagai77:20211129002616p:plain

このNodeを付けたり外したりしてInstructionの数が増えたり減ったりするのを確認したんですが、再現出来ません。理由はこのノードが見つからないからです。

<Shader Translation Steps

MaterialのShaderがどうやって実際のInstructionまで変換されるのかについての解説です。

f:id:kazuhironagai77:20211129002644p:plain

最初のMaterial BPからHLSLの変換はまあ誰でも知っています。2つ目のHLSLからAssemblyへの変換も分かります。最後のそれぞれのVideo Cardに対応したCommandに変換する処は全く知らんかったです。

因みに、Materialに表示されているInstruction数は三番目のAssembly言語におけるInstructionの数だそうです。

なのでLoopの全ての可能性をInstruction数に含んでしまう訳です。

うーん。勉強になる。

<Shader Playground

この最後のそれぞれのHardware独自のCommandに変換するところをもっと詳しく勉強します。そのためにShader Playgroundを使用します。

これですね。

f:id:kazuhironagai77:20211129002707p:plain

このShader Playgroundがあんまりにも素晴らしいからこれからはUnityやUnrealは使用しないでここにCode書いていきます。って言ってます。

f:id:kazuhironagai77:20211129002723p:plain

f:id:kazuhironagai77:20211129002728p:plain

f:id:kazuhironagai77:20211129002735p:plain

え。と思ったら

f:id:kazuhironagai77:20211129002818p:plain

だって。

正直、それはそれでHLSLの勉強が出来て助かると思ってしまいました。

HLSLのコードです。

f:id:kazuhironagai77:20211129002842p:plain

これを以下の条件でCompileします。

f:id:kazuhironagai77:20211129002901p:plain

以下の結果になります。

f:id:kazuhironagai77:20211129002926p:plain

ほぼ同じコードで同じ事をします。

f:id:kazuhironagai77:20211129002945p:plain

前とほぼ同じですがSineが追加されています。

これを前と同じCompilerでCompileすると

f:id:kazuhironagai77:20211129003003p:plain

こうなります。

ここからがShader Playgroundの凄い所です。

このCompilerの値をRadeon GPU Analyzerに変更すると

f:id:kazuhironagai77:20211129003025p:plain

以下に示した様にRadeon 用に書き直したAssembly Codeを示してくれるんです。

f:id:kazuhironagai77:20211129003044p:plain

凄い。

全然違う。

しかしこれ位で驚いてはいけません。

何とCodeが表示されている上の部分の設定をISA Breakdownに変更すると

f:id:kazuhironagai77:20211129003100p:plain

以下に示した様にそれぞれのInstructionのcycle数まで示してくれるんです。

f:id:kazuhironagai77:20211129003119p:plain

SinのCycle数は16もありますね。

もう丸裸と同じですね。

ただ残念な事にGeForceはないです。のでこの計算結果は厳密に言えばGeForceの時と同じかどうかは分かりません。

はい。

Tutorialによると、ここで注目するのはSineのInstructionの数だそうです。

4個ありますね。

これは

f:id:kazuhironagai77:20211129003229p:plain

計算に使用される変数がFloat4でFloatが4つあるからです。

しかしAssembly Codeを見直すとそこでは一行で書かれています。

f:id:kazuhironagai77:20211129003249p:plain

これはFloat4じゃなくてFloatだとしてもAssembly Codeでは同じ1行で示されます。しかし実際のCycleはFloat4の場合はFloatの4倍の長さになります。

更にSineは計算するのに16 cyclesも使用しています。

以下にTutorialにのっていたAssembly CodeのそれぞれのInstructionのCycle数を示します。

f:id:kazuhironagai77:20211129003311p:plain

全然違いますね。

Shader Performance Measurement - Shader Graph Basics - Episode 21 [11]のまとめ>

はい。これで最初に説明した

  • InstructionではLoopはすべての可能性についてCountされている。
  • InstructionはDataが大きくなる事による余計なCostについてもCountされていない。
  • 幾つかのInstructionは他のInstructionより極めて高いCostがかかる。

の具体的な理由が説明されました。

Dataが大きくなるとはFloatからFloat4になる事です。

それで解決策なんですがそれは次のTutorialでやるそうです。

うーん。今回のTutorialは本気で神回でした。

4.NPCAIを作成するためのAIの復習の続き(Environment Query System

今週からEnvironment Query Systemの勉強を開始します。

公式のDocumentであるEnvironment Query System [12] を見ると

Starting Outに一個

f:id:kazuhironagai77:20211129003349p:plain

Essentialsに4つの解説兼Tutorialが載っています。

f:id:kazuhironagai77:20211129003410p:plain

これらをやっていきます。

4.1 今まで勉強したEnvironment Query Systemの復習と整理

その前に今までに勉強したEnvironment Query Systemについて一回復習します。

自分のBlogを読み直すと結構良い感じにまとまっています。その結果、自分のBlogで復習した方が速く理解出来ます。のでBlogの復習からやります。

2021-02-01のblog2021-02-07のBlogでEnvironment Query Systemについて勉強しています。

2021-02-01のblogではOnline LearningのIntroduction to AI with Blueprintを勉強しています。

f:id:kazuhironagai77:20211129003441p:plain

その中でEnvironment Query Systemについて勉強したんでした。

2021-02-07のBlogでは何と、Environment Query System [12]の

f:id:kazuhironagai77:20211129003500p:plain

を勉強していました。しかもかなり本格的に勉強して記録もしっかりしています。

Environment Query System Quick Startを勉強した事なんてすっかり忘れていました。

これは復習して正解でした。

2021-02-01blogの復習>

Online LearningのIntroduction to AI with Blueprintでは以下のLectureでEQSについて勉強しています。

  • 講義22: Creating the First EQS Query
  • 講義23: Creating the Second EQS Query
  • 講義24: Using the EQS Testing Pawn
  • 講義 25: EQS Gameplay Debugger

です。

<<講義 22: Creating the First EQS Query>>

ここで講義とは直接関係ないんですが、超重要な発言しています。

f:id:kazuhironagai77:20211129003536p:plain

4.26ではEnvironment Query Systemは標準装備になっている事です。

Environment Query System [12]でも

f:id:kazuhironagai77:20211129003549p:plain

と書かれていますが、EQSは既に標準装備になっています。

EQSを使用する目的に

f:id:kazuhironagai77:20211129003611p:plain

と書いていますが、こんな事EQSを使ったら出来るようになるんでしょうか?全く覚えていません。

後、EQSはBehavior TreeでTaskのように使用すると書いていますね。

f:id:kazuhironagai77:20211129003626p:plain

確かにEQSがTaskの代わりとして使用されています。

<<講義23: Creating the Second EQS Query>>

ここでは、EQS Queryを使用してPlayerに最も近い場所かつPlayerから見つからない場所を探す実装を勉強しています。

ただし

f:id:kazuhironagai77:20211129003723p:plain

動画を見てただけなので実装はしていません。

こうやって見直すと自分の弱点が良く見えてきますね。本当に実装嫌っています。

見たり感想をまとめたりするのは好きですが、実際の物作りは例えSoftwareでProgrammingしか書かなくて良い場合でもやってないですね。

その後、代案として講義で説明された実装をBlogにまとめると書いてあります。

まとめられた内容を読みましたが、あんまり分かり易くないですね。

まず以下に示した様にSimpleGrid: generate around Querierノードを追加するとあります。

f:id:kazuhironagai77:20211129003747p:plain

でもどこのBPに追加しているのかは書かれていません。Behavior Treeなのか別なEQS専用のBPクラスがありそこに作成しているのかはこのBlogからは分かりません。

f:id:kazuhironagai77:20211129003826p:plain

そのノードにPlayerから見えない場所か?距離は?そこにたどり着く道は存在するのか?などをチェックする機能を追加しています。

<<講義24: Using the EQS Testing Pawn>>

f:id:kazuhironagai77:20211129003855p:plain

と書かれていました。

あー。すっかりこんなDebugがある事忘れていました。

EQS Testing Pawn BPクラスと言うEQSをテストする為だけに作成されたクラスがあるんです。それの使用方法がまとめられています。

今回の復習ではこのクラスの存在を思い出しただけで十分です。

<<講義 25: EQS Gameplay Debugger>>

これ何の説明もしてません。先週、復習したGameplay Debuggerのnum3を押すとEQSのDebugが出来ますが、それの使用方法について解説した講義だと推測されます。

2021-02-07Blogの復習>

ぱっと読んだらEQSに対してかなり重厚な勉強をしています。

まずEQSに対して仮説を立ててそれを検証しながら勉強を進めています。

f:id:kazuhironagai77:20211129003922p:plain

この仮説に基づき

f:id:kazuhironagai77:20211129003937p:plain

のやり方を判明させるのを目的としています。

何というかやる気を感じます。この週はどうしちゃったんでしょうか?

ここからEnvironment Query System [12]の

f:id:kazuhironagai77:20211129003957p:plain

をやっていきます。

<<Required Project Setup>>

以下のクラスを作成しました。

f:id:kazuhironagai77:20211129004020p:plain

UE4のAIで必要ないつもの4つのクラスに+2つのクラスをEQS様に追加して作成しています。2つの新しいクラスはEnvironment QueryとEnvQueryContext_BlueprintBaseから作成しています。

<<Environment Query Context>>

f:id:kazuhironagai77:20211129004104p:plain

これを作成して終わりです。コメントには何をやっているのか全然分からないと書かれていました。

<<EQS Setup>>

Environment Queryから派生して作成したEQS_FindPlayerにBPで実装します。

f:id:kazuhironagai77:20211129004125p:plain

先程も出て来たSimple Grid: generate around Querierノードを追加してます。

この後ずっとこのノードの設定方法について推測しています。

ここは来週、実際に

f:id:kazuhironagai77:20211129004145p:plain

をやる時に読み直します。

<<Blackboard and Behavior Tree Setup>>

この内容はスキップしています。確かにこれはEQSの勉強とは関係ないです。

<<Behavior Tree: Patrol Setup>>

Get Random Reachable Point in Radiusノードについて検証しています。

f:id:kazuhironagai77:20211129004214p:plain

このNodeが「Reachableじゃない時はfalseを返すのでは無くて、GetRandomReachablePointInRadius関数の返した値は全てReachableですが、何らかの理由で値が返せない時に、falseが返されるみたいです。」と言う結論になると書かれています。

時間があったらこれも検証し直してみましょう。

<<Behavior Tree: In Combat Setup>>

ここではBehavior TreeからEnvironment Queryから作成したEQS_FindPlayerを呼び出す方法が説明されています。

<<AI Controller Setup並びにFinal Setup>>

EQSに関係ないのでSkipしています。

<<テスト>>

BugがあってTutorial通りに動いてないと書かれえていました。波乱万丈です。自分で書いてあれですが、読んでて面白いです。

次の章でEQSのDebug方法について習うのでそれを勉強した後で直すと書かれています。

これを読んだとき思わず笑みがこぼれてしまいました。

<<End Result>>

GamePlay DebuggerでEQSを見る方法が紹介されていたそうです。

何かのテストを行って望んだ結果が出ている事が書かれていますが、

f:id:kazuhironagai77:20211129004258p:plain

書かれている内容からは今一全体像が把握出来ません。

上の図だとPlayerの操作するキャラとNPCの位置関係が分からないのでこの結果で正しいのかが不明です。

<<EQS Testing Pawnいろいろ>>

最後に色々なテストを行っています。

これで終わりかと思ったらこれからまだ色々やっています。

<<EQS Quick Start 勉強まとめ(仮)>>

EQSの勉強した内容をまとめています。

f:id:kazuhironagai77:20211129004330p:plain

いや勉強した内容をまとめると言うより勉強して分からなかった事をまとめています。

<<EQSのDebugの復習>>

復習と言いながら、また疑問を書いています。

f:id:kazuhironagai77:20211129004349p:plain

Num/を押すとDivideが選択出来るそうです。

f:id:kazuhironagai77:20211129004413p:plain

これは今は質問の意味が分からないですね。来週、もう一回やるのでその時には質問の意味も理解出来るようになるでしょう。

この問題に対する解答も書かれていました。

f:id:kazuhironagai77:20211129004429p:plain

これはBlogの解説を読んだんですが今の知識では意味が分かりません。今週はパスします。

<<EQSのバグの直し>>

最後にここまで学んだEQSのDebug知識を使用して先程作成したけどきちんと動いていないEQSを直します。

色々検討していますが、これも来週やった後で読む事にします。今の知識では良く分かりません。

<EQSの復習まとめ>

今週はここまでとします。自分の書いたBlogとは思えないです。凄くよくまとまっています。

5.Game DesignポケモンHxHの念能力 Part 2

5.1 先週の内容をまとめ直す

先週、HxHの念能力をどうやってGameに落とすのかを考察している昔のBlog(2021-02-01のBlog)を発見しました。

読み直したら以外に面白かったんです。それでどうしてこんなに面白いのか考察しました。

結論はHxHの念能力はポケモンなどの火とか水などのタイプ別ゲームとは全く違う機能があり、それがHxHの念能力を凄く興味深いものにしていたんです。

ポケモンに代表される火とか水などのタイプ別ゲームは、基本的には戦略ゲームなんです。分かり易く言うと戦闘する前に勝敗が決定します。戦闘中に出来る事は非常に限られています。

それに対して念能力は戦術ゲームなんです。戦闘が不利な条件で開始しても戦闘中の工夫で逆転して勝利する事も可能になります。

この逆転の要素がHxHの念能力を面白くしています。

具体的に言うと、味方の戦闘力やStatusを一時的に上げる(強化系)、味方や敵の属性を変化させる(変化系)、召喚する(具現化系)、敵を眠らせる(操作系)などです。

これらの能力は戦局を一変します。今まで有利だったのが一気に不利になりえますし、その逆もありえます。

これが戦闘を面白くさせているんです。

ここから議論を一般的な戦闘システムに展開する為に、一端まとめます。

まず戦闘が開始する前に勝敗が決してしまうポケモンなどの火とか水などのタイプ別な要素などを戦略的要素、戦闘中でも逆転出来るHxHの念能力な要素を戦術的要素と呼ぶ事にします。

これらは、一般的なゲームでは魔法として使用されていますが、タイプ別のモンスターや念能力のタイプのようにその種族や個人の特徴として存在する場合もあります。

この分類を使ってまず少年マンガの戦闘システムを分析してみます。

ドラゴンボール

ドラゴンボールは戦闘力が全てを決定します。つまり戦闘する前に勝敗が決定してしまう、戦略的な戦闘システムです。

界王拳のような戦闘中でも逆転出来る戦術的要素は極僅かに存在しますが勝敗はほぼ100%、戦う前に決定している戦略的な戦闘システムです。

<ワンピース>

ワンピースには戦闘システムが存在しません。その場限りのルールがあって話の展開にそって戦闘ルールがどんどん変更してしまいます。ので考えるのは無駄です。

これ凄い不思議な話で、ワンピースは七武海やワンピースそのもののアイデアをゲームから発展させているにも関わらず、ゲームに必須である戦闘システムが存在していないんです。これが映画ファンであらゆる映画を観たみたいな人が書いた漫画なら納得ですが凄い不思議です。

<ナルト>

ナルトの戦闘システムは大変複雑で簡単には言えませんが、戦闘力などが高い方やタイプ別で有利に立った方が勝つ戦略的な要素と、感知タイプや幻術使いなどの戦闘中でも逆転出来る戦術的な要素が存在しています。これに体術などの直接攻撃の要素や召喚術などもあります。

戦略的な要素と戦術的な要素が半々で存在している戦闘システムとみなせるでしょう。

よし。段々調子に乗って来ました。

次はゲームの戦闘システムに対してこの分類を適応してみます。

まずはRPGゲームの戦闘システムに対してです。

JRPGの代表としてドラゴンクエストの戦闘システムから見てみます。

ドラゴンクエストの戦闘は面白いんです。見てて飽きない。それはHxHの念能力のような戦闘中でも逆転できる戦術的な魔法がふんだんにちりばめられているからだと思います。

ただし私、あんまりゲームをしないので具体的な内容が分かりません。

【ドラクエ5】呪文・特技一覧【DQ5】を参考にして議論する事にします。

ドラゴンクエスト5だけは一寸だけやったからです。

基本的にはドラゴンクエストの戦闘システムは、戦略的な戦闘システムだと思います。レベルを上げてぶん殴れば勝てるからです。ここで紹介されている魔法も大体は戦略的要素が高い、つまり高い攻撃力のみが重要なものが多いです。その中で戦術的な要素を感じるのが、グループ全体に攻撃する魔法です。これは戦闘中に最適な攻撃方法を考える必要が生まれます。一体の強い敵を先に倒すのか、沢山の弱い敵を先に倒すのかの選択を迫られます。

更に戦術的な要素そのものである味方の戦闘力を上げたり、敵を眠らせたりする魔法も結構あります。

何故かこれらの戦闘システムを面白くするための必須の戦術的な要素を持つ魔法は補助魔法に分類されています。

この補助魔法を先程のHxHの念能力別に分類しています。

<<強化系>>

スカラ、バイキルド、マホキテフバーハなど。

<<変化系>>

なし。

ドラゴンクエストには属性がないからなくてもおかしくはないのかも。

<<具現化系>>

なし。

ドラゴンクエストには召喚魔法もないのでなくてもおかしくはない。

<<操作系>>

マヌーサラリホールカニマホトーンなど

<<放出系>>

これは分類が難しいので後回し。

となりました。

見事にこれらの補助魔法はHxHの念能力にフィットします。

ドラゴンクエストの戦闘が面白い理由の一端が解明しました。

しかしドラゴンクエストの戦闘システムの分析をここまでまとめて二つの疑問が出て来ました。

最初の疑問は、なんでこれらの戦局を一変する魔法が補助魔法のような分類になっているんでしょうか?こっちが主の魔法じゃないんでしょうか?というモノです。

これは結局、ドラゴンクエストがレベルを上げてぶん殴る事で勝つ戦略的なゲームに属するからでしょう。戦闘中に逆転出来る戦術的な魔法は補助に留まっている必要があったんだと思います。

次の疑問は、回復系魔法は戦局を一変する魔法で戦術的な魔法です。ドラゴンクエストでも重要な魔法となっています。しかしHxHの念能力にはぴったし当てはまるタイプがありません。

あ、分かった。HxHは漫画だからゲームほど回復系の能力が必要じゃないんです。

だったらHxHの念能力のような戦術的な魔法だけを集めてもう一回分類したら良いと思いました。

更にNarutoの感知タイプみたいなのも念能力のタイプに入っていないので追加しました。

そしたらこうなりました。

f:id:kazuhironagai77:20211129004628p:plain

ここまで先週は考えました。

5.2 新しい戦闘システムの作成

先週のこの考察を踏まえて、新しい戦闘システムが構築出来るのではないのかと思い結構考えました。

まず、HxHの念能力のような戦闘中に戦局を逆転出来る戦術的な魔法は、これがRPGの戦闘を面白くする要にも拘わらず、現在のJRPGでは補助魔法として不当な低い評価をされています。

私がこの原因は以下の理由によるものだと思っています。

この理由は、戦闘中の工夫で勝敗が変わってしまうと戦闘前に必死にレベルを上げたり、貴重なポケモンを集めたりする必要がなくなってしまうからです。だからJRPGの戦闘システムは常に戦闘前に勝敗が決定する戦略型戦闘システムになっています。そうする事で、レベルを上げたり、ポケモンを集めたりする価値を保っています。しかしそれだと戦闘する意味そのものが無くなってしまうので少しだけ戦術面の工夫ができるように、HxHの念能力のような戦闘中に戦局を逆転出来る戦術的な魔法は、威力を弱めて補助魔法として少しだけ戦闘に影響を与える事が出来る程度、追加しています。

これを改善します。

<案1>

Playerが操作する魔術師はHxHの念能力のような戦闘中に戦局を逆転出来る戦術的な魔法のみを使用出来る。

Playerが操作する魔術師が召喚したMonsterはポケモンのようなタイプ別モンスター兼タイプ別の魔法のような戦闘前に勝敗が決定する魔法だけ使用出来る。

f:id:kazuhironagai77:20211129004705p:plain

この形のポイントは3体のmonsterが同時に戦う事です。そうするとPlayerが操作する魔術師が強力なHxHの念能力のような戦闘中に戦局を逆転出来る戦術的な魔法を発動しても、3体全部の不利を逆転する事は出来ません。一体位なら出来るでしょう。

これでポケモンのようなタイプ別モンスター兼タイプ別の魔法のような戦闘前に勝敗が決定する戦略的な面白さを保ちつつ、HxHの念能力のような戦闘中に戦局を逆転出来る戦術的な魔法も使用出来る事で面白い戦闘システムも確保できる気がします。

<案2

HxHのグリーンアイランドのカードの様に、HxHの念能力のような戦闘中に戦局を逆転出来る戦術的な魔法はカード化、もしくはアイテム化して一回使用すると消滅するようにする。

f:id:kazuhironagai77:20211129004737p:plain

これだけだといくらでも貯めれるので貴重性がなくなります。のでHxHのグリーンアイランドのカードの様にカード化限度枚数とゲームのクリア条件に全ての種類の魔法カードをそろえる条件は付ける必要があります。

作るのなら案2の方が簡単ですね。

このアイデアはかなり使える気がします。もう少し継続して検討する事にします。

6.RPGの作成の続き

Landscape4は自分で作成したMonster生成クラスがあるので敢えてLoad Stream Levelで作り直す必要はないと思うようになりました。のでLoad Stream Levelノードは別なmapを作成した時に使用する事にします。

それで今週のRPGの製作はやる事がなくなってしまいました。のでこれから作成する必要がある箇所をMap1を探索しながら検討します。

6.1 修正が必要な個所を見つける

Map1にPlayerが操作するキャラが現れた時点でLandscapeが出来ていないので見た目が変です。

f:id:kazuhironagai77:20211129004805p:plain

Effectを追加してワープしている所をアピールするとか、画面を暗くしてLandscapeが生成出来ていない事を隠すなどをする必要があります。

井戸の前に立っています。

f:id:kazuhironagai77:20211129004825p:plain

こういうObjectの前に立った時も(!!)を表示してEボタンをクリックする事で、「井戸だ。水が満ちている。」のようなコメントが表示出来るようにしたいです。

宿屋ですが、看板が英語になったままです。日本語に直します。

f:id:kazuhironagai77:20211129004852p:plain

以下の二つのEffectは重いので近づいた時だけ点火するようにしたいです。

f:id:kazuhironagai77:20211129005109p:plain

このABCの看板は

f:id:kazuhironagai77:20211129005136p:plain

地図についているWarp機能のワープ先です。

f:id:kazuhironagai77:20211129005200p:plain

この機能を消すのか、今は使用出来ないけど将来的には使用出来るようにするのか考える必要があります。

戦闘画面に移動する時も

f:id:kazuhironagai77:20211129005222p:plain

以下のLoad画面が3秒間表示されます。戻るときだけでいい気がします。

f:id:kazuhironagai77:20211129005243p:plain

後Load画面とLoad中に表示される文章の数をもっと多くする必要があります。

戦闘画面ですが空が明かるすぎます。

f:id:kazuhironagai77:20211129005303p:plain

Good Skyを入れて戦闘が開始した時と同じ明るさにしたいです。

戦闘に勝利した後、石像に話掛ける時、石像の頭に(!!)が表示されても見えません。

f:id:kazuhironagai77:20211129005332p:plain

頭を上げる必要があります。

f:id:kazuhironagai77:20211129005349p:plain

戦闘後に戦闘場を動き回るのためにはMonsterの死体は邪魔です。

f:id:kazuhironagai77:20211129005412p:plain

消してしまいましょう。

この警告が唐突過ぎます。

f:id:kazuhironagai77:20211129005439p:plain

立て看板を作成してそれを読んだら、このようなWidgetが表示されるようにしたいです。

Playerの操作するキャラが最初からとんでもないお金を持っています。

f:id:kazuhironagai77:20211129005459p:plain

0に戻します。

ポーズ画面の名前の欄にKUMOと表示されています。直します。

f:id:kazuhironagai77:20211129005518p:plain

HP、MPのみが表示されていて最大HPと最大MPが分かりません。

落下による死亡の時も

f:id:kazuhironagai77:20211129005536p:plain

以下のLoad画面が表示されます。

f:id:kazuhironagai77:20211129005552p:plain

要らないか落下死専用のLoad画面を表示したいです。

同じMonsterしかいません。Monsterの種類を増やしたいです。

f:id:kazuhironagai77:20211129005614p:plain

使用出来る魔法が2種類の火の魔法しかありません。

f:id:kazuhironagai77:20211129005644p:plain

増やしたいです。

最初の村で全てのItemと全ての武器が買えるようになっています。

f:id:kazuhironagai77:20211129005747p:plain

f:id:kazuhironagai77:20211129005754p:plain

直します。

どこかのBPにPrint Stringが配置されたままです。

f:id:kazuhironagai77:20211129005824p:plain

消します。

ぱっと見ただけでこんなに問題がありました。

それで来週からはこれらを直していこうと思います。

6.2 ゲームの制作に関して改善が必要な点

ここまで制作してどうしても改善が必要な個所が2つあります。それをここにまとめておきます。

<目的をはっきりさせる。Gameを作成したいのか、Gameで使用する一部のパーツを作成したいのかなど>

一つ目は、また粒度(Granularity)の話になりますが、もし目的がゲームの作成ならば、一人で制作するのですから全部を全て作成する事は出来ません。ゲームの作成に必要なパーツを集めてプラモデルのように組み立てる事を主な作業にすべきでした。

ゲームの作成が目的ならば

  1. ゲームの設計
  2. そのゲームの作成に必要なパーツの決定
  3. それぞれのパーツを集める、もしくは作成する
  4. パーツを組み立てる
  5. テスト

の順で作成する事になると思います。

ここでRPGを作成するとすると必要なパーツもそこで決定します。このパーツを全部一人で作成したい訳です。私は。これだと終わりません。ある程度は既に存在しているモノを利用する事も考える必要があります。

例えば今回のケースだとGameのEffectがあります。

もうNiagaraの勉強そのものが面白くなってしまってGameの製作そっちのけで勉強しています。それはそれで良いのですが、目的をはっきりさせないとGame制作の方が永遠に終わらなくなってしまいます。

このGameは4.24で制作しているのでNiagaraは使用出来ないんです。だから魔法のEffectを追加するとなるとCascadeで自分で作成するか、今あるEffectをそのまま使用するかしかないです。つまりこのGameの製作においてNiagaraの勉強は全く役に立ちません。

恐らくこのGameに使用するEffectは無料で頂いた以下のAssetにあるEffectをそのまま使用する事になると思います。

f:id:kazuhironagai77:20211129005903p:plain

後Game Designに関しては、販売するためでなくGame作成の勉強のためなら既存のGameの丸コピをしても良かったと思います。

そうする事でGame Designというパーツは既に存在しているモノをそのまま利用できるからです。

例えば今回のGameの場合だったら、ドラゴンクエストの1と全く同じGameを作成しても良かったと思うんです。勉強が目的だから。そうした方が一定のLevelが保てるのと、技術が足りない部分がはっきりしたりしたと思います。

今回はどんなパーツが必要なのかも知らなかったし、それぞれのパーツを自作するためにどこまで勉強が必要なのかも分からなかったですのである程度の回り道をするのは仕方ないです。

次回作はもっと計画をしっかり立てて作成する事にします。

<テスト用のProjectと本番用のProjectを分ける>

本番用のProjectでテストしていると何時まで経ってもテスト用のままになってしまいます。

これはどうやったら分けられるのかちょっとまだ分かりません。でも分けないと完成しない気がします。

7.UE5におけるWorld Partitionの勉強の続き

7.1 先週の間違い

f:id:kazuhironagai77:20211129005935p:plain

ここWorld Compositionではなく

f:id:kazuhironagai77:20211129005953p:plain

でした。

完全に書き間違えています。

7.2 Level Instancing [13]を勉強する

今週はこれを勉強します。

まずLevel Instancingが何を指しているのか不明です。その辺を明らかにする事から始めます。

f:id:kazuhironagai77:20211129010019p:plain

って書かれています。

うん。これじゃほとんど分からないですね。

今までWorld Partitionを勉強して来ましたが、Non World Partition Worldって何を指しているんでしょうね。

現状、World Partitionを起動させるためにはEngineのWorld Partitionにチェックを入れるしかないはずです。

f:id:kazuhironagai77:20211129010038p:plain

でこれをするとProject全部のLevelがWorld Partitionになるはずです。

となるとNon World Partition WorldはProject内には存在出来ないですよね。全部World Partitionになりますから。

EngineのWorld Partitionにチェックを入れない状態で存在するMapにWorld Partitionの機能を使用すると言う事でしょうか?

そんな事可能なんでしょうか?

その後に、create complex streaming strategiesと書かれています。

f:id:kazuhironagai77:20211129010059p:plain

一番目は何を言っているのか不明です。Level Instanceは特別なActorを使用する必要があるんでしょうか?

2番目は意味が分かります。

複数のStreamingを同じLevel上で行う事が出来るとあります。UE4ではこれは出来ないそうです。今知れてよかったです。実は複数のStreamingを組んでみようと思っていました。

3番目の意味も分かります。

Sub Level内にSub Levelを作成する事も出来るみたいです。

これまでの文章から推測するにLevel InstancingはUE4のLoad Stream Levelノードの進化版じゃないでしょうか?

まあ結局、何をしているのか不明です。

ネットで調べたら、Tech Art Aid 氏の動画、UE5 Quick Tip: Packed Level Instances (Prefabs?) [14] がありました。

これを見ると単に幾つかのActorをまとめて一つのActorとして扱う機能のようです。

World Partitionとは関係なさそうです。

うん。分からん。

今回は分かる所が分かれば良い位の気持ちで読んでいきます。

<Creating Level Instances

Level Instanceの作り方が説明されています。UE5 Quick Tip: Packed Level Instances (Prefabs?) [14]では実演されているので、自分でも試してみます。

以下に示した4つCubeでLevel Instanceを作成してみます。

f:id:kazuhironagai77:20211129010124p:plain

4つのCubeを選択したまま、Shift + 右クリックします。

以下に示した表示が示されるのでそこからCreate from selectionを選択します。

f:id:kazuhironagai77:20211129010143p:plain

すると以下に示したNew Level Instanceが表示されます。

f:id:kazuhironagai77:20211129010201p:plain

TypeにPacked Level Instanceを選択します。

するとどこにSaveするかと聞いて来ますのでこのLevelがあるFolderを指定しました。

f:id:kazuhironagai77:20211129010219p:plain

このNew Mapがその時にSaveしたものです。統合したActorをSaveするんじゃなくて統合したActorのあるMapを新しくSaveしています。

4つのCubeは一つのActorとして動かせるようになりました。

World Outlinerでも以下に示した様に

f:id:kazuhironagai77:20211129010242p:plain

一個のActorとして表示されています。

<<Packed Level Instances>>

先程、Level Instanceを作成するのにPacked Level Instanceを選択しましたが、ここではそれについて勉強します。

f:id:kazuhironagai77:20211129010303p:plain

先程、Group化したCubeのGroup化を最小限のStatic Mesh Instanceで行う方法のようですね。

Static Mesh以外はPackされないそうです。

<Editing Level Instances

Level Instancesの編集方法について解説しています。

編集画面を開きます。

Level Instancing [13]には2種類のやり方が載っていました。

一つ目は右クリックして表示させたメニュー欄からEdit(Level Instanceの方を選ぶ、その下のC++のEditは選ばない)を選択する方法です。

f:id:kazuhironagai77:20211129010325p:plain

2つ目はDetailにあるEditボタンを押す方法です。

f:id:kazuhironagai77:20211129010347p:plain

Tech Art Aid 氏はUE5 Quick Tip: Packed Level Instances (Prefabs?) [14] では2つ目の方法を使用して編集画面を開いていますね。

こっちでやってみます。

画面が真っ白になりました。

f:id:kazuhironagai77:20211129010405p:plain

この後、Tech Art Aid 氏のUE5 Quick Tip: Packed Level Instances (Prefabs?) [14] では編集のやり方が説明されるのですが、公式のDocumentであるLevel Instancing [13] にはそれが書かれていないようです。

一応、Tech Art Aid 氏のやり方をここで記しておきます。

以下に示した様にCubeの位置を変更しました。

f:id:kazuhironagai77:20211129010425p:plain

Level Instanceを選択した状態で右クリックしてCommitを選択します。

f:id:kazuhironagai77:20211129010447p:plain

これで変更がSaveされるそうです。

変更を消したい場合はその下のDiscardを選択すれば良いそうです。

試しにCommitを選択したら以下のようにCubeの位置がずれたLevel Instanceに変更されました。

f:id:kazuhironagai77:20211129010512p:plain

後、Commitを選択したら自動的に編集画面から出る事も出来ました。

何気に編集画面から出れなかったらどうしようか心配してたんで、編集画面からの出方も分かって良かったです。

因みにDiscard を選択した場合も編集画面から出れました。

Tech Art Aid 氏のUE5 Quick Tip: Packed Level Instances (Prefabs?) [14] ではこの後、Level InstanceをDuplicateしたりしています。

面白そうなので私もやってみました。

f:id:kazuhironagai77:20211129010540p:plain

f:id:kazuhironagai77:20211129010555p:plain

<Level Streaming at Runtime

Level Instancing [13]はここで突然、Embedded ModeとLevel Streaming Modeについての解説を始めます。

がそれらを何処で指定するのかとかの説明が全くないです。

結局どこでそれらの指定をしているのか分からなかったです。

ので軽く読むだけにします。

<<Embedded Mode>>

書かれている事を私が理解した範囲で書くと以下の様になりました。

まずEmbedded Modeつまり通常のModeではLevel Instanceは編集の状態でのみ存在しています。Runtime中はLevel Instanceは廃棄され、Level Instance内のそれぞれのActorがWorld Partitionに追加されます。

後、Level Instancing [13]ではOne File Actor (OFPA) Systemを使用するLevel Instanceはと但し書きされていますが、これが文章のどの範囲のLevel Instanceを指しているのか分からないです。

想像で考えるとRuntime中は全てのLevel Instanceが無くなると考えるのがより自然なのでOne File Actor (OFPA) Systemを使用してないLevel Instanceでも廃棄されそうです。

これは他のLevel InstanceのTutorialが出てから検討するしかないですね。

その後のNoteにもう少し情報が書かれていました。

f:id:kazuhironagai77:20211129010629p:plain

やっぱりRuntime中はOne File Actor (OFPA) Systemを使用してないLevel Instanceも廃棄されるみたいですね。

だたこれを読むと廃棄されたOne File Actor (OFPA) Systemを使用してないLevel InstanceはWorld Partitionには追加されないみたいです。

これって大変学術的な書かれ方しているから気が付きにくいですが、Level Designを効率よくするためにLevel Instanceを沢山使用して、いざGame をPlayしたらLevel Instanceが全部消えてしまった。みたいな事態が起きるわけですよね。

Level Designを担当している人達って専門学校で1,2年ソフトの使い方だけを勉強したほとんど素人に毛が生えたレベルの人たちですよね。

その人達にイキナリこの問題が降りかかる訳ですか。

解決出来るんでしょうか?

<<Level Streaming Mode>>

f:id:kazuhironagai77:20211129010650p:plain

OGPAを使用していないLevel InstanceはWorld Partitionに追加されません。しかし代わりに通常の Level Streaming を使用します。

と書かれていました。

と言う事は、Runtime中はOne File Actor (OFPA) Systemを使用してないLevel Instanceは廃棄されますが、廃棄されたLevel Instance内のActor達は通常の Level StreamingとしてWorld Partitionに追加されるので、いざGame をPlayしたらLevel Instanceが全部消える事はないと言う事でしょうか?

いやでもこれ、Level Streaming Modeにセットした場合は、と言うニュアンスが言外に入っている可能性もありそうです。

一番、確かなのは実験して確認する事ですね。

OFPAのActorを含むLevel Instanceと含まないLevel Instanceを使用してLevel を作成してGame をPlayしてみれば良いわけです。

う。でもこれを実行するにはEmbedded Mode とLevel Streaming Modeの切り替えとする方法が分からないと出来ないですね。

現状は、お話として聞いておく位しか出来ないのかもしれませんね。

その後の文章ですが、

f:id:kazuhironagai77:20211129010707p:plain

One File Actor (OFPA) Systemを使用してないLevel InstanceはSub LevelとしてLoadされます。と解釈出来ますね。

うん。それぞれのActorが勝手にLoadされるんじゃなくてLevel InstanceそのものがSub Levelに変換されるみたいですね。

じゃあ、これでも良いじゃん。と思ったらその後の解説を読むと結構コストがかかるみたいな事が書かれています。

ええー。

Level Instanceの最初で

f:id:kazuhironagai77:20211129010722p:plain

Level Instanceを使用すると沢山のLevel InstanceをStreamしたり、Sub Level の中にSub Levelがあるような複雑なLevelを作成したり出来るって言ってたじゃないですか。

この辺の具体的な作成方法やコストの問題についての説明は残りの文章の短さから推測するとなさそうですね。

その後は、コストを掛けたくなければ

f:id:kazuhironagai77:20211129010736p:plain

を使えと書かれていました。

<<Data Layers>>

Data LayerはEmbedded ModeでもLevel Streaming Modeでも使用出来ますとだけ説明されていました。

Level Instancing [13]の勉強まとめ>

Level Instanceは簡単に言えば幾つかのActorをまとめて一つとして扱う方法です。

だったらBP内に幾つかのActorをComponentとして付加すれば良いじゃんとなりますが、それとは構造が全く違うみたいです。

実際の作成方法も結構複雑です。Tech Art Aid 氏のUE5 Quick Tip: Packed Level Instances (Prefabs?) [14] でやり方を細かく示してくれています。

Level InstanceのLevel Streaming at RuntimeにはEmbedded ModeとLevel Streaming Modeがあります。ありますがそれぞれの指定方法は説明されてなくて実際にどうやって試したら良いのかは不明です。

このEmbedded ModeとLevel Streaming Modeの解説部分はかなり深く読み込みました。

のでそこから色々な知見を得る事が出来ました。

一つ、心残りなのがOne File Actor (OFPA) Systemを復習してから読んだらもっと理解が進んだと思う事です。

確かOne File Actor (OFPA) Systemも自動でセットされると思っていたら手動でセットする必要があった気がします。その辺が曖昧なまま読んでいたので、もしその辺をはっきりさせてから読んだらもっと深い知見が得られたかもしれません。

Embedded ModeとLevel Streaming Modeに関して言えば、誰かがやり方をYouTubeで示したら一発で解決するのでそれを待つのが正解でしょう。

以上です。

8.まとめと感想

今週は別な用事が入ってしまい、UEの勉強は中止しなければならなくなってたんですが、うまい具合に用事が解決してそれなりに勉強出来ました。

ただ今週は「6.RPGの作成の続き」で実際のコードを全く書かなかったので、見た目はそれなりに進んだように見えるだけかもしれませんね。やっぱり文章だけ書くのは楽だと実感しました。特に「5.Game Design:ポケモン+HxHの念能力 Part 2」を書いていてそれを感じました。

Programを書く場合にしろ、NodeやModuleの機能を調べるにしろ、仮説を立ててそれを検証するための実装を書いたりとかの色々な文章にならないけどやらないといけない部分があります。Game Designに関してはその辺をスキップ出来るので結構、言いたい事だけ書けてしまいますね。

そういう意味ではあんまりGame Designに関してはここには書きたくなかったんですが、戦闘が開始する前に勝敗が決してしまうポケモンなどの火とか水などのタイプ別な要素などの戦略的要素、戦闘中でも逆転出来るHxHの念能力な要素を戦術的要素と分類する方法は、それを超えるほど凄い発見なのではないのかとも思ったので敢えて載せる事にしました。

<参照(Reference)>

[1] Sensei, K. [英語喉®︎カズ先生 (シカゴ大学Ph. D. ) ]. (2021, November 21). 木村ここみさんの英語をシカゴ大学Ph.D.が評価してみた [Video]. YouTube. https://www.youtube.com/watch?v=a6F2SnFohRo

[2] CGHOW. (2021a, August 23). Convertible Floor in UE5 Niagara Tutorial | Download Files [Video]. YouTube. https://www.youtube.com/watch?v=pxSdLRMv8hY

[3] CGHOW. (2021b, November 22). HLSL Triangle code to UE4 Material nodes Tutorial | Download Files [Video]. YouTube. https://www.youtube.com/watch?v=JUnjDu33Nq8

[4] Epic Games. (n.d.-e). Material Nodes. Unreal Engine Documentation. Retrieved November 28, 2021, from https://docs.unrealengine.com/4.27/en-US/Resources/ContentExamples/MaterialNodes/

[5] Epic Games. (n.d.-f). Material Properties. Unreal Engine Documentation. Retrieved November 28, 2021, from https://docs.unrealengine.com/4.26/en-US/RenderingAndGraphics/Materials/MaterialProperties/

[6] Epic Games. (n.d.-h). Shading Models. Unreal Engine Documentation. Retrieved November 28, 2021, from https://docs.unrealengine.com/4.26/en-US/RenderingAndGraphics/Materials/MaterialProperties/LightingModels/

[7] Epic Games. (n.d.-d). Material Blend Modes. Unreal Engine Documentation. Retrieved November 28, 2021, from https://docs.unrealengine.com/4.26/en-US/RenderingAndGraphics/Materials/MaterialProperties/BlendModes/

[8] Epic Games. (n.d.-i). Subsurface Shading Model. Unreal Engine Documentation. Retrieved November 28, 2021, from https://docs.unrealengine.com/4.26/en-US/RenderingAndGraphics/Materials/LightingModels/SubSurface/

[9] Epic Games. (n.d.-g). Materials Content Examples. Unreal Engine Documentation. Retrieved November 28, 2021, from https://docs.unrealengine.com/4.27/en-US/Resources/ContentExamples/Materials/

[10] Epic Games. (n.d.-a). 1.3 - Translucent Light Mode. Unreal Engine Documentation. Retrieved November 28, 2021, from https://docs.unrealengine.com/4.27/en-US/Resources/ContentExamples/MaterialProperties/1_3/

[11] Cloward, B. [Ben Cloward]. (2021, November 4). Shader Performance Measurement - Shader Graph Basics - Episode 21 [Video]. YouTube. https://www.youtube.com/watch?v=E82XxlXMJs4&list=PL78XDi0TS4lEBWa2Hpzg2SRC5njCcKydl&index=22

[12] Epic Games. (n.d.-b). Environment Query System. Unreal Engine Documentation. Retrieved November 28, 2021, from https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/ArtificialIntelligence/EQS/

[13] Epic Games. (n.d.-c). Level Instancing. Unreal Engine Documentation. Retrieved November 28, 2021, from https://docs.unrealengine.com/5.0/en-US/WorldFeatures/WorldPartition/LevelInstancing/

[14] Tech Art Aid. (2021, September 15). UE5 Quick Tip: Packed Level Instances (Prefabs?) [Video]. YouTube. https://www.youtube.com/watch?v=PtGDgMIbyyg

 

「Unreal Engine 4.xを使用してRPGを作成する」の足りない部分を作成する 村人用のAIの開発 Part3

f:id:kazuhironagai77:20211121225859p:plain

<前文>

<Kyle Rittenhouse Trialって何?>

最近まで全く知らなかったんですが、今アメリカではこの裁判のニュースでもちきりです。それで慌ててどんな事件なのか調べました。

所があまりにも断片的なソースが多すぎて全体像の把握が出来ません。

NY TimeのこのVideo、A Fatal Night in Kenosha: How the Rittenhouse Shootings Unfolded | Visual Investigations [1]を見てやっとどんな事件だったのか全体像が分かりました。

今更、この話題を追っても遅きに失するで、既にあらゆる議論が尽くされてしまっています。

しかも日本にいるとアメリカの生の空気を感じる事が出来ないので、どっちの意見が事実に近いのかとかそういう事も良く分からないので軽はずみに自分の意見を言う訳にもいきません。

ただ、この映像を見るともうアメリカは実質、内戦状態なんじゃないの?と思ってしまいます。

そしてそれは私がずっと前から抱いていた不安、アメリカの衰退の始まりのような気がします。

日本もかなり終わっていますが、アメリカもこれじゃボロボロじゃないですか。

右派と言うかこの武装市民に共通する思想、「力尽くで、秩序を回復する。」は問題の解決からほど遠いです。成功しても相手に憎しみを生み出し、将来的には更なる巨大な敵を生み出します。しかし彼等はその事に気が付いておらず、Footballの試合でもしているかのようにひたすら力押ししています。

対する左派は、上下の連結が完全に終わっていて上は自分の利益ばっかり追って下に負担ばかり押し付けていています。下が上に文句を言うと右派が邪魔してるからそれは出来ないと言いますが、右派が邪魔出来ない分野、例えば大学ローンの免除なんかでも全くやろうとしてない所を見ると右派の邪魔なんで元から存在していない事が丸わかりです。

ハッキリ言って詰んでいます。

しかしだからと言って日本に未来がある訳では全然なく日本の状況はアメリカより更に悪いかもしれません。

日本は技術立国であるにも拘わらず、企業は30年の間、技術の積み重ねを止めてしまいました。

アメリカにいた時に韓国人の友達から良く聞いたのが、韓国だと夜の10時まで実験してるがアメリカは8時過ぎるとアメリカ人から文句が出るので8時までしか実験出来ない。これじゃ韓国との競争に勝てない。と言う話です。

その時、私は日本の企業は5:30で仕事を終にしてるだけでなく、沢山の上司の許可を取らないとそもそも実験すら出来ない事を知っていたのでこれって日本やばいんじゃないの?と思いました。

大体、PHP文庫を読むと1980年代のバブルの頃の日本では、技術系の会社は徹夜で実験してた事、近所の人達からあそこの会社は電気が消えない。って言われている話が散々書かれています。30年実験しなかったらもう外国の技術に追い付く事は無理ですよね。

が、日本のやばさは企業だけじゃないんです。

日本はそもそも東大クラスの工学系の大学院生の数が少なすぎるんです。例えばComputer Scienceの分野だとアメリカや中国は5万人位います。日本は精々1000人ぎりいるかいないか位でしょう。

基本的に工学系の大学院生ってのは給料もらって勉強するんです。考えたらすぐ分かる事ですが、東大クラスの工学系の大学院に入学できる学力を持っている学生なんでどの国でもそんなにいません。だから給料払う事で世界中からリクルートしてくる訳です。そうやって国が科学技術の基礎力を保持しつつ、企業がお金になりそうな分野の技術をリスク取って開拓する訳です。

戦闘力に50倍の開きがあったらポケモンみたいなタイプ別に優劣があったとしても勝負にならんでしょう。

更に日本は法律を変えてまで、中村修二氏のような一人で革命的な開発をした人を追い出してしまっています。だから奇跡的にある分野だけ成功する可能性まで潰してしまっています。私が噂で聞いたのは次世代のCPUは彼がアメリカに渡った後に開発した素材を使用して作成するらしいです。他の候補もあるらしいですが彼が開発した素材を使用したものが最も有力な候補だそうです。

日本も完全に詰んでいます。

前文には、日本人が誤解しているアメリカ、特に日本文化とキリスト教文化の違いから生じる誤解とその対策について在米歴10年の私が気が付く範囲ですが書いておく予定でしたが、今回は単なる私の感想になってしまいました。

たまにはこんなのも良いでしょう。

それでは今週の勉強を始めます。

<本文>

1.今週の予定

今週は以下の内容をやっていきます。

  • Niagara: Position変数の調査
  • Material : Content Exampleをみる
  • NPCAIを作成するためのAIの復習の続き(Debugについて)
  • World CompositionによるMap1の作成(Itemの配置など)
  • UE5におけるWorld Partitionの勉強の続き

2.Niagara: Position変数の調査など

2.1  先週のまとめ

先週、Twisted Ribbon in UE4.27 Niagara Tutorial | Download Files [2] を勉強して以下に示したRibbonを作成しましたがこれが原点にしかおけません。

f:id:kazuhironagai77:20211121230009p:plain

Niagara SystemのParticle:Position変数の値に元のPositionの値を追加すれば指定した位置におけるはずと試してみました。

f:id:kazuhironagai77:20211121230023p:plain

そしたら

f:id:kazuhironagai77:20211121230036p:plain

こんな変な形になってしまいました。

今回はParticle:Position変数について勉強してParticleの発生位置を自由に設定できるようにします。

2.2 Niagara: Position変数について

まず、Fountain Emitterを追加したNSを作成します。

これをLevel上に配置すると配置した場所にParticleをまき散らします。

f:id:kazuhironagai77:20211121230116p:plain

別に原点に拘る事もありません。

このEffectのParticle Position変数を見てみます。

Particle Spawn SectionのSphere Location ModuleのSphere LocationにParticle:Position変数が使用されています。

f:id:kazuhironagai77:20211121230211p:plain

以下の様に変形してZ軸方向に500を足してみます。

f:id:kazuhironagai77:20211121230228p:plain

地面から5m位の位置からParticleが発生するようになりました。

f:id:kazuhironagai77:20211121230252p:plain

やっぱりParticle : PositionがNSの発生する位置を指定しています。

2.3 Twisted Ribbon in UE4.27 Niagara Tutorial | Download Files [2]の最初だけ作成してPositionをみる

最初の部分だけ作成しました。

f:id:kazuhironagai77:20211121230330p:plain

Set:Particle Positionの設定です。

f:id:kazuhironagai77:20211121230353p:plain

これでRibbonはいつでも原点に現れます。

f:id:kazuhironagai77:20211121230418p:plain

これを以下の様に変えます。

f:id:kazuhironagai77:20211121230510p:plain

これで元々のPositionの値がParticle:Positionに追加されるのでNSを置いた位置にNSが現れるはずです。

f:id:kazuhironagai77:20211121230540p:plain

おお、出来ました。

でもNSの位置を移動させると付いて来ません。

f:id:kazuhironagai77:20211121230602p:plain

あ。これの意味は分かりました。

Emitter Update SectionのEmitter State ModuleのLoop BehaviorにOnce、Particle Update SectionのParticle State ModuleのKill Particles When Lifetime Has Elapsedのチェックを外しているからです。

f:id:kazuhironagai77:20211121230632p:plain

f:id:kazuhironagai77:20211121230639p:plain

試しにLoop Behaviorにinfinity、Kill Particles When Lifetime Has Elapsedのチェックを入れてみます。

f:id:kazuhironagai77:20211121230712p:plain

移動しても今度はついてきます。

f:id:kazuhironagai77:20211121230737p:plain

うーん。これで生成場所はNSの場所になりますね。

でも前のやり方でもPlayを押してテストすると指定した場所にRibbonを表示しますね。

Play前です。

f:id:kazuhironagai77:20211121230757p:plain

Play中です。

f:id:kazuhironagai77:20211121230818p:plain

これだったら前のやり方でも悪くはないですね。

2.4 Convertible Floor in UE5 Niagara Tutorial [3] を勉強する

本当は自分でNiagaraRibbon Renderingを使用して何かOriginalなVFXを作成しようと思い実際に試したんですが、滅茶苦茶になってしまいました。まだ自分だけで何かを作成するのは無理でした。守破離で言えばまだ守の段階でした。ので今回はCGHOW氏のConvertible Floor in UE5 Niagara Tutorial [3]を勉強する事にします。

f:id:kazuhironagai77:20211121230851p:plain

これをやっていきます。

びっくりしたんですがCGHOW氏の本名ってAshif Aliだそうです。この名前から推測するとほぼ100%イスラム教徒ですね。勝手にインド出身と思っていましたがもしかするとパキスタンの方かもしれませんね。

うーん。インド辺りは良く分からないです。

今週は兎に角、しっかり学ぶを目標にします。

いつも通りFountain Effectから開始しています。

f:id:kazuhironagai77:20211121230945p:plain

要らないModuleを全部消します。

f:id:kazuhironagai77:20211121231005p:plain

今回はSpawn Rateまで消しています。

Spawn Burst Instantaneous Moduleを使用するんでしょうか?

Spawn Particles in Grid Moduleを使用しています。

f:id:kazuhironagai77:20211121231035p:plain

後、このModuleを使用するためにParticles Spawn SectionにGrid Location Moduleを追加しています。

f:id:kazuhironagai77:20211121231059p:plain

Spawn Particles in Grid Moduleが存在しているのすら初めて知りました。これってUE5 のNiagaraだけに存在しているんでしょうか?

確認してみます。

普通にありました。

先に進みます。

以下のようなParticleが作成されています。

f:id:kazuhironagai77:20211121231131p:plain

Emitter Update SectionのSpawn Particles in Grid ModuleのZ Countを0にセットします。

f:id:kazuhironagai77:20211121231158p:plain

こんな風にSpriteの配置が変化しました。

f:id:kazuhironagai77:20211121231219p:plain

今度はRender SectionにMesh Renderer Moduleを追加します。勿論、Sprite Renderer Moduleは消します。

f:id:kazuhironagai77:20211121231244p:plain

Mesh Renderer ModuleのMeshに1M_Cubeを追加します。

f:id:kazuhironagai77:20211121231304p:plain

こんな感じになりました。

f:id:kazuhironagai77:20211121231330p:plain

今度はParticle Spawn SectionのGrid Location ModuleのXYZ DimensionsのXとYの値を110にセットしました。

f:id:kazuhironagai77:20211121231357p:plain

f:id:kazuhironagai77:20211121231407p:plain

こんな感じになりました。

f:id:kazuhironagai77:20211121231434p:plain

今度はこのCubicに色を付けるためのMaterialを作成します。

f:id:kazuhironagai77:20211121231454p:plain

今回のMaterialはこんだけです。

Renderer SectionのMesh RendererのOverride Materialsにチェックを入れて先程作成したMaterialを追加します。

f:id:kazuhironagai77:20211121231626p:plain

f:id:kazuhironagai77:20211121231640p:plain

こんな色に変わりました。

f:id:kazuhironagai77:20211121232318p:plain

今度はScratch Moduleを使用して何かするそうです。

以下の実装を作成しました。

f:id:kazuhironagai77:20211121232343p:plain

うーん。Particle:Position変数のXの値を取り出してるだけですね。

Particle Update SectionにColor Moduleを追加しまう。

f:id:kazuhironagai77:20211121232410p:plain

Color Moduleに以下の実装を追加しました。

f:id:kazuhironagai77:20211121232431p:plain

二つの色を表示するためのLerpを使用してるんですね。

成程です。

更にそのLerpに先程Scratch Moduleで作成した変数であるOutput Xをセットしてます。

結果です。

f:id:kazuhironagai77:20211121232458p:plain

ああ。Xの位置は真ん中だからこういう色の配置になっているんですね。

でもこれXの位置を動かす必要がありますよね。

どうやって動かすんでしょうか。

まず先程のXの値にSubノードを追加します。

f:id:kazuhironagai77:20211121232626p:plain

引く値はInputでModuleの外で指定します。

f:id:kazuhironagai77:20211121232652p:plain

あ。

何となくですが想像つきました。

これで移動するための変数をWipe変数にセットするのかと思ったら、その前に色の変化がShape過ぎるからそちらを直すそうです。

その為にDivideをSubtractの後に追加しました。

f:id:kazuhironagai77:20211121232712p:plain

何でこれで色がFadeするのか不明です。

試してみます。

f:id:kazuhironagai77:20211121232737p:plain

色がFadeしました。

f:id:kazuhironagai77:20211121232758p:plain

理由は後で考える事にします。

更に以下の実装を追加する事で、

f:id:kazuhironagai77:20211121232816p:plain

こんな色に変化します。

f:id:kazuhironagai77:20211121232837p:plain

この理由については後で考えます。

WipeにCurveを追加します。

f:id:kazuhironagai77:20211121232858p:plain

DefaultではCurve IndexにはNormalized Ageがセットされているので、

f:id:kazuhironagai77:20211121232920g:plain

色が動きます。

今度は色だけでなくMeshのサイズも変更します。

MeshのサイズもColorでやった時と同じようにoutput X変数を使用すれば出来ます。

f:id:kazuhironagai77:20211121233001p:plain

まずParticle Update SectionにScale Mesh Size Moduleを追加します。

f:id:kazuhironagai77:20211121233027p:plain

そしたらMeshが消えてしまいました。

f:id:kazuhironagai77:20211121233048p:plain

その理由は、Particle Spawn SectionのInitialize Particle ModuleのMesh Scale ModeがUnsetになっているからです。

f:id:kazuhironagai77:20211121233112p:plain

Mesh Scale ModeにUniformをセットします。

f:id:kazuhironagai77:20211121233133p:plain

またBlockが表示されるようになりました。

f:id:kazuhironagai77:20211121233159p:plain

Particle Update SectionのScale Mesh Size Moduleに

f:id:kazuhironagai77:20211121233223p:plain

以下のセットをします。

f:id:kazuhironagai77:20211121233244p:plain

結果です。

f:id:kazuhironagai77:20211121233318g:plain

動いていますね。

よく見ると下側にもBlockが伸びています。

f:id:kazuhironagai77:20211121233352p:plain

下にBlockが伸びても仕方ないので直します。

Renderer sectionのPivot OffsetにZにだけ50を追加しました。

f:id:kazuhironagai77:20211121233418p:plain

結果です。

f:id:kazuhironagai77:20211121233445g:plain

0より下はないですから。

回転を加える場合です。

Particle Update SectionにUpdate Mesh Orientation Moduleを追加します。

f:id:kazuhironagai77:20211121233521p:plain

設定は以下の様にします。

f:id:kazuhironagai77:20211121233544p:plain

こんな結果です。

f:id:kazuhironagai77:20211121233614g:plain

回転が途中で止まってしまうのでRotation VectorのYの値を2.5に変更しています。

よく見ると波が最後まで行かない場合もありますね。

どっかでやり方を間違えている可能性がありますね。

この後でCubeのサイズを変更する方法も紹介していますが、今週はここまでとして残りは来週やる事にします。

3.Material : Content Exampleをみる

今週はContent ExampleのMaterialの項目をみてどこが理解出来てどこの勉強が足りないのかを把握する事にします。

Content ExampleにはMaterialに関係したMapが以下に示した数だけあります。

f:id:kazuhironagai77:20211121233655p:plain

一個ずつ見て行きましょう。

3.1 Material Nodesを見る

多分これが一番基本的なやつでしょう。これから見て行きます。

<Base Color

f:id:kazuhironagai77:20211121233722p:plain

Base Colorです。

やっぱりこれがMaterialの一番基本的な機能を紹介していますね。

<Metallic

Metallic の機能についての解説です。

f:id:kazuhironagai77:20211121233747p:plain

Metallicは0か1以外の値は取れないはずなのに0.5が例として使用されています。

f:id:kazuhironagai77:20211121233805p:plain

一応解説には0.5の値を取る場合はほとんどないと書かれています。

Metallic が1の時はMaterialが金属の時です。

f:id:kazuhironagai77:20211121233825p:plain

このScreenshotを見て突然思いだしたのですが、Specular lightを鏡面反射光と訳している3d Graphicsの教科書があります。

この訳って結構誤解を生む表現だと思います。

鏡面反射光と聞くと普通は上のScreenshotだと鏡のように回りの風景を写している部分を指している事になりかねないからです。3D GraphicsにおいてSpecular lightは白く輝いている点状の反射光を指します。

f:id:kazuhironagai77:20211121233856p:plain

f:id:kazuhironagai77:20211121233902p:plain

の事です。

これはDot Productと内積以上のクソ訳ですので、いつか徹底的に追及します。

<Specular

Specular Reflectionの話をしていたらSpecularについての解説が次にありました。

f:id:kazuhironagai77:20211121233930p:plain

Specularが0のやつを見れば分かりますが白く光ってる反射光がありません。

f:id:kazuhironagai77:20211121233958p:plain

これがSpecular lightが無い状態です。

Specularが1の時です。

f:id:kazuhironagai77:20211121234019p:plain

白く光っている箇所がありますね。この部分がSpecular lightに当たります。

いやいや、Specularが0でも白く光ってる部分があるじゃないか?と指摘する人がいるかもしれません。

確かに下のScreenshotをみるとSpecularが0にもかかわらず白く光っています。

f:id:kazuhironagai77:20211121234044p:plain

これはうろ覚えなんですが、PBRの計算方法では、Roughnessの値が最終的にSpecularの値に幾分かの影響を与えていたからだと思います。

昔、Epic社の出した論文(たしかReal Shading in Unreal Engine 4だったと思います。)を元にOpenGLでPBRの実装を自分で作成したのですが、その時Roughnessの値がSpecularの値に還元されているのに、自分でSpecularの値を指定する事も出来るので混乱した事を覚えています。

実際、この灰色のプラスチックの部分のMaterialを見ると

f:id:kazuhironagai77:20211121234108p:plain

Roughnessに0.2の値が加えられています。

ただMetallicの値が0.3と自然界ではありえない値がセットされているので、それもこの白い反射光の生成に影響を与えている可能性もあります。

<Roughnessについて>

Metallicの項でSpecularについての話題を出したら次の項がSpecularで、Specularの項でRoughnessについての解説をしたらこの項がRoughnessでした。

f:id:kazuhironagai77:20211121234140p:plain

Roughness = 0の場合です。

f:id:kazuhironagai77:20211121234204p:plain

黒い部分に使用されているMaterialの実装です。

f:id:kazuhironagai77:20211121234232p:plain

Roughness=0.8の場合です。

f:id:kazuhironagai77:20211121234255p:plain

うーん。全くSpecular lightがなくなりました。

<Emissive について>

f:id:kazuhironagai77:20211121234804p:plain

Emissiveに1以上の値を入れると光始める事は知っています。

それ以上の事は知らないです。

<Opacityについて>

f:id:kazuhironagai77:20211121234846p:plain

OpacityはMaterialの設定がDefaultではなかったはずです。

それから確認します。

f:id:kazuhironagai77:20211121234911p:plain

Blend ModeがAdditiveに変更されていますね。

これについてちょっと調べて見ます。

公式のDocumentであるMaterial Blend Modes [4] をみるとAdditiveの項に以下に示した様な詳しい解説がありました。

f:id:kazuhironagai77:20211121234939p:plain

黒が透明として扱われると書かれていますね。貴重な情報です。

そう言えばMaterialに関する公式のDocumentを今まで見ていませんでした。

ちょっと見てみます。

公式のDocumentのMaterials [5] です。

f:id:kazuhironagai77:20211121234959p:plain

色々な分野の解説がここにまとめられていました。

f:id:kazuhironagai77:20211121235019p:plain

この辺の話題は直ぐに読みたい分野です。

f:id:kazuhironagai77:20211121235040p:plain

f:id:kazuhironagai77:20211121235047p:plain

この分野なんか今、勉強している所と丸被りしてます。

f:id:kazuhironagai77:20211121235121p:plain

まだ見なければならないMaterialがこんなにあるので、今回は公式のDocumentは読みませんが後でまとめて勉強します。

f:id:kazuhironagai77:20211121235146p:plain

<Opacityをみる>

f:id:kazuhironagai77:20211121235215p:plain

Sub Surfaceって人間の皮膚を再現するための機能でしたっけ。

Sub Surface無しが左、有りが右です。

f:id:kazuhironagai77:20211121235242p:plain

何か粘土っぽさが増している気がします。

Materialの設定をみるとBlend ModeがOpaqueで更にShading ModelがSubsurfaceにセットされています。

f:id:kazuhironagai77:20211121235302p:plain

公式のDocumentのShading Models [6] にはSubsurfaceの解説が載っています。

f:id:kazuhironagai77:20211121235340p:plain

更にその先のLinkにSubsurface Shading Model [7]もあります。

ぱっと読みましたが、あんまり詳しい解説ではなかったです。

左がOpacityが0で、右がOpacityが0.5です。

f:id:kazuhironagai77:20211121235413p:plain

右の方が人間の皮膚などの光の反射をより正確に表しているはずですが、こうやって単に2つ並べると右の方が汚いです。

<Opacity Maskについて>

f:id:kazuhironagai77:20211121235443p:plain

この機能はNiagaraの勉強で散々使用したので知っています。

設定はBlend ModeがMaskedですね。

f:id:kazuhironagai77:20211121235514p:plain

公式のDocumentであるMaterial Inputs [8] にOpacity MaskとOpacityの違いが説明されていました。

f:id:kazuhironagai77:20211121235539p:plain

透明が不透明かをはっきりさせたい時はOpacity Maskを使用する訳ですね。

<Normalについて>

f:id:kazuhironagai77:20211121235601p:plain

うーん。

このまま見てるだけだとあんまり勉強にはならないかもしれませんね。

Normal Mapと言うと今制作中のGameのガラス瓶の一部に陰が全くつかない理由はそれらのガラス瓶に使用されているMaterialにNormal Mapが使用されていないからじゃないのか?という仮説を随分前に建てました。

f:id:kazuhironagai77:20211121235627p:plain

これですね。

f:id:kazuhironagai77:20211121235646p:plain

今考えるとNormal Mapの影響はあんまりないでしょうね。

むしろBlend Modeの設定が違うのが理由でしょうね。

こっちが陰のないガラス瓶に使用されていたMaterialの設定で

f:id:kazuhironagai77:20211121235706p:plain

こっちが陰のあるガラス瓶に使用されているMaterialの設定です。

f:id:kazuhironagai77:20211121235727p:plain

実際にこのNormal Mapの例のNormal Mapを使用していない方も陰がしっかりついています。

f:id:kazuhironagai77:20211121235745p:plain

試しにこっちのMaterialの設定をみたら

f:id:kazuhironagai77:20211121235810p:plain

陰なしのガラス瓶と一緒でした。

うーん。

分からん。

<World Position Offsetについて>

f:id:kazuhironagai77:20211121235909p:plain

使用されているMaterialの内の一つを開いてみました。

f:id:kazuhironagai77:20211121235932p:plain

設定は一番基本のやつでした。

f:id:kazuhironagai77:20211122000015p:plain

これも何でMaterial内でStatic Meshの位置が動かせるんだ。とか、動かせるようになっているんだ。とかいぶかしげに思うかもしれませんが、OpenGLなどのvertex shaderを思い出すと、ああ、GPUの中でVertexの位置を動かしているからか。と理解出来ます。

<World Displacement について>

f:id:kazuhironagai77:20211122000046p:plain

初めて知らない奴に出会いました。

なんだこれは。と思って見たらTessellationについてでした。

f:id:kazuhironagai77:20211122000108p:plain

何だ。Tessellationならこの前(2021-10-31のBlog)使用したわ。と安心してMaterialを開いたら

f:id:kazuhironagai77:20211122000129p:plain

World Displacement とTessellation Multiplierは違いますね。

これは個別の勉強が必要ですね。後でする事にします。

<Tessellation Multiplierについて>

Tessellation Multiplierだけでもサンプルが配置されていました。

f:id:kazuhironagai77:20211122000152p:plain

そのサンプルで使用されているTessellationの設定です。

f:id:kazuhironagai77:20211122000214p:plain

因みに2021-10-31のBlogで使用したTessellationの設定はこれです。

f:id:kazuhironagai77:20211122000236p:plain

Tessellationについての公式のDocumentがないか探したら1.12 - Tessellation Multiplier [8] が出て来ました。

f:id:kazuhironagai77:20211122000255p:plain

いやちょっと待ってよ。

Material Nodeって項目があるじゃないですか?

f:id:kazuhironagai77:20211122000316p:plain

最初から教えて下さいよ。こういうのは本当に。

公式のDocumentのMaterial Nodes [9] のPageです。

f:id:kazuhironagai77:20211122000338p:plain

今まで見てきた内容の全てに関しての詳しい解説がここに載っていました。

f:id:kazuhironagai77:20211122000357p:plain

これをもう一回見ないといけないのかよ。

やるしかないです。

1.1 Base Color [10]

公式Documentの1.1 Base Color [10]を読んでいきます。

f:id:kazuhironagai77:20211122000420p:plain

しっかりContent Exampleで提供されているサンプルの解説です。って書かれていますね。

読みます。

あんまり大した解説じゃなかったですね。

要点をまとめると

  • RPGの3つの値をパスする
  • 値は0~1の間
  • Textureをパスする事も出来る。

位でした。

1.2 – Metallic [11] >

これも短い解説だけです。

腐食したり錆びたりした金属は0と1の間の値を取ると書いてある部分は間違っていると思います。これは錆びた部分は0、錆びてない部分は1になるが正解だと思います。

こんなにグダグダになるとは思わなかったので一端仕切り直しをします。

ここでこれは中止にして来週やる事にします。

3.2 Derivatives DDX DDY - Shader Graph Basics - Episode 18 [12]を勉強する

予定を変更してBen Cloward氏のDerivatives DDX DDY - Shader Graph Basics - Episode 18 [12]を勉強する事にします。

軽く全部見ました。

今回はDDXノードとDDYノードについての理論と3つの応用について勉強します。

f:id:kazuhironagai77:20211122000602p:plain

<理論>

DDXが提供された点のx軸方向の傾きを返し、DDYが提供された点のy軸方向の傾きを返すそうです。

このTutorialでははっきりとは述べていませんでしたが、Pixel上の点とその左右、もしくは上下の点をWorld Coordinateまで変換して傾きを求めているみたいです。

<応用1>

DDXとDDYを使用してNormal Vectorを計算します。

計算したNormal VectorはTransform ノードを使用してTangent Coordinateに変換した後にNormal Inputにパスします。

以下に実装を示します。

f:id:kazuhironagai77:20211122000642p:plain

結果です。

f:id:kazuhironagai77:20211122000656p:plain

なんでこんなにカクカクになるんでしょうね。

後、Transform VectorノードはCoordinate間の変換をするためのノードです。

f:id:kazuhironagai77:20211122000714p:plain

<応用2

Long Lat Textureを球体に貼る。

以下の実装でLong Lat Textureを球体に貼る事が出来ます。

f:id:kazuhironagai77:20211122000736p:plain

使用したLong Lat Textureはこれです。

f:id:kazuhironagai77:20211122000752p:plain

偶然ですがTutorialに使用しているImageと全く同じモノを見つけました。

結果です。

f:id:kazuhironagai77:20211122000811p:plain

Tutorialによるとこの球体に一か所だけ切れた場所があるそうですが、

f:id:kazuhironagai77:20211122000836p:plain

これですかね。

この線をDDX、DDYを使用して消すそうです。

以下の実装をしました。

f:id:kazuhironagai77:20211122000857p:plain

結果です。

f:id:kazuhironagai77:20211122000911p:plain

確かに線が消えています。

理屈は全然分からないですね。

<応用3>

Hight Map TextureをBump Mapのように使用して球をデコボコにする。

これは実装が複雑過ぎるの見るだけにします。

以下の実装をしていました。

f:id:kazuhironagai77:20211122000937p:plain

このノードが上の計算と同じ事をしてくれているそうです。

f:id:kazuhironagai77:20211122000951p:plain

Perturb Normal LQノードを使用してTutorialと同じ実装を作成しました。

f:id:kazuhironagai77:20211122001009p:plain

こんな結果になりました。

f:id:kazuhironagai77:20211122001025p:plain

はっきり言ってTutorialのような

f:id:kazuhironagai77:20211122001055p:plain

デコボコにはなりませんでした。

使用したTextureの違いのせいでしょうか?

4.NPCAIを作成するためのAIの復習の続き(Debugについて)

公式のDocumentのAI Debugging [13]を勉強していきます。

4.1 AIのDebugを勉強する前にしなければならない事をやる

<キーボードが日本語設定のUE4に必要な設定の変更>

ここで大変だったのが日本語設定のUE4だと’を押してもDebug機能が働かない事です。

2021-02-07のBlogを見ると

f:id:kazuhironagai77:20211122001143p:plain

と書かれていました。

あれ。こんな簡単だったけ。兎に角、試してみます。

f:id:kazuhironagai77:20211122001201p:plain

Playを押してゲームを開始します。そして1を押します。

普通に出て来ました。

f:id:kazuhironagai77:20211122001221p:plain

<Play中にTab keyを押す事で自在に動きまる>

2021-02-01のBlogでOnline Learningにある

f:id:kazuhironagai77:20211122001247p:plain

を勉強していますがそこでDebug中の移動に関して

f:id:kazuhironagai77:20211122001301p:plain

と述べています。

確かこれのやり方は後で判明したんですが、覚えていません。

調べます。

ありました。同じ週のBlogに書かれていました。

f:id:kazuhironagai77:20211122001315p:plain

試してみました。

f:id:kazuhironagai77:20211122001515p:plain

<AI Debugが表示されない>

f:id:kazuhironagai77:20211122001543p:plain

対象となりNPCを見ながらDebug key(私の設定の場合は1)を押します。

4.2 AI Debugging [13] を勉強する

もうどうでもいいですけど、今度はAI Entityですか。Agentって読んだりして統一してほしいです。

f:id:kazuhironagai77:20211122001604p:plain

AIによって操作されるNPCと一々言うのは面倒ですが、

<Enabling AI Debugging

f:id:kazuhironagai77:20211122001630p:plain

Apostropheを押す事でAIのDebugが出来ます。と書かれています。

ふと思ったんですが、公式のDocumentなので日本語訳ってついているはずです。

その日本語訳ではどうしてるんでしょうか?

f:id:kazuhironagai77:20211122001656p:plain

普通にApostropheを押したら出来ますって書かれていますね。

ひょっとすると今は出来る様になっているでしょうか?

わざわざこのためにAIを組むのは面倒なので昔、AIを組んだProjectを開いてApostropheを試してみました。

Shift+7を押してみましたが、AI Debugは表示されませんね。

うん。

分かりません。

でも実用面では、Shift+7で出来たらそれでOKですし、出来なかったら上記の方法で直せば良いだけです。

Numpadのkeyで表示される内容が変えられるとあります。

f:id:kazuhironagai77:20211122001717p:plain

表示されているDebug AIを読むと最初から1のAIと2のBehavior Treeの情報は表示されていますね。

f:id:kazuhironagai77:20211122001738p:plain

ちょっと見にくいですがAIの情報です。

f:id:kazuhironagai77:20211122001757p:plain

Behavior Treeの情報です。

f:id:kazuhironagai77:20211122001824p:plain

思い出して来ました。

この辺は前結構しっかり勉強したはずです。

Numpadの4を押してPerceptionを起動します。

f:id:kazuhironagai77:20211122001857p:plain

これですわ。前回はこれを見てMonsterのAIを調節していたんです。

<Nav Mesh

Nav MeshですがNumpadの0を押すとNav Meshが表示されます。としか説明していません。

f:id:kazuhironagai77:20211122001925p:plain

確かにNumpadの0を押したら現在使用中のNav Meshが表示されています。

f:id:kazuhironagai77:20211122001948p:plain

これらの表示の解説はないですね。

これだけでは何をDebugしているのかは分かりません。

先週のバグでMonsterが動かない時がありましたが、

f:id:kazuhironagai77:20211122002012p:plain

こういう時にこのDebugをすると使用中のNav Meshが視覚化されてNav Meshが働いていないとかが分かるのでしょうか?

それぐらいしかこのDebugの使い道が分かりません。

<AI

今度はNumpadの1を押した場合です。

f:id:kazuhironagai77:20211122002039p:plain

今度は表示されているそれぞれのParameterについての解説がありました。

Controller Nameは使用しているAI Controllerの名前ですね。

Pawn Name は対象のNPCの名前みたいです。名前を確認したらNPCとなっていました。

f:id:kazuhironagai77:20211122002059p:plain

Movement Modeですが、これ具体的に何を指しているのか分かりません。

Baseは現在、NPCがいるMeshを表しているそうです。

Nav DataはNavigation classを表してるとありますが、それが何なのかが分かりません。Defaultだとどうなるんでしょうか?

Path FollowingはNPCが向かっている方向を示しているんでしょうか?MovingがNPCが現在動いている事を示しているのかもしれませんね。

Behavior。これは分かります。Behavior Treeのどれが実行されているかを示してるはずです。

違いました。

Behavior Treeが実行されていたらRunningと表示されるそうです。

f:id:kazuhironagai77:20211122002124p:plain

じゃさっきのMovement ModeはNPCが走ったらRunningとかに変わるんでしょうか?

変わらなかったです。

調べたらCharacter クラスのCharacter Movement内に

f:id:kazuhironagai77:20211122002138p:plain

Default Land Movement ModeとDefault Water Movement Modeがありました。

f:id:kazuhironagai77:20211122002156p:plain

これを表しているでしょうか?

でもこれを知る必要ってどんな時なんでしょうか?

Movementについては全然知らないので実は重要なのかもしれませんが分かりませんね。

Treeは使用しているBehavior Treeを表示します。これは沢山のBehavior Treeを使用するようになると重要になりそうです。

Active Taskは現在Behavior Treeで実行されているTaskを表示します。

この辺はBehavior TreeのDebugを使用した方が分かり易いですね。実際、ここではMove toが実行されていると表示されていますが、使用しているBehavior TreeであるNPC_BTを開いてみたらTaskのMove toは3つもあってどのMove to を使用しているのかはこれからは分かりません。

Game Taskは

f:id:kazuhironagai77:20211122002217p:plain

と説明されていました。このQueueが所謂Computer scienceでいう所のQueueならば処理待ち中のTaskの数と言うことでしょうね。

そう言えばQueueとかStackってどのComputer scienceの教科で習ったんでしたっけ。当たり前過ぎて覚えていません。

今、日本で流行っている3カ月でProgrammerになれるみたいな学校って本当にこういう基礎教えているんでしょうか。こういう基礎って地味に後で効いてきますよね。知らないと。

Montageは全く何の事か分からん。

説明を見たら

f:id:kazuhironagai77:20211122002241p:plain

と書かれていました。

Animationに関係がある事は分かりました。

Third Person Anim BPを開くと

f:id:kazuhironagai77:20211122002304p:plain

Montageと言う言葉はそこかしこで使用されています。

調べて見ます。

公式のDocumentでAnimation Montage[14] がありました。

f:id:kazuhironagai77:20211122002322p:plain

このRemarkはMontageが何なのかを簡潔に説明していますね。

しかもこんな沢山の節がその中にあります。

f:id:kazuhironagai77:20211122002340p:plain

この辺を勉強した後じゃないとここのMontageが何を指しているのかは分からないです。

この辺は後でじっくり勉強しましょう。

<Behavior Tree

Behavior Treeに関してです。

f:id:kazuhironagai77:20211122002409p:plain

左側ですが、今使用しているNodeを表示してるそうです。

となると以下のNodeが使用されている事が分かります。

f:id:kazuhironagai77:20211122002442p:plain

f:id:kazuhironagai77:20211122002447p:plain

f:id:kazuhironagai77:20211122002454p:plain

f:id:kazuhironagai77:20211122002500p:plain

Behavior TreeのDebugから確認しても同じ結果を示していました。

f:id:kazuhironagai77:20211122002545p:plain

右側のBlackboard は今Behavior Treeで使用されているBlackboard内の変数とその値を示してます。

この情報は結構有り難いです。

<EQS

これは来週EQSを勉強した後にやります。

<Perception

はいやっとPerceptionに来ました。

f:id:kazuhironagai77:20211122002611p:plain

これについては解説がありませんでした。

多分ですが赤で囲ったGreenがSight、その両脇のGreenがRange Inでしょう。

f:id:kazuhironagai77:20211122002630p:plain

でもそうするとRange OutのNeon Pinkがないですね。

となると以下のNeon Pinkの部分がRange Outでその中のGreenが Range Inと言う事になりますね。

黄色のHearingもこれなら緑の内側の枠になります。

Range LoSについては分かりませんね。

f:id:kazuhironagai77:20211122002719p:plain

後はこのボールですがLast Known Locationと言うそうです。

f:id:kazuhironagai77:20211122002739p:plain

NPCから見えたPlayerの操作しているキャラの位置を示すものだそうです。

これでDebugの復習も大体終わりました。

5.Game Designについて

AIのDebugの復習のために2021-02-01のBlogを読んでいたら、HxHの念能力をGameに応用したらこうなる。的な話が書かれていました。

f:id:kazuhironagai77:20211122002801p:plain

こんな事を書いた事すっかり忘れていたんですが、改めて読み直したら大変面白かったです。

それで何でこんなに面白かったのか後で考えてみました。

その時のBlogにも書かれていますが、戦闘が開始した時点で勝敗が決定してしまっているのを戦術次第で逆転出来る可能性が出て来るからだと思います。

私を含めて多くの人がHxHの念能力をポケモンなどの火とか水などのタイプによる分類の亜流と捉えています。

これが間違っていました。

ポケモンなどのタイプによる分類を突き詰めると戦闘の勝敗は戦う前に全部決まってしまいます。言い換えれば戦略が全てです。

それに対してHxHの念能力は戦闘中の使い方を工夫する事でいくらでも逆転出来る可能性があります。つまり戦術で戦略を凌駕する事が可能になるんです。

つまりポケモンなどのタイプによる分類とHxHの念能力の分類は全く違うものなんです。ここを理解しないと何でHxHの念能力が面白いのかが分からなくなってしまうんです。

Turn制のゲームで今最も人気があるのは、タイプ別で勝敗が決まるポケモンだと思います。しかしあまりゲームをしない私でもポケモンの戦闘の勝敗は戦う前に結構な確率で決まってしまう様に感じます。ここにHxHの念能力を組み合わせる事が出来ると、ポケモンの戦闘における戦略的な面白さにHxHの念能力による戦術的な面白さが加わった今までにない仕組みのTurn制のゲームが出来る気がします。

これってひょっとすると次世代のTurn制ゲームのためのとっかかりを見つけたのかもしれません。

RPGにおける魔法をHxHの念能力のような戦闘中に使用すると逆転勝利につながるものと、ポケモンの様な火とか水などの属性に関するモノ(つまり戦闘前に準備すべきもの)に分類して、今まで漠然と存在していたRPGの魔法を2種類に分類しました。

その中でHxHの念能力のような戦闘中に使用すると逆転勝利につながるもの(仮に戦術的魔法と呼ぶ事にします。)を念能力に合わせて分類し直すと、結構無理が出て来ました。

そこで新しく分類表を作成し直して以下の様にしました。

<祝福系>

味方のStatusを一時的にUpする魔法

回復、治癒を行う魔法。

味方の不利な属性を有利な属性に変更する魔法

HxHの強化系と変化系に回復能力や徐念の能力を加えた。

<呪い系>

敵のStatusを一時的にDownしたり、眠らせたりするタイプの魔法。

毒のような持続的なダメージを与える魔法。

敵の有利な属性を不利な属性に変更する魔法。

HxHの操作系と変化系にドラゴンクエストの補助魔法の一部を追加した。

<召喚系>

Monsterを召喚するだけ。

HxHの具現化系の能力はここに追加

<霊感>

敵の戦闘力や使用出来る魔法の種類を見たり、自分の存在を敵から感知されないようにするタイプの魔法。

Narutoの感知タイプのようなもの

流石に今回のRPGに組むのは無理ですが次回のゲームにはこのアイデアはぜひ追加したいです。

6.World CompositionによるMap1の作成(Itemの配置など)

一応、先週でItemの配置以外のMap1の改良は終わったので色々なテストをしてバグ出しをしたいと思います。

6.1 銀河鉄道に乘ってLandscape4に移動した後、Map1に戻って来る

普通に戻ってこれました。

f:id:kazuhironagai77:20211122002856p:plain

6.2 Start 画面からMap1に移動

Start 画面からMap1に移動しました。

f:id:kazuhironagai77:20211122002923p:plain

問題なく始められます。

勿論、Warpした後、Landscapeが表示されない問題は解決していません。

f:id:kazuhironagai77:20211122002941p:plain

6.3 死亡した後、特に落下死の後

死亡した後に表示されるLoad画面が戦闘時に移動する時と同じです。死亡専用のLoad画面を作成しこの画面で使用する必要があります。

f:id:kazuhironagai77:20211122003001p:plain

死亡後に表示される画面です。

ゲームオーバーではなく墜落死ですね。

f:id:kazuhironagai77:20211122003014p:plain

6.4 墜落死画面の直し

墜落死画面を直していきます。

f:id:kazuhironagai77:20211122003033p:plain

墜落死用のテストのために崖を登っていたんですが、結構楽しいです。

f:id:kazuhironagai77:20211122003049p:plain

これだけで1本のゲームになりそうです。

6.5 山の隙間に短剣(小)を配置する

取りあえず静的に短剣(小)を配置してみました。

f:id:kazuhironagai77:20211122003119p:plain

これを取りに行きます。

f:id:kazuhironagai77:20211122003139p:plain

こんな感じで配置されていました。

装備してみます。

f:id:kazuhironagai77:20211122003252p:plain

普通に使えますね。

6.6 山の隙間に短剣(小)を配置する

探検(小)が配置されているSub Level3_3のBPに以下の実装をしました。

f:id:kazuhironagai77:20211122003314p:plain

当然、Game Instance BP内には

f:id:kazuhironagai77:20211122003326p:plain

新しい配列、Item Spawn Data 3_3を作成し

f:id:kazuhironagai77:20211122003348p:plain

先程、静的に配置した短剣(小)のDataを写しました。

Sub Level3_3のBPに作成した関数、Spawn ItemはMap1のBP内に設定されているものをそのままCopyしました。

f:id:kazuhironagai77:20211122003409p:plain

これ見るとMonsterをSpawnした時と少しだけ実装が違います。なぜか最初にLevel名を確認しています。

何故これをやったのか覚えていないのでこのままにしておきます。

テストします。

f:id:kazuhironagai77:20211122003425p:plain

はい。短剣(小)が動的に生成されていました。

6.7 取ったアイテムが二度と再生されないようにする

先週、Monsterでやったのと同じ様に一回取ったアイテムが再生されないようにします。

何と、一回取ったアイテムをGame Instance のItem Spawn Dataから消去する実装はWidget BPであるPick Up Item内で実装されていました。

f:id:kazuhironagai77:20211122003451p:plain

その部分を以下の様に改良しました。

f:id:kazuhironagai77:20211122003506p:plain

Remove Picked Item関数の実装。

f:id:kazuhironagai77:20211122003526p:plain

まだ一か所にしかItemを配置していないのでこれだけです。後でSwitch内のNameが増えます。

Remove Picked Item Helper関数の実装です。

f:id:kazuhironagai77:20211122003540p:plain

今度は参照するData Tableは間違っていません。

テストします。

一回Itemを取ってから、Monsterと戦闘して戻って来ました。

f:id:kazuhironagai77:20211122003606p:plain

Itemは再生されていません。

出来ました。

7.UE5におけるWorld Partitionの勉強の続き

先週、World Partitionの勉強をしていて

f:id:kazuhironagai77:20211122003631p:plain

One File Per ActorとLevel Instancingの勉強はしていない事に気が付きました。

今週はこれらを勉強します。

7.1 One File Per Actor [15] の勉強

公式のDocumentであるOne File Per Actor [15]を勉強します。

UE4までは一人がLevel Designをしている時は他の人はその人が作業を終えてからLevel Designをする必要がありました。UE5は同時に複数の人がLevel Designをする事が出来ます。

それを可能にしたのがこのOne File Per Actor(OFPA)だそうです。

One File Per Actor(OFPA)はLevel上に配置されたActorのDataを別なFileにSaveするそうです。

<Enabling One File Per Actor

えっ。

One File Per Actorって勝手に自動でやってくれてるんじゃないの?

こっちでEnableに設定しないといけないの?

と思いながら読んだら、手動で色々な粒度(granular)に設定出来て、その設定方法についての解説のようです。

それぞれのActorのDetail画面から設定する方法です。

例えばMap上に配置したCubeの場合ですと、

Cube(Instance)を選択して

f:id:kazuhironagai77:20211122003704p:plain

Actorの中の

f:id:kazuhironagai77:20211122003754p:plain

Package Modeを

f:id:kazuhironagai77:20211122003816p:plain

ここで突然説明が終わってしまっています。

これをExternalにしないといけないのか、InternalでもOne File Per Actor(OFPA)が作動しているのか分かりません。

というかInternalだとOne File Per Actor(OFPA)が作動していないのなら、最初の解釈が間違えていてOne File Per Actor(OFPA)を起動するには手動でセットする必要があるとなります。

解説を見てみます。

f:id:kazuhironagai77:20211122003848p:plain

うーん。

これ読むとInternalでもExternalでもOne File Per Actor(OFPA)は作動しているけどSaveするDataの細かさが違うとは読めませんね。

Actor is packaged alongsideはOne File Per Actor(OFPA)ではない従来のActorのDataの保持方法を指しているように思えます。

良く分からない。

この辺を詳しく解説した他のTutorialが出るのを待つか、Package ModeをInternal にしたまま、2人で同時のLevelを編集してもActorがきちんとSaveされているかを確認するかしないと結論は出せませんね。

と思ったら図の下に詳しい解説がありました。

f:id:kazuhironagai77:20211122003902p:plain

読んでなかった。

分かりました。

最初の解釈が間違っていました。

2行目の文に以下の様に書かれていますが、

f:id:kazuhironagai77:20211122003921p:plain

このEnableは「OFPAを使用出来るようにするためには」と言う意味が主で「手動で出来る」と言う意味が主ではなかったです。

このPackaging ModeをExternalにして初めてそのActorはOne File Per Actor(OFPA)でSaveされるようになるみたいですね。

後、Granularの意味は粒度というより「細かく」と解釈するのが正しいみたいですね。

調べたら粒度はgranularityでした。

次はLevel毎にOne File Per Actor(OFPA)を設定出来る方法が書かれていました。

--ここでEnable World Composition と述べている箇所は、Use External Actorsの間違いです。次の週に訂正を載せます。--

World SettingのEnable World Compositionにチェックを入れれば良いそうです。

f:id:kazuhironagai77:20211122003943p:plain

いやその後がまだありました。

チェックを入れた後でSaveする必要があり、Saveすると

f:id:kazuhironagai77:20211122004000p:plain

出て来るのでこれをYesと選択する必要があるそうです。

試してみます。

Enable World CompositionにCheckを入れた瞬間に聞いて来ました。

f:id:kazuhironagai77:20211122004019p:plain

これだけ確認出来れば十分なのでNoを押してCancelします。

あれ、それでもチェックが付いていますね。

f:id:kazuhironagai77:20211122004036p:plain

Yesを選択した場合はこのLevelに存在している全てのActorをexternal packagingに移すのは理解しましたが、Noを選択した場合はどうなるのでしょうか?

Cancelした場合とは違い一部のActorはExternal packagingに移すのかもしれませんね。

<<Enabling One File Per Actorのまとめと感想>>

軽く読んだだけですが、幾つか重要な知見を得る事が出来ました。

まずOne File Per Actorは勝手に自動でやってくれている訳ではなかったです。手動でセットする必要があります。

次にOne File Per Actorの設定方法は2種類あり、一つ目はActorのInstance毎にセットする方法で、そのActorのInstanceのみがOn File Per Actorになります。2つ目の方法はLevel毎にセットする方法で、そのLevelに配置されているActorのInstanceすべてがOne File Per Actorとなります。

正しこの2つ目のやり方で

f:id:kazuhironagai77:20211122004059p:plain

にNoと答えた時に一部のActorはOne File Per Actorにセットされるのかどうかは不明です。

後、おまけでGranularは細かいが正しい訳で、粒度は間違っていました。粒度の正しい訳はGranularityでした。

この単語についてはいつか前文で詳しく検討したいです。

<Converting Sub Levels

Use External Actorsを使用した場合、つまり先程の2番目のやり方で、OFPAにした場合ですね。この時は今のLevelに存在しているActorのInstanceのみがOFPAになるそうです。

うーん。ちょっと意味が分からない。

どういう事?

先を読んだら分かりました。

このLevelに属している全てのSub Levelに存在しているActorのInstanceもOFPAにするためにはそれぞれのSub LevelをLoadしてActiveな状態にしてUse External Actorsを使用する必要があると書かれていました。

つまり今LoadしてなかったりActiveな状態になってないSub Level上に存在しているActorのInstance達はOFPAにはなってない。と言う事です。

でもそれだと一々新しいSub Levelを読むたびにUse External Actorsを使用する必要があって大変面倒くさいです。

それを解消するためのCommandがあるそうです。

UE4Editor.exe  -run="ConvertLevelsToExternalActorsCommandlet" -nosourcecontrol -convertsublevels " OFPAにしたいLevelの場所"

だそうです。

勿論、試しませんが一応頭に入れておくだけします。

<OFPA With Source Control

source control applicationが何を指しているのか分かりませんね。

まずView Changelist windowを開いて見ますか。

うーん。これも分からん。

あ。分かりました。Source Control ってGithubみたいな所でVersion ControlしてProgrammingを一括で管理している時の話でした。私は今一人でPRGを作っているのでVersion Controlは使用してませんから私のUE5からでは出来ないはずです。

今度、二人以上でGameを作成する事になったらVersion Controlを使用するのでそん時に試します。

8.まとめと感想

今週と言うか最近の傾向として、量は沢山やったんですが質が落ちている気がします。やれる量には限りがあります。精々頑張っても2倍が限界でしょう。その代わり質は3倍でも10倍でも下手したら100倍にも出来ます。もっと頑張る方向を質を向上する方に向けるべきでした。

質を向上するための努力は量を増やす努力とは方向性が違います。

昔どうすれば質を向上出来るのかまとめたんですが無くしてしまいました。のでもう一回ここに書いて置きます。

  • 練習は完璧を作らない。練習が作るのは習慣だけである。完璧な練習のみが完璧を作る
  • 三時間、三週間、三カ月で成果の確認を。期待した成果が出ない時はその練習や勉強の中止を。
  • よい教科書やTutorialは常に探しておく。人が30時間かけて理解した事でも、説明するのは30分で済む。
  • ストレスを貯めない。ストレスがあると頭が働かなくなる。
  • 良く休む。
  • 成功した人の意見を聞く。失敗した人ややらない人、出来ない人でも威厳があってもっともらしい事を言う人は多い。しかしそういう人の意見を聞くのは無駄。
  • 慌てない。正しくやる人には、常に十分な時間がある。
  • データは正確に読むように心がける。Correlation(相関関係)とCausation(因果関係)を間違えない様にする。

後、最近気が付いたのは一端、こいつは駄目だ。と一端烙印を押した人が、たまたま凄い発見をしたり良いアイデアを思いついた時に、その発見やアイデアそのものをきちんと検討しないで、こいつが言ってんだから駄目に決まっている。とはなから無視して折角の良い発見やアイデアを無駄にしてしまう事がある事です。

<参照(Reference)>

[1] The New York Times. (2021, October 28). A Fatal Night in Kenosha: How the Rittenhouse Shootings Unfolded | Visual Investigations [Video]. YouTube. https://www.youtube.com/watch?v=VpTW2AJE9MQ

[2] CGHOW. (2021b, October 11). Twisted Ribbon in UE4.27 Niagara Tutorial | Download Files [Video]. YouTube. https://www.youtube.com/watch?v=RvTQup0Jxf4

[3] CGHOW. (2021a, August 23). Convertible Floor in UE5 Niagara Tutorial | Download Files [Video]. YouTube. https://www.youtube.com/watch?v=pxSdLRMv8hY

[4] Epic Games. (n.d.-f). Material Blend Modes. Unreal Engine Documentation. Retrieved November 21, 2021, from https://docs.unrealengine.com/4.27/en-US/RenderingAndGraphics/Materials/MaterialProperties/BlendModes/

[5] Epic Games. (n.d.-h). Materials. Unreal Engine Documentation. Retrieved November 21, 2021, from https://docs.unrealengine.com/4.27/en-US/RenderingAndGraphics/Materials/

[6] Epic Games. (n.d.-j). Shading Models. Unreal Engine Documentation. Retrieved November 21, 2021, from https://docs.unrealengine.com/4.27/en-US/RenderingAndGraphics/Materials/MaterialProperties/LightingModels/

[7] Epic Games. (n.d.-k). Subsurface Shading Model. Unreal Engine Documentation. Retrieved November 21, 2021, from https://docs.unrealengine.com/4.27/en-US/RenderingAndGraphics/Materials/LightingModels/SubSurface/

[8] Epic Games. (n.d.-c). 1.12 - Tessellation Multiplier. Unreal Engine Documentation. Retrieved November 21, 2021, from https://docs.unrealengine.com/4.27/en-US/Resources/ContentExamples/MaterialNodes/1_12/

[9] Epic Games. (n.d.-g). Material Nodes. Unreal Engine Documentation. Retrieved November 21, 2021, from https://docs.unrealengine.com/4.27/en-US/Resources/ContentExamples/MaterialNodes/

[10] Epic Games. (n.d.-a). 1.1 - Base Color. Unreal Engine Documentation. Retrieved November 21, 2021, from https://docs.unrealengine.com/4.27/en-US/Resources/ContentExamples/MaterialNodes/1_1/

[11] Epic Games. (n.d.-b). 1.2 - Metallic. Unreal Engine Documentation. Retrieved November 21, 2021, from https://docs.unrealengine.com/4.27/en-US/Resources/ContentExamples/MaterialNodes/1_2/

[12] Cloward, B. (2021, October 14). Derivatives DDX DDY - Shader Graph Basics - Episode 18. YouTube. Retrieved November 21, 2021, from https://www.youtube.com/watch?v=1HTMoCaY0xw&list=PL78XDi0TS4lEBWa2Hpzg2SRC5njCcKydl&index=18

[13] Epic Games. (n.d.-d). AI Debugging. Unreal Engine Documentation. Retrieved November 21, 2021, from https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/ArtificialIntelligence/AIDebugging/

[14] Epic Games. (n.d.-e). Animation Montage. Unreal Engine Documentation. Retrieved November 21, 2021, from https://docs.unrealengine.com/4.27/en-US/AnimatingObjects/SkeletalMeshAnimation/AnimMontage/

[15] Epic Games. (n.d.-i). One File Per Actor. Unreal Engine Documentation. Retrieved November 21, 2021, from https://docs.unrealengine.com/5.0/en-US/WorldFeatures/OneFilePerActor/

「Unreal Engine 4.xを使用してRPGを作成する」の足りない部分を作成する 村人用のAIの開発 とWorld Compositionの設定Part2

f:id:kazuhironagai77:20211114211542p:plain

<前文>

前文には、日本人が誤解しているアメリカ、特に日本文化とキリスト教文化の違いから生じる誤解とその対策について在米歴10年の私が気が付く範囲ですが書いておきます。

<英語はテニス、日本語はボーリング>

これって私がアメリカに行ったばっかしの時に日系人の人から教えてもらった話で、日本人の英語を勉強する人達の間では結構有名な話だと思っていたんですが、知らない人もいるみたいなんでもう一回解説します。

日本語しか知らない人は会話のやり方にもルールがあるなんて夢にも思わないかもしれませんが、実際は会話をする時は暗黙のルールがあってみんなそれに従ってしゃべっています。その会話のルールが英語と日本語だと違うという話です。

その会話のルールが英語の会話はテニス、日本語の会話はボーリングに似ているだそうです。

英語の会話ではテニスのように、必ず相手の発言に対して打ち返す必要があります(ただし一部の日本人がするように会話を遮って自分の話をするのはもっとルール違反です。適切なタイミングで言い返す必要があります)。ところが日本語の会話のルールだとボーリングのように誰かが発言したら、それをみんなで見て(聞いて)いないといけません。日本で育った私には誰かの発言に対して打ち返すなんて発想はまるでなかったです。

日本語の会話のルールだと相手が喋り終わるまで、おとなしく聞いているのが正しいのですが、英語の会話のルールでそれをやっていると会話をする気がないとみなされて激怒されてしまいます。

これを聞いてハイ分かりました。と直ぐに出来る様にはなりません。(実際、多人数の会話で私がそれが出来る様になったのはそれから何年も後の事でしたし。)しかし目指す方向はこの話から理解出来ました。

トヨタと電気自動車>

トヨタは日本で最も外貨を稼いでいる会社みたいですが、この英語の会話においてもっとも基本である打ち返すと言う行為を全くしない会社です。前もPriusの事故でアメリカの消費者から訴えられた時に、アメリカ人から沢山の会話のボールが投げられたにも拘わらず全て無視してとうとうアメリカを激怒させる事態になってしまいました。

今回、電気自動車と地球温暖化防止の問題で、またトヨタがやり玉に挙げられています。

今回も前のように英語圏からの発言に対して無視し続けたら、前回以上の惨事になります。

欧米人が怒っているのは、トヨタ地球温暖化防止のための電気自動車の普及に反対しているからではなくて、自分達の発言に対してトヨタが無視しているからなんです。

英語の出来ない日本人が英語と日本語は会話のルールが違うなんて夢にも思わないのと同じように、欧米人も日本語の会話のルールがヨーロッパ言語と全く違うなんて夢にも思っていません。単に失礼な態度を取っていると思われています。

<私が考える解決策>

怒れる欧米人達を無視し続けるのは、あまり良い対策とは思えません。と言うか最悪の対応です。このまま行くと前のPriusの事件よりも恐ろしい事態を引き起こす可能性もあります。

ここに私が考える最悪の事態を避ける為の解決策を書いて置きます。

<<Redditで直接、質問を受け付けそれに解答する>>

はい。

Elon MuskとかBill Gatesとかが良くやっていますが、トヨタの社長がRedditで直接、質問に対して回答するんです。

別に、相手の意見に無理に同意する必要はありません。単に自分たちが何で環境保全の観点から水素の方が電気より優れていると思っているかを正直に説明するだけで良いんです。

知らない事は知らないで十分です。

へんな質問をする奴や、はなから文句を言うつもりの奴はRedditのルールに基づいてBlockすれば良いだけです。

これやったらトヨタは我々の意見を無視していると言う主張を真っ向から消滅する事が出来ます。

無視していない以上、欧米の電気自動車推進派はトヨタに対して激怒する訳にはいかなくなります。怒ると言う行為自体がキリスト教の大罪の一つですからよっぽど理由がないと怒れないんです。

<<科学系のYoutuberとコラボ>>

流石にRedditで一般人からの質問に一々回答するのは難しい場合は、英語圏の科学系のYoutuberとコラボすれば良いです。

ただし社長が直接、表に出ないと駄目です。そこで社長が科学系のYoutuberに対して説明してそのYoutuberが視聴者に説明すると言う2段戦法です。

<前文まとめ>

昔の日本では、クジラの肉を普通に食べていたそうです。クジラが絶滅しそうになった原因はアメリカが鯨油をとる為に乱獲したからでもあります。

しかしそんな事はどうでもよくて、今となってはクジラの肉を食べるのは日本人にとってもかなりの勇気がいる行為になりました。

このままトヨタが何も対策を打たないとトヨタの車を買うのはクジラの肉を食べる位の勇気がいるような近未来が来る気がします。

それでは今週の勉強を始めます。

<本文>

1.今週の予定

今週は以下の内容をやっていきます。

  • Niagara: 先週の復習
  • Material : Ben Cloward氏のTutorialを勉強する
  • NPCのAIを作成するためのAIの復習の続き(Perceptionの勉強)
  • World CompositionによるMap1の作成(Bugの修正)
  • UE5におけるWorld Partitionの勉強の続き

2.Niagara: 先週の復習

2.1 Twisted Ribbon in UE4.27 Niagara Tutorial [1]の復習

先週、勉強したTwisted Ribbon in UE4.27 Niagara Tutorial [1]のNodeや関数などで知らない機能などを復習します。

<Return Normalized Exec Index

これです。

f:id:kazuhironagai77:20211114211747p:plain

Dynamic Input Parameterの一つです。

Cursorを合わせると以下の解説が表示されます。

f:id:kazuhironagai77:20211114211801p:plain

0から1の間の数字を返す事以外は不明ですね。

中身を見てみます。

f:id:kazuhironagai77:20211114211815p:plain

これだけです。

f:id:kazuhironagai77:20211114211829p:plain

あれ。これって見た記憶があります。

あ。

先週この辺までは調べていました。

先週、調べたりない所を調べます。

Execution Countの機能に関しては、

f:id:kazuhironagai77:20211114211842p:plain

と推測しています。

でもこれが合っているのか不明です。今、読んでみるとなんでそう思えるのかの根拠が書かれていませんし。

色々調べてみましたがこのDynamic Inputに関しての資料は見つかりませんでした。

実験してみる事にします。

以下の様な最も基本的なEmitterを組みます。

f:id:kazuhironagai77:20211114211855p:plain

Spawn Rateは1にセットします。

f:id:kazuhironagai77:20211114211908p:plain

Life Timeも1にセットしました。

f:id:kazuhironagai77:20211114211920p:plain

こんな感じです。

f:id:kazuhironagai77:20211114211933p:plain

ここのParticle Update SectionにSet Positionを追加します。

f:id:kazuhironagai77:20211114211956p:plain

そしてParticleのPositionのXにReturn Normalized Exec Indexをセットします。

f:id:kazuhironagai77:20211114212009p:plain

これでReturn Normalized Exec Indexの値の変化に伴ってX方向にSpriteが移動するはずです。

結果です。

f:id:kazuhironagai77:20211114212022p:plain

なんの変化もありません。

Spawn Rateを5にしてみました。

f:id:kazuhironagai77:20211114212035p:plain

僅かな動きか観測されました。

動きを大きくするためにNormalized Index Scaleに20をセットします。

f:id:kazuhironagai77:20211114212048p:plain

こんな感じです。

f:id:kazuhironagai77:20211114212115g:plain

これを見ると、同時期に生存しているParticleの間で0から1の値が割り振られているみたいです。最初に生成されたParticleが0、最後に生成されたParticleが1の値を持っているようです。

この仮説を検証するためにSpawn Rateの値を変更してみます。

Spawn Rate=2の時です。

f:id:kazuhironagai77:20211114212148p:plain

f:id:kazuhironagai77:20211114212156p:plain

二つ発生しています。Return Normalized Exec Indexの値はそれぞれ0と1と考えられます。

Spawn Rate =3の時です。

f:id:kazuhironagai77:20211114212216p:plain

はい。想像した通りの結果になりました。Return Normalized Exec Indexの値はそれぞれ0と0.5と1と考えられます。

これからSpriteの数を増やすのにSprite同士が重なると見にくいのでSpriteのサイズを半分にしました。

f:id:kazuhironagai77:20211114212229p:plain

f:id:kazuhironagai77:20211114212234p:plain

Spawn Rate =4の時です。

f:id:kazuhironagai77:20211114212250p:plain

4つSpriteが発生しています。

Return Normalized Exec Indexの値はそれぞれ0と0.25、0.5、0.75、1となっているはずです。

今度はLife Timeを変更してみます。

Spawn Rateを1に戻します。

Life Timeの値を1から2に変更します。

これでSpriteは一秒間に一回生成され、それぞれのSpriteの寿命は2秒になるので同時に存在するSpriteは2個になります。と言う事はReturn Normalized Exec Indexの値はそれぞれのSpriteで0と1になるはずです。

f:id:kazuhironagai77:20211114212304p:plain

なっていました。

Return Normalized Exec Indexの値は実際はどうなっているのかは分かりませんが、現象としては、

同時期に現れるSpriteの中での現れた順番(ただし最初は0/同時期に現れるSpriteの数

の値が入っているようです。

今度はSpawn Burt Instantaneous Moduleで試してみます。

f:id:kazuhironagai77:20211114212326p:plain

Spawn Countを3にしました。

f:id:kazuhironagai77:20211114212351p:plain

これで0、0.5.1にSpriteが発生するはずです。

f:id:kazuhironagai77:20211114212542p:plain

してました。

確認のためにSpawn Countを4にします。

f:id:kazuhironagai77:20211114212556p:plain

はい。予測通りの結果が出ました。

となるとTwisted Ribbon in UE4.27 Niagara Tutorial [1]でReturn Normalized Exec Indexを使用した理由は、単にRibbonの長さを1にするためだったと言う事でしょうか?

先週と同じ形をもう一回作成しました。

f:id:kazuhironagai77:20211114212611p:plain

Return Normalized Exec IndexのScalingの値を2にしました。

f:id:kazuhironagai77:20211114212624p:plain

Tubeの長さが2倍になりました。

f:id:kazuhironagai77:20211114212637p:plain

うーん。

2021-07-04のBlogで解説しているRibbonの構成をしたに示しますが、

f:id:kazuhironagai77:20211114212651p:plain

この緑色のParticleの位置が均等に配置される効果もあるかもしれませんが、Return Normalized Exec Indexを使用した理由は、基本的には単にRibbonの長さを1にするためだったようです。

以下の部分ですがTutorial内で説明がありました。

f:id:kazuhironagai77:20211114212704p:plain

Spawn RateでRibbonのためのParticleを次々と作成しているのでJittery thingが出来ています。それを無くすためにSpawn Burst Instantaneous Moduleを使用します。

Jittery Thingって以下に示した縞々が動いている時にちょっとだけつぶれて見える事を言っているんでしょうか?

f:id:kazuhironagai77:20211114212719p:plain

こんな感じです。

f:id:kazuhironagai77:20211114212811g:plain

Spawn Burst Instantaneous Module に変更したら一瞬だけRibbonが表示されるようになってしまいました。

f:id:kazuhironagai77:20211114212839p:plain

それでEmitter Update SectionのEmitter State Module

f:id:kazuhironagai77:20211114212851p:plain

のLoop BehaviorをOnceにして

f:id:kazuhironagai77:20211114212907p:plain

Particle Update SectionのParticle State Moduleの

f:id:kazuhironagai77:20211114212940p:plain

Kill Particle When Life Time Has ElapsedのCheckを外します。

f:id:kazuhironagai77:20211114212954p:plain

するとRibbonがずっと表示されるようになりました。

f:id:kazuhironagai77:20211114213009p:plain

今度は先程のようなJittery thingは無くなっています。

f:id:kazuhironagai77:20211114213031g:plain

これってSpawn Burst Instantaneous Moduleを使用すれば別にこの方法じゃなくても消せるはずですよね。

別な方法を試してみます。

Particle Spawn SectionのInitialize Ribbon ModuleのLife Timeの値を5にしました。

f:id:kazuhironagai77:20211114213115p:plain

これだと5秒間はRibbonを表示していますが、その後一瞬だけ消えてしまいます。

うーん。だからこっちを使用してるんですね。

f:id:kazuhironagai77:20211114213132p:plain

大体納得しました。

RibbonにCurveをつける>

この部分は読み直したら大体理解出来ましたが、先週のBlogには何をやっているのか不明と書いていたので一応解説します。

f:id:kazuhironagai77:20211114213206p:plain

Ribbon Link Order変数にはそれぞれのParticleの番号が入っています。

f:id:kazuhironagai77:20211114213241p:plain

その番号に対して50だったらZ軸に対して100の位置、100だったらZ軸に対して0の位置と指定しています。

その結果、

f:id:kazuhironagai77:20211114213255p:plain

こんな曲がった形のRibbonを作製する事が出来ます。

でもそれならReturn Normalized Exec Index 変数を使用して範囲を0から1の間にしても同じだと思うんですが。

f:id:kazuhironagai77:20211114213310p:plain

ほら、同じ結果が出ています。

f:id:kazuhironagai77:20211114213326p:plain

この場合はこれも要らないですし。

f:id:kazuhironagai77:20211114213344p:plain

あれ?

Execution IndexをRibbon Link Orderにセットしなかったら以下のようになってしまいました。

f:id:kazuhironagai77:20211114213401p:plain

何か勘違いしている?

Ribbon Link Order変数の解説を以下に示します。

f:id:kazuhironagai77:20211114213415p:plain

これ読むと、Ribbon Link OrderはParticle同士をRibbonで繋げる時の順番を指定するための変数だったです。

つまりここでRibbonを作る順番をExecution Index通りにしないとさっきのようにグチャグチャになってしまう訳です。

f:id:kazuhironagai77:20211114213430p:plain

ふーん。これはRibbonのEffectを作製する時に結構役立ちそうな情報ですね。

勉強になりました。

<Material内のノードについて>

<<Panner>>

Pannerノードは、基本的なノードらしいですが使用したの初めてです。

f:id:kazuhironagai77:20211114213454p:plain

こんな解説がしてありました。

f:id:kazuhironagai77:20211114213511p:plain

これだけ読むとPannerは単にTextureを動かすノードですね。

試しに以下のMaterialを組んでみましたが

f:id:kazuhironagai77:20211114213525p:plain

f:id:kazuhironagai77:20211114213530p:plain

動いていますね。

f:id:kazuhironagai77:20211114213547g:plain

<Step

f:id:kazuhironagai77:20211114213615p:plain

このStep、公式のDocumentが見つかりません。

これを見てもView Documentationが選択出来ない状態になっています。

f:id:kazuhironagai77:20211114213632p:plain

うーん。

Stepという単語があまりに一般的過ぎてDocumentまでたどり着けないのかな?

Groupを見るとMathに属しています。

f:id:kazuhironagai77:20211114213648p:plain

公式のDocumentのMath Expressions [2]を見ましたが載ってませんでした。

うーん。

分からん。

Ben Cloward氏のSmoothstep - Shader Graph Basics - Episode 15 [3] なら検索に出て来ます。

なんかヒントになるかもしれないと見てたら、Unityで解説しています。

f:id:kazuhironagai77:20211114213702p:plain

うん。ひょっとしてUnityにStepってNodeがあって、しかも機能的にもUnrealと一緒だったりして。

ちょっと探して見ます。

Unity公式のDocumentにStep Node [3] がありました。

f:id:kazuhironagai77:20211114213716p:plain

これを見るとInの値がEdgeの値より大きかったら1を小さかったら0を返すとあります。

UEでも同じでしょうか?

試してみます。

f:id:kazuhironagai77:20211114213731p:plain

こんな感じです。

f:id:kazuhironagai77:20211114213743p:plain

1が返って来た。と言う事でしょうか?

X>Yだと1が返る。と言う事でしょうか?

X<Yにしてみました。

f:id:kazuhironagai77:20211114213757p:plain

今度は黒いです。

f:id:kazuhironagai77:20211114213811p:plain

XがUnityのInと同じでYがUnityのEdgeと同じみたいですね。

うん。

まあ機能が理解出来たのでTextureの時にどうなるかを見てみます。

これでテストしてみます。

f:id:kazuhironagai77:20211114213827p:plain

Fresnelは以下の様に設定しました。

f:id:kazuhironagai77:20211114213840p:plain

結構白い部分が多いです。

X>Yの部分は白く、Y>Xの部分は黒くなるはずです。

X=0.2 の場合です。

f:id:kazuhironagai77:20211114213854p:plain

X=0.5です。

f:id:kazuhironagai77:20211114213907p:plain

X=0.8 の場合です。

f:id:kazuhironagai77:20211114213919p:plain

ああ、分かりました。

Twisted Ribbon in UE4.27 Niagara Tutorial [1]では

f:id:kazuhironagai77:20211114213936p:plain

黒い部分を透明にしているんです。

確認のために以下の実装をしてみました。

f:id:kazuhironagai77:20211114213949p:plain

穴あいています。

f:id:kazuhironagai77:20211114214002p:plain

はい。Stepの意味も何とか理解しました。

<Set Particle Position Moduleの位置の移動>

f:id:kazuhironagai77:20211114214024p:plain

これは意味を理解した今なら簡単でSet Particle Position ModuleはScratch Moduleの後ならどこでも良いです。

f:id:kazuhironagai77:20211114214042p:plain

Set Particle Position Moduleを使用する前にRibbon Link Order変数にExecution Indexの値をAssignしておく必要があります。

f:id:kazuhironagai77:20211114214110p:plain

のでこれでも大丈夫です。

因みにこれを忘れると先程のように以下のような変な形のRibbonが出来ます。

f:id:kazuhironagai77:20211114214141p:plain

以上です。

2.2 Twisted Ribbon in UE4.27 Niagara Tutorial [1]の残りをやる

色やWidthを変えて以下の様にしました。

f:id:kazuhironagai77:20211114214201p:plain

EmitterをDuplicateして色やサイズを変更します。

f:id:kazuhironagai77:20211114214215p:plain

こんな感じです。

f:id:kazuhironagai77:20211114214230p:plain

うーん。

今度はこのEffectをBPからControlするための実装をしていきます。

まずUser Parameterに以下の変数を作製しました。

f:id:kazuhironagai77:20211114214242p:plain

あ。もう分かりました。

この変数たちをそれぞれのParameterにセットしていくわけですね。

Particle Update SectionのSet PositionのXのAにLength変数をセットします。

f:id:kazuhironagai77:20211114214255p:plain

Particle Update SectionのSet Ribbon TwistのAのAにTwist Speed変数をセットします。

f:id:kazuhironagai77:20211114214309p:plain

Particle Update SectionのScale Ribbon Width ModuleのScale CurveにWidth変数をセットします。

f:id:kazuhironagai77:20211114214324p:plain

あれ。二つ目のEmitterのScale Curveに同じ値はセット出来ませんよね。

f:id:kazuhironagai77:20211114214337p:plain

こうしました。

そう言えばCurve変数は?

Curve変数を抜かしていました。

Particle Update SectionのSet PositionのScale CurveにCurve変数をセットします。

f:id:kazuhironagai77:20211114214352p:plain

この後、BPからこれらの値をセットしていますが説明が簡単過ぎて何をしているのか良く分かりません。

自分で作ってみます。

ActorにComponentとして今作成したNSをつけます。

f:id:kazuhironagai77:20211114214406p:plain

それぞれのUser Parameterの変数にActorの変数をセットします。

f:id:kazuhironagai77:20211114214423p:plain

取りあえずはこれでテストします。

f:id:kazuhironagai77:20211114214442p:plain

こんな感じです。

f:id:kazuhironagai77:20211114214457p:plain

Lengthを2倍にしてみます。

f:id:kazuhironagai77:20211114214510p:plain

Ribbonの長さが2倍になりましたね。

Curveを2倍にしました。

f:id:kazuhironagai77:20211114214526p:plain

Twist Speedを9から3に変更しました。

f:id:kazuhironagai77:20211114214540p:plain

これはあんまり変化してないです。

最後にWidthを1.5倍にします。

f:id:kazuhironagai77:20211114214557p:plain

はい。

Tutorialのとはかなり違いますがUser Parameterの値をBPから呼び出せたのでOKとします。

一つこのNSに不満があるのですが、どこにこのActorを置いてもこのNSが出現するのは原点からになります。

この点は改良したいです。

2.3 Twisted Ribbon in UE4.27 Niagara Tutorial [1]の発生場所を調節する

どこにこのActorを置いてもこのNSが出現するのは原点からになるのはParticle のPositionに元のPositionの値を足してないからだと思っています。

これを試してみます。

取りあえず金色のRibbonのだけParticleのPositionを追加してみました。

f:id:kazuhironagai77:20211114214617p:plain

金色のRibbonの部分がBeamみたいに飛んでいきました。

f:id:kazuhironagai77:20211114214631p:plain

うーん。もう少し考えないといけないですね。

これは来週考える事にします。

3.Material : Ben Cloward氏のTutorialを勉強する

3.1 Smoothstep - Shader Graph Basics - Episode 15 [3] を勉強する

もうこれは運命みたいなもんですね。今週はSmoothstep - Shader Graph Basics - Episode 15 [3]を勉強します。

まずぱっと全部見ました。

うーん。今回はUnityとUEで紹介しているSmooth Stepを使用した応用例が違いますね。どちらかと言うとUnityで作成したヤツの方が興味深いです。UE5の応用例はLandscapeを勉強した時に似た機能を既に勉強していますし。Unityで紹介されている応用例もUE5で作成してみます。

<理論>

Smoothstep - Shader Graph Basics - Episode 15 [3]も最初はGraphを使用して数式の解説から始まっています。

私もDesmosのGraphic Calculatorを使用してTutorialと同じ図を作製します。

f:id:kazuhironagai77:20211114214709p:plain

ほぼ同じGraphを作製しました。

Powerの時の勉強でやりましたが、Materialでは色などを0から1の間の数字で表すので、xが0の時にyが0、xが1の時にyが1である関数は非常に重要です。

Smooth Stepに使用されている関数は、xが0の時にyが0、xが1の時にyが1でありかつ0から1への変化が滑らかな曲線で行われています。

どうやってその関数を作製したのかをここで解説しています。

<<y=x>>

最初の式はy=xです。

f:id:kazuhironagai77:20211114214730p:plain

これは単にxが0の時にyが0、xが1の時にyが1である式の一例として紹介しただけのようです。

この式は直線ですので滑らかな曲線はどこにもないですね。

<<y =x ^2>>

f:id:kazuhironagai77:20211114214750p:plain

Y=x^2のGraphです。

まずこの関数で描かれる線はxが0の時にyが0、xが1の時にyが1でしかも曲線です。

しかしよく見ると0から0.2までは滑らか曲線ですが、0.8から1までは結構激しく曲がっています。0.8から1の間はもっと滑らかな曲線がほしいです。

<<y = 1- (x-1)^2>>

f:id:kazuhironagai77:20211114214810p:plain

y = 1- (x-1)^2ってあまり馴染みのない関数ですが、この関数、0.8から1の間がとても滑らかな曲線を描いています。

しかも先程のy = x^2と正反対の曲線を描いています。

f:id:kazuhironagai77:20211114214824p:plain

当然ですが、0から0.2位まではy=x^2、0.8から1まではこの関数と同じ結果を出す関数がほしくなります。

それが次の関数になります。

<<y =x^2 (3-2x)>>

f:id:kazuhironagai77:20211114214842p:plain

どうやってこの関数を発見したのか検討も付かないですが、兎に角この関数だと0から0.2位まではy=x^2、0.8から1まではy = 1- (x-1)^2と同じような滑らかな曲線を示しています。

おお。これをSmooth Stepで使用しているのかと思ったらこの関数でもまだ完璧ではなくて

f:id:kazuhironagai77:20211114214857p:plain

0より小さい値はずっと0、1より大きい値はずっと1にしたいんです。

それで最後の式が登場します。

<<q = max (0, min(1,x))の時、y = q^2(3-2q)>>

f:id:kazuhironagai77:20211114214916p:plain

はい。これが今まで述べた全ての条件を満たした関数です。

<Smooth Stepノードの基本>

Tutorialの例とはちょっと違いますがこっちの方がSmooth Stepの機能がはっきり分かるのでこの実装で検証します。

f:id:kazuhironagai77:20211114214947p:plain

こんな結果です。

f:id:kazuhironagai77:20211114215002p:plain

これにSmooth Stepを掛けます。

黒い部分は更に黒く、白い部分は更に白くなります。ただし非常に滑らかに変化もします。

f:id:kazuhironagai77:20211114215016p:plain

こんな結果になりました。

f:id:kazuhironagai77:20211114215030p:plain

黒い部分は更に黒く、白い部分は更に白くなっていますが全体の滑らかさは保ったままです。

これがSmooth Stepです。

Tutorialでは更にMinとMaxの機能について解説していました。

同様のテストを行います。

f:id:kazuhironagai77:20211114215043p:plain

<<Max = 0.5 の場合>>

f:id:kazuhironagai77:20211114215101p:plain

こんな結果です。

f:id:kazuhironagai77:20211114215114p:plain

Fresnel ノードで0.5以上の値だったところが全部1になっているはずです。

<<Max = 0.5 、Min=0.4の場合>>

今度は、Minも0.4にします。

f:id:kazuhironagai77:20211114215133p:plain

Fresnel ノードで0.4以下の値を示した箇所は全部黒くなっているはずです。

f:id:kazuhironagai77:20211114215246p:plain

こうなるとSmooth Stepの特徴である滑らかな変化がはっきりしませんね。

<<Max = 0.8 、Min=0.3の場合>>

f:id:kazuhironagai77:20211114215305p:plain

こんな感じです。

f:id:kazuhironagai77:20211114215317p:plain

これなら黒から白に変わる時に少しだけ滑らかな変化がみられます。

<応用編1:消えるStatic Mesh

これは見た目が非常に映えるので結果から先に記録しておきます。

f:id:kazuhironagai77:20211114215400g:plain

球が消えたり出現したりしています。

実装方法です。

f:id:kazuhironagai77:20211114215436p:plain

MinとMaxの値をSineで時間によって変化させているのと、ValueにGradientのあるTextureを使用して作成しています。

更に以下の様に改良する事で、境界線のみを表示する事も可能です。

f:id:kazuhironagai77:20211114215455p:plain

結果です。

f:id:kazuhironagai77:20211114215519g:plain

実際に使用するにはもう少し工夫が必要かもしれませんね。

色々微調整してみました。

f:id:kazuhironagai77:20211114215558g:plain

うーん。

光らせるのは嫌いと言いながら思いっきり光らせています。

やっぱり光らせて印象を強くさせるのは手っ取り早いです。

<応用編2:地面からの距離でMaterialが変化する>

何を言っているのか良く分からないので先に実装から説明します。

f:id:kazuhironagai77:20211114215638p:plain

結果です。

f:id:kazuhironagai77:20211114215657p:plain

Absolute World PositionにMaskしてBの値だけ渡しているので地面から高さに応じて黒の部分と白の部分が生じます。

こんな感じです。

f:id:kazuhironagai77:20211114215723g:plain

これだとただの影じゃん。という感想になってしまいますね。

色付けて見ました。

f:id:kazuhironagai77:20211114215752g:plain

この技術を使用してLandscapeでCameraから遠い所にあるMaterialは別なものを表示出来る訳です。

<おまけ>

f:id:kazuhironagai77:20211114215828p:plain

この技術を使用してセルルック調のMaterialを作製してみました。

うーん。

Smoothに変化しない方がセルルック調になりそうですね。

試しに同じやつをStepノードで作成してみました。

f:id:kazuhironagai77:20211114215844p:plain

これだけ見ると結構よさげですが、Cubeなんか滅茶苦茶です。

f:id:kazuhironagai77:20211114215903g:plain

Stepで輪郭線は出さない方が良いみたいです。

輪郭線の部分を濃い肌色で置き換えてみました。

f:id:kazuhironagai77:20211114215957g:plain

うーん。

今回はこんなもんですか。

3.2 Length & Distance - Shader Graph Basics - Episode 16 [4] を勉強する

後、何をするか考えていなかったので、もう一個、Ben Cloward氏のTutorialをやる事にします。

どれでも良かったんですがたまたまこれが目に入ったんでこれをやる事にします。

まずぱっと全部を見ました。

基礎ではLengthノードとDistanceノードの違いについて解説しています。応用ではこのノードを使用した3つの例が実装されているんですがどれも面白いです。

早速やってみます。

<基礎編>

DistanceノードとLengthノードの違いについてです。

UE5では以下の二つのノードになります。

f:id:kazuhironagai77:20211114220045p:plain

Lengthノードですが名前がVector Lengthとなっていました。しかもVector 3とVector 2の両方に対応しています。

それよりもDistanceノードです。

Distanceで探しても出て来ません。

f:id:kazuhironagai77:20211114220131p:plain

ずっと下にスクロールしたら出て来ました。

f:id:kazuhironagai77:20211114220145p:plain

このTutorialが今年の9月に作られたんじゃなかったら諦めていたところです。

LengthはVectorもしくは線分をパスします。そしてパスされたVectorもしくは線分の長さを返します。それに対してDistanceは2つの位置をパスします。そしてパスされた2つの位置の距離を返します。

Tutorialはこれで分かったでしょう。と応用編へ行ってしまうのですが、ちょっとこの説明では分かりにくい部分もあるので以下の実装を作製してテストします。

f:id:kazuhironagai77:20211114220201p:plain

ここではObjectの位置とCameraの位置をDistanceノードにパスしてDistanceノードの計算結果をDebug Scalar Valuesを使用して表示しています。

f:id:kazuhironagai77:20211114220225p:plain

これと同じ事をLengthでやるには以下に示したように差分のVectorを計算する必要があります。

f:id:kazuhironagai77:20211114220241p:plain

結果は同じです。

f:id:kazuhironagai77:20211114220254p:plain

<応用編1:カメラからの距離で明るくなるMaterialの作成>

実装です。

f:id:kazuhironagai77:20211114220314p:plain

まあ。これは当たり前と言えば当たり前ですね。

敢えて述べるとすればAbsolute World Positionノードを使用しているので距離が近いときはPixel毎に色の違いが表示されるはずと言う事とUE5の単位、Unreal Unitは基本的には1㎝なので10000で割る必要があると言う2つです。

結果です。

近い時です。

f:id:kazuhironagai77:20211114220331p:plain

Pixel毎のGradientが見えるかと言えば少しだけ見えますという感じです。

遠い時です。

f:id:kazuhironagai77:20211114220348p:plain

完全に白くなっています。

<応用編2:ゆらゆら揺れるStatic Meshをつくる>

これと最後の奴が面白いです。

最初に結果から表示します。

f:id:kazuhironagai77:20211114220441g:plain

まるで風に揺られている木のような動きです。

実装方法を以下に示します。

f:id:kazuhironagai77:20211114220516p:plain

ここで凄いのは上に行く程揺れ幅は大きく一番下では揺れていない事です。

Local Position ノードは何を返しているんでしょうか?

f:id:kazuhironagai77:20211114220531p:plain

Material関数に対する一般的な解説しかしてませんね。

World PositionのLocal 板でしょう。それだとPixel毎に色が違って見えているのも納得ですし。

このGradientをSinと掛けてY軸のOffsetに追加しています。これで上に行く程揺れ幅は大きく一番下では揺れていない不思議なMaterialを作製しています。

自分で別な方法でこのY軸のゆらゆらを再現して見ようとしたんですが、出来なかったです。World Offsetにパスする値には何か条件があるんでしょうか?

まだ良く分からない事が多いですね。

と言うかちょっと頭が働かなくなって来ました。

Materialの勉強はここまでにします。続きは来週やります。

ちょっと休憩してから考え直したら出来ました。

f:id:kazuhironagai77:20211114220546p:plain

こんな感じです。

f:id:kazuhironagai77:20211114220606g:plain

Distanceノードは使用していませんがゆらゆら木の様に揺れるところは再現出来ました。

<応用編3:ライトに照らされている様に見えるMaterialをつくる>

これは先に作成して後から何をやっているのかを検証する事にします。

以下に実装部を示します。

f:id:kazuhironagai77:20211114220636p:plain

こんな結果です。

f:id:kazuhironagai77:20211114220722g:plain

どうしてこんな結果になるのかを検証します。

この部分は一つ前の応用編と同じですね。これでLightを左右に動かしているんですね。

f:id:kazuhironagai77:20211114220804p:plain

試しにY軸に変更してみます。

f:id:kazuhironagai77:20211114220816p:plain

こんな結果になりました。

f:id:kazuhironagai77:20211114220834g:plain

Distanceノードの時です。

f:id:kazuhironagai77:20211114220900p:plain

こんな結果です。

f:id:kazuhironagai77:20211114220915p:plain

うーん。これを調節するために残りの計算がある訳ですね。

f:id:kazuhironagai77:20211114220930p:plain

光の強さを弱くしています。

f:id:kazuhironagai77:20211114220948g:plain

これだと黒い部分が移動しているんですね。

当然1-xノードを使用して反転していますね。正確に反転させるためにSaturateをその前に掛けています。

f:id:kazuhironagai77:20211114221016p:plain

ただこの結果だとほぼほぼ白くなっていますね。

f:id:kazuhironagai77:20211114221029p:plain

最後に32乗しています。

f:id:kazuhironagai77:20211114221042p:plain

Y=x^32の式をDesmosでGraph化しました。

f:id:kazuhironagai77:20211114221056p:plain

兎に角、暗くしたみたいですね。

実装の意味は理解出来ましたね。自分でこれを一から思いつけるかと言えば出来ないですが。

4.NPCAIを作成するためのAIの復習の続き(Perceptionの勉強)

4.1 AI Perception [6] を勉強する

やっとAI Perceptionまで来ました。ここまで来るのに思っていたのより10倍位かかりました。

一番最初にUE4のAIの勉強として使用したRyan Laley氏のTutorial [7]もAI Perceptionから始まっています。

f:id:kazuhironagai77:20211114221122p:plain

公式のOnline LearningであるIntroduction to AI with Blueprintsでも

f:id:kazuhironagai77:20211114221136p:plain

AIはNav Meshの次に教えられています。

f:id:kazuhironagai77:20211114221151p:plain

ただ何をここで勉強したのかまではもう覚えていません。

まず公式のDocumentのAI Perception [6]を勉強してこれらのTutorialの内容と比較して何が大切かなどをまとめる事にします。

AI Perception [6]を開いてびっくりしたんですが、Nav MeshのDocumentみたくNav Meshを開くとその中に沢山のTutorialがあるんじゃなくてこれしかないです。

f:id:kazuhironagai77:20211114221208p:plain

まあやる側としては楽で良いです。

さらっと読んだらTutorialと言うよりAI Perceptionで使用するための機能などの紹介が主でした。これだけ読んでもAI Perceptionを追加する事は出来ないですね。どこか別のTutorialでUE4_AIのPerceptionの作成方法を勉強した人がそこで使用した機能の意味をしっかり理解するために利用するのには便利そうです。

以下にそれぞれの項目で何が語られているのかを簡単にまとめておきます。

<前文>

AI Perception SystemとAI Perception Component、On Perception Updatedについて簡単な解説がされています。

Nav MeshではAIにControlされるキャラをAgencyと呼んでいますが、ここでは単にPawnと呼んでいます。勉強する側からの要望としてはこの辺の名称は統一してほしいです。PawnはともかくAgencyは何を指しているのか一瞬分からなくなります。ここではAIが操作するNPCと呼ぶ事にします。

<AI Perception Component

これをNPCにComponentとして追加する事で色々な環境の変化を知覚する事が出来るようになります。

ただこれNPCのAI ControllerのBP内にComponentとして追加します。と書かれていました。

あれ?

そうでしたっけ。

確認します。

Ch4_3を開いてMonsterに使用しているMy AI Controller BPを開きました。

f:id:kazuhironagai77:20211114221235p:plain

確かにAI Perceptionがここで使用されていました。

<<AI Perception Properties>>

AI Perception クラスにあるProperty、AI Perceptionについての解説です。

前にこの辺を勉強した時に作成したProjectを見つけたのですが以下に示したように、それにはAI Sight Config、AI Hearing Config、AI Damage Sense Configの3つがセットされDominant Senseには何もセットされていませんでした。

f:id:kazuhironagai77:20211114221257p:plain

<<<AI Damageについて>>>

このDocumentの解説によるとAI DamageはEvent Any Damage、 Event Point Damage、or Event Radial DamageなどのEventに対して反応するそうです。

AI DamageのSenseを開くと以下の様な項目が表示されます。

f:id:kazuhironagai77:20211114221317p:plain

それぞれの項目が何を管理しているか解説されていました。必要になったら読む事にします。

残りの項目のAI Damageと同じ構成なのでその機能を使用する時に読む事にします。

<<Perception Events>>

この部分に関してですが全く覚えていません。

前にAIの勉強した時に作成したProjectのAI Controller BPを見直すと以下のようなOn Perception Updated (AI Perception) を使用した実装が見つかりました。

f:id:kazuhironagai77:20211114221337p:plain

Documentを読むとPerception Eventがある事でNPCが環境の変化を受け取れると説明されていました。

環境が変化した事で発生するEventなんでしょうが、いつ、どこで、どのように使用するのか全然分からないです。これは他のTutorialを復習する時にもう一回勉強する事にします。

<Stimuli Source

これは覚えています。Player が操作するキャラにつけるComponentです。

何で敵があえてこっちが知りたい情報を教えてくれるんだ。と怒った記憶があります。

このProjectのThird Person Character BPを開いたらAI Perception Stimuli Sourceが追加されていました。

f:id:kazuhironagai77:20211114221356p:plain

ただ使い方までは覚えていません。これも別なTutorialで復習します。

<<Stimuli Properties>>

さっきのAI ControllerのAI PerceptionにはAI Sight Config、AI Hearing Config、AI Damage Sense Configの3つが指定されていましたが、こっちはAISense_Sightしかセットされていませんでした。

f:id:kazuhironagai77:20211114221415p:plain

<<Stimuli Function Calls>>

これは何を指しているのか不明ですね。他のTutorialをやってみて必要だった復習します。

<AI Perception Debugging

これはDebugの時に一緒に復習します。

4.2 2021-02-01のブログを復習する

2021-02-01のブログにOnline LearningのIntroduction to AI with Blueprintの勉強内容が簡潔にまとめられています。

f:id:kazuhironagai77:20211114221450p:plain

この中でPerceptionに関係している箇所を読み直します。

<AI Perception Theory

f:id:kazuhironagai77:20211114221539p:plain

結構書き込んでいて、全く内容を忘れてしまっている今では結構重要な情報です。

やっぱり書いている時はこんな事わざわざ書く必要あるんだろうか?と自問自答しながら書いていましたが、今こうやって見直すととても役に立っています。

Blogを始めていろんな事を新しく学びましたが、その中でも最も重要でかつ不変の真理と思うのが「書いておけば必ず後で役に立つ。」と言う事です。

「AI Perception Component と AI Perception Stimuli Sourceについての解説、そしてTarget Perception Updated eventについての説明がちょっとだけあります。」と書かれています。今の私はまさしくこれらの使用方法について知りたいんです。復習する時はこの講義から見直します。

<Setting up AI Perception

f:id:kazuhironagai77:20211114221559p:plain

この講義は実際にどうやってAI Perceptionを実装するのかの実演がされているみたいですね。Sight以外の知覚の設定方法についても解説しているのでしょうか?

<AI Perception and the Gameplay Debugger

ここはDebugについてですね。

f:id:kazuhironagai77:20211114221618p:plain

Debugについての復習はDebugでまとめてしようと思っていたんですが、AI Perception専用のDebugがある訳ですね。

うーん。やっぱりそれでも後でやる事にします。

f:id:kazuhironagai77:20211114221633p:plain

後はこれのやり方です。

これのやり方、確か後で発見したはずです。どうやったのかは覚えていませんが。

<Using the AI Perception Events

f:id:kazuhironagai77:20211114221651p:plain

Eventの使用方法についての実演のようです。カメラの位置を上手く移動出来ないと確認が出来ないと言っていますね。復習する前にカメラの位置の変え方を調べる必要がありますね。

<Introduction to AI with Blueprint Quiz 3

f:id:kazuhironagai77:20211114221710p:plain

何を言っているのかすら分かりません。

4.3 Ryan Laley氏のUnreal Engine 4 Tutorial - AI - Part 2 AI Perception [8] を勉強する

更とみて大体理解しました。

実際、AI Perception自体はこのTutorialでも後半半分だけで作成しています。

その部分だけ以下にまとめておきます。

<AI PerceptionをAI Controllerに追加する>

f:id:kazuhironagai77:20211114221735p:plain

これは先程の復習でも出て来ました。

<AI PerceptionのSense ConfigにAI Sight Configをセットする>

f:id:kazuhironagai77:20211114221753p:plain

この例では視覚で敵を認識するのでSightをセットします。

<AI Perception Stimuli SourceをThird Person Characterに追加する

f:id:kazuhironagai77:20211114221812p:plain

これも先程勉強した通りです。

<AI Perception Stimuli Source のAI PerceptionにAI Sens e_ Sightを追加する

f:id:kazuhironagai77:20211114221839p:plain

これも先程の勉強したやり方と同じですね。Auto Register as Sourceにチェックを入れていますが、これについては意味がわかりません。

公式のDocumentのAI Perception [6]にAuto Register as Sourceの解説がありました。

f:id:kazuhironagai77:20211114221853p:plain

これにチェックしないとNPCのAIがどの知覚で認識するか自動で決まらないと言う事でしょうか?

読んでも今一理解出来ないですね。

<AI Controller BP内でPlayer の操作するキャラをNPCが知覚出来るようにコードを組む>

先程はここの作成方法が分からなかったです。

早速、AI Controller BP内にOn Target Perception Updated(AI Perception)を追加しました。

f:id:kazuhironagai77:20211114221912p:plain

このノードの機能が分からない。時にOn Perception Updatedとの違いが分からりません。と思っていたら公式のDocumentのAI Perception [6]にしっかり解説されていました。

まずOn Target Perception Updatedですが、

f:id:kazuhironagai77:20211114221928p:plain

と書かれています。On Perception Updatedに関しては

f:id:kazuhironagai77:20211114221945p:plain

と書かれています。

Stimulus Structを返してほしい時はOn Target Perception Updateノードを選択する必要があると言う事のようです。

次にStimulus StructをBreakしてます。

f:id:kazuhironagai77:20211114222015p:plain

次に対象のActorがPlayer が操作するキャラである事を確認するためにCast to Third Person Characterノードを繋げています。

f:id:kazuhironagai77:20211114222029p:plain

これはAI Perceptionとは関係ないのでコメントはなしで先に進みます。

Blackboardクラスの変数の値を以下の方法で変更します。

f:id:kazuhironagai77:20211114222044p:plain

Make Literal NameにはBlackboardクラスに作成した変数の名前が入ります。

NPCのAI Controller内でPlayer の操作するキャラを知覚するだけでなく、知覚した後にBlackboardクラスの変数の値を変更する事でBehavior Treeの行動を変化させる機能もここで作成しています。

納得しました。

5.World CompositionによるMap1の作成(Bugの修正)

一週間、考えましたがMap1は一端消して作り直す事にします。

その際に、World Compositionは止めてLoad Stream Levelノードを使用する事にします。

World Compositionの使用を中止する理由は2つです。

Landscape自体が消えると以下に示した様な変な背景が制作されてしまう事が一つ

f:id:kazuhironagai77:20211114222106p:plain

遠くの山が見えなくなるのはオカシイのがもう一つの理由です。

反対に町の人なんかは町から離れたら全く見えなくてもオカシクないです。

のでWorld Compositionを使用するよりもLoad Stream LevelノードでLandscape以外のActorのLoad /Unloadの管理をした方が自然に近くなるとの結論が出ました。

5.1 Map1のActor全部をPersistent Levelに戻す

最初1個ずつ戻していたんですが、らちが明かない。

何か良い方法はないかなと探していたらありました。

World Outlinerの表示をTypeからLevelに変更します。

f:id:kazuhironagai77:20211114222126p:plain

これでどのActorがどのSub Levelに属しているのかが丸分かりになります。

ここでMap1に属していないやつは全部Map1に移せばいいんです。

f:id:kazuhironagai77:20211114222141p:plain

全部のActorをPersistent Levelに移しました。

とはいかなかったです。幾つかのActorが問題ありそうなので移す前に対応を考える必要があります。

f:id:kazuhironagai77:20211114222159p:plain

これって前に作成したLandscapeが残っているんでしょうか?

調べたらSub Level 1-1のLandscape Streaming Proxyが無いんです。色々弄ってみるとどうもSub Level 1-1のLandscape Streaming ProxyがLandscape5と言う名前に変更されているみたいです。なんでこうなったんでしょう?

当然ですがLandscape Streaming Proxyはそのままで残しています。これらのSub Levelは後で全部消してしまいます。

f:id:kazuhironagai77:20211114222214p:plain

Level Boundもです。

f:id:kazuhironagai77:20211114222227p:plain

良く考えなくてもこれらのActorの機能が分かっていません。

勝手に消して後で問題が発生したらどうしましょう?

後、先週作成した2つのTrigger Boxです。

f:id:kazuhironagai77:20211114222243p:plain

これらは消してしまいます。新しいTrigger Boxをまた作成する事にします。

ここまでやって気が付いたんですが、Level2_5がSave出来るようになってます。

f:id:kazuhironagai77:20211114222311p:plain

あれ。

どうしよう。

一寸考えます。

考えました。もう一回ActorをそれぞれのSub Levelに移します。これをする事でどこでSub Level2_5がSave出来なくなるバグが発生したのかを特定出来るからです。

5.2 Map1のActorをそれぞれが属するSub Levelに戻す

一応、今の時点でPlayが出来る事を確認しておきます。

f:id:kazuhironagai77:20211114222332p:plain

Monster発生用のTrigger boxを消したのにMonsterが発生していますが、それは以下に示した実装部からMonsterを生成したからです。

f:id:kazuhironagai77:20211114222347p:plain

当然ですがSub Level、Level2_5からやります。

Level2_5に配置されているActorは全部Persistent LevelからLevel2_5に移しました。

以下にLevel2_5 を見えない状態にした図を示します。

f:id:kazuhironagai77:20211114222411p:plain

ここでLevel2_5を消しても表示されているActorつまりLevel2_5の上に配置されているのにPersistent Levelに配置されてるActorはGood Sky、Post Process Volume、Atmospheric Fog、Sky Light、Sphere Reflection Capture、そしてNav Mesh Bounds Volumeです。どれもLevel2_5とは直接関係ないActor達です。

残りのActorは全てLevel2_5に移しました。

f:id:kazuhironagai77:20211114222433p:plain

しかしLevel2_5は普通にSave出来ます。

テストします。

普通に表示されています。

f:id:kazuhironagai77:20211114222448p:plain

遠くに行くとUnloadもされます。

f:id:kazuhironagai77:20211114222501p:plain

今度はTrigger Boxを追加します。

f:id:kazuhironagai77:20211114222514p:plain

先週作成した実装も追加します。

f:id:kazuhironagai77:20211114222527p:plain

普通にSave出来ますね。

f:id:kazuhironagai77:20211114222548p:plain

Playしてみます。

Monsterを倒して戻って来ました。

f:id:kazuhironagai77:20211114222608p:plain

倒したMonsterは消滅しています。

全て上手くいっています。

それでは他のSub Levelもやっていきます。

Level3_6も直しました。Trigger boxも新しく追加しました。

f:id:kazuhironagai77:20211114222622p:plain

それ以外のSub Levelも全部やりました。

テストします。

f:id:kazuhironagai77:20211114222637p:plain

Monsterが追いかけて来ませんね。

原因が不明なのでもう一回テストしたら今度は普通に歩いていました。

f:id:kazuhironagai77:20211114222652p:plain

他の箇所をチェックします。

村の中で石で舗装された地面に草が生えている箇所があります。

f:id:kazuhironagai77:20211114222705p:plain

村人との会話は面白いです。

f:id:kazuhironagai77:20211114222720p:plain

PCからファンの音が大きくなる時があるんですが、その理由が分かりました。夕方から夜になる時と夜から朝になる時になっています。

今はテストを兼ねて一日を5分で設定しているので仕方ない部分もあるのかもしれません。一日を30分とかにしたらPCの負担も減ると思われます。

特にSave出来ないSub Levelも発生していないので先に進みます。

5.3 先週中止したMonsterの追加をやる

Sub Level 2_5にMonsterをもう一体発生させる。

Monster Spawn Data 2_5 に新しいMonsterのDataを追加します。

f:id:kazuhironagai77:20211114222741p:plain

テストします。

f:id:kazuhironagai77:20211114222754p:plain

出来ています。

出来ていますが、突然止まるときがあります。

MonsterのAIももっと自然にPlayerの操作するキャラを追いかけるように改良する必要がありそうです。

5.4 Level 2_4にMonsterを追加する

先週のバグの発生が結構精神的なショックだったみたいで、どうやって動的なMonsterを生成していたのかとか、どうやって倒したMonsterを消したのかとかを忘れてしまいました。

思い出しながら作成してみます。

取りあえずMonster BPを静的に配置してみました。

f:id:kazuhironagai77:20211114222822p:plain

動きません。

これはNav Meshが働いていないみたいです。

新しいNav Meshに交換しました。

ここで隣のNav MeshをDuplicateして配置しようとしたらLevel 2_4がsave出来なくなりました。

どうやらSub Level間を跨いでDuplicateしたNav Meshを配置しようとすると新しいNav Meshが配置されたSub LevelはそのNav MeshがSave出来なくなるみたいです。

これが先週のバグの原因だったみたいです。

新しいNav MeshをNav Mesh Bounds Volumeから作成してしかもそのNav MeshはPersistent Levelに配置しました。

そしたらLevel 2_4は普通にSave出来るようになりました。

f:id:kazuhironagai77:20211114222843p:plain

テストします。

今度はMonsterは普通に徘徊しています。

f:id:kazuhironagai77:20211114222856p:plain

これを動的に生成するようにします。

まずMonster Spawn Data 2_4をGame Instance BP内に作成して

f:id:kazuhironagai77:20211114222910p:plain

先程、静的に配置したMonsterのdataを追加します。

f:id:kazuhironagai77:20211114222922p:plain

Level 2_4のBPにLevel2_5で実装したMonsterの生成方法を実装します。

先週、Level2_5で実装したやり方と全く同じです。

f:id:kazuhironagai77:20211114222936p:plain

これでテストします。

f:id:kazuhironagai77:20211114222951p:plain

普通に徘徊しています。

今度はMonsterの数を増やしてみます。

3体追加しました。

f:id:kazuhironagai77:20211114223008p:plain

特に問題なく動いています。

Level 2_5のMonsterも生成するようにするとかなり壮観な眺めになります。

f:id:kazuhironagai77:20211114223021p:plain

今度は倒したMonsterが消滅するための実装を作製します。

Game Mode BP内のRemove Defeated Monster from Map 1関数にLevel 2_4の場合を追加します。

f:id:kazuhironagai77:20211114223037p:plain

Level 2_4のためのTrigger Boxを追加して

f:id:kazuhironagai77:20211114223052p:plain

Trigger Box用の実装もLevel 2_4のBP内に追加します。

f:id:kazuhironagai77:20211114223106p:plain

これで倒したMonsterは消滅するはずです。

テストします。

Monsterを2体倒しました。

戦闘から戻ったら2体だけ生成されています。

f:id:kazuhironagai77:20211114223131p:plain

Level 2_4のMonsterは全体で4体なので出来ています。

5.5 Blueprint Function Libraryを使用して重複箇所を簡単にする

後二つ、作成すれば終りなので力技でコードを書いても良いですが、折角全く同じ実装を幾つかのSub Levelで行うのだからBlueprint Function Libraryを使用して重複箇所を簡単にして見ようと思います。

f:id:kazuhironagai77:20211114223153p:plain

何と、Blueprint Function LibraryクラスからはSpawn Actor From Class ノードが使用出来ません。

f:id:kazuhironagai77:20211114223207p:plain

はい。力技で全部のSub LevelにSpawn Monsterの実装を作成していきます。

5.6 Level 2_3にMonsterを配置する

f:id:kazuhironagai77:20211114223225p:plain

f:id:kazuhironagai77:20211114223231p:plain

f:id:kazuhironagai77:20211114223237p:plain

f:id:kazuhironagai77:20211114223243p:plain

結果です。

f:id:kazuhironagai77:20211114223257p:plain

普通に戦闘したら消滅しました。

5.7 残りのSub LevelにMonsterを配置する

f:id:kazuhironagai77:20211114223317p:plain

Monster Trapも追加しました。

f:id:kazuhironagai77:20211114223353p:plain

取りあえずこれでMap1は完成とします。

来週、World Compositionに対しての総括を行います。

6.UE5におけるWorld Partitionの勉強の続き

先週の勉強で、

f:id:kazuhironagai77:20211114223418p:plain

と書いています。ので今週はData Layerについて勉強します。

6.1 World Partition - Data Layers [9] を勉強する

公式のDocumentには以下の解説がされています。

f:id:kazuhironagai77:20211114223438p:plain

要するにUE4のWorld CompositionやLoad Stream Levelで手動でActorをそれぞれのSub Levelに分配していた事をUE5のWorld Partitionは自動でやってくれます。Data Layerはその時に分けたActorのグループ(これをLayerと呼ぶらしい。)を整理するのに使用されていると。

これだとそれぞれのLayerはwp.Runtime.ToggleDrawRuntimeHash2Dで今まで見てた図とそんなに変わらないと思いますが、どうなんでしょう。

<Data Layer Outliner

Tutorialでは以下のようにそれぞれのLayerが表示されていますが

f:id:kazuhironagai77:20211114223506p:plain

私のData Layerには何も表示されていません。

f:id:kazuhironagai77:20211114223520p:plain

ひょっとしてActorを配置していないからなのかと思い、Cubeを適当に配置しましたが何の変化もありませんでした。

色々試しましたが、それぞれのLayerが表示される事はありませんでした。

これは分からん。とあきらめ、取りあえず先を読んたら以下の説明がありました。

f:id:kazuhironagai77:20211114223534p:plain

うん。Layerって自分で作成するの?

試しにCreate Empty Data Layerを選択したら

f:id:kazuhironagai77:20211114223550p:plain

出来ました。

うーん。Layerは自動で作成されると思っていたんですが、違うんでしょうか?

取りあえずCubeを配置してAdd Selected Actors to New Data Layerを選択してそのCubeをData Layer1に追加しました。

f:id:kazuhironagai77:20211114223605p:plain

f:id:kazuhironagai77:20211114223611p:plain

Data Layer1のIs Initially Visibleのチェックを外して

f:id:kazuhironagai77:20211114223624p:plain

Playを押すとCubeが消えました。

f:id:kazuhironagai77:20211114223643p:plain

今度はIs Initially VisibleにチェックしてPlayを押すと

f:id:kazuhironagai77:20211114223657p:plain

今度もCubeは消えてしまいました。

あれっと思ったらData Layer – RuntimeのInitial StateがUnloadになっていました。

f:id:kazuhironagai77:20211114223711p:plain

ここをLoadedに変更してもう一度Playを押すと

f:id:kazuhironagai77:20211114223726p:plain

それでもCubeは表示されません。

あれ。

これだったらLoadされているはずだから表示されてもいいはずですが。

今度はIs Dynamically Loadedのチェックを外します。

f:id:kazuhironagai77:20211114223747p:plain

流石に今度はCubeが表示されるでしょう。

Playを押します。

f:id:kazuhironagai77:20211114223802p:plain

今度は表示されました。

うーん。

良く分からない。

良く分からないと言えばWorld OutlinerでCubeのLayerを表示させようとしましたが、何も表示されません。これもよく分からないです。

f:id:kazuhironagai77:20211114223818p:plain

まあいいです。先を読んでみます。

<Actor Details Panel

UE5のActorを選択すると以下の項目がDetail内に表示されます。

f:id:kazuhironagai77:20211114223837p:plain

多分ですがこれについての説明でしょう。

f:id:kazuhironagai77:20211114223850p:plain

Data Layer内にもう一個Data Layerを作製する事が出来るとあります。

それを先程のActorを選択した時にDetail内に表示されるData Layerで作成するのでしょうか?

新しいData Layerを作製してそれを追加してみます。

f:id:kazuhironagai77:20211114223904p:plain

追加するも何も作成した瞬間に自動で追加されていました。

f:id:kazuhironagai77:20211114223917p:plain

うーん。これもどんな機能なのか具体的な事は全く分からないですね。

<Showing Data Layers in the Viewport

Viewport 1のShowをクリックすると

f:id:kazuhironagai77:20211114223941p:plain

Data Layerがあるそこに作成したData Layerが表示されます。

f:id:kazuhironagai77:20211114223954p:plain

これを選択する事でそれぞれのData Layerに属するActorを表示出来ます。

<Managing Files

公式のDocumentには以下の解説が最初にされています。

f:id:kazuhironagai77:20211114224012p:plain

これ読むとMMOのような大量のUserが同じMap内でゲームをするのが前提条件になっています。MMO自体の仕組みをよく知らない私にはどうやって個々のUserのDataをSaveすべきか自体が良く分かっていませんので、こうするとOverlapしているDataを減らせます。と言われても今一ピンと来ません。

そしてこのDocumentの最初の疑問に戻ります。OverlapしたDataを減らすためにLayerを作っているなら最初からLayerってあるべきなのに

f:id:kazuhironagai77:20211114224029p:plain

自分でLayerを作成するまでData Layerには何も表示されません。

しかも作成したLayerは

f:id:kazuhironagai77:20211114224043p:plain

自動では表示されないというおまけ付きです。

今まで、

f:id:kazuhironagai77:20211114224056p:plain

で設定してLoadしたりUnloadしてたActor達はLayerに自動的に割り振られていたからそう言う事が出来たんじゃないのかと言う疑問が生じます。

この辺の謎が解明しないとこのDocumentを読んでも、よく意味が分からないです。

その辺の謎はこのままData Layerの勉強を続けて行けば、ジグソーパズルの作成のように全体像が見えてきたら一気に理解が進むはずなので今は気にしないで進みます。

次の文章では、それぞれのLayerはDisplay LabelとID番号を持っていて、そうする事のメリットを語っています。

この辺はData Layerの使い方を理解した後にもう一回読みます。

<Using Data Layers with Blueprints

BPからData Layerの設定が変更出来る事とその例を解説しています。

<Converting from Previous Layer System

ここは注意書きのようなもので、World Partitionに変更したら前に作成していたData LayerのDynamically Loaded は自動的にDisabledにセットされます。説明されていました。

6.2 World PartitionのData Layerの疑問点のまとめ

World PartitionのData Layerについて公式のDocumentで勉強したんですが、逆に訳わからなくなってしまいました。勿論、全部が分からないと言う訳ではなく理解した部分は沢山あります。のでその辺を整理します。

まずData Layerの理論的な理解と操作の方法に分かれて説明します。

Data Layerの操作方法については大体は理解しました。Data LayersはWidowから表示出来るData LayersとActorのDetailに表示されているData Layersによって操作されますがその操作方法は大体覚えました。

Viewport1のShowからLayerを表示する方法も覚えました。

BPからData Layersの設定を変える方法は読んだだけで実際に試す所までは出来なかったです。

Data Layerの理論についてですが、こっちが良く分かっていません。

World Partitionで以下の様に設定すると

f:id:kazuhironagai77:20211114224145p:plain

Loading Rangeより外側に位置するActorは自動的にUnloadされます。

これを管理しているのがData Layersだとずっと思っていたのですが、どうやらこれが勘違いだったみたいです。

またこれは操作に関する内容になるかもしれませんが、Data Layerは自分でData Layers内に作成する必要があり、

f:id:kazuhironagai77:20211114224202p:plain

それぞれのLayerに属するActorも自分で指定する必要があるみたいです。

指定する方法についてですが、それぞれのActorのDetailのData Layersに属するLayerを選択した場合と

f:id:kazuhironagai77:20211114224216p:plain

単にActorを選択して更にWorld LayersからLayerを選択してAdd Selected Actors to Selected Data Layerを選択した場合の違いも分かりません。

f:id:kazuhironagai77:20211114224236p:plain

最初、一つのActorを二つ以上のLayerに同時にセット出来るのかと思いましたが、これは不明です。

更に、Data Layerの設定で

f:id:kazuhironagai77:20211114224249p:plain

Initially VisibleかつInitial StateをLoadedにしてもPlay中に自動的にLoadされないです。Initial StateがLoadedなのに表示されない理由が分かりません。

これらの疑問はData LayersのTutorialで実際の作成手順を見れば解決するはずです。

Data LayersのTutorialを探してみます。

6.3 Data Layersに関係したTutorialを探す

Open Worlds with World Partition | Exploring Unreal Engine 5 [10]

先週、見たTutorialで詳しい解説がしてたと思ったんですが、

詳しい解説をしていたのはWorld Partition [11] のOne File Per Actorについてでした。

f:id:kazuhironagai77:20211114224311p:plain

How to Use Data Layers in Unreal Engine 5 (Dark Realm Access) [12]

これはTutorialと言うよりUE5のDemoでDark Worldの表示方法についての解説でした。

しかしData Layerについて幾つかの新しい情報がありました。

まずDemoでData Layersが実際に使用されている事です。

これはDemoを見ればData Layersに関するある程度の情報が得られると言う事です。今の私のPCではDemoを動かす事は出来ませんので、実際に試すにはかなり後になりそうですが。

もう一つ分かった事が、このDemoでは同じLandscapeに二つの世界Dark WorldとDesertを作成しています。Data Layersは距離に応じてActorをLoadしたりUnloadしたりする機能の事ではなく全く別な機能のようです。

ここからはそのDemoとこのVideoからの推測です。

Gameで同じ地形上に、今の世界と1000年後の世界を作成したいとします。そんな時にData Layerを使用すると同じLevel上に同時に作成出来るんじゃないでしょうか?

それがData Layerの機能のように感じました。

となるとどうやってData Layerを切り替えるのかを知りたいですね。

単に

f:id:kazuhironagai77:20211114224331p:plain

としただけではこのData Layerに属しているActorは表示されませんから。

おそらくTrigger Boxか何かを使用してBP内で指定するのでしょうが、その具体的な方法が知りたいです。

Unreal Engine 5 - Data Layers Tutorial [13]

私が見た時点ですが3割の人がBad buttonを押しています。

f:id:kazuhironagai77:20211114224352p:plain

内容を見たら、音が無いのと、4分の動画なのに後半の2分間、関係ない話をしているからで、Data Layerの内容そのものについては十分信頼出来そうです。

ここでは、World PartitionをEnableする方法とその後にData Layerを作成してそのData LayerにActorを移す方法が紹介されていました。

この後で、そのData Layerをどうやって最初から表示するのかが説明されていたら完璧だったんですが、それでもかなりの新しい情報が得られました。

<ここまでのまとめ>

やっぱりData Layerの機能はRangeによってActorをLoadしたりUnloadしたりするためのものではないです。

同じLevel上に、全く別のActorを配置して1000年後の世界なんかを表現したりするための物の様です。

そこが分かると今までモヤモヤしていた部分がはっきりしてきます。

後はどうやってPlay中にloadしたりunloadしたりする事が出来るのかが分かれば大体分かったと言えますね。

この辺りはDemoを見れば分かるはずです。

今週の勉強で分かった事はこんな事ぐらいでしょうか。

7.まとめと感想

今週は、まさかWorld Compositionのバグが直るとは思っていなかったのでそこで予定が結構変わってしまいました。

Nav Meshを別なSub LevelからDuplicateして配置するとその配置されたSub LevelではSave出来なくなる(実際はSaveは出来ますがSaveした後でもSaveが必要な表示になっている。)ようです。

しかしWorld Compositionはそれ以外にも幾つかの問題を抱えており、Landscapeは最初に一括でLoadして個々のActorはLoading Stream Levelノードを使用して一々Loadした方がPCに対する負担が少ない気がしています。

後、LandscapeをLoadするのはPlayer が操作するActorが生成された後なので、Userは地面の無い画面を1秒位眺めている必要があり、見た目が悪いと言う問題もあります。

World Compositionと言う機能を勉強する事は大変重要ですが、その後どこにどうやって使用するかを考えるのも同じ位重要になりそうです。

NiagaraRibbonについての勉強をしました。

Particle Position変数がそれぞれのParticleの発生する位置を指定しているのは間違いないのでWorld Coordinateの値がしっかり入っていれば位置を自由に指定出来ると思ったのですが出来なかったです。これは来週検討します。

MaterialはStep、Smooth Step、LengthそしてDistanceについて勉強しました。やっぱりMaterialの関数は0と1の間の挙動がどうなっているのかを理解するのが大事ですね。

AIはPerceptionについての復習をしました。やっぱり前に勉強していた内容は直ぐに思いだしました。

World PartitionについてはData Layersについて勉強しました。Data Layersは勉強する前に想像していた様なものではなくて、同じLevel上に1000年後の世界なんかを作成するために使用するみたいです。ただ現時点では参考に出来る資料が少ないので何とも言えないです。

今週は以上です。

8.参照(Reference

[1] CGHOW. (2021, October 11). Twisted Ribbon in UE4.27 Niagara Tutorial | Download Files [Video]. YouTube. https://www.youtube.com/watch?v=RvTQup0Jxf4

[2] Epic Games. (n.d.-b). Math Expressions. Unreal Engine Documentation. Retrieved November 14, 2021, from https://docs.unrealengine.com/4.27/en-US/RenderingAndGraphics/Materials/ExpressionReference/Math/

[3] Unity3d.com. (n.d.). Step Node | Shader Graph | 6.9.2. Unity3D. Retrieved November 14, 2021, from https://docs.unity3d.com/Packages/com.unity.shadergraph@6.9/manual/Step-Node.html

[4] Cloward, B. [Ben Cloward]. (2021a, September 16). Smoothstep - Shader Graph Basics - Episode 15 [Video]. YouTube. https://www.youtube.com/watch?v=dn3y5KVxylQ

[5] Cloward, B. [Ben Cloward]. (2021b, September 23). Length & Distance - Shader Graph Basics - Episode 16 [Video]. YouTube. https://www.youtube.com/watch?v=wTHKzjYBH7U&list=PL78XDi0TS4lEBWa2Hpzg2SRC5njCcKydl&index=16

[6] Epic Games. (n.d.-a). AI Perception. Unreal Engine Documentation. Retrieved November 14, 2021, from https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/ArtificialIntelligence/AIPerception/

[7] Laley, R. (n.d.). AI. YouTube. Retrieved November 14, 2021, from https://www.youtube.com/playlist?list=PL4G2bSPE_8ukuajpXPlAE47Yez7EAyKMu

[8] Laley, R. [Ryan Laley]. (2019, January 24). Unreal Engine 4 Tutorial - AI - Part 2 AI Perception [Video]. YouTube. https://www.youtube.com/watch?v=X5l0u7M-ILo&list=PL4G2bSPE_8ukuajpXPlAE47Yez7EAyKMu&index=2

[9] Epic Games. (n.d.-d). World Partition - Data Layers. Unreal Engine Documentation. Retrieved November 14, 2021, from https://docs.unrealengine.com/5.0/en-US/WorldFeatures/WorldPartition/DataLayers/

[10] Polygon Hive. (2021, June 9). Open Worlds with World Partition | Exploring Unreal Engine 5 [Video]. YouTube. https://www.youtube.com/watch?v=4z9Ea7eCxt4

[11] Epic Games. (n.d.-c). World Partition. Unreal Engine Documentation. Retrieved November 14, 2021, from https://docs.unrealengine.com/5.0/en-US/WorldFeatures/WorldPartition/

[12] MR3D-Dev. (2021, May 27). How to Use Data Layers in Unreal Engine 5 (Dark Realm Access) [Video]. YouTube. https://www.youtube.com/watch?v=4O4t0BXcuwE

[13] DonThaMon. (2021, May 28). Unreal Engine 5 - Data Layers Tutorial [Video]. YouTube. https://www.youtube.com/watch?v=QueqScGNDUM

 

「Unreal Engine 4.xを使用してRPGを作成する」の足りない部分を作成する 村人用のAIの開発 + World Compositionの設定

f:id:kazuhironagai77:20211107223822p:plain

<前文>

久しぶりのMinimal Pairについて

今週、ちょっと時間が取れて久しぶりにMinimal Pairについての調査をしていたら、結構重大な発見をしたので今週の前文はそれを記録しておく事にします。

RとLの音の違いについてです。

まず前提条件から話しますが、日本人の通訳者やバイリンガルLevelの人でも、一般の日本人が思っている程、RとLの音は区別出来きていません。

彼らはRとLの発音は出来きますが、一般のアメリカ人の会話のスピードでRとLの音を聞くとどっちか全く分からない人がほとんどです。(唯一の例外が小学生以下でアメリカで暮らした事がある人達で、彼らはLとRの絶対音感みたいなのを持っています。)

私も10年、アメリカに住んでいたので英語は日本語と全く変わりないLevelで聞き取れていました。のでそんな事ある訳ないだろう。結構余裕ぶってMinimal PairによるLとRの音の違いが認識出来るかどうかのテストを受けたら、全然区別出来なくてショックを受けました。

ただし全く区別出来ないと言う訳ではなく、単語の最初の音がRやLの場合はそれなりに区別がつきます。

まずRの時はほとんどの場合でウが聞こえます。Lの場合は三割位の場合は、半分くらいムに近い音が聞こえます。日本語のラリルレロと全く区別がつかない場合はLです。

最後の音の場合は、全く違う音になります。これは間違えようがありません。Rの音は丸まります。Lも音はウともオともつかない所謂Dark Lになります。これは全く違う音なので間違えようがないです。

難しいのは子音の次にLやRがある場合です。FryとFlyのような場合です。これは本当に区別がつきません。

FlyでもDark Lで発音する人もいてそういう人の発音なんかファイとしか聞こえません。

そう言う訳で、LとRの音の区別と付けるのは、英語がしゃべれる日本人にとっても難しいんです。

今回、RayとLayのMinimal Pairを整理していたら、Layの音で、三割位が、ムに聞こえて、残り3割位が日本語のラリルレロと全く区別がつかない音に聞こえて、更に残り3割がなんとPlayと聞こえて来たんです。

それだけじゃないんです。

Rayの音を聞いていた時、半分がウの音が最初に聞こえて、残り半分がBrayに聞こえて来たんです。

(P)layと(B)ray。

これ、何か気が付きませんか?

PとBは同じ発音をしますが、Pは無声音でBは有声音です。そこだけが違うんです。日本語で言えば濁音が有声音にあたります。カキクケコとガギグゲゴの違いです。

で思ったんですが、

LとRの違いって、ラリルレロとラ”、リ”、ル”、レ”、ロ”の違いじゃないのかなと。

良くRの音って半母音っていうじゃないですか?

母音は有声音ですから。

後、有声音って声帯を振動させるじゃないですか。

Rの音って舌をどこにもつけないじゃないですか、舌先って結構振動しているんじゃないでしょうか?

勿論、反論もあってDark Lも母音だと言う人もいるからそうなるとオカシクなります。

まあ、全く的外れに終わるかもしれませんが検討する価値は結構あるアイデアだと思っています。流石に忙しいのでこれの調査をする事は出来ませんが一応記録に留めておく事にします。

それでは今週の勉強を始めます。

<本文>

1.今週の予定

今週は以下の内容をやっていきます。

  • Niagara先週の復習と何かをやる
  • Material : Ben Cloward氏のTutorialを勉強する
  • NPCAIを作成するためのAIの復習の続き(Nav Meshの勉強の続き)
  • World CompositionによるMap1の作成(動的に生成するActorの追加など)
  • UE5におけるWorld Partitionの勉強の続き

2.Niagaraの勉強

2.1 Niagara : Time Distortion Effect - UE4 Tutorial [1]の復習

先週、このTutorialは終わらせる事が出来ましたが、理解していないノードや実装部分が沢山あります。それらを検証していきます。

Sphere Mask ノードについて>

先週、SphereMaskノードを使用しましたが、AとBの意味が良く分かりません。

f:id:kazuhironagai77:20211107223943p:plain

これを調べます。

公式のDocumentのSphereMask [2]を見ると

f:id:kazuhironagai77:20211107223957p:plain

AとBについて述べてそうな箇所はありますが、具体的な意味は分かりません。

f:id:kazuhironagai77:20211107224010p:plain

これを読むとBがSphereを作成する中心で、AからBにチェックされる点と読めます。

f:id:kazuhironagai77:20211107224027p:plain

うーん。良く考えたらObject PositionとAbsolute World Positionについても良く分かっていませんでした。

f:id:kazuhironagai77:20211107224039p:plain

f:id:kazuhironagai77:20211107224045p:plain

うーん。同じ事を言っているような気もします。

そうだDebugFloatノードで調べて見ましょう。

f:id:kazuhironagai77:20211107224058p:plain

以下の様に表示されました。

f:id:kazuhironagai77:20211107224112p:plain

表示されている値はこのActorのLocationの値でした。

f:id:kazuhironagai77:20211107224125p:plain

今度は

f:id:kazuhironagai77:20211107224138p:plain

で試してみます。

f:id:kazuhironagai77:20211107224151p:plain

字が汚くて良く読めません。

f:id:kazuhironagai77:20211107224205p:plain

でもTransformのLocationとほぼ同じ数字を表しています。

もう一回解説を読み直してみます。

f:id:kazuhironagai77:20211107224218p:plain

Current Pixelって言っていますね。後、Emissiveに繋げれば可視化出来ると。

やってみます。

f:id:kazuhironagai77:20211107224234p:plain

おお。

こういう事か。

f:id:kazuhironagai77:20211107224245p:plain

Absolute World PositionはそれぞれのPixelがさしているObjectのWorld Coordinateにおける値を返しているようです。

今、Planeが

f:id:kazuhironagai77:20211107224259p:plain

に配置されてます。

RとGの座標が以下の様に対応していると考えると

f:id:kazuhironagai77:20211107224312p:plain

示してる色と合致します。

左上はR =0、G=0、B=50 で青、右上はR=1以上、G=0、B=50 でPink、右下はR=1以上、G=1以上、B=50で白です。青と緑を混ぜた色が何だったのかは忘れました。

調べたら以下の色でした。

f:id:kazuhironagai77:20211107224325p:plain

やっぱり同じ色ですね。

分かり易いようにz軸が0になるようにPlaneを移動させました。

f:id:kazuhironagai77:20211107224343p:plain

でもそれだと実装の意味が分からないと思っていたら、先週やった実装は以下のものでした。

f:id:kazuhironagai77:20211107224358p:plain

ちょっと間違えていました。

DebugFloatノードで検証したらActor PositionはObject Positionと同じ結果が出ました。

上記の実装の結果は以下の通りです。

f:id:kazuhironagai77:20211107224440p:plain

うーん。

良く分からん。

これは例が難しすぎます。

もっと簡単な例で考えてみます。

f:id:kazuhironagai77:20211107224455p:plain

これなら円の中心が原点になるはずです。

f:id:kazuhironagai77:20211107224507p:plain

f:id:kazuhironagai77:20211107224512p:plain

なっていますね。

Bに関しては、球の中心で間違いないようですね。

じゃAは何なのかと言うのが分からないんです。

半径はRadiusで決定します。色のGradientはHardnessで決まります。

Aにも原点を入れてみます。

f:id:kazuhironagai77:20211107224528p:plain

む。真っ白になりました。

あ。

分かりました。先程見たようにAbsolute World PositionはそれぞれのPixelの値を返すのでそれぞれのPixelの位置によって値が微妙に違っているはずです。それがGradientを作っていたんです。

じゃHardnessは何をしているんでしょうか?

Hardness = 0.1の時です。

f:id:kazuhironagai77:20211107224542p:plain

Hardness = 0.5の時です。

f:id:kazuhironagai77:20211107224554p:plain

Hardness = 1の時です。

f:id:kazuhironagai77:20211107224606p:plain

Gradientの割合を調節しているようですね。

もう一回、Absolute World Positionの解説を読んだら今度は意味が分かりました。

f:id:kazuhironagai77:20211107224619p:plain

つまりそれぞれのpixelのWorld Coordinateにおける位置を返していたんです。その位置がBで指定した球の中心から半径内にあれば、それぞれの距離に対応したGradientの色で表示されます。指定した半径の外にある場合は色は無しになります。

今回やったように、Aに原点を指定したら全てのPixelの計算値は原点と同じになります。

つまりこのMaterialを使用しているStatic Meshに球状の印を示したい時は、必ずそれぞれのpixelのWorld Coordinateにおける位置をSphere MaskノードのAに返す必要があります。それが出来る関数の一つが、Absolute World Positionノードだったわけです。

最初の解説に戻ります。

f:id:kazuhironagai77:20211107224641p:plain

はい。

今はAの行っている意味が分かります。Bが球の中心だけどAの位置はBに対してどの位離れているの?球の半径には入っているの?球の半径に入っている場合は、中心からどれくらい離れているの。

それを確認します。

ここで大切なのは、Absolute World PositionノードをAに接続するとこのMaterialを使用しているStatic Meshの表面が画面に写っている限り、全てのPixelの位置をそれぞれ調べて返してくる事です。何万個でも返してきてそれぞれの距離をWorld Coordinateで計算します。

最初の文のOne input…of a pointがAにパスするdataの事で、その後の文がBにパスするDataの解説をしています。

やっと理解出来ました。

<波紋を作成する>

f:id:kazuhironagai77:20211107224709p:plain

この部分は先週のMaterialの勉強のSineの部分で既にやっているのでスキップします。

<MaterialのTessellation

これはMaterialの勉強する時にやります。これもスキップします。

<Parameter Collectionを使用してMaterial BPと他のBPと値をやり取りする方法>

これもMaterialを勉強する時にやる事にします。

ただ勘違いしている可能性もあるので一応、Parameter Collectionを使用するとMaterial BPと他のBPの間で値をやり取り出来る事だけ確認しておきます。

まずParameter Collectionを作成します。

f:id:kazuhironagai77:20211107224746p:plain

Playerの操作するキャラの位置をパスするため、vectorを追加します。

f:id:kazuhironagai77:20211107224800p:plain

Vectorの名前はThird Person Positionとします。

作成したParameter CollectionをDragしてMaterial内に持ち込みます。

f:id:kazuhironagai77:20211107224814p:plain

Bにつないで円の中心にします。

今度はLevel BPを開いてPlayerが操作するキャラの位置を先程作成したParameter Collectionにパスします。

f:id:kazuhironagai77:20211107224829p:plain

そのために使用するノードは

f:id:kazuhironagai77:20211107224843p:plain

です。

テストします。

f:id:kazuhironagai77:20211107224856p:plain

f:id:kazuhironagai77:20211107224906p:plain

キャラの位置によって円の中心が移動しています。

はい。

Parameter Collectionを使用するとMaterial BPと他のBPの間で値をやり取り出来るのは確認出来ました。

<Tessellationを使用した時の最適化について>

これもTessellationを勉強する時にやります。

以上です。

2.2 UEにおけるVFXに対しての個人的な感想

今、Blogを見直したら2021-04-26のBlogからほぼ毎週Niagaraの勉強をして来ました。

Niagaraの構造や機能についてはまだかなり勉強する内容はありそうですが、それなりに理解してきました。

ところが、VFXのデザインに関しては全く分かりません。

デザイナーが己のセンスのみに頼って作成しているのか、何かのマニュアルがあってそれに沿って製作しているのかですら今の所不明です。

そう言う訳で、まあ勝手な素人の言い分となりますが、現状のEffectのデザインに対しては個人的には結構な不満があります。

それをまとめておきます。

<光り過ぎ>

Effect全般に言えますが、光り過ぎじゃないでしょうか?

暗がりなら光っているのは目立ちますが、明るい所で光っても何も見えません。ゲームなので背景をいつも暗くする事は出来ないと思います。

普通の色でEffectを作っても良い気がします。

<透明過ぎ>

TransparentなMaterialは高コストです。アニメ調の炎までTransparentなMaterialを使用する必要があるんでしょうか?

<マンガやアニメで多用されているEffectがない>

折角、何十年における漫画やアニメで効果的なEffectの蓄積があるのに、それがEffect化されていないと思いました。

一部はEffect化されているのかもしれませんが、私は見た事ないです。

例えば、集中線。

マンガだと速いパンチを打つと拳の先が消えて集中線だけになります。

こういうEffectは結構基本だと思いますが見た事ないです。

後、だからと言ってそっくりそのまま作成するのもオカシイは思います。

例えばですが、マンガの流血シーンは白黒だから目立つのであって、色の付いているゲーム画面でマンガそっくりの流血シーンを再現しても迫力に欠けます。と言うかゲームの派手な配色からすると流血した事すら気が付かないかもしれません。

流血シーンはキャラの色を一時的に真っ白にするとかの大胆な変更があってもそれでマンガの流血シーンと同じ位のImpactがある方が本質を再現しているのかもしれません。

<カメラに対しての見栄え>

EffectのほとんどはSpriteで制作されている訳で、Cameraに対してどう映るかが重要だと思います。その辺の検討があんまりされてない気がします。

2.3 CGHOW氏の何かをやる

Ribbonを使っているそうなのでTwisted Ribbon in UE4.27 Niagara Tutorial [3] をやる事にします。

Niagara SystemにFountainを追加して新しいNSを作成します。

f:id:kazuhironagai77:20211107225001p:plain

要らない機能を全部消します。

f:id:kazuhironagai77:20211107225328p:plain

Render SectionにRibbon Renderer Moduleを追加します。

f:id:kazuhironagai77:20211107225342p:plain

Ribbon Renderer ModuleのShape変数にTubeをセットします。

f:id:kazuhironagai77:20211107225356p:plain

更にParticle Spawn SectionにInitialize Ribbon Moduleを追加します。

f:id:kazuhironagai77:20211107225411p:plain

更にParticleのPosition 変数を追加します。

f:id:kazuhironagai77:20211107225425p:plain

そのPositionにMake Vectorをセットします。

f:id:kazuhironagai77:20211107225437p:plain

f:id:kazuhironagai77:20211107225443p:plain

今度はxにMultiply Floatをセットします。

f:id:kazuhironagai77:20211107225456p:plain

Aに100、BにReturn Normalized Exec Indexをセットします。

f:id:kazuhironagai77:20211107225509p:plain

Return Normalized Exec Indexは初めて使用します。

f:id:kazuhironagai77:20211107225521p:plain

と書かれていました。

Dynamic Input Scriptを開くと以下に示した実装がされています。

f:id:kazuhironagai77:20211107225533p:plain

短いので今読んでしまいます。

まずMap Getノードです。

f:id:kazuhironagai77:20211107225545p:plain

Inputは以下の二つですね。

f:id:kazuhironagai77:20211107225557p:plain

EngineのExecution Count変数は以下の解説がありました。

f:id:kazuhironagai77:20211107225610p:plain

タイプはInt32のようです。

これを見るとNSではParticle一つ一つに番号が振ってあるようですね。その番号を管理するのがEngineのExecution Count変数みたいです。でもEngineのExecution Count変数は一個しかないから、Particleが一個出来るたびに番号が一個上がっていくようなものですね。

その値をNormalizeしてます。

f:id:kazuhironagai77:20211107225643p:plain

Normalizeって0から1の間にするって事でしょう。どうやってするんですかね。生成した全部のParticleで割るんでしょうか?

その値にNormalized Index Scaleを掛けています。

f:id:kazuhironagai77:20211107225657p:plain

以上です。

うーん。Execution Count変数とその正規化の母数が分からないと何をしているのか良く分からないです。これは後で調べる事にします。

Emitter Update SectionにSpawn Burst Instantaneous Moduleを追加します。

f:id:kazuhironagai77:20211107225711p:plain

Spawn Burst Instantaneous Module のSpawn Count 変数に100をセットします。

f:id:kazuhironagai77:20211107225724p:plain

Emitter Update Section のEmitter State ModuleのLoop BehaviorにOnceをセットします。

f:id:kazuhironagai77:20211107225738p:plain

更にParticle Update SectionのParticle State  ModuleのKill Particle When Lifetime Has Elapsedのチェックを外します。

f:id:kazuhironagai77:20211107225752p:plain

この辺の設定は全く何をやっているのか分かりません。

後で調べます。

こんな感じになりました。

f:id:kazuhironagai77:20211107225835p:plain

Particle Spawn SectionのInitialize Ribbon ModuleのRibbon Twist Mode変数にDirect Setをセットします。

f:id:kazuhironagai77:20211107225850p:plain

そしてRibbon Twist変数にMultiply FloatをセットしてAに20、BにまたReturn Normalized Exec Index変数をセットします。

すると

f:id:kazuhironagai77:20211107225905p:plain

こんな捻じれた形になりました。

この形、アメリカのあるお菓子に形がそっくりです。何かお腹が減って来ました。

Ribbon Width変数に20をセットします。

f:id:kazuhironagai77:20211107225920p:plain

こんな感じに変わりました。

f:id:kazuhironagai77:20211107225933p:plain

Particle Spawn SectionのSet (PARTICLES) Position ModuleのZにFloat From Curveをセットします。

更に以下の様な設定にします。

f:id:kazuhironagai77:20211107225948p:plain

すると以下に示した様に

f:id:kazuhironagai77:20211107230001p:plain

Ribbonの最後の部分がZ軸にそって上がります。

これを利用してRibbonにCurveをつけます。

まず新しいDynamic Inputを作成します。

f:id:kazuhironagai77:20211107230015p:plain

何をするためのものか全く分かりません。全部終わった後で検討します。

今度はScratch Pad Moduleを使用して以下のModuleを作成しました。

f:id:kazuhironagai77:20211107230028p:plain

うーん。何をやっているのか良く分かりませんね。これも後で調べます。

作成したScratch ModuleをParticle Spawn SectionのPositionの前にセットします。

f:id:kazuhironagai77:20211107230043p:plain

一個追加ですが、先程作成したDynamic InputはCurve Index変数にセットしてありました。

f:id:kazuhironagai77:20211107230057p:plain

それを直しました。

Curveの設定を以下の様にします。

f:id:kazuhironagai77:20211107230113p:plain

すると以下の様に自由に真ん中で曲げれるようになります。

f:id:kazuhironagai77:20211107230129p:plain

今度はParticle Update SectionにScale Ribbon Width Moduleを追加します。

f:id:kazuhironagai77:20211107230143p:plain

設定は以下のようにします。先程のParticleと同じです。

f:id:kazuhironagai77:20211107230158p:plain

うーん。段々分からなくなって来ました。

こんな形になりました。

f:id:kazuhironagai77:20211107230212p:plain

今度はMaterialを作成します。

f:id:kazuhironagai77:20211107230225p:plain

Textureが同じのがないので似たのをセットしました。

PannerノードとかStepノードとか見た事ないノードを多用しています。

内容に関しては後で検討します。

f:id:kazuhironagai77:20211107230239p:plain

こんな感じです。

f:id:kazuhironagai77:20211107230406g:plain

Particle Spawn SectionのInitialize Ribbon ModuleのColorの色を変えます。

f:id:kazuhironagai77:20211107230430p:plain

こんな感じになりました。

f:id:kazuhironagai77:20211107230448p:plain

今度はParticle Update SectionにDynamic Input Parameters Moduleを追加します。

f:id:kazuhironagai77:20211107230502p:plain

Erodeの値に0.2をセットします。

f:id:kazuhironagai77:20211107230515p:plain

以下の様に変化しました。

f:id:kazuhironagai77:20211107230556p:plain

凄い。

でも何でこうなるのかが分からない。これも後で調べます。

Set Particle Position ModuleをParticle Spawn SectionからParticle Update Sectionに移します。

f:id:kazuhironagai77:20211107230611p:plain

うーん。こんな事して良いんでしょうか?

たしか先程、Set Particle Position Moduleの後にScratch Moduleをセットしないといけないみたいな話をして他と思ったのですが。

これも後で調べます。

更にSet Particle Position Moduleの後にRibbon Twistを追加します。

f:id:kazuhironagai77:20211107230624p:plain

Parameterはこんな感じです。

f:id:kazuhironagai77:20211107230638p:plain

大体の意味は分かりますが一応、後で確認します。

結果は

f:id:kazuhironagai77:20211107230649g:plain

となりました。

ここからは微調整に入るみたいですが、今週はここまでにします。残りは来週やります。

3.Material の勉強

3.1 Ben Cloward氏のTutorialを勉強する

なんと、PowerについてのTutorialが新しくUploadされていました。Power - Shader Graph Basics - Episode 20 [4] です。これを勉強します。

Powerは頻繁に使用されるノードですが、今一良く分かって無くて、単なる掛け算ノードとどう違うのかと思ったりしています。その辺も含めて勉強したいと思います。

はい。

最初から何でPowerを使用するのかの解説がありました。

Graphを作成するのにDesmos [5] と言うサイトを使用しています。便利そうなので私も使用します。

Ben Cloward氏の解説をまとめるとこんな感じになります。

まずMaterialで使用する数字は大体が、0から1の間の数字です。

それはそうですね。色が0から1の間で表されるから、どうしてもほとんどの数字は0から1の間になります。

ここでPowerのGraphを見てみます。

Y=x^kのGraphです。

K = 1の場合です。

f:id:kazuhironagai77:20211107230737p:plain

K = 2の場合です。

f:id:kazuhironagai77:20211107230749p:plain

K=3の場合です。

f:id:kazuhironagai77:20211107230801p:plain

K=10 の場合です。

f:id:kazuhironagai77:20211107230814p:plain

はい。Powerの式はkの値がどうなろうが必ず0と1の値を通ります。

そしてKの値が大きくなればなるほど、yの値は中々上昇しないで最後で急に上昇します。

つまり色のContrastを調節するのに使用出来るわけです。

因みにKが0<k<1の時は

K=0.1

f:id:kazuhironagai77:20211107230827p:plain

k=0.2

f:id:kazuhironagai77:20211107230839p:plain

K=0.5

f:id:kazuhironagai77:20211107230851p:plain

K=0.9

f:id:kazuhironagai77:20211107230905p:plain

逆向きのCurveになります。

MaterialのPowerノードはPowerのこの性質を利用していたんですね。

もう長年の疑問の一つが解決しました。

Tutorialでやっているように実際のIllustrationで試してみます。

イラストはこのサイトのを利用させてもらいました。

f:id:kazuhironagai77:20211107230919p:plain

ありがとうございます。

f:id:kazuhironagai77:20211107230931p:plain

以下に実装を示します。

f:id:kazuhironagai77:20211107230945p:plain

K=1の時です。

f:id:kazuhironagai77:20211107230957p:plain

K=2の時です。

f:id:kazuhironagai77:20211107231008p:plain

全然、絵の印象が変わりました。

K=5の時です。

f:id:kazuhironagai77:20211107231021p:plain

今度は暗すぎますね。

K=0.1 の時です。

f:id:kazuhironagai77:20211107231034p:plain

全体が白くなってしまいました。

K=0.5 の時です。

f:id:kazuhironagai77:20211107231046p:plain

K=0.9の時です。

f:id:kazuhironagai77:20211107231059p:plain

うーん。

Powerの数学的な機能は理解できましたが、芸術的な変化は数字の変化と全然一致してませんね。

星空を選択したのは、星の光が強調されると思ったからですが、これを見るとそんな単純な話ではなかったです。

Powerを組むのはProgrammerの仕事ですが、Powerの数値を弄って美しい色を抽出するのはデザイナーに任すべきですね。

今度はPowerのコストについての話です。

K=2の時のコストです。

f:id:kazuhironagai77:20211107231112p:plain

TutorialでInstructionの数と実際のコストは必ずしも一致しない事を何度も念を押して確認していますが、今回は一応Instructionの数と実際のコストがLinearの関係にあるとします。

Multiplyノードを使用して同じ計算をします。

f:id:kazuhironagai77:20211107231125p:plain

すると

以下に示した様にコストが減少しました。

f:id:kazuhironagai77:20211107231137p:plain

つまり、Powerで計算するよりMultiplyで計算した方がコストは必ず低くなるんです。

もしPowerの値が予め決まっているならば、Multiplyを使用すべきという話でした。

これってもっと噛み砕いて言うと、DesignerにPowerの数値を弄らせる必要があるかどうかと言う事でしょう。

私の意見は、その値を弄った結果の変化が絵として見えるなら、どんな値でもDesignerに決定権を与えるべきでしょう。ので今回のように、絵で表現出来る場合はコストが多少かかってもPowerを使用してDesignerが調節出来るようにすべきですね。

残り2つの例もやっていきます。

<陰影の強調>

これはUnityで解説されています。

f:id:kazuhironagai77:20211107231156p:plain

UnityのMaterialはこのTutorialシリーズで見てるだけなので一個一個のノードの意味まではわかりませんが、多分下に示した実装と同じでしょう。

f:id:kazuhironagai77:20211107231211p:plain

これで試してみます。

Powerを追加します。

f:id:kazuhironagai77:20211107231224p:plain

K=1の時です。

f:id:kazuhironagai77:20211107231237p:plain

K=2の時です。

f:id:kazuhironagai77:20211107231248p:plain

黒く部分が多くなりました。

K=5の時です。

f:id:kazuhironagai77:20211107231320p:plain

もっと黒くなりました。

OpenGLの勉強でOutlineを出す時にOutlineの太さをPowerの値を調節して変える方法が紹介されていたんですが、何でPowerの値を変えるとOutlineの太さが変わるのかその時は全く分かりませんでした。

こうやって黒くしてOutlineに当たる部分の割合を増やしていたんですね。

数年越しの謎が解けました。

<Gamma Correctionについて>

以下に示したsRGBはUE5のTextureをクリックすると表示されるEditorにあるParameterです。

f:id:kazuhironagai77:20211107231346p:plain

これが普通のRGBにGamma Correctionを掛けて調節しているそうです。

Gamma Correctionの理論的は解説は、このサイト(Gamma Correction and Why It Matters) [6] が分かり易いそうです。

後で読む事にします。

何らかの理由でこのGamma Correctionを外したい時は、そのTextureに0.45乗するとGamma Correctionの効果が外れるそうです。

f:id:kazuhironagai77:20211107231359p:plain

逆に何らかの理由でGamma Correctionの補正が効いていないTextureにGamma Correctionの補正を効かせたい時はそのtextureに2.2乗するとよいそうです。

ただしこれらは厳密な値とはちょっと違うらしいです。それなりに正しい値が出来ると解釈していた方が安全らしいですが。

以上です。

3.2 TextureのCoordinateについての検証

TextureのCoordinateを以下の様に取っている理由を思い出しました。

f:id:kazuhironagai77:20211107231419p:plain

TextCoordノードがそうやっていたからです。

左上が0つまり原点になっています。

f:id:kazuhironagai77:20211107231432p:plain

ただこれ見るとU軸が赤V軸が緑になっていますね。私の図はU軸が緑、V軸が赤になっていてそこは逆でした。

でもこれ見ると合ってますね。

後は回転が軸中心で回れば全部説明出来ます。

先週は回転をTextureを回したと仮定したら上手く説明出来ました。

でも私は軸というかカメラ側を回して全部理屈通りの説明が出来るようにしておきたいんです。ちょっとそれについて検討します。

絵がどっちを向いているのか分かりづらいのでカツラを追加しました。

f:id:kazuhironagai77:20211107231452p:plain

-0.5ずらしました。

f:id:kazuhironagai77:20211107231505p:plain

回転させます。

Degree =90 です。

f:id:kazuhironagai77:20211107231517p:plain

Degree=180です。

f:id:kazuhironagai77:20211107231530p:plain

Degree=270です。

f:id:kazuhironagai77:20211107231543p:plain

Degree=360です。

f:id:kazuhironagai77:20211107231556p:plain

はい。

思い出しました。カメラが別の座標軸の中で移動すると考えると全て上手くいったんです。

それでもう一回やってみます。

f:id:kazuhironagai77:20211107231608p:plain

青で原点を作成しました。カメラが移している部分は以下になります。

f:id:kazuhironagai77:20211107231622p:plain

TexCoordを-0.5移動させます。

f:id:kazuhironagai77:20211107231636p:plain

カメラの写している部分です。

f:id:kazuhironagai77:20211107231650p:plain

今度はカメラを回転させます。

ここで大切な事はカメラは元のCoordinateを中心に回る事です。

90度回転させました。

f:id:kazuhironagai77:20211107231705p:plain

写っている画像です。

f:id:kazuhironagai77:20211107231718p:plain

実際の画像です。

f:id:kazuhironagai77:20211107231731p:plain

180度回転させました。

f:id:kazuhironagai77:20211107231744p:plain

写っている画像です。

f:id:kazuhironagai77:20211107231756p:plain

実際の画像です。

f:id:kazuhironagai77:20211107231808p:plain

もうこれで十分でしょう。

因みにTexCoordに2を掛けると以下に示したようにTextureのサイズが半分になるのも

f:id:kazuhironagai77:20211107231822p:plain

カメラのサイズが2倍になったと考えると納得出来ます。

これでTextureの移動、回転、拡大縮小に関しては完璧に説明出来る様に成りました。

3.3 氷のMaterialについての検証

Niagara Systemを勉強していてVFXにおけるMaterialの占める割合の大きさにびっくりしました。

それで氷のEffectを作るのに氷専用のMaterialの作成方法を先に勉強しておくべきとなりそれをやる事にします。

ただし今週は様子を知るのが目的なので軽く見るだけです。

無料で配布されている時に貰ったIce CoolのMaterialを見てみます。

f:id:kazuhironagai77:20211107231843p:plain

こんな感じです。

f:id:kazuhironagai77:20211107231857p:plain

IceCoolを開くと以下に示した4つのFolderがあります。

f:id:kazuhironagai77:20211107231913p:plain

Materialsを開くとなっています。

f:id:kazuhironagai77:20211107231925p:plain

Effectには以下のMFが入っています。

f:id:kazuhironagai77:20211107231938p:plain

もう良く分からなくなりました。

この氷の塊に使用されているMaterialを調べます。

f:id:kazuhironagai77:20211107231951p:plain

MI_IceBergと書かれています。

f:id:kazuhironagai77:20211107232010p:plain

開くとMI_IceEnvironmentBaseが親です。

f:id:kazuhironagai77:20211107232027p:plain

親もMaterial Instanceなんですね。

MI_IceEnvironmentBaseを開くと

f:id:kazuhironagai77:20211107232039p:plain

M_IceCoolが親とありました。やっとMaterialが分かりました。

M_IceCoolを開きます。

こんな感じでした。

f:id:kazuhironagai77:20211107232055p:plain

このMaterialの分かる部分を見て行こうと思います。

まずResultノードです。

f:id:kazuhironagai77:20211107232107p:plain

設定は以下に示した様になっています。

f:id:kazuhironagai77:20211107232120p:plain

さらのMaterialに同じ設定をしてみます。

f:id:kazuhironagai77:20211107232132p:plain

この時点で全然違います。

まずNormalがないです。そしてCustomized UV0と言う選択肢にすらないOutputがあります。

どうやってNormalが使用出来るようになるのか全然分かりませんが、このNormalから見てみます。

f:id:kazuhironagai77:20211107232147p:plain

お、最初に見たMFが出て来ました。

f:id:kazuhironagai77:20211107232159p:plain

これを見ます。

f:id:kazuhironagai77:20211107232212p:plain

Texture SampleにTexture Sampleが繋がっています。

f:id:kazuhironagai77:20211107232226p:plain

こんな使用方法も初めて見ました。

f:id:kazuhironagai77:20211107232238p:plain

この部分は青の色に対して調整出来るようにしているみたいですね。青だからz軸にあたるのか。

f:id:kazuhironagai77:20211107232251p:plain

VectorのZ成分が変わってしまったのでもう一回Normalizeする必要がありますね。

f:id:kazuhironagai77:20211107232303p:plain

成程、最初のZ軸を加工しないVersionの使用も選択出来るようになっています。

次のノードです。

f:id:kazuhironagai77:20211107232320p:plain

ES2とかES3_1とかって携帯電話用の設定でしょう。どのDeviceで使用するかによってどの実装を実行するかをここで指定しているみたいです。

Defaultを遡ります。

f:id:kazuhironagai77:20211107232333p:plain

このFalseの場合は、先程読んだ実装に繋がっています。Trueの時ですが、

f:id:kazuhironagai77:20211107232345p:plain

Detail Mapと言う実装と繋がっています。

f:id:kazuhironagai77:20211107232357p:plain

ここで先程のNormalの青の変更をする時に使用したParameterであるClass Detail UV ScaleがTexCoord[0]に乗算されています。

これでDetail NormalのTextureのサイズと普通のNormalのTextureのサイズを同じにしているのでしょうか?

でもそれなら普通のNormalの計算はなんでBの値だけに乗算しているのでしょうか?

f:id:kazuhironagai77:20211107232410p:plain

ここでDetail Normalと普通のNormalを混ぜています。

その前のノードがさっき見たこれなんですが、

f:id:kazuhironagai77:20211107232424p:plain

ここでFalseを選択した場合、普通のNormalではGlass Normal Scaleの値は全く使用しません。にも拘わらずDetail Normal MapではTextureのサイズの調整にGlass Normal Scaleの値が使用されるままです。

これってこの一個前のノードから接続した方が正確な値になったんじゃないでしょうか?

単なる感想ですが。

最後の部分です。

f:id:kazuhironagai77:20211107232437p:plain

何これ?

Glass Normalを使用しない場合は、単にPixel Normal WSの値をWorld Spaceに返しています。更にGlass Normalを使用しない場合なんか(0,0,1)を返しています。

これでも良いって事ですよね。

成程。

勿論そうじゃない場合は今までの実装で計算した値をTangent Spaceに、今までの実装で計算した値をWorld Coordinateに変換した値をOutput World Spaceに返しています。

結構、読めますね。

f:id:kazuhironagai77:20211107232457p:plain

最後、Tangent Spaceからの値をResult ノードのNormalに接続しています。

Normalに接続するのですから当然です。

今週はこれ位にしておきます。

結構、Materialの勉強の成果が出ている事が確認出来ました。

4.NPCAIを作成するためのAIの復習の続き(Nav Meshの勉強の続き)

今週もNav Meshの勉強をしていきます。

今週は以下の二つをやっていく予定です。

f:id:kazuhironagai77:20211107232526p:plain

4.1 Using Navigation Invokers [7] を勉強する

Navigation Invokersの使い方を勉強するそうです。今回のTutorialは簡単そうです。

<Overview

Navigation InvokersはComponentでNav MeshをRun timeに生成出来る機能を持っているそうです。

<GoalsとObjectives

Navigation Invokersの使用方法を勉強します。

<1 - Required Setup

前に作成したProjectを使用します。

<2 - Creating Your Test Level

Project SettingのEngine-Navigation SystemのNavigation Enforcing Generate Navigation Only Around Navigation Invokersにチェックを入れます。

f:id:kazuhironagai77:20211107232635p:plain

Project SettingのEngine-Navigation MeshのRuntime、Runtime GenerationにDynamicをセットします。

f:id:kazuhironagai77:20211107232657p:plain

こっちは元からDynamic にセットされていました。

Nav Mesh Bounds Volumeを配置します。

f:id:kazuhironagai77:20211107232718p:plain

FloorのScaleを100倍にしろとか書かれていたのですが、流石に100倍はデカすぎと思い10倍にしました。それに合わせてNav Mesh Bounds Volumeのサイズも変更しています。

<3 - Creating your Agent

まずいつものNPCを作成します。

f:id:kazuhironagai77:20211107232738p:plain

Get Random Reachable Point In Radiusノードの半径は1000にしました。この単位は多分cmなので10mです。Floorの元々の大きさが10mで10倍しているので100mなはずです。多分これで大丈夫でしょう。

AI Move to ノードのAcceptance Radiusの値が5.0なんですが、これって5cmって事でしょうか。

ちょっと覚えていません。

分かりました。

Mathew Wadstein のWTF Is? AI Move To in Unreal Engine 4 ( UE4 ) [9] でAcceptance Radiusの簡単な実験が載っていました。Acceptance Radiusの値はcm です。

後、AI Move to ノードのAcceptance RadiusDestinationつまり目的地からの距離でした。目的地からこれだけ離れていても目的地に着いた事にする。と言う意味です。

それなら5cmでも問題ないですね。

ここからが本番です。

Add ComponentからNavigation Invokerを追加します。

f:id:kazuhironagai77:20211107232751p:plain

Navigation Radiusの設定は元からTutorialの指定した値になっていました。

f:id:kazuhironagai77:20211107232807p:plain

これだけだそうです。

試してます。

BP_NPC_Invokerを配置したらNav Meshが生成されました。

f:id:kazuhironagai77:20211107232819p:plain

Nav Meshのサイズが大きい過ぎるので、先程の値を以下の様に変更しました。

f:id:kazuhironagai77:20211107232833p:plain

f:id:kazuhironagai77:20211107232838p:plain

これでテストしてみます。

f:id:kazuhironagai77:20211107232946g:plain

動的にNav Meshが作成されているのが分かります。

4.2 Optimizing Navigation Mesh Generation Speed [8] を勉強する

これだけ表示がAdvancedになっています。

f:id:kazuhironagai77:20211107233012p:plain

難しいんでしょうか。

後、

f:id:kazuhironagai77:20211107233025p:plain

と書かれています。

試しに開いて見たら

f:id:kazuhironagai77:20211107233038p:plain

読みにくい。

これは後でチェックします。

<Overview

私が現状の知識で理解した範囲で解釈すると、Nav Meshはタイルを組み合わせて構成されていて、そのタイルの構成方法を編集する方法をここで勉強するみたいです。

ただしこれらの値を正しく設定するにはNav Meshに対しての深い知識と高度な技術が必要で、普通にAIを利用する人達はいじる必要はないみたいです。

今回はこんな機能もあるんだ。ぐらいに理解しておきます。

<Use the Highest Cell Size and Cell Height Possible

Project SettingにあるNavigation MeshのGeneration、Cell Sizeと同じ個所のCell Heightは

f:id:kazuhironagai77:20211107233101p:plain

Tutorialの解説によるとCell Size とCell HeightはNavigation Tileを生成するためのVoxelのサイズを決定する時に使用されるそうです。

これらの値が小さい方が、Nav Meshはより最適な距離を導き出しますが、コストは大きくなります。

またRecastNavMesh-Defaultの

f:id:kazuhironagai77:20211107233117p:plain

DetailにもCell SizeとCell Heightの設定が出来ます。

f:id:kazuhironagai77:20211107233131p:plain

こっちはそのLevelに関しての設定と言う事でしょうね。

確認する方法は?

この設定の変化を可視化する方法はあると思いますがそれはTutorialには載っていませんでした。

RecastNavMesh-Defaultの

f:id:kazuhironagai77:20211107233147p:plain

f:id:kazuhironagai77:20211107233154p:plain

とかのこの辺のParameterを使用したら可視化出来そうですが、

f:id:kazuhironagai77:20211107233206p:plain

そういうのはないんでしょうか?

試しにCell Sizeを199に変更してみました。

f:id:kazuhironagai77:20211107233221p:plain

こんな風になりました。

f:id:kazuhironagai77:20211107233244p:plain

今度は1.9に変更しました。

f:id:kazuhironagai77:20211107233257p:plain

こんな感じになりました。

f:id:kazuhironagai77:20211107233311p:plain

Edgeの分割が更に細かくなっていると言えばなっていますが、大半のMeshの形状は同じでした。

後、Tutorialの解説を読むと

f:id:kazuhironagai77:20211107233355p:plain

と書かれているので、この後にCell Sizeを変えた例の図を貼る予定だったんだけど忘れてしまったんじゃないのかなと読めます。

Reloadしたら図が出て来ました。

f:id:kazuhironagai77:20211107233412p:plain

やっぱし。しかもこの図、しっかりDraw Poly Edgesを使用しています。

あぶねー。

この節の内容半分Missするところでした。

こんな事あるんですね。びっくりです。これからはTutorialを勉強する時は図やGraphがしっかり表示されているか確認して進める事にします。

<Limit the Tile Size

読んだんですが、CellとTileの関係を忘れてしまって内容が頭に入って来ません。

先にCellとTileの復習をします。

RecastNavMesh-Defaultの以下のParameterにチェックを入れます。

f:id:kazuhironagai77:20211107233431p:plain

f:id:kazuhironagai77:20211107233436p:plain

すると以下の図に示した様にTileだと思われる四角が表示されました。

f:id:kazuhironagai77:20211107233450p:plain

これがTileなんですね。

今度はCell Sizeを1.9に変更しました。

f:id:kazuhironagai77:20211107233502p:plain

f:id:kazuhironagai77:20211107233509p:plain

Tileの大きさは変わってない気がしますね。

もう一回、Draw Poly Edgesをチェックします。

f:id:kazuhironagai77:20211107233522p:plain

以下の様にTile内にEdgesが表示されました。

f:id:kazuhironagai77:20211107233603p:plain

これがCellなんでしょうね。

よし。

この解釈でもう一回読み直します。

f:id:kazuhironagai77:20211107233638p:plain

f:id:kazuhironagai77:20211107233648p:plain

と書かれています。沢山のCellを組み合わせて一個のTileを作成すると読めます。

この解釈であってそうですね。

f:id:kazuhironagai77:20211107233710p:plain

「(一般的に言って)沢山のCellによって組み立てられている大きなTileは小さなTileよりも生成するコストが高いです。」

はい。

これは分かります。

正確に言うと、ちょっとandの文法が良く分かりませんが、こんな感じの意味だと理解は出来ます。

しかし次の文の意味が良く分かりません。

f:id:kazuhironagai77:20211107233730p:plain

f:id:kazuhironagai77:20211107233736p:plain

「しかしTileを処理する時は、The System(これが何を指しているのか分からない、EditorかEngineの事?)もTileの辺に隣接しているCellの処理を行います。」

要はTileの辺の周りのCellに関してはNav Meshだけじゃなくて、The Systemも計算に使用するのでTileが小っちゃくても計算が常に速くなる訳じゃないと言う事でしょうか。

でもtileの大きさってCellのサイズを弄っても変わらないですよね。

あ、分かりました。

これからTileの大きさを変更する方法を勉強するんです。

<<Recommendation>>

その下に書かれているRecommendationでTileの一辺には32から128個のCellが含まれる位がお勧めである。と書かれています。

重要なのはその次で、Cell Sizeを64に変更したらTile Size UUは64*32から64*128の間の値、つまり2048~8192にセットしろと書かれています。

つまりこのTile Size UUがTileの大きさを決定しているんす。

Cell SizeとTile Sizeを以下のように設定しました。

f:id:kazuhironagai77:20211107233758p:plain

Tileの大きさが約4分の1になりました。

f:id:kazuhironagai77:20211107233813p:plain

成程。こうやってむやみにTileの数を増やすと、計算コストが返って高くなる場合もある訳ですね。

納得です。

(後で計算したらCellの数とTileのサイズは一応お勧めの範囲ではありました。)

<Use Simplified Collision for Your Meshes

当然ですが、Nav Mesh上に配置されているActorのCollisionの状態がNPCの適切なルートの決定に影響を及ぼします。

計算を軽くするためにはNav Mesh上のActorのCollisionはSimpleな方が良いそうです。

Static Meshを開いてCollisionの所をチェックすると

f:id:kazuhironagai77:20211107233831p:plain

Simple CollisionとComplex Collisionがあります。これのSimple Collisionを常に選択しておくべきと言う事らしいです。

でも具体的にはどうすれば良いのか分かりません。

<Reduce the Number of Objects That Affect the Navigation Mesh

Nav Meshの計算には、Nav Mesh上に配置されている全てのObjectが使用されます。

小さいObjectでNPCの移動に影響がないモノは、DetailのCollisionにあるCan Ever Affect Navigationのチェックを外してしまいましょう。

f:id:kazuhironagai77:20211107233851p:plain

これはやり方も分かりました。

<Useful Developer Tools to Manage Navigation Generation

<<Locking and Unlocking the Navigation Mesh Generation at Strategic Times>>

Navigation Meshの生成を止めたり止めているのを止めたりするための機能があるそうです。

Tutorialでは、Nav Mesh上に配置されるべきObjectが配置される前にNav Meshが生成されると、Objectが配置された後にもう一回Nav Meshの計算をする必要が出来ます。のでObjectが配置されるまでNav Meshの計算を中止させるのに使用するのと便利と書かれていました。

やり方は

bInitialBuildingLockedをTrueにするだけだそうです。

うん。

どうやってそれをするの?

Unreal Engine 4のAPIbInitialBuildingLocked [10]を見てみるとUNavigationSystemV1クラスが保持する変数のようです。UNavigationSystemV1クラスを呼んでこれればそこからbInitialBuildingLockedの値をセット出来そうではあります。

この辺はUE4C++でガンガンCodeを書かなくなければならなくなった時にもっと調査する事にします。

<<Enable Multi-threaded Navigation Mesh Generation>>

これもUE4C++でガンガンCodeを書かなくなければならなくなった時に勉強し直します。

MaxSimultaneousTileGenerationJobsCountの値をセットする事でmulti-threaded によるNavigation Mesh の生成を管理出来るようになるそうです。

ただしFRecastNavMeshGenerator::Init()にある働いているThreadの数が限界になるそうです。

<<Use Dynamic Obstacles with Full Dynamic Navigation Mesh Generation>>

今度はDynamic Obstaclesを使用する方法です。

Dynamic Obstacles の項目は、

f:id:kazuhironagai77:20211107233926p:plain

ずっと配置されているActorのDetail内を探していましたが、そこには無くて、Static Meshを開いてDetailのNavigationに行くとありました。

私が理解した範囲ではこのチェックがついていると、このMeshが配置されてた時にこのMeshを配置した回りだけNav Meshを再構築するみたいです。

<<Use Data Chunk Streaming for Static Navigation Meshes Loaded in Sublevels>>

これはSub LevelをLoad する時の場合だそうです。

イムリーな話題です。

Navigation Meshの構成が変わるのがSub LevelをLoadする時だけならNavigation Mesh Generation MethodをStaticにセットしてNav Mesh Data Chunk Streamingを使用すると良いそうです。

これは分かったですがこの設定ってどこでするんでしょうか?

色々調べたんですが、どうやってこの設定をするのかの情報は見つからなかったです。

<まとめと感想>

Optimizing Navigation Mesh Generation Speed [8]はAdvancedなんで軽く読むだけにしました。

一応、専門用語とその機能は理解したはずです。

Sub LevelをLoadする時の最適化の具体的なやり方が分からなかったのはちょっと残念でした。

5.World CompositionによるMap1の作成(動的に生成するActorの追加など)

5.1 Monsterを動的に生成する

Monsterを動的に生成する方法ですが、先週、もっと良いアイデアが思い付くかもしれないと検証だけして一端中止しました。

それでですね。その事をすっかり忘れていました。

MaterialのTextureの回転については覚えていたんですが、こっちはすっかり忘れていました。

なので、先週言ったやり方で作成する事にします。

<Level 3_6用のMonster Spawn Dataの作成>

Game Instance BP内にStruct Monster Spawn Dataの配列であるMonster Spawn Data 3_6を作成します。

f:id:kazuhironagai77:20211107234049p:plain

要素に、先週、静的に配置したMonsterのDataを移します。

f:id:kazuhironagai77:20211107234124p:plain

f:id:kazuhironagai77:20211107234129p:plain

取りあえずはこれで十分です。

<Monster の動的な生成>

Map 3_6のBP内にMonster発生用の実装を作成しました。

f:id:kazuhironagai77:20211107234149p:plain

Map1のBP内で実装されているMonster発生用の実装と全く同じやり方です。

Map1のBPではSpawnした後に以下の実装がされていますが、生成したMonsterのDataが必要になる事はないので以下の部分は無駄な気がします。

f:id:kazuhironagai77:20211107234207p:plain

後で調べます。要らない事が判明したら消します。

テストします。

f:id:kazuhironagai77:20211107234221p:plain

Monsterが生成されていました。いきなり成功です。

<MonsterをUnload、Loadしてみる>

f:id:kazuhironagai77:20211107234241p:plain

Unloadされてから戻って来ましたが、普通にLoadされています。

5.2 Monsterを倒したら発生しないようにする

先週決めたやり方でやってみます。

Game Instance BP内にName型の変数、Sub Level Nameを作成します。

f:id:kazuhironagai77:20211107234300p:plain

ここにSub Levelの名前を保持します。

Level3_6内にTrigger Boxを配置します。

f:id:kazuhironagai77:20211107234315p:plain

このTrigger Box内にplayerが操作するキャラが侵入したら先程作成したSub Level NameにLevel 3_6 がセットされるようにします。

f:id:kazuhironagai77:20211107234331p:plain

今度は倒したMonsterが二度と生成されないようにMonster Spawn Dataを変更します。

Game Mode BP内の以下の実装部で、その作業を行っています。

f:id:kazuhironagai77:20211107234345p:plain

このRemove Defeated Monster from Map 1内の実装を変更します。

f:id:kazuhironagai77:20211107234400p:plain

以下のようなHelper関数を作成して

f:id:kazuhironagai77:20211107234415p:plain

実装を以下の様に改造しました。

f:id:kazuhironagai77:20211107234427p:plain

これで一度倒したMonsterは再生しないはずです。

テストします。

Monsterが消えません。

Helper関数内で参照にしているMonster Spawn Dataが前のままでした。

f:id:kazuhironagai77:20211107234442p:plain

直しました。

f:id:kazuhironagai77:20211107234456p:plain

これ前も同じ間違いをしてたのもついでに思い出しました。

後、この間違いを見つけるのに一時間位かかりました。

もうクタクタです。

f:id:kazuhironagai77:20211107234515p:plain

今度は倒したMonsterが復活して発生する事はなくなりました。

5.3 複数のMonsterを発生させる

取りあえず、一体Monsterを静的に配置してみました。

勿論落ちないように板を下に配置しています。

f:id:kazuhironagai77:20211107234533p:plain

発生はしますが徘徊していませんね。

f:id:kazuhironagai77:20211107234548p:plain

理由が分かりました。

Nav Meshが効いていません。

隣のNav Mesh内に配置すると動きだします。

取りあえずの処置で、隣のNav Meshのサイズを大きくしてみました。

f:id:kazuhironagai77:20211107234601p:plain

今度は普通に徘徊しています。

f:id:kazuhironagai77:20211107234613p:plain

今度はこのMonsterを動的に発生させます。

先程作成したMonster Spawn Data 3_6にこのMonsterのdataを追加します。

f:id:kazuhironagai77:20211107234626p:plain

テストしてみます。

f:id:kazuhironagai77:20211107234641p:plain

おお徘徊しています。

5.4 Monsterの発生するタイミングを遅らせる

Playerの操作するキャラはMapが作成されてから3秒間、動けなくなっています。その間にMonsterに襲われるのはUnfairなので、Monsterが発生する時間を3秒後にします。

f:id:kazuhironagai77:20211107234702p:plain

テストします。

Screen Shotは上手く取れなかったんですがMonsterの発生が少しだけ遅れるので戦闘から戻った後、ギリギリ逃げれる時間は取れました。

5.5 別のSub LevelにMonsterを発生させる

以下に示したようにMap1にはもう一つ別のNav Meshがあります。

f:id:kazuhironagai77:20211107234729p:plain

今度はここにMonsterを発生させます。

試しに一体、静的にMonsterを配置させてみます。

f:id:kazuhironagai77:20211107234802p:plain

テストします。

f:id:kazuhironagai77:20211107235107p:plain

普通に徘徊して、近づいたら追いかけて来ました。

このMonsterが配置されているSub LevelはLevel 2_5です。

Game Instance BP内にこのSub Level内に発生するMonsterのDataを保持するための配列を作成します。名前はMonsterSpawnData2_5とします。

f:id:kazuhironagai77:20211107235124p:plain

先程配置したMonsterと同じ位置のMonsterのDataを追加しました。

f:id:kazuhironagai77:20211107235137p:plain

Level 2_5に以下の実装を追加しました。

f:id:kazuhironagai77:20211107235150p:plain

テストします。

f:id:kazuhironagai77:20211107235204p:plain

普通に発生しています。

今度は戦闘で倒した後は復活しない実装を追加します。

f:id:kazuhironagai77:20211107235216p:plain

Trigger Boxを配置してから気が付きましたが、MonsterはこのSub Level内のみを徘徊する訳ではないです。例えば隣のSub Levelに移動する事もあります。

隣のSub Level内でこのMonsterと戦闘になったらこのMonsterを倒しても消滅しなくなります。

ちょっと考える必要が出て来ました。

以下に示したようにNav Meshを分けてみました。

f:id:kazuhironagai77:20211107235229p:plain

これで試してみます。

f:id:kazuhironagai77:20211107235242p:plain

普通にMonsterは動いていますね。

こんな感じです。

f:id:kazuhironagai77:20211107235256p:plain

以下のようにNav Meshを配置してみました。

f:id:kazuhironagai77:20211107235309p:plain

試してみます。

4体のMonsterが見えますね。最後の一体はまだ生成されていないのかもしれません。

f:id:kazuhironagai77:20211107235325p:plain

裏から回って確認してみます。

f:id:kazuhironagai77:20211107235338p:plain

あれ?一体もいなくなってしまった?

最後の一体だけ見れないのでそれ以外を消して正面から確認しました。

f:id:kazuhironagai77:20211107235352p:plain

Monster動いていました。

このやり方でMonsterを動的に生成する事にします。

先の動的に生成したMonsterが戦闘で倒されたら二度と復活しないようにします。

前のLevel3_6でやったのと同じやり方でやりました。

それで出来たんですが、

その後からLevel2_5をSaveしてもSave出来てない印が表示されるようになってしまいました。

f:id:kazuhironagai77:20211107235406p:plain

色々試してみたんですが、Saveは出来るんです。しかしこのSave出来てない印が常に表示されるようになってしまっています。

結論から言うと原因は分からないです。

今週はここまでで一端中止します。

6.UE5におけるWorld Partitionの勉強の続き

今週は自分でWorld Partitionを使用しながらLandscapeの作成でもしようと思ったのですが、さっきのSub LevelがSaveしてもSave出来てない表示のままになるバグが直せないので何か心が折れてしまいました。

それで今回は簡単な内容に変更します。

World PartitionのTutorialを見て感想をまとめる回にします。

6.1 Open Worlds with World Partition | Exploring Unreal Engine 5 [11] を見る

公式のDocumentからOne File Per ActorとHierarchical Level of Detailの解説がありました。

One File Per ActorはLevel上に配置されたActorの情報を別なFileで管理する事で複数の人が同時にLevel Designを行える機能位の理解しかなかったですが、このTutorialを軽く見てる限りでは当たらずとも遠からずだと思いまいした。

Hierarchical Level Of Detailはどんな機能なのか全くわかってなかったですが、このTutorialの解説を聞いた限りでは、山など遠くにあってもUnloadすべきでないものに対して、Leve of Detailを下げて表示する機能みたいです。

これは大変興味深いので後で自分でDocumentを読む事にします。

6.2 World Partition - Hierarchical Level of Detail [12] を読む

最初から遠くにあるActorでもUnloadしてほしくないものがある。と書かれていますね。先程の解釈で間違いないですね。

Static Mesh Actorsに対しての機能みたいですね。Landscapeで作成した山とかは関係ないんでしょうか?

f:id:kazuhironagai77:20211107235441p:plain

思いっきり書かれていました。LandscapeやWater Componentは今の所対応していません。と

<Creating HLOD Layers

これ先程のTutorialを見てたらcmdからやらないといけないみたいに言っていたので、今回は見るだけにします。

ぱっと見たらこの後の節でHLOD Layersを実際に使用する時にcmdから指令をしないといけないみたいで、ここではCmdは使用してませんでした。

なのでここは自分でもやってみる事にしました。

f:id:kazuhironagai77:20211107235501p:plain

中を開くとこんな感じになっていました。

f:id:kazuhironagai77:20211107235514p:plain

公式のDocumentにそれぞれの項目の解説が載っていますね。

f:id:kazuhironagai77:20211107235529p:plain

この項目はないですね。

Cell SizeとLoading RangeはAlways Loadedがチェックされている時は効かないそうです。

試しにAlways Loadedにチェックを入れてみました。

f:id:kazuhironagai77:20211107235542p:plain

Cell SizeとLoading RangeだけじゃなくてParent Layerも消えました。

Cell SizeとLoading RangeはHLOD用のActorのための設定のようです。

と言う事はこのCell SizeとLoading Rangeは必ず元のCell SizeとLoading Rangeより大きくする必要があるって事でしょうか。

後、どんな遠くに行っても消えない訳じゃないって事ですね。あ。絶対消えてほしくないならAlways Loadedにチェックすれば良いと言う事か。

納得しました。

<<Choosing a Layer Type>>

Layer Typeについての解説です。

f:id:kazuhironagai77:20211107235602p:plain

<<<Instancing>>>

Instanced Static MeshってGraphic Card内で再生するやつじゃなかったじゃないでしょうか。

<<<Merged MeshとSimplified Mesh>>>

この二つはsingle proxy meshに変換すると解説されていますが、single proxy meshが何を指しているのかが分かりません。UE5の新しい機能なんでしょうか。

<<Mesh Merge Settings>>

Mesh Merge Settingsを選択すると以下の項目が表示されます。

f:id:kazuhironagai77:20211107235630p:plain

これらの項目について解説しています。

<<Proxy Settings>>

Simplified Meshを選択した場合に表示される項目です。

f:id:kazuhironagai77:20211107235647p:plain

これらの解説をしています。

この辺はまずAlways LoadedでHLODを使いこなせるようになってから勉強する感じでしょうね。

<Using HLOD Layers

はい。ここではcmdを使用するので今回は読むだけです。

<<Adding Actors>>

Static Meshを選択するとHLODの項目があるのでそこに先程作成したHLODをセットします。

f:id:kazuhironagai77:20211107235709p:plain

Data Layerでコレコレをしろ。と書かれていますがData Layerって何でしょうか?

Windowを見るとありますね。表示させてみます。

f:id:kazuhironagai77:20211107235723p:plain

ふむ。

f:id:kazuhironagai77:20211107235735p:plain

何も表示されませんね。

これってひょっとしてHierarchical Level of Detailの前の節で解説しているData Layerを読まないといけないって奴でしょうか。

f:id:kazuhironagai77:20211107235749p:plain

ここはスキップしておきます。

次はWorld SettingのHLODにセットしています。

f:id:kazuhironagai77:20211107235801p:plain

ini fileで指定する事で同様の設定が出来るみたいです。

f:id:kazuhironagai77:20211107235817p:plain

Ini fileについても勉強せねばと思いつつ何時も後回しにしています。

Configフォルダーを開いたら.iniファイルがこんなにあります。

f:id:kazuhironagai77:20211107235830p:plain

この時点でどれに書くのか分かりません。

Ini fileについては後でまとめて勉強する事にします。

<<Generating HLODs>>

ここからcmdを使用します。

なのでここは読むだけにします。

ぱらっと読んだですが、どうやらWorldPartitionHLODsBuilderを使用してHLODsを生成するらしいですが、現状ではWorldPartitionHLODsBuilderはcmdからしか実行出来ないみたいです。ので現状ではcmdを使用する必要がある訳ですね。

WorldPartitionHLODsBuilder を使用するためにまずUE4Editor.exeのあるFolderに移動します。

私の場合は以下のFolderにありました。

f:id:kazuhironagai77:20211107235848p:plain

Cmdに以下のコードを打ち込みます。

YourProject YourMap -run=WorldPartitionBuilderCommandlet -AllowCommandletRendering -Builder=WorldPartitionHLODsBuilder

これってProjectは同じFolder内に無くてもいけるんでしょうか?

勿論、自分で試してる気はありません。

まあ、この辺は後でCmdを使用しなくても出来るようになるはずですのでその時まで待つだけです。

<Visualizing HLODs

HLODの可視化の仕方についてです。

<<In the Editor>>

EditorではView Modeから選択しろと書かれているので

f:id:kazuhironagai77:20211107235946p:plain

これの事でしょうか?

色が変わって見えるみたいですが、HLODを作成していないので実際に確認する事は出来ません。

<<At Runtime>>

wp.Runtime.ToggleDrawRuntimeHash2Dで見れるそうです。

以上です。

7.まとめと感想

今週は、結構上手く行っていたんですが、World CompositionでSaveしてもSave出来ていない表示になってしまうバグを一個作ってしましました。

このバグが何をしても直せません。

正直ショックです。

今まで、後から直せないのは理解が足りない証拠と信じて頑なにGit Hubの使用を避けていました。がこれからは結構真剣に検討したいと思います。

だた、このRPGは出来れば今年中に完成させて、来年はUE5で別なGameの作成を開始したいと思っていますのであんまりWorld Compositionだけに拘るのもアレかなと思ったりもしています。

NiagaraにしてもVFXは結局Materialに依存しています。Materialを極める必要があります。そのために今回Materialの勉強でtexcoord[]の機能を完全に理解出来たのは大きかったと思います。

AIはやっとNav Meshの勉強が終わりました。結構知らない事ばかりでした。

World Partitionの勉強をするとUE5についてもっと知りたくなります。Naniteなんかも勉強したくなって来ました。

8.参照(Reference

[1] UnrealCG. (2021, October 14). Time Distortion Effect - UE4 Tutorial [Video]. YouTube. https://www.youtube.com/watch?v=3ejuQVasl7w

[2] Epic Games. (n.d.-d). Utility Expressions. Unreal Engine Documentation. Retrieved November 7, 2021, from https://docs.unrealengine.com/4.26/en-US/RenderingAndGraphics/Materials/ExpressionReference/Utility/

[3] CGHOW. (2021, October 11). Twisted Ribbon in UE4.27 Niagara Tutorial | Download Files [Video]. YouTube. https://www.youtube.com/watch?v=RvTQup0Jxf4

[4] Cloward, B. [Ben Cloward]. (2021, October 28). Power - Shader Graph Basics - Episode 20 [Video]. YouTube. https://www.youtube.com/watch?v=1EiEjynmgIY&list=PL78XDi0TS4lEBWa2Hpzg2SRC5njCcKydl&index=20

[5] desmos. (n.d.). Desmos | Graphing Calculator. Retrieved November 7, 2021, from https://www.desmos.com/calculator

[6] Davidović, D. (2014, April 1). Gamma Correction and Why It Matters. Game Development Envato Tuts+. Retrieved November 7, 2021, from https://gamedevelopment.tutsplus.com/articles/gamma-correction-and-why-it-matters--gamedev-14466

[7] Epic Games. (n.d.-c). Using Navigation Invokers. Unreal Engine Documentation. Retrieved November 7, 2021, from https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/ArtificialIntelligence/NavigationSystem/UsingNavigationInvokers/

[8] Epic Games. (n.d.-b). Optimizing Navigation Mesh Generation Speed. Unreal Engine Documentation. Retrieved November 7, 2021, from https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/ArtificialIntelligence/NavigationSystem/OptimizingNavigationMeshGenerationSpeed/

[9] Wadstein, M. [Mathew Wadstein ]. (2016, August 3). Mathew Wadstein [Video]. YouTube. https://www.youtube.com/channel/UCOVfF7PfLbRdVEm0hONTrNQ

[10] Epic Games. (n.d.-a). bInitialBuildingLocked. Unreal Engine Documentation. Retrieved November 7, 2021, from https://docs.unrealengine.com/4.27/en-US/API/Runtime/NavigationSystem/UNavigationSystemV1/bInitialBuildingLocked/

[11] Polygon Hive. (2021, June 9). Open Worlds with World Partition | Exploring Unreal Engine 5 [Video]. YouTube. https://www.youtube.com/watch?v=4z9Ea7eCxt4

[12] Epic Games. (n.d.-e). World Partition - Hierarchical Level of Detail. Unreal Engine Documentation. Retrieved November 7, 2021, from https://docs.unrealengine.com/5.0/en-US/WorldFeatures/WorldPartition/HLOD/

「Unreal Engine 4.xを使用してRPGを作成する」の足りない部分を作成する 村人用のAIの開発5

f:id:kazuhironagai77:20211031195447p:plain

<前文>

<Dot Product内積なのか? Part 2

先週、以下に日本とアメリカが表面上は似ている様で一寸深みに入ると全然違うと言う事を言いたくて、その例として内積とDot Productについて話しました。

そしたら予想以上に複雑で逆にこっちが混乱してしまってグダグダになってしまい一端中止しました。

もう「日本とアメリカが表面上は似ている様で一寸深みに入ると全然違う」と言う話は一端置いておいて、内積の英訳はDot Productで良いのかについて集中する事にします。

先週の復習を軽くします。

まず内積の英訳を日本語の辞書で調べるとInner ProductとかScaler Productと出て来ます。

Dot Productじゃないの?とInner ProductとDot Productの違いを調べると、計算方法や定義は全く同じなのですが、使用している数字が実数のみの場合がDot Product、複素数も含む場合がInner Productと言う解説が出て来ます。

納得しました。

と思ってでも一応確認のために量子化学の教科書で確認したら複素数を含む計算でも普通にDot Productって使っていてアレってなりました。

そして先週の結論としては内積を英語に訳す時が、Dot Productで良いと言うか、Dot Productって言わないと通じないんじゃね。と言う事で一応結論づけました。

所で英語のDot Productを日本語に訳す時はどうなのか?

それも調べる必要があるなと思い調査したら、とんでもない事実が出て来ました。何とPythonでDot Productと言うとScalerじゃなくてVectorを返してくるんです。

何それとなった所で力尽きました。

今、見直すと2つ問題があります。

一つ目は英語のDot Productを日本語に訳す時です。Dot Productの日本語訳をドット積であると仮定して検索していました。この訳が正しい事を示す引用がなかったです。

2つ目は数学や工学においてドット積と内積の違いがDot ProductとInner Productの違いと同じなのかについて調べてなかった事です。

これらをクリアした後で、PythonにおけるDot Productの定義について調査する必要がありました。

まず一つ目の問題から検討します。

GoogleでDot Product 訳と打つと以下の検索結果が出て来ます。

f:id:kazuhironagai77:20211031195517p:plain

まずはGoogle の訳です。

f:id:kazuhironagai77:20211031195530p:plain

Weblioでは

f:id:kazuhironagai77:20211031195543p:plain

点乗積と訳されています。

読み方はてんじょうせきだそうですが、てんじょうせきで変換しても点城跡や天井積しか表示されないと言う、本当に日本語として定着しているのか不思議な単語です。

最後に英ナビ!辞書ですが

点乗積と訳されています。

読み方はてんじょうせきだそうですが、てんじょうせきで変換しても点城跡や天井積しか表示されないと言う、本当に日本語として定着しているのか不思議な単語です。

最後に英ナビ!辞書ですが

f:id:kazuhironagai77:20211031195612p:plain

なんとこの辞書には内積がDot Productの訳に入っています。しかも点乗積という聞いた事のない単語が入っていない所も特徴です。

何となくですが、英ナビ!辞書は、通訳や留学生などの実際に日本語と英語を翻訳する必要がある人達が使用している辞書って感じがします。理屈は良いから通じる単語を示せ。的な意思を感じます。

今度は、ドット積と内積の違いについて調べます。

f:id:kazuhironagai77:20211031195627p:plain

これ見てまず感じたのが、日本の学者の専門用語に対しての不真面目感です。

日本中でDot Productを扱う人達が、内積とドット積の違いについて混乱しているのに、学者による内積とドット積についての違いについての解説が全くないんです。二番目に表示されている「内積とドット積の話」が東北大学が唯一、学者が書いているらしい記事でそれ以外の記事は一般の人が片手間に調べた内容をまとめたものです。

これ見て、何かやる気がなくなりました。

用語の定義が曖昧なまま、学問を学ぶ事は出来ません。科学は宇宙全体で共通で、用語の定義が英語と日本語で変わるはずがありません。にも関わらず専門家による内積やドット積といった基本的な用語の定義がされていないんです。

Dot Productの日本語訳は内積ではありません。日本語の内積の定義は曖昧過ぎて、数学的に厳密な定義がされているDot Productと=で結ぶ事は絶対に無理です。またDot Productの訳にドット積や点乗積を用いる辞書もありますが、それらの用語も定義が曖昧で数学的に厳密な定義がされているDot Productと=で結ぶ事は絶対に無理です。

結論が出ました。

英語のDot Productを日本語に訳す時は、Dot Productとそのまま使用すべきです。内積にしろドット積にしろ訳した瞬間にDot Productの持つ厳密性が失われます。

内積の翻訳はNaisekiとするべきです。定義が曖昧すぎてDot Productと訳すと後で色々な問題を生じる可能性が大です。どうしてもDot Productと言いたいならkind of dot productと言うべきでしょう。

全然話は変わりますが、大雨の次の日に雨が降ると巨大な沼が誕生する近所の公園にたまたま通ったんです。そしたら全然水が溜まってないです。あれ。と思っていたらその公園のすぐ隣に大きな病院が建てられた時に、県の予算で排水の大掛かりな工事も同時に行ったそうです。病院が水没してしまったら大変ですから。

当然ですよね。

専門家による内積やドット積の厳密な定義がされていないと言う事はその逆なんです。そこに何も作る気がないから内積やドット積の厳密な定義もしないんです。

日本のITに対するやる気を見ました。

PythonのDot Product問題についてはまた別な機会にやります。今はやる気がなくなってしまいましたので。

それでは今週の勉強を始めます。

<本文>

1.今週の予定

今週は以下の事についてやります。

  • Niagara : 先週の続きをやる
  • Material : Ben Cloward氏のTutorialを勉強する
  • NPCAIを作成するためのAIの復習の続き(Nav Meshの勉強の続き)
  • World CompositionによるMap1の作成(動的に生成するActorの追加など)
  • UE5におけるWorld Partitionの勉強の続き

話はまた脱線しますが、NvidiaのVideo CardとEpic Games社のUnreal Engineのコンビはインフラに還元したら1000億円位の投資 と等価と思うです。例えば最先端の化学の工場か研究所を作ったら1000億円位普通にかかります。UEを使いこなせるって他の分野だったら1000億円のインフラを使いこなしてるのと同じ事なんですよ。

今の時代って19世紀の産業革命と同じ事が起こっていると思うんです。いわゆる情報化革命と言う奴です。19世紀の産業革命で起きた最も大きな変化って、貴族から工場でモノを大量生産して売る資本家たちに権力が移動した事だと思うんです。そして今度の情報化革命でも資本家から誰かに権力が移る乱世の時代なんです。

そんな時代に1000億円のインフラを使いこなしてるの人ってもはや戦国武将と同じですよ。天下を狙える立場ですよ。

何でみんなその事に気が付かないんですかね。私には不思議でならないです。

2.Niagara : Time Distortion Effect - UE4 Tutorial [1] を勉強する

2.1 先週の勉強の復習をする

先週、何をやったのかもう忘れているのでその復習をします。

<Spawn RateをそれぞれのInstanceのEditorから変更出来るようにする>

Spawn Rateの値を以下の様にセットする事でそれぞれのInstanceのSpawn RateをUE4のEditorから変更出来る様に出来ます。

まずUser ParameterにFloat型の変数、Flake Amountを作成します。

f:id:kazuhironagai77:20211031195722p:plain

f:id:kazuhironagai77:20211031195730p:plain

その変数をSpawn Rateにセットします。

f:id:kazuhironagai77:20211031195744p:plain

以下に示したようにFlake Amountの値をUE4のEditorからセット出来るようになりました。

f:id:kazuhironagai77:20211031195803p:plain

<指定したStatic Meshの形状にParticle を発生させる>

今まで勉強したやり方の一つと同じ方法でやっています。

f:id:kazuhironagai77:20211031195825p:plain

<EffectをStatic MeshにAttachする方法>

これが先週、新しく学んだことです。

以下に示したようにStatic MeshにComponentとしてEffectをAttach出来ます。

f:id:kazuhironagai77:20211031195846p:plain

この時注意しないといけない事はStatic MeshのParameterであるAllow CPU Accessにチェックする必要がある事です。

f:id:kazuhironagai77:20211031195903p:plain

これから調べて見ますか。

公式のDocumentであるbAllowCPUAccess [2] によると以下の解説がされていました。

f:id:kazuhironagai77:20211031195924p:plain

これ読むとStatic MeshのGeometryのDataをCPUからGPUに移す時、普段はCPUの側のGeometryのDataは消してしまいますが、これにCheckを入れた場合は消さないで残しておくようです。

成程、先週、EffectのEmitter PropertiesのSim TargetをGPUにセットし直しましたが

f:id:kazuhironagai77:20211031200015p:plain

この部分とは全く関係なかったんですね。

一寸だけ、GPUで計算しているのに何でCPU Access何だろうと思いました。

この部分で分からない所が、一個あります。

Sample Static Mesh ModuleではCubeでセットしているのに

f:id:kazuhironagai77:20211031200035p:plain

f:id:kazuhironagai77:20211031200042p:plain

ComponentとしてStatic Meshに追加するとそのStatic Meshの形にParticleを発生するところです。

f:id:kazuhironagai77:20211031200056p:plain

これは後で調べます。

<Static Meshの色をParticleに追加する事とG Bufferについて>

Static Meshの色をParticleにパスする事はBuilding advanced effects in Niagara | Unreal Engine [3]で勉強しました。

今回はその時とは違いG Bufferを使用しています。

このG Bufferについて勉強します。

Learn OpenGLDeferred Shading [4] に簡単な解説がありました。

f:id:kazuhironagai77:20211031200116p:plain

これは実際に自分でOpenGLを使用して作成してみないと本当の意味では理解出来ませんが、一応理解した限りで自己流にまとめてみました。

Deferred shadingではLightingなどのRendering Costのかかるモノは後にRenderingする事にしてそれ以外のモノ、特にGeometryに関するモノを先にRenderingしてBufferに保存しておきます。その保存しているBufferをG-Bufferと言うそうです。

あ。思いだしました。

そう言えばこれ昔勉強しました。

このG BufferにAccessする訳ですね。

これならStatic Meshの色を調べるのも簡単ですね。何でBuilding advanced effects in Niagara | Unreal Engine [3]ではこの方法でやらなかったんでしょうか?G Bufferを使用すると何らかのDisadvantageがあるんでしょうか?

G Buffer Color Moduleの実装を見てみます。

最初のPositionの値をWorld SpaceからScreen UV にWorld Position to Screen UV ノードで変換しています。

f:id:kazuhironagai77:20211031200130p:plain

これもG Bufferの意味を理解した後なら納得ですね。

ただScreen UVのCoordinateが-1から1なので0から1なのかは不明です。後、0から1の場合なら左上が原点であるのかも不明です。

その後で、Decode Base Color NodeでG buffer の指定した位置の色を取り出しています。

f:id:kazuhironagai77:20211031200143p:plain

G-Bufferの他の値は取り出せないんでしょうか?

f:id:kazuhironagai77:20211031200156p:plain

これ見ると結構色々な値がG Bufferに保持されているんですね。光のRenderingの計算は後ですると先程の説明でありましたが、ここにDiffuse ColorやSpecularの選択も出来ますね。Diffuse ColorやSpecularは先に計算しているみたいですね。

<Cameraとの距離によって発生するParticleの量を調整する>

これは2つの事を知る必要があります。

一つ目は、Spawn Rate ModuleにあるSpawn Probabilityです。

f:id:kazuhironagai77:20211031200213p:plain

ここをチェックする事で発生するParticleの量を0から100%の割合で調節する事が出来ます。

この値とCameraとの距離を関連すければ良い訳です。

2つ目はCameraとの距離の計算方法です。以下にまとめました。

  1. Cameraの位置、ParticleのセットされたStatic Meshの位置をGetします。
  2. Particle0100%の間で表示したい距離を決めます。
  3. 2の値でCameraStatic Meshの距離を割ります。
  4. 3の値をInverseします。

4の値をSpawn ProbabilityにセットすればCamera がStatic Meshにいる時に100%のParticleが発生します。そして指定した距離より離れた時はParticleの発生する数は0になります。

具体的には、Cameraの位置は、

f:id:kazuhironagai77:20211031200234p:plain

から得ます。

公式DocumentのEmitter Update Group [5] によると

f:id:kazuhironagai77:20211031200247p:plain

と書かれています。

Cameraに関する情報をNiagaraのModuleからaccess出来るようにする変数でしょうね。

Camera Queryから繋げられるノードを調べると以下の種類のノードが表示されます。

f:id:kazuhironagai77:20211031200301p:plain

前回は、ここでCalculate Particle Distances CPUノードではなくGet Camera Properties CPU/GPUノードを使用しました。

多分、Calculate Particle Distance CPUノードはそれぞれのParticleとCamera の距離を返すので、Get Camera Properties CPU/GPUノードを使用したんでしょうね。

f:id:kazuhironagai77:20211031200315p:plain

先週のBlogを読み返すと、何でCPU/GPUとあえて言っているのか不思議に思っていますがこの意味が分かりませんでした。

後、これは単なる推測ですが、

f:id:kazuhironagai77:20211031200327p:plain

のForward Vector World、Up Vector World、そしてRight Vector Worldは

f:id:kazuhironagai77:20211031200339p:plain

Camera の軸をWorld Spaceで表した値だと思います。

Particleの発生するStatic Meshの位置は

f:id:kazuhironagai77:20211031200352p:plain

で得る事が出来ます。

Particleを表示する距離の指定はMap GetノードにFloat型の変数を追加する事で出来る様になります。

f:id:kazuhironagai77:20211031200408p:plain

その後の計算は自分で計算しても良いですが、このTutorialではDistance Based Fall Offノードを使用しています。

f:id:kazuhironagai77:20211031200421p:plain

以上です。

2.2 Niagara : Time Distortion Effect - UE4 Tutorial [1]の続きをやる

今度は床のEffectを作成します。

まず床のMaterialを作成します。

f:id:kazuhironagai77:20211031200440p:plain

特に特徴のあるMaterialじゃないですね。

f:id:kazuhironagai77:20211031200517p:plain

こんな感じです。

f:id:kazuhironagai77:20211031200532p:plain

微調整しました。

また先程のMaterialに戻って以下の実装をします。

f:id:kazuhironagai77:20211031200545p:plain

Sphere Maskノードはこの前のDisintegration in UE5 Niagara Tutorial | Download Files [6] の勉強で使用した時に勉強しました。

勉強したんですが、AとBの値の中間が球の中心になるのか忘れてしまいました。後で確認します。

この値をEmissive Colorに繋げます。

f:id:kazuhironagai77:20211031200559p:plain

こんな感じになります。

あー。分かりました。この範囲の円を振動させるんですね。

以下の実装をしました。

f:id:kazuhironagai77:20211031200740p:plain

結果です。

f:id:kazuhironagai77:20211031200904g:plain

うーん。何でこんな感じになるのか今一理解出来ません。

この計算は色んな所で使用するので後でじっくり検証します。

Sineノードの計算結果は-1から1なので0から1に変更するために以下の実装をします。

f:id:kazuhironagai77:20211031200937p:plain

でもこれって-1から1なので0から1に変更するためだけじゃないですよね。

この実装、Powerの部分が良く分からないんです。LerpのAlphaって結局0から1の範囲ですよね。折角sin値に1足して、0.5を掛けて値を0から1の範囲に変更したのに何でPowerをするんですかね?

この辺も後で検証します。

f:id:kazuhironagai77:20211031201007g:plain

こんな感じになりました。

大体は良いんですが、

以下の状態の時、真ん中の円と最後の円の外側が全部選択されています。

f:id:kazuhironagai77:20211031201045p:plain

この部分は余計なのでMaskして外します。

まず中心の円から消します。

f:id:kazuhironagai77:20211031201057p:plain

f:id:kazuhironagai77:20211031201104p:plain

こうなりました。

f:id:kazuhironagai77:20211031201122g:plain

消えてますね。

ウーン。何で消えるのか分からない。いや消えるのは分かりますが、5乗する意味が不明です。

今度は円の外側を消します。

以下の実装を更に掛けます。

f:id:kazuhironagai77:20211031201157p:plain

消えました。

f:id:kazuhironagai77:20211031201213g:plain

これもSaturateを入れたり掛けたりしている部分が謎です。後でしっかり検証します。

今度はこの波紋に合わせて、Meshの波を起こします。

MaterialのTessellationの設定を以下の様に変更します。

f:id:kazuhironagai77:20211031201237p:plain

これはWorld Displacementを使用するためのものです。

次に以下の実装をWorld Displacementに繋げます。

f:id:kazuhironagai77:20211031201250p:plain

結果です。

f:id:kazuhironagai77:20211031201314g:plain

MaterialのTessellationについてまだ勉強していないのでここは復習する時も軽くにしておきます。

床以外のActorにもこのMaterialを適用します。

f:id:kazuhironagai77:20211031201343g:plain

今度はこのEffect(Materialですが)がCharacterに沿って起きる様にします。

Parameter Collectionからクラスを作成します。

f:id:kazuhironagai77:20211031201408p:plain

Vector Parameterを一つ作成します。

f:id:kazuhironagai77:20211031201423p:plain

今度はThird Person CharacterのBPを開いて以下の実装をします。

f:id:kazuhironagai77:20211031201438p:plain

あまりConstruction Scriptを使用した事はないんですが、これってC++でいうConstructorのBP版であると理解しています。

と言う事はこの設定だとThird Person Characterが移動した後の位置の情報はパスされないんじゃないでしょうか?

更にMaterialのActor PositionノードをCollection Parameterノードと交換します。

f:id:kazuhironagai77:20211031201452p:plain

はい。やっぱりTickにコードを足しました。

f:id:kazuhironagai77:20211031201507p:plain

こんな感じです。

f:id:kazuhironagai77:20211031204216g:plain

サイズが大きすぎてUpload出来なかったので画質を落としました。

f:id:kazuhironagai77:20211031213849g:plain

残りの半分です。これも画質を落としています。

このEffectをこのMaterialに追加します。

f:id:kazuhironagai77:20211031204412p:plain

Tessellationの部分を以下の様に変更して

f:id:kazuhironagai77:20211031204425p:plain

World Displacementの部分を丸コピーします。

f:id:kazuhironagai77:20211031204438p:plain

こんな感じです。

f:id:kazuhironagai77:20211031204503g:plain

今度は床の光っている箇所に下記のTextureを混ぜてキラキラさせます。

f:id:kazuhironagai77:20211031204546p:plain

こんな感じです。

f:id:kazuhironagai77:20211031204602p:plain

こんな感じです。

f:id:kazuhironagai77:20211031204614p:plain

この部分の実装はTextureのサイズを変更しているだけですね。TexCoordの代わりにAbsolute World Positionを使用した理由は分かりません。後で検証します。

この垂直の部分

f:id:kazuhironagai77:20211031204629p:plain

は要らないので外します。

以下のコードを

f:id:kazuhironagai77:20211031204645p:plain

Emissive ColorのLerpの前に掛けます。

f:id:kazuhironagai77:20211031204702p:plain

はい。消えました。

f:id:kazuhironagai77:20211031204715p:plain

Tutorialに何でこのやり方で垂直面の投影が消えるのかの解説がありましたが、後で自分で検証します。

今度は以下の部分のStatic Meshに先週作成したNiagara Effectを追加します。

f:id:kazuhironagai77:20211031204730p:plain

この部分は微調整なので記録はスキップします。

今度はParticle のEffectをゆっくりにします。

これは単に以下の実装を追加しただけでした。

f:id:kazuhironagai77:20211031204742p:plain

こんな感じです。

f:id:kazuhironagai77:20211031204756g:plain

火のEffectがゆっくり動いています。

特に検証しなくてはならない箇所はないです。

今度はMaterialの最適化を行います。

ここで使用したMaterialはTessellationを使用しているためコストがかなり高いです。最適化をします。

一つ目の方法はLODを使用する方法です。

f:id:kazuhironagai77:20211031204820p:plain

このCouchを使用して作成します。

CouchのStatic Meshを開いてMaterial Slotsを一個追加します。

以下に示した様に、元のMaterialをElement1にセットしてここで作成したMaterialをElement0にセットします。

f:id:kazuhironagai77:20211031204836p:plain

そしてLOD PickerのCustomをCheckします。

f:id:kazuhironagai77:20211031204849p:plain

更にLOD SettingsのNumber of LODsの値を2にします。

f:id:kazuhironagai77:20211031204926p:plain

Apply Changesボタンを押します。

LOD1が現れるので、Materialに元のCouch用のMaterialをセットします。

f:id:kazuhironagai77:20211031204947p:plain

LOD SettingsのAuto Compute LOD DistanceのCheckを外します。

f:id:kazuhironagai77:20211031205000p:plain

LOD1のScreen Sizeに0.8をセットします。

f:id:kazuhironagai77:20211031205013p:plain

テストします。

近づくとCouchもグネリますが、

f:id:kazuhironagai77:20211031205027p:plain

離れると普通のCouchに戻ります。

f:id:kazuhironagai77:20211031205040p:plain

むー。

初めてLODの設定を自分で変えました。LODにはこんな使い方もあるんですね。設定の詳細については後で検証します。

二つ目の方法はNiagaraの最適化です。

カメラが凄く遠く移動してParticleが何も生成しない状態でもEmitter Updateは常に働いています。それはDistance Check Moduleを動かす必要があるからです。

f:id:kazuhironagai77:20211031205053p:plain

これを直します。

まずStatic MeshにAttachしたNSを選択します。

そしてAuto Activate のCheckを外します。

f:id:kazuhironagai77:20211031205106p:plain

すると以下に示した様にBoxに近づいてもParticleは発生しません。

f:id:kazuhironagai77:20211031205119p:plain

以下の方法でStatic MeshにAttachしたNiagara SystemをActivate出来るとありましたが

f:id:kazuhironagai77:20211031205134p:plain

これをどう繋げるのかの説明はなかったです。これの使用方法についても後で検証します。

これでお終いです。

2.3  UnrealCG氏のTime Distortion Effect - UE4 Tutorial [1]を勉強した感想

UnrealCG氏のTutorialであるTime Distortion Effect - UE4 Tutorial [1]を一応終わらせました。そんなに沢山はないですが感じた事を忘れない内にまとめておきます。

まずやってびっくりしたのがCGHOW氏とやり方が全く違う事です。

二人ともインド出身なので流派と言うか学閥と言うか、同じ流れを汲んでいるのかと思っていたのですがやり方が全く違います。インドのComputer Scienceの深さを感じました。

UnrealCG氏はTextureも全て提供してくれているのでほとんど全ての人がTutorialを見るだけで再現出来る作りになっています。しかしそのせいで寄付金は少なくなってしまってますね。

後、このTutorialをやってみて思ったのは、FXにおけるMaterialの占める割合の大きさです。60%位はMaterialが占めています。

Niagaraの勉強をしているのかMaterialの勉強しているのか分からなくなります。

そんだけです。

3.Material : Ben Cloward氏のTutorialを勉強する

3.1 Sine and Cosine - Shader Graph Basics - Episode 19 [7] を勉強する

前の章でMaterialにおけるSineの意味が良く分からないと言っていましたら

f:id:kazuhironagai77:20211031205231p:plain

Ben Cloward氏がSine とCosineについてのTutorialを作成してくれていました。もうこれを勉強するしかないですよね。

まずぱっと全部見ました。

今回はUnityが主で解説していました。UEは最後にCodeを紹介するに留めていましたが、そこでUEのSinノードの結構重大な特徴を紹介していたりしてました。

全体の構成は

  • 0:003:45 SineCosineの定義について
  • 3:456:50 Sineの計算結果を-11から01に変換する方法
  • 6:509:49 Sineを使用して波紋を作成する方法
  • 9:4911:51 Sineを使用して位置を移動する方法
  • 11:5116:18 Sineを使用してTextureを回転させる方法
  • 16:18~最後 UEでの実装方法

となっていました。

Sine とCosineの所の解説で、Freya Holmér氏から図を借りたと言っていましたが、友達なんでしょうか?

Freya Holmér氏は3D GraphicsのTutorialをYouTubeに上げていて、私も3Dの理論が分からなくなったりした時に良く利用しています。

Sineを使用して波紋を作成する方法は、これ私が知りたかったそのものズバリを解説しています。後で詳しく検証します。

Sineを使用して位置を移動する方法は、今一よく理解していないんです。何でMaterialを移動するとActorが動くんでしょうか?これの後でしっかり検証します。

Sineを使用してTextureを回転させる方法ですが、これって先週、Materialで勉強した内容そのものです。行列に戻した時にどんな式になっているのかが注目です。後UnityではY軸がUEのZ軸にあたるのでそれによる変化も勉強します。

最後のUEでの実装ですが、これはUnityの実装を見ながらUEは自分で実装する事にします。そして最期に答え合わせする事にします。

<SineCosineの定義について>

この部分は特に記録する内容はないです。自明の事だけ説明していました。

Freya Holmér氏の作成した図がSineとCosineが可視化されていて直観的に理解しやすいです。

f:id:kazuhironagai77:20211031205308p:plain

こういう図ってOpenGLでもProcessingでも何でも良いですが、作成しようと思えば簡単に出来ると思いますが、実際に作成した人はほとんどいないです。その辺をしっかり作成して講義で使用するところが、Freya Holmér氏の非凡な所なんでしょうね。

<Sineの計算結果を-1~1から0~1に変換する方法>

基本中の基本ですがしっかり復習します。

f:id:kazuhironagai77:20211031205327p:plain

こんな感じです。

f:id:kazuhironagai77:20211031205345g:plain

それでは検証していきます。

まず最初のsin(X)の値です。

f:id:kazuhironagai77:20211031205409p:plain

-1から1の間で移動しています。

何かカクカクですがExcelに触るの久しぶりで滑らかな線の引き方を忘れてしまいました。

今度はその結果に0.5を掛けてみます。

f:id:kazuhironagai77:20211031205425p:plain

値がSin(x)の半分になっています。

今度はそれに0.5を足します。

f:id:kazuhironagai77:20211031205438p:plain

値が0~1の間になりました。

うーん。「houdiniとunreal engine 4で学ぶリアルタイムvfx」でノードの機能を一々グラフ化して説明していたんですが、それが大変分かり易かったです。

のでそれを真似したんですが、あんまり分かり易くないですね。

0以下がどこかパッと見で分からないからでしょうか?

f:id:kazuhironagai77:20211031205634p:plain

図を少し改良してみました。

これ見て思ったんですが最初が0じゃないんですね。

f:id:kazuhironagai77:20211031205651p:plain

試しにCosineで計算してみましたが、Cosineだと1から始まって1で終るんですね。

ひょっとするとCosineを使用した方が綺麗に見える可能性もありますね。

やっぱり何でも実際にやってみるものです。

Sineを使用して波紋を作成する方法>

はい。これを知りたかった。

「2.2 Niagara : Time Distortion Effect - UE4 Tutorial [1]の続きをやる」で

f:id:kazuhironagai77:20211031205712p:plain

にsineを掛けると

f:id:kazuhironagai77:20211031205725p:plain

波紋が発生しますがこの理屈が今一分かっていません。ここでしっかり勉強します。

まずTutorial通りに実装しました。

f:id:kazuhironagai77:20211031205745p:plain

こんな感じです。

f:id:kazuhironagai77:20211031205919g:plain

一個ずつノードを見て行きます。

f:id:kazuhironagai77:20211031205942p:plain

Fracは小数点以下の値のみを返すはずです。0から1の間の値が返されているのでしょうか?

ExcelでGraphにするのはあんまり分かり易くないのでPreviewを表示させる事にしました。

f:id:kazuhironagai77:20211031210005g:plain

0~1の間の値が返っているのは間違いないみたいです。が数字でみたいですね。

調べたらDebug Floatノードを使用すれば数字が見れるみたいです。

f:id:kazuhironagai77:20211031210029p:plain

Fracに繋いでみました。

f:id:kazuhironagai77:20211031210042p:plain

以下の様な表示がされました。

f:id:kazuhironagai77:20211031210055p:plain

0から1の間の値が返っています。

後、Fracの返し値は2Vectorじゃなかったです。でも同じ値を2個返してくれています。親切設計ですね。

f:id:kazuhironagai77:20211031210109p:plain

今度は1を引いています。何でOne Minusノードを使用しなかったんでしょうね。

それは兎も角、Previewを見ると真っ黒です。

f:id:kazuhironagai77:20211031210122p:plain

0~1の間の値から1を引いたら-1~0の値に変わるので当然ですね。Debug Floatノードを使用して数字も確認しておきます。

f:id:kazuhironagai77:20211031210137p:plain

-0.9999から0の間の数字が表示されているみたいです。

それにGradientのTextureを足します。

f:id:kazuhironagai77:20211031210151p:plain

すると円が大きくなるanimationがPreviewに表示されます。

f:id:kazuhironagai77:20211031210223g:plain

録画したら平板全体が真っ白になる時があるんですが、Previewでは確認出来ません。カットしたかったんですがやり方が分かりません。

何で白い円が大きくなるのかの理由が分かりました。

-1をこのTextureに足したら、全部真っ黒になります。

-0.5を足したら半分だけ真っ黒くなります。

0を足したら円が全部表示されます。

そんだけの理由でした。

次は8を掛けています。

f:id:kazuhironagai77:20211031210254p:plain

0から1の間の値だったのが0から8の間の値に変化しました。

これは白の色を濃くしています。

f:id:kazuhironagai77:20211031210307p:plain

円内で真っ白な部分の割合が増えています。つまり白が濃くなっています。

次はClampしています。

f:id:kazuhironagai77:20211031210322p:plain

正直Clampするなら0と1の間でいいんじゃないと思いますがどう違うんでしょうか。多分先の計算に影響するのだと思います。

これにPiを掛けています。

f:id:kazuhironagai77:20211031210339p:plain

Sinノードに繋ぐのにPiを掛けておくと何か便利な事があるんでしょうか?

これも最後まで見ないと分からないですね。

はい。最後にSinノードにつながりました。

f:id:kazuhironagai77:20211031210355p:plain

前にも表示しましたがこんな感じです。

f:id:kazuhironagai77:20211031205919g:plain

Clampの値を1にしてみます。

f:id:kazuhironagai77:20211031210533p:plain

輪の数が1個になりました。

Clampの値を2にしました。

f:id:kazuhironagai77:20211031210553p:plain

輪の数は1個のままです。

Clampの値を3にしました。

f:id:kazuhironagai77:20211031210606p:plain

輪の数は2個のままです。

これがClampノードの役割のようですね。

今度はPiノードを抜いてみました。

f:id:kazuhironagai77:20211031210619p:plain

沢山あった輪が消えて一個の太い輪が表示されるようになりました。Piは輪の数をClampの値で調節するのに必要だったようです。

成程分かりました。

Sinで計算するので0から5の値も結局-1から1の間に変化するんです。それが輪を生み出しているです。

ちょっと遊んでみます。

まずsin()なので先程の実装と組み合わせて0~1の値に変換します。

f:id:kazuhironagai77:20211031210632p:plain

なんと灰色のバックが生まれました。

f:id:kazuhironagai77:20211031210645p:plain

何にもない所は0.5になるのか。うーん。

先程差のなかったClampの値が1と2の時です。

Clampの値が1

f:id:kazuhironagai77:20211031210659p:plain

Clampの値が2

f:id:kazuhironagai77:20211031210710p:plain

しっかり違いが出て来ます。

今度はSinの代わりにCosを使用してみます。

f:id:kazuhironagai77:20211031210725p:plain

うーん。Cosは灰色の部分がちょっとしかないですね。

f:id:kazuhironagai77:20211031205804g:plain

どうしてこんな違いが生じるのかは時間があるとき検討します。

Sineを使用して位置を移動する方法>

以下の実装で

f:id:kazuhironagai77:20211031210816p:plain

こんな動きしています。

f:id:kazuhironagai77:20211031210837g:plain

World Position Offsetに繋いでいるのか。それなら納得です。Vertexの値を弄っている訳ですね。

ここはそれだけです。

<Sineを使用してTextureを回転させる方法>

はい。来ました。

以下の計算をしています。

f:id:kazuhironagai77:20211031210909p:plain

Cos X + Sin Y

Cos X – Sin Y

ですね。

f:id:kazuhironagai77:20211031210923p:plain

あれ? 

先週の gameDev Outpost氏のUE4 - Materials and UV Rotation [9] と同じ計算してます。

うーん。でもUnityだと反時計回りに回ってますね。

分かりませんね。

座標軸が違うんでしょうか?

<UEでの実装方法の確認>

ここで大切な事はUEのSineノードのPeriodに

f:id:kazuhironagai77:20211031210955p:plain

6.28を入れる必要がある事です。これがDefault値では1になっています。

3.2 UEのMaterialの回転の謎に迫る

先週、何で-0.5を足すと中心で回転するのか分からないと言っていました。

分かりました。

一週間かかってある仮説を思い付きました。

まず仮説をここに説明します。その後で実験して検証します。

その前に先週の計算を少し直しました。

f:id:kazuhironagai77:20211031211015p:plain

DegreeからRadianの計算を追加して

f:id:kazuhironagai77:20211031211030p:plain

SineとCosineのPeriodに6.28をセットしました。

f:id:kazuhironagai77:20211031211044p:plain

f:id:kazuhironagai77:20211031211049p:plain

これでDegreeとRadianの変換も正しいはずです。

一応テストしてみます。

f:id:kazuhironagai77:20211031211108p:plain

f:id:kazuhironagai77:20211031211114p:plain

前に計算したDegreeとRadianとSin(x)の表です。結果をこの表に足していきます。

f:id:kazuhironagai77:20211031211139p:plain

0を入れます。

f:id:kazuhironagai77:20211031211156p:plain

結果です。

f:id:kazuhironagai77:20211031211209p:plain

大体同じ値なんですが90度の時だけ0が返っています。

Radianの値を調べたら

f:id:kazuhironagai77:20211031211224p:plain

1.5707で計算値の1.571とほぼ一致しています。

f:id:kazuhironagai77:20211031211237p:plain

試しに1.57をSinに入力してみると

f:id:kazuhironagai77:20211031211250p:plain

1と正しい値が出て来ます。

f:id:kazuhironagai77:20211031211303p:plain

でも元に戻すと

f:id:kazuhironagai77:20211031211321p:plain

0って表示されます。

f:id:kazuhironagai77:20211031211338p:plain

うーん。これは私のVideo Cardの問題かもしれません。Driverに問題が有って古いVersionをずっと使用していますので。

今回は90度の場合は見なかった事にして先へ進みます。

Texture Coordinateの座標がこれで正しいのかちょっと自信がないですがこれは後で調べます

f:id:kazuhironagai77:20211031211403p:plain

0.5、0.5移動した時です。

f:id:kazuhironagai77:20211031211417p:plain

-0.5、-0.5移動した時です。

f:id:kazuhironagai77:20211031211429p:plain

で回転なんですがTextureの左上を中心に回転するんです。

こんな風に

f:id:kazuhironagai77:20211031211444p:plain

f:id:kazuhironagai77:20211031211450p:plain

f:id:kazuhironagai77:20211031211457p:plain

これしか思いつかなかったです。

0度の時です。

f:id:kazuhironagai77:20211031211511p:plain

90度の時です。

f:id:kazuhironagai77:20211031211524p:plain

仮説と合います。

f:id:kazuhironagai77:20211031211539p:plain

180度の時です。

f:id:kazuhironagai77:20211031211556p:plain

f:id:kazuhironagai77:20211031211601p:plain

あってます。

270度の時です。

f:id:kazuhironagai77:20211031211614p:plain

f:id:kazuhironagai77:20211031211620p:plain

これも合ってます。

それでは0.5、0.5ずらした時はどうでしょうか?

90度回転した時です。

f:id:kazuhironagai77:20211031211633p:plain

画面から外れてしまいます。

f:id:kazuhironagai77:20211031211646p:plain

外れています。

ずっと絵が写りません。

ぐるっと回して最初に移る時は口が写ります。

f:id:kazuhironagai77:20211031211701p:plain

330度の時です。

実際の図も口が最初に写っています。

f:id:kazuhironagai77:20211031211715p:plain

これだと実際の結果と合いますね。

でも単に座標軸が間違っているだけかもしれませんね。

後、OpenGLを勉強した時、座標軸を回転させると全部辻褄があった事を覚えているんです。この回転方法だと座標軸じゃなくて絵を回していますね。

来週も引き続き検討する事にします。

4.NPCAIを作成するためのAIの復習の続き(Nav Meshの勉強の続き)

今週は、Navigation Systemの

f:id:kazuhironagai77:20211031211735p:plain

を勉強します。

その前に今までのAIの勉強で何をやって来たのかとこれから何をする目的だったのかをもう一回確認しておきます。

目的ですが、村人のAIを作る事です。

そのためにMonsterのAIを復習しました。

その時のまとめが不十分だったのでまとめ直しました。

そのまとめ直した部分が私が作成したTutorialです。

その私が作成したTutorialはAIの基礎を学ぶ前に学ぶ内容をまとめたものですのでそれだけでは村人のAIは作れません。

その後に

f:id:kazuhironagai77:20211031211751p:plain

を学ぶ必要があります。

まあ全部を学ばなくても村人のAIは作れそうですが、折角の機会なので勉強してしまいます。

4.1 Custom Navigation Areas and Query Filters Preparation Guide [10] をやる

ここは次のTutorialで使用するLevelを作成するためのTutorialなのでさっと作ってしまいます。

f:id:kazuhironagai77:20211031211811p:plain

4.2 Custom Navigation Areas and Query Filters [11] を勉強する

<Overview

AIは移動するNPCと目的地との最適なルートをNav Mesh上のPolygonで指定されているコストに基づいて計算します。

Nav MeshのそれぞれのPolygonにNavigation Modifier VolumesとNavigation Query Filtersを使用する事でコストを自由に指定する事が出来ます。

<GoalとObjectives

Navigation Areas と Query Filtersの使用方法の基礎を学ぶ

<1 - Creating Custom Area Classes

やり方はTutorialそのままで出来るので結果だけ簡潔にまとめて書いて置きます。

Nav Modifier Volumeを

f:id:kazuhironagai77:20211031211841p:plain

Nav Mesh内に配置して、Area Classに

f:id:kazuhironagai77:20211031211855p:plain

BP、Nav Areaから作成したクラスをセットします。

f:id:kazuhironagai77:20211031211909p:plain

Nav Areaクラスは

f:id:kazuhironagai77:20211031211930p:plain

そのAreaのコストとそのAreaの色を指定出来ます。

以下の様に配置した3つのNav Modifier Volumeに3つの別々のNav Areaをセットしました。

f:id:kazuhironagai77:20211031211945p:plain

Tutorialを見るとここまで簡単にやっていますが、Nav Modifier Volumeを認識してくれなくて上記の赤や青の色が表示されなくて大変でした。

一端、UE4 Editorを再起動したら何か認識してくれました。

一応、原因を調べたらDefault Costが1にセットされていると認識されないみたいな説が出て来ました。

これだけ確認します。

白い部分ですが、新しいNav Modifier Volumeを作成してDefault Cost が1である新しいNav Areaをセットしました。

f:id:kazuhironagai77:20211031211959p:plain

f:id:kazuhironagai77:20211031212005p:plain

f:id:kazuhironagai77:20211031212010p:plain

普通に認識しています。

良く分かりません。

Nav AreaのDefault Costを色々変えてテストしましたが、全ての場合で最適なルートを選んでいました。

f:id:kazuhironagai77:20211031212027p:plain

上記の例だと、Default Costは青=2、ピンク=4、赤=3、白=0で設定しています。

AIは赤―>白ルートを選択しています。最適なルートです。

でももしこれが人間だったら白というとても通り易いAreaがある事は出発した時は分からない訳で、青Areaを選択すると思います。

その辺はちょっと不満でした。

後、Nav Modifier VolumeはPolygon毎にCostを指定はしませんね。次のNavigation Query Filterがそれをするんでしょうか?

<2 - Creating Navigation Query Filters

こっちも実際のやり方はTutorialに沿ってやれば問題なく出来るので、ここには簡単なまとめを記録しておくだけにします。

Navigation Query Filtersの機能はAIで操作するCharacterにセットするBPで、上記で作成したNav AreaのCostにそのキャラ特有のCostを追加するものでした。

簡単にやり方を記します。

Navigation Query Filterクラスから新しいクラスを作成します。

f:id:kazuhironagai77:20211031212044p:plain

以下の様にArea ClassにCostを上書き設定します。

f:id:kazuhironagai77:20211031212059p:plain

AIが操作するキャラを選択して、以下に示したFilter Classに先程作成したNavigation Query Filterクラスをセットします。

f:id:kazuhironagai77:20211031212115p:plain

これで完成です。

AIに操作されるキャラは新しいコストに基づいて最適なルートを作成します。

f:id:kazuhironagai77:20211031212128p:plain

以上です。

Navigation Query Filterは想像していたのとは全く違っていましたね。でも使い方は覚えました。

4.3 Using Avoidance With the Navigation System [12]を勉強する

先週、話してたこれですね。

f:id:kazuhironagai77:20211031212146p:plain

要するにAIが動いてるActorと衝突しないための機能です。

そう言えば、先週のテストでAIで操作されるNPC同士が衝突してお互いに動けなくなっている時がありました。

f:id:kazuhironagai77:20211031212159p:plain

これを解消する訳ですね。

<Overview

Reciprocal Velocity Obstacles (RVO) と Detour Crowd Managerを使用してAIに操作されたキャラは動いている物体を避けます。

Reciprocal Velocity Obstacles (RVO)が動いているそれぞれのAIに操作されているNPCの速度を計算します。

Detour Crowd ManagerがReciprocal Velocity Obstacles (RVO)が計算した値に基づいてNPC同士の衝突を回避します。

<GoalsとObjectives

Reciprocal Velocity Obstacles (RVO) と Detour Crowd Managerの使い方を覚えます。

<1 - Required Setup

前か使用しているProjectに新しいMapを作成して代用します。

<2 - Creating Your Test Levelと3 - Creating Your Agent

出来ました。

f:id:kazuhironagai77:20211031212234p:plain

真ん中でにらみ合って全く動きません。

f:id:kazuhironagai77:20211031212250p:plain

<4 - Adding Reciprocal Velocity Obstacles Avoidance to Your Agent

CharacterのCharacter Movementを選択します。

f:id:kazuhironagai77:20211031212310p:plain

Character Movement:  AvoidanceにUse RVO Avoidanceがあるのでチェックします。

f:id:kazuhironagai77:20211031212323p:plain

今度はお互いに避けて目的地につけました。

f:id:kazuhironagai77:20211031212338p:plain

あれ。RVOは他のNPCの速度を計算するだけじゃなかったの?

これだけでも衝突を避ける事が出来るみたいですね。

<5 - Adding Detour Crowd Avoidance to Your Agent

今度は、CharacterのAI Controller ClassにDetour Crowd AI Controllerをセットします。

f:id:kazuhironagai77:20211031212359p:plain

これだけでした。

テストすると

f:id:kazuhironagai77:20211031212416p:plain

スムーズな動きをして他のNPCの動きを躱して目的地に着きました。

これは凄いですがAI ControllerにDetour Crowd AI Controllerをセットする必要があります。

AI ControllerからBehavior Treeを呼び出す場合、Detour Crowd AI Controllerから呼び出せるのか、もしくはDetour Crowd AI Controllerの機能を丸コピー出来るようにする必要があります。

この辺の問題を解決する必要があります。

<まとめと感想>

最初、RVOとDetour Crowd Managerに対して以下の様な解釈をしていましたが全然違いましたね。

f:id:kazuhironagai77:20211031212436p:plain

もう一回、Overviewを読み直してみます。

Detour Crowd Manager は RVO の計算を使用して衝突を回避します。のように言っている文章は確かにありますね。ただそれから推測してRVOは単なる速度の計算と解釈したところから、勘違いが始まったみたいですね。

両方とも衝突をさけるための方法で、Detour Crowd Manager はある種のRVO の計算を使用して衝突を避けています。とも読めます。

こればっかしは前提となる知識がないと正しく読むのは難しいですね。

まあ今は理解したからどうでもいいですが。

以上です。

5.World CompositionによるMap1の作成(動的に生成するActorの追加など)

5.1 キャラの重力を切る

戦闘から元のLevelに戻って来る時に、Landscapeが生成されていなくて落ちて死んでしまったら、World Compositionを使用する意味が全くなくなります。そうなったらWorld Compositionは外して元に戻す必要が出て来ます。

なのでまずキャラの重力を切って3秒空中に浮かせる事で、Landscapeが生成される前に落ちて死ぬ事を防げるのかを試します。

やり方は先週試した方法と同じです。

RPG Game ModeのEvent BeginPlayに以下の実装を追加しました。

f:id:kazuhironagai77:20211031212503p:plain

Landscapeが生成されていませんが、キャラは浮いているので死ぬ事はありません。

f:id:kazuhironagai77:20211031212554p:plain

設定は1.5秒間浮いています。その間にLandscapeが生成されて

f:id:kazuhironagai77:20211031212607p:plain

重力が戻って落ちた時には地面の上に普通に着地しました。

Landscapeが生成される時間はもしかしたらPCの性能によって変わるかもしれません。その場合はEボタンを押したら重力が復活する。その代りEボタンを押さないと身動き出来ない。とかにすれば良いと思います。

5.2 静的に配置したMonsterと戦闘してみる。

Monsterの戦闘後に元のMapに戻って来る時は大丈夫なのかを試してみます。

Trapを静的に配置しました。この中に入ったらMonsterが発生します。

f:id:kazuhironagai77:20211031212634p:plain

Monsterと戦闘しました。

f:id:kazuhironagai77:20211031212652p:plain

落ちて死ぬ時とLandscapeの生成が間に合って助かる時の2パターンがあります。

f:id:kazuhironagai77:20211031212707p:plain

重力の無い時間を3秒に変更します。

テストします。

f:id:kazuhironagai77:20211031212726p:plain

3秒あったら大丈夫ですね。必ずLandscapeが生成されます。

しかし3秒は長いのでその間、何かのEffectを表示する必要がありますね。後で考えます。

闘技場の最初、3秒間浮いているのはかなり変です。ので闘技場のMapへ移動した時は重力は切らない事にします。

<闘技場Mapへの移動は重力を切らないようにする>

以下の実装を追加しました。

f:id:kazuhironagai77:20211031212744p:plain

テストします。

戦闘画面に移動しました。

f:id:kazuhironagai77:20211031212759p:plain

全く宙に浮かないで闘技場に落ちました。出来ています。

元のMapに戻って来る時は3秒間浮いています。

f:id:kazuhironagai77:20211031212813p:plain

出来ました。

5.3 Monsterを一体だけ静的に配置してみる。

Monsterと戦闘しても無事に元のMapに戻ってこれる事が判明したので、一体Monsterを静的に配置してみます。

調べたい事は、

  • LandscapeがLoadやUnloadされた時の影響
  • 戦闘後の影響

などです。特にLandscapeがLoadされるよりも先にMonsterが生成されて地面から落ちる事がないのかを調べます。

こんな感じで配置しました。

f:id:kazuhironagai77:20211031212841p:plain

テストします。

f:id:kazuhironagai77:20211031212854p:plain

思いっきり落下しています。

Playerの操作するキャラと同じように重力を切ってみます。

f:id:kazuhironagai77:20211031212908p:plain

効果なかったです。動的に生成する時はあるのかもしれませんね。

MonsterBPにStatic なPlaneを足してみました。

f:id:kazuhironagai77:20211031212923p:plain

今度は落ちませんがMonsterが移動しなくなりました。

f:id:kazuhironagai77:20211031212936p:plain

AIが全く効いていません。

どうしちゃったんでしょうか?

何か心配になって来ました。

Monster BPを壊しちゃったんでしょうか?

確認のためにMap1_Testを開いて見たら普通に歩いていました。

f:id:kazuhironagai77:20211031212950p:plain

うーん。

謎ですね。

Nav Meshが効いていないのでしょうか?

一端、板をMonster BPから外してMap上に板を配置する事にします。

テストしましたが結果は同じでした。

何と、配置されていたMonster BPのCapsule ComponentがStaticになっていました。

f:id:kazuhironagai77:20211031213007p:plain

直しました。

f:id:kazuhironagai77:20211031213020p:plain

今度は普通に徘徊しています。

今度はMonster BPをSub LevelであるLevel 3-6に移しました。これでLoad やUnloadの影響を見ます。

一端Mapの端まで行って戻って来ましたが普通にMonsterは生成されました。

f:id:kazuhironagai77:20211031213035p:plain

LoadやUnloadに関しては問題は見られませんね。

細かい点でまた問題が発生するかもしれませんが、一応大丈夫です。

5.4 ここまでWorld Compositionを使用した感想

LandscapeはそこまでLoadしたりUnloadする必要はないのかな。と思って来ました。

というかSub Levelのサイズの問題だと思うんです。今の私が使用しているサイズのMapだと別にLandscapeの一部を消す必要は無い気がします。

ただしEffectや木や岩などのLandscape以外のActorはSub Levelを作成して頻繁にLoad やUnloadしても良い気がします。つまりLoad Stream Levelノードを使用したSub Levelの管理です。

以下に私が考える理想の形をまとめます。

まずWorld Compositionによるlandscapeの読み込みはかなりでっかい領域で使用すべきです。

f:id:kazuhironagai77:20211031213055p:plain

私が考えていたような100mとかの範囲だと見た目が変な所が結構目立ちます。

f:id:kazuhironagai77:20211031213110p:plain

それ以外にもゲームをPlayする人は遠くの村の家が見えなくても気にしませんが、遠くの山が見えなくなったら気にします。だって山は遠くに有っても見えるモノですから。

最低でも500mにすべきです。

しかし500m^2内のActorを全て表示する必要は全然なくて配置されているActorは精々半径50mのものが表示されていれば十分です。つまりLoad Stream Levelノードを使用したSub Levelで100m毎にActorをsub Levelに入れて管理します。

これが出来るかどうかはやってみなければ分かりませんが、今、考えている理想形はこんな感じです。

Map1に関しては折角World Compositionを使用したので経験値を高める為に、このまま最後までやってみます。

UE5のWorld Partitionを使用すると、一応、今までの理解した範囲だと上記の理想的な状態を自然に再現してくれるので、早めにUE5に移行すべきとも考えています。

5.5 Monsterを動的に生成するための検証 Part 2

先週の調査ではMonsterを倒した時の管理などの検討が全くしてなかったのでもう一度検討します。

Map1では以下の方法でMonsterを動的に生成しています。

f:id:kazuhironagai77:20211031213132p:plain

ここでMonsterを生成するのに使用しているのがGame InstanceのMonster Spawn Dataです。

先週の考えではこれを沢山作ればいい。と考えていましたが、Monsterを倒した時に以下のチェックを外します。

f:id:kazuhironagai77:20211031213146p:plain

この実装がどうなっているのかを調べる必要がありました。

ありました。RPG Game Mode Base BP内の実装です。

f:id:kazuhironagai77:20211031213159p:plain

ここでどのMapにおける戦闘だったのかを判断しています。

Map1なのでRemoved Defeated Monster from Map 1関数を使用します。

Removed Defeated Monster from Map 1関数の中身です。

f:id:kazuhironagai77:20211031213214p:plain

Monsterの名前で消すMonsterを確認しています。

成程。

参考までにLandscape1のMonsterの生成方法も見てみます。

f:id:kazuhironagai77:20211031213227p:plain

ああそうだ。Landscape1ではそれそれのBlockで発生するMonsterを分割してDataにまとめたんでした。

f:id:kazuhironagai77:20211031213241p:plain

うーん。

これを作成した時はSub Levelについて知らなかったのでこの部分はもう一回、設計し直したいですね。

ただこの部分で実装したやり方は今のSub Level上でのMonsterの動的な生成の参考にはなります。

Monster Territory Numberを使用してどのBlockのMonster dataからMonsterを消すのかを判明してます。

f:id:kazuhironagai77:20211031213253p:plain

よし分かりました。

このMonster Territory Numberの代わりにどのSub Levelにいるのかが分かる関数があれば、Dataをバラバラにしても大丈夫なはずです。

その関数があるかどうかをまず探します。

なさそうです。

UE4 Answer HubのHow To Get Current Sub Level Name  [13] に

Sub Level毎のTrigger boxを作成してどのSub Levelに入っているのかを記録する方法が紹介されていました。

f:id:kazuhironagai77:20211031213306p:plain

これやるならMonster のData を管理しているMonster Spawn Dataの項目に新しくSub Level Nameを追加した方が楽な気がします。

f:id:kazuhironagai77:20211031213320p:plain

しかし前に、何気なく追加したらこのStructを使用して管理していたDataが全部消えてしまった記憶があります。

こっちはなるだけ触りたくありません。

妥協案としてMonsterが発生するSub LevelにだけTrigger Boxを生成します。

こんな感じにします。

Map1でMonsterが発生するSub Levelの一つは以下に示したようにSub LevelであるLevel 3-6です。

f:id:kazuhironagai77:20211031213338p:plain

なので以下の部分にTrigger boxをセットします。

f:id:kazuhironagai77:20211031213354p:plain

Game Instance内にこのSub Level名を保持出来る変数を一個追加しておきます。

Player が操作するキャラがこのTrigger Box内に侵入したら、そのGame Instance内の変数にこのSub Levelの名前を保持させます。

戦闘から帰還した時は、Game Instance内の変数に保存されているSub Level名からどのMap1のMonster Dataを読めばいいのか判明します。

これで行きます。

本来なら直ぐ実装しますが、他にも良いアイデアがあるかも知れないので一週間寝かせます。来週実装します。

6.UE5におけるWorld Partitionの勉強の続き

6.1 先週までの勉強のまとめ

World Partitionの勉強が以外と大切になりそうなのでしっかりやる事にします。

Blogを読み直すと、Smart Poly氏のUnreal Engine 5 | Open World Tutorial Using World Partition [14] を途中まで勉強して、公式のDocumentであるWorld Partition [15] を勉強しました。

それしかやってなかったんですね。これだけの勉強しかしてないのに結構理解してますね。

6.2 Unreal Engine 5 | Open World Tutorial Using World Partition [14]を見直す

Unreal Engine 5 | Open World Tutorial Using World Partition [14]の勉強を途中で止めてしまったので一応全部見ておきます。

大体知っている事でしたが二つ重要な話が載っていました。

一つ目はWorld Partitionの以下の部分が表示されない時は、

f:id:kazuhironagai77:20211031213428p:plain

一回そのLevelを閉じて別なLevelを開き、もう一回そのLevelを開くと現れるそうです。

試してみます。

新しいLevelを作成してLandscapeを追加しました。

f:id:kazuhironagai77:20211031213445p:plain

World Partition Setupには何も表示されません。

別なMapを開きもう一度このMapを開くと以下の様にWorld Partition Setup内にRun Time Settingの表示が現れました。

f:id:kazuhironagai77:20211031213458p:plain

しかしLandscapeが表示されていません。

f:id:kazuhironagai77:20211031213514p:plain

そこでもう一つの重要な話です。

もう一つはUE4で言う所のSub LevelのLoadの仕方です。

f:id:kazuhironagai77:20211031213532p:plain

World Partitionを表示します。

f:id:kazuhironagai77:20211031213549p:plain

Load Selected Cellsを選択します。

これを試してみます。

f:id:kazuhironagai77:20211031213604p:plain

LandscapeがLoad出来ました。

はい。

これだけ知っていれば十分な気がします。来週はWorld Partition を使用してLandscapeを実際に作成します。

7.まとめと感想

今週はホントに予定通りに終わらないと思っていたら何とか終わりました。

TextureのCoordinateはひょっとすると以下の絵で言う

f:id:kazuhironagai77:20211031213626p:plain

Screen Spaceと勘違いしてたかもしれませんね。

来週これは確認します。

8.参照(Reference

[1] UnrealCG. (2021, October 14). Time Distortion Effect - UE4 Tutorial [Video]. YouTube. https://www.youtube.com/watch?v=3ejuQVasl7w

[2] Epic Games. (n.d.-a). bAllowCPUAccess. Unreal Engine Documentation. Retrieved October 31, 2021, from https://docs.unrealengine.com/4.27/en-US/API/Runtime/Engine/Engine/UStaticMesh/bAllowCPUAccess/

[3] Epic Games [Unreal Engine]. (2020, May 27). Building advanced effects in Niagara | Unreal Engine [Video]. YouTube. https://www.youtube.com/watch?v=syVSRDQxrZU

[4] Vries, J. (n.d.). LearnOpenGL - Deferred Shading. LearnOpenGL. Retrieved October 31, 2021, from https://learnopengl.com/Advanced-Lighting/Deferred-Shading

[5] Epic Games. (n.d.-d). Emitter Update Group. Unreal Engine Documentation. Retrieved October 31, 2021, from https://docs.unrealengine.com/4.27/en-US/RenderingAndGraphics/Niagara/EmitterReference/EmitterUpdate/

[6] CGHOW. (2021, September 20). Disintegration in UE5 Niagara Tutorial | Download Files [Video]. YouTube. https://www.youtube.com/watch?v=4dYg4bvf4Rc

[7] Cloward, B. [Ben Cloward]. (2021, October 21). Sine and Cosine - Shader Graph Basics - Episode 19 [Video]. YouTube. https://www.youtube.com/watch?v=IFyZNSyjyFA&list=PL78XDi0TS4lEBWa2Hpzg2SRC5njCcKydl&index=19

[8] Holmér, F. (n.d.). Freya Holmér. YouTube. Retrieved October 31, 2021, from https://www.youtube.com/user/Acegikm0

[9] gameDev Outpost. (2020, May 4). UE4 - Materials and UV Rotation [Video]. YouTube. https://www.youtube.com/watch?v=4ITTsrm-MDo

[10] Epic Games. (n.d.-c). Custom Navigation Areas and Query Filters Preparation Guide. Unreal Engine Documentation. Retrieved October 31, 2021, from https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/ArtificialIntelligence/NavigationSystem/CustomNavigationAreasAndQueryFiltersLanding/CustomNavigationAreasAndQueryFiltersPreparationGuide/

[11] Epic Games. (n.d.-b). Custom Navigation Areas and Query Filters. Unreal Engine Documentation. Retrieved October 31, 2021, from https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/ArtificialIntelligence/NavigationSystem/CustomNavigationAreasAndQueryFiltersLanding/CustomNavigationAreasAndQueryFilters/

[12] Epic Games. (n.d.-f). Using Avoidance With the Navigation System. Unreal Engine Documentation. Retrieved October 31, 2021, from https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/ArtificialIntelligence/NavigationSystem/Avoidance/

[13] Epic Games. (n.d.-e). How To Get Current Sub Level Name - UE4 AnswerHub. UE4 Answer Hub. Retrieved October 31, 2021, from https://answers.unrealengine.com/questions/947667/how-to-get-current-sub-level-name.html

[14] Smart Poly. (2021, June 3). Unreal Engine 5 | Open World Tutorial Using World Partition [Video]. YouTube. https://www.youtube.com/watch?v=efN4bGbzr78

[15] Epic Games. (n.d.-g). World Partition. Unreal Engine Documentation. Retrieved October 31, 2021, from https://docs.unrealengine.com/5.0/en-US/WorldFeatures/WorldPartition/

「Unreal Engine 4.xを使用してRPGを作成する」の足りない部分を作成する 村人用のAIの開発4

f:id:kazuhironagai77:20211024224245p:plain

<前文>

前文には、日本人が誤解しているアメリカ、特に日本文化とキリスト教文化の違いから生じる誤解とその解決法について気が付く範囲ですが書いていきます。

アメリカに約10年暮らしていた私からすると、アメリカ人と日本人の常識って表面上は似ているんですが、そこにたどり着くための道程が全く違うんです。今日はそんな話です。

<Dot Product内積なのか?>

Dot Product。最近もMaterialの勉強で新しく勉強し直しました。

2021-10-03のBlogを見ると以下のように書かれています。

f:id:kazuhironagai77:20211024224312p:plain

いやあ、分かり易いですね。

大満足です。

と書いて後で気が付いたんですが、内積って良く以下に示したような図で説明されていますよね。

f:id:kazuhironagai77:20211024232327p:plain

ベクトルAとBがあってAの影をB上に投影した時に出来る線の大きさが内積。みたいな解説です。

先程のBlogを書いたときは、この説明方法がある事をすっかり忘れていました。

それで後から思いだした時、「あれ、この説明でも良くない。というかこっちの方が正確だよね。」とか言われたらどうしようかと、焦ってかなり内積について見直しました。

そしたら、この説明方法かなり無理があると言うか、直観的に理解すると間違って理解してしまう可能性も含んでいて2021-10-03のBlogに紹介した説明と比べるとかなり落ちる事が分かりました。

以下にその理由をまとめておきます。

  • 影に方向がある。つまり内積の最大の特徴である計算結果がScalerになってVectorではない事がこの図だと分からない。
  • 太陽の位置によって影の大きさが変わってしまうが、その辺を無視している。太陽が真上の場合で、と言う条件は図を見ただけでは直観的には理解しづらい。言い換えると地面と言う平面に対するNormal Vector(法線)という概念を隠して説明している。

そう言う訳で、この説明は実際はかなり分かりにくいので、安心しました。

はい。お終いとしようとしたら、ある疑問にぶつかりました。

Dot Productって内積だったっけ?

ここからが本題になります。

何となく、Dot Productの日本語訳は内積と思っていましたが、一応確認したんです。そしたらGoogle Translatorは

f:id:kazuhironagai77:20211024232405p:plain

って。更にWeblioでは点乗積。

f:id:kazuhironagai77:20211024232422p:plain

英辞郎では

f:id:kazuhironagai77:20211024232436p:plain

ドット積、点乗積と出ています。

え、Dot Productって内積じゃないの?

内積、英語で検索すると

まずGoogle Translateでは

f:id:kazuhironagai77:20211024232502p:plain

と出て来ます。

そしてWeblioでも

f:id:kazuhironagai77:20211024232517p:plain

となってDot Productではないです。

えー。ですよ。

ただ私、Dot Productは良く聞きますが、Inner Productって正直、聞いた覚えがないです。本当の英語なんでしょうか?

何か、非常に怪しい。

内積を直訳した造語なんじゃないのって気がします。

それで今度はInner Productを調べました。

f:id:kazuhironagai77:20211024232531p:plain

Inner Productと言う言葉自体はあるんですね。

じゃDot ProductとInner Productはどう違うのか調べて見ました。

色々な人が色々な所で答えていますが、私にはこの解答が一番分かり易かったです。

What's the difference between inner product, dot product and scalar product? [1]より

f:id:kazuhironagai77:20211024232545p:plain

Euclidean Spaceと言うのは実数のみ存在する空間と言う意味でしょう。つまり複素数がない世界です。

その場合はDot Productと言います。答えが実数でなくVector複素数を含んでいる場合はInner Productと言います。

分かりました。

まとめ直します。

まず、Inner ProductとDot Productの計算方法も定義も全く同じです。

違いは扱う数字にあります。

実数のみを扱う場合はDot Productと言い、実数に加えて虚数も扱う場合はInner Productと言うのが正確な定義のようです。

つまり全てのDot ProductはInner Productですが、Inner ProductはDot Productではない場合もあるわけです。

うーん。

理解はしましたが、私Inner Productを実際に大学で習った記憶がないんです。電気とかで複素数をガンガン使う人には当たり前の事なんでしょうか?

あ、量子化学の計算で複素数の計算を沢山してました。これを調べれば実際に複素数のDot Productの時はInner Productと言うのか確認できるはずです。

量子化学の教科書で調べて一番最初に出て来たヤツ[2]を

f:id:kazuhironagai77:20211024232600p:plain

Dot Productで検索しました。14頁に以下の文章がありました。

f:id:kazuhironagai77:20211024232615p:plain

流石に今これを読んですぐに何を言っているのか思い出すのは無理ですが確か

f:id:kazuhironagai77:20211024232629p:plain

この部分の計算は複素数を含んでいたはずです。

でもDot Productって言っています。

うん。

更に検索で調べた限りでは、この教科書にはInner Productと言う言葉は一回も使用されてなかったです。

やっぱり虚数の計算をする時もDot Productって言っています。

つまり英語ではInner Productって言葉、あんまり聞いた事がないという私の感覚は結構合っています。

厳密に言えば、日本語の内積の訳はInner Productかもしれませんが、実際に英語に訳す時はDot Productの方が理解されやすいというかInner Productだと下手すると理解されない可能性もあるかもしれません。そんくらい聞いた事がないです。

内積を英語に訳す時は、Dot Productと言っておいた方が無難な気がします。

次に、Dot Productを日本語に訳す時は内積と訳しても大丈夫か調べます。つまり今度は日本語でドット積と内積についての違いを述べている文献を当たります。

Noteにそのものずばりの解説がありました。「ドット積と内積の違い」[3]です。

f:id:kazuhironagai77:20211024232649p:plain

いや、そんな事は無いんじゃない。行列って結局はVectorの表現を変えただけだから。と思って読み進むとなんと、

f:id:kazuhironagai77:20211024232703p:plain

マジで!

Pythonちゃん。本当なの!

一応、公式の文献で確認します。NumPyのAPI中にあるnumpy.dot [4] をみると

f:id:kazuhironagai77:20211024232726p:plain

f:id:kazuhironagai77:20211024232732p:plain

本当に行列を返しています。

これ以上は前文でやるには長くなり過ぎるため、一端中止にして続きは来週します。

それでは今週の勉強を始めます。

<本文>

1.今週の予定

今週も以下の内容でやっていきます。

  • Niagara : 何かやる。
  • Material : Ben Cloward氏のTutorialを勉強する
  • NPCAIを作成するためのAIの復習の続き
  • World CompositionによるMap1の作成(バグの直し)
  • UE5におけるWorld Partitionの勉強の続き

2.Niagara : 何かやる。

2.1 先週までの復習

今週、何を勉強するのかを決める前に、先週までずっとやっていたStatic MeshからParticleを発生させるEffectの勉強がきちんと区切りがついたのかを一応確認します。

2021-10-10のblogを見直すとStatic MeshからParticleを発生させるEffectの勉強の目的は

f:id:kazuhironagai77:20211024232817p:plain

であると述べていました。

<Meshが消える技術>

Meshが消える技術は、MaterialのOpacity Maskにどういう値をPassするかです。

f:id:kazuhironagai77:20211024232835p:plain

Building advanced effects in Niagara | Unreal Engine [5]では、

f:id:kazuhironagai77:20211024232849p:plain

Dither Temporal AA ノードを使用していますし、

先週まで勉強していたCGHOW氏のDisintegration in UE5 Niagara Tutorial | Download Files [6]では

f:id:kazuhironagai77:20211024232903p:plain

Sphere Maskノードが担当してます。

<Particle をMeshに沿って発生さえる技術>

Particle をMeshに沿って発生さえる技術は、先週のBlogに良くまとめられていますが、Particle Spawn SectionのInitialize Mesh Reproduction Sprite ModuleやSample Static Mesh Moduleが担当しています。

更に深く解説すると

f:id:kazuhironagai77:20211024232922p:plain

Random Tri Coordノードを使用して指定したStatic MeshからMeshを一個だけ選択します。そのMeshの位置をGet Tri Positionノードを使用して特定します。最後にその位置をParticle のPositionにセットします。

Particle のPosition変数はParticleを発生する位置を指定するための変数なので、上記のやり方で指定したStatic Meshに沿ってParticleを発生させる事が出来ます。

<発生したParticleを動かす技術>

Disintegration in UE5 Niagara Tutorial | Download Files [6]ではStatic MeshからParticleを発生させているので単にCurl Noise Force Moduleを使用するだけでParticleが動きます。

Building advanced effects in Niagara | Unreal Engine [5]では

f:id:kazuhironagai77:20211024232941p:plain

を使用していました。どちらにしてもParticleが発生した後は、普通のParticleを動かすのと変わらないと言う事でした。

<Particle をMeshの消えた部分に沿って発生さえる技術>

後、今回はまとめませんが、このEffectで最も複雑なのはParticle をMeshの消えた部分に沿って発生させる技術です。この部分を理解するのは結構大変です。

<まとめ>

一応は、勉強の目的は達しています。このEffectで最も複雑なParticle をMeshの消えた部分に沿って発生させる技術の部分のまとめはまた今度やります。

2.2 今週は何を勉強するのかを決める

もうしばらくはMeshからParticleを発生させるタイプのEffectはやりたくないです。

何か面白いEffectはないかなと探そうと思った矢先にUnreal CG氏のTime Distortion Effect - UE4 Tutorial [7] がお勧めで表示されていました。

f:id:kazuhironagai77:20211024233010p:plain

凄い!

これに決めました。

ただBen Cloward氏のTutorial でDistortion Shader - UE4 Materials 101 - Episode 4 [8] のTutorialで

f:id:kazuhironagai77:20211024233036p:plain

こんなのを作成しているのがあります。

と言う事は、もしかすると80%位、Materialが主で20%位しかNiagaraを使用していないかもしれません。

まあそれでもやってみる事にしました。

2.3 Unreal CG氏のTime Distortion Effect - UE4 Tutorial [7]を勉強する

CascadeのEffectの製作をした時に、Unreal CG氏のTutorialに非常にお世話になりました。

ただその当時の私はあんまりVFXというモノが何なのか理解していなかった事と、Cascadeの仕組みをParticleを発生させるための観点から理解するという概念を全く持ってなかったため全然、身に付かず単にUnreal CG氏の言われた通りのEffectを制作するだけでした。

今回はもう少し深堀りして仕組みまできちんと理解出来るようにしたいです。

UE4を使用して作成しています。Versionまでは分からないですね。いつもの4.26でやる事にします。

Unreal CG氏のTutorial用に別のLevelを作成しました。

f:id:kazuhironagai77:20211024233100p:plain

Third Person Example Mapとはちょっとだけ違いますが、まあ許容範囲でしょう。

NSをFountain Templateを使用して作成しました。

f:id:kazuhironagai77:20211024233117p:plain

まずParticle Spawn SectionのAdd Velocity Cone Moduleの値を

f:id:kazuhironagai77:20211024233130p:plain

以下の様に変更します。

f:id:kazuhironagai77:20211024233150p:plain

Particleが全然上に飛ばなくなっちゃいましたね。

f:id:kazuhironagai77:20211024233208p:plain

Particle Update SectionのGravity Force Moduleを切ってCurl Noise Force Moduleを追加します。

f:id:kazuhironagai77:20211024233222p:plain

こんな感じです。

f:id:kazuhironagai77:20211024233236p:plain

この後M_FlakeをSprite RendererのMaterialにセットしますが、M_Flakeの作成方法が分かりません。

と思ったらこの動画最初から見てなかったです。途中から見てました。最初にM_Flakeの作成方法が出てました。

指定された場所からTextureをDown Loadしました。

f:id:kazuhironagai77:20211024233252p:plain

こんなトコまで無料で提供してくれているのか。感服です。

f:id:kazuhironagai77:20211024233306p:plain

M_Flake出来ました。

Render SectionのSprite Renderer ModuleのMaterialにセットします。

f:id:kazuhironagai77:20211024233319p:plain

こんな感じになりました。

f:id:kazuhironagai77:20211024233334p:plain

Spawn Rateですが、

f:id:kazuhironagai77:20211024233347p:plain

に新しいFloat 型の変数、Flake Amountを作成してSpawn Rate ModuleのSpawn Rate変数にセットします。

f:id:kazuhironagai77:20211024233401p:plain

こうする事でLevel上に配置されたこのNSのInstanceのSpawn Rateを

f:id:kazuhironagai77:20211024233414p:plain

Flake Amountから調節出来るようになります。

f:id:kazuhironagai77:20211024233428p:plain

更にFlake Amount変数のDefault値は

f:id:kazuhironagai77:20211024233442p:plain

System Settings SectionのUser Parameters Moduleを選択すると、以下の様に表示されるので

f:id:kazuhironagai77:20211024233455p:plain

そこで設定出来ます。

これは言われてみればその通りですが、新しい技ですね。覚えました。

この後で、Static MeshからのParticle のSpawnをやっています。

f:id:kazuhironagai77:20211024233509p:plain

はい。

お馴染みのやり方です。

f:id:kazuhironagai77:20211024233524p:plain

こんな感じです。

この後、CubeにInheritedするやり方を紹介しています。

f:id:kazuhironagai77:20211024233538p:plain

あれ

f:id:kazuhironagai77:20211024233552p:plain

頭の中心からしかParticleが発生していません。

Tutorialでは

f:id:kazuhironagai77:20211024233606p:plain

こんな感じで全身からParticleが発生しています。

その後の例で、Static Meshの設定からAllow CPU Accessにチェックを入れないと駄目と言っていたのでこのCubeのAllow CPU Accessにチェックを入れてみました。

f:id:kazuhironagai77:20211024233646p:plain

そしたらTutorialと同じ様にCubeの全体からParticleが発生するようになりました。

f:id:kazuhironagai77:20211024233707p:plain

一応Tutorialと同じModelでも試しました。

f:id:kazuhironagai77:20211024233721p:plain

今度はParticleに発生する箇所の色を付けます。

f:id:kazuhironagai77:20211024233736p:plain

新しいScratch Moduleを作成してG buffer Colorと名付けます。

f:id:kazuhironagai77:20211024233811p:plain

ここの名称ですが最初のScratch Pad Moduleを作成した時しか名前の入力が出来ません。

f:id:kazuhironagai77:20211024233827p:plain

こっちの名称は変更出来ますが、この名前を変更してもModuleの方の名前はScratch Moduleのままです。

名前の変更方法あるんでしょうか?

INPUTであるNew GBuffer変数を追加しました。

f:id:kazuhironagai77:20211024233841p:plain

GBufferを使用するのは多分始めてです。GBufferが何を指しているのかは後でしっかり復習します。

f:id:kazuhironagai77:20211024233856p:plain

Decode Base Color ノードを繋げました。

このノードも初めて使用します。後でこのノードについても調べます。

Decode Base ColorのScreen UVに値をセットします。

f:id:kazuhironagai77:20211024233909p:plain

Particle のPositionをWorld Position to Screen UVノードを使用してCoordinateを変換します。そしてScreen UVに値をパスします。

これも初めて見る実装です。Coordinateの変換は話には沢山聞いていましたが、実際にNiagaraで使用したのは初めてです。

Screen UVはカメラが撮影したImageを指していると思われます。

f:id:kazuhironagai77:20211024233923p:plain

OpenGLだと以下に示した様なCoordinateに分けられますが、

f:id:kazuhironagai77:20211024233939p:plain

Learn OpenGLCoordinate Systems [9] より

NiagaraのScreen UVは、最後のScreen Spaceに当たるみたいですね。

CLIP SPACEとSCREEN SPACEの違いを忘れてしまったんですがCoordinate Systems [9]に説明がありました。

f:id:kazuhironagai77:20211024234003p:plain

座標軸が、-1~1だったのが、0からPixel数に変化しているのが違いみたいですね。すっかり忘れていました。

UEのNiagaraにおけるScreen UVの座標はどこが0なんでしょうね。左上か左下か?

これも後で調べます。

採取した色をParticle Colorにセットします。

Tutorialでは以下の方法でセットしていますが

f:id:kazuhironagai77:20211024234017p:plain

Alphaの値をZで代用してるのは良いんでしょうか?

1を入れた方がマシじゃないでしょうか?

f:id:kazuhironagai77:20211024234103p:plain

でもMaterialの色と同じ色になっています。

こんな方法でStatic Meshの色をParticleに移植出来るんですね。驚きです。

もし○○したかったら、とTutorialで言っていますが、何をしたいのか早口過ぎて聞き取れません。Particleをカメラ寄りに発生したいなら、と言っている気もしますがどうでしょう?分かりませんね。

兎に角やります。

Camera Offset ModuleをGbuffer Colorの前にセットします。

f:id:kazuhironagai77:20211024234118p:plain

値は30にセットします。

f:id:kazuhironagai77:20211024234132p:plain

こんな感じです。

f:id:kazuhironagai77:20211024234145p:plain

正直何が変わったのか分かりません。

Camera Offsetを200にしてみました。

f:id:kazuhironagai77:20211024234200p:plain

Particle がカメラの前で発生する様になりました。

f:id:kazuhironagai77:20211024234215p:plain

何で今、こんな機能を追加したのかは不明ですが、Camera Offset Moduleの機能は大体理解しました。後でもっと詳しく調べますが。

次の実装の目的を説明していますが、また聞き取れません。

実装部を先に見た所、カメラとEffectの配置された位置によって発生するParticleの量を0から100%まで変化させる機能を追加しているようです。

この機能は興味深いです。やってみましょう。

Emitter Update SectionにScratch Moduleを新しく作成します。

f:id:kazuhironagai77:20211024234229p:plain

Emitter Update SectionにScratch Moduleを作成するのも初めてですね。何気に興味深いです。

f:id:kazuhironagai77:20211024234243p:plain

Map Get ノードにInput New Camera Queryを追加しました。

あれ、今回はScratch Moduleの名前を変更しませんでしたね。後から変更するんでしょうか?そしたらどうやって名前を変更するのか習えますね!

Camera Queryってどんな変数タイプなんでしょう。後で調べる事にします。

f:id:kazuhironagai77:20211024234255p:plain

Get Camera Properties CPU/GPUノードを追加します。

Camera Queryが初めて使用する変数のタイプなので、そのタイプが持つ関数も勿論初めて使用するモノばかりです。Get Camera Properties CPU/GPUノードも勿論初めて使用します。

Get Camera Properties CPU/GPUノードのCPU/GPUってどういう意味なんでしょう?

普通にGet Camera Propertiesノードで良いと思うのですが、敢えてその後にCPU/GPUを付ける位だから何か意味が有るんでしょうね。

出力もCamera Position World以外は不明ですね。

f:id:kazuhironagai77:20211024234308p:plain

まあ、このノードも後でじっくり調べましょう。

今度はMap GetノードにENGINE OWNER Position変数を追加します。

f:id:kazuhironagai77:20211024234321p:plain

ENGINE OWNER Position変数は、このNSのInstanceがLevel上に配置された時のWorld Spaceにおける位置の情報を保持しているはずです。

f:id:kazuhironagai77:20211024234335p:plain

このENGINE OWNER Position変数の値をDistance Based FallOffノードのStart Positionに繋ぎました。

あ。もう分かりました。

Get Camera Properties CPU/GPUノードのCamera Position Worldの値をこのDistance Based FalloffノードのEnd Positionに繋ぐ訳です。そしてNormalized Falloffで出力すればカメラとNSの距離によって0から1の値が得られます。

途中までは合ってましたが、Distance Based FallOffノードのDistanceの値をMap GetノードのINPUT Distance変数から取っています。

f:id:kazuhironagai77:20211024234349p:plain

Start PositionがあってEnd Positionがあれば、その距離は計算で出ます。その距離を0から1に変換するためには、計算した距離に対する100%の距離が必要でした。それをここでPassしているんですね。

f:id:kazuhironagai77:20211024234404p:plain

Map SetノードにFloatタイプの新しい変数、EMITTER SpawnProを追加します。この変数に先程のDistance Based FallOffノードのNormalized Distance Invertedの値をパスします。

これでこのScratch Moduleは完成のはずです。

Applyボタンをクリックします。

f:id:kazuhironagai77:20211024234417p:plain

何かWarningが表示されています。

TutorialでScratch Moduleから名前を変更しました。クリックしたら名前の変更が出来るようになっていたんですが、あれさっきは何回もクリックしても出来なかったんですが。

試してみます。

f:id:kazuhironagai77:20211024234430p:plain

普通に出来ましたね。???です。

Spawn Rate ModuleのSpawn Probability変数に先程作成したEMITTER SpawnProをセットします。

f:id:kazuhironagai77:20211024234443p:plain

TutorialではDistance Check ModuleのDistance変数に1000を代入してテストしてます。

f:id:kazuhironagai77:20211024234458p:plain

離れるとParticleが発生しなくなり、近づくとParticleが発生しています。

同様のテストを試してみます。

Distance Check ModuleのDistance変数の値を500に変更します。

f:id:kazuhironagai77:20211024234512p:plain

こんな感じです。

f:id:kazuhironagai77:20211024234527p:plain

カメラを近づけます。

f:id:kazuhironagai77:20211024234544p:plain

Particleが発生しました。

おお。出来ました。

今度は発生するParticleのサイズを大きい破片と小さい破片に変更します。

今あるEmitterを大きい破片用にします。

Initialize Particle ModuleのSprite AttributesのSprite Size を以下の様に変更します。

f:id:kazuhironagai77:20211024234558p:plain

EmitterをDuplicateして

f:id:kazuhironagai77:20211024234612p:plain

設定を少し変えます。

f:id:kazuhironagai77:20211024234626p:plain

f:id:kazuhironagai77:20211024234631p:plain

こんな感じです。

f:id:kazuhironagai77:20211024234646p:plain

凄い綺麗です。

次の機能を作成します。

またどんな機能を作成するのか聞き取れません。本当にインド人の英語は早口です。

あ。

そうだ。再生速度を0.75に設定して聞きなおしてみます。

うーん。

Prismatic? Effectを作成しますって聞こえますね。

床のグネグネを作成するんでしょうか?

まあやっていくうちに分かるでしょうね。

新しいMaterialを作成します。名前はM_Prismと名付けました。

f:id:kazuhironagai77:20211024234703p:plain

Blend ModeをTranslucentにセットします。

f:id:kazuhironagai77:20211024234716p:plain

Rotatorノードを使用しています。

f:id:kazuhironagai77:20211024234730p:plain

Materialの勉強でTexture Coordinateに掛け算したり足し算したりしましたが何で、回転させる事はしないのか不思議に思っていましたが、やっぱり回転させる機能を持つNodeはあるんですね。

また新しい事を学びました。

Materialの内容はここでは全部載せる必要ないな。と思って作成していたら

f:id:kazuhironagai77:20211024234745p:plain

上記の実装で以下のMaterialが出来ました。

f:id:kazuhironagai77:20211024234801p:plain

凄い。これは後でしっかり勉強し直します。

これで床のEffectを作成するのかと思ったら違ったみたいです。

またEmitterをDuplicateして今度はRefractionを作成しました。

f:id:kazuhironagai77:20211024234817p:plain

Render SectionのSprite Renderer ModuleのMaterialに先程作成したMaterialであるM_Prismをセットします。

f:id:kazuhironagai77:20211024234832p:plain

後は、他のParameterを微調整して以下の様になりました。

f:id:kazuhironagai77:20211024234847p:plain

更に微調整します。

f:id:kazuhironagai77:20211024234901p:plain

Cubeが少しですが崩壊しているように見えますね。

f:id:kazuhironagai77:20211024234917p:plain

更に微調整しました。

うーん。

微妙ですね。

Tutorialと同じように階段にこのEffectを付けてみました。

f:id:kazuhironagai77:20211024234936p:plain

Tutorialと比べると何か違います。

f:id:kazuhironagai77:20211024235000p:plain

今週はここまでですね。

結構時間がかかりました。

3.Material : Ben Cloward氏のTutorialを勉強する

3.1 Detail Normal Mapping - Shader Graph Basics - Episode 13 [10] を勉強する

まず、パラっと見たんですが、これってTutorialで使用しているTextureと同じモノがないと、自分で確認するのは無理だと思いました。

Quixelから岩の3DモデルとTextureそしてその岩に使用しているMaterialなどは手に入りました。

f:id:kazuhironagai77:20211024235049p:plain

このTutorialで使用しているもう一つのTextureですが、

f:id:kazuhironagai77:20211024235104p:plain

RとGには通常のNormal Mapが入っていて、Blue channelにはRoughnessのためのMultiplierがあり、

f:id:kazuhironagai77:20211024235117p:plain

Alpha ChannelにはColorのためのOverlayが入っています。

f:id:kazuhironagai77:20211024235131p:plain

これはどうやって手に入れるんでしょうか?

自分で探すにしてもどういう基準でこれらのTextureがそれぞれの使用のために選ばれたのが不明です。

今までずっと神回だったのですが、今回のMaterialのTutorialはかなりガックリな内容になるかもしれませんね。

それはそれでパッとやってしまいましょう。

先程のTextureの様に色々なDataを一個のTextureにまとめている場合はCompression SettingはBC7を選ぶべきと言っていました。

f:id:kazuhironagai77:20211024235144p:plain

流石にこういう話は役に立ちます。

今回、自分で実装出来ない場合は講義を簡単にまとめるだけにするかもしれません。それはそれで後から読んだときに役に立つでしょうし。

もう一つ大切な事はTextureがColorのDataを保持していない時はsRGBは外しておく事だそうです。

f:id:kazuhironagai77:20211024235157p:plain

これは知っていました。

講義のMaterialを真似て以下のMaterialを自作しました。

f:id:kazuhironagai77:20211024235210p:plain

Roughnessは以下のGreenのChannelに入っているためそこだけは変更しました。

f:id:kazuhironagai77:20211024235223p:plain

ただDpRFの残りのChannelに入っているDataが何なのかが分かりません。

作成したMaterialを使用したRockが以下のものです。

f:id:kazuhironagai77:20211024235237p:plain

確かに近づくと単なる写真になります。

f:id:kazuhironagai77:20211024235252p:plain

拡大しても写真に見えないようにこれからしていくわけです。

この近づいたときに使用するためのTextureですが、

f:id:kazuhironagai77:20211024235305p:plain

これで代用する事にします。

と言ってもこのNormal TextureのRGだけ使用します。

以下の実装を作成しました。

f:id:kazuhironagai77:20211024235320p:plain

動画ではMaskノードが抜けていましたが、どう考えても講義の解説通りに解釈するとMaskノードでRGを指定する必要があります。のでそこは追加しました。

よく動画の解説を聞いたら以下の部分はNormal MapがNormal MapとしてTextureに保持されていない場合に必要な工程だそうです。

f:id:kazuhironagai77:20211024235335p:plain

Normalの範囲は-1から1です。しかし通常のTextureの値は0から1です。ので通常のTextureをNormal Mapとして使用する場合は、上記の様に2を掛けて1引く必要があります。ただしTextureがNormal Mapとして指定されている場合はその必要はないそうです。

うーん。こういう情報は本当に勉強になります。

やっぱ凄いです。

でもMaterialはどこでこのTextureはNormal Mapじゃないと判断するんでしょうか?

f:id:kazuhironagai77:20211024235349p:plain

ここでしょうか?

兎に角、以下のように直しました。

f:id:kazuhironagai77:20211024235403p:plain

Derive Normal Zノードですが、TutorialのTextureはNormal MapがRGしかなくてBは計算から求めるしかないです。

Derive Normal Zノードの機能を公式のDocumentで調べるとVector Operation Expressions [11] に以下の説明があります。

f:id:kazuhironagai77:20211024235417p:plain

この計算をしても良いんですが、今私が使用しているNormalにはBの値も提供されているので、

f:id:kazuhironagai77:20211024235430p:plain

これでいく事にします。

最後のBlend Angle Corrected Normalノードは先週、勉強したRNM方式によるBlendingのはずです。

最終的に以下の様な実装になりました。

f:id:kazuhironagai77:20211024235447p:plain

これでテストします。

こんな感じになりました。

f:id:kazuhironagai77:20211024235503p:plain

比較ためにBlendする前のMaterialも撮影しました。

f:id:kazuhironagai77:20211024235523p:plain

DetailのNormalをBlendした場合、細かい部分の陰影が存在しています。

後、結構重要なのが、DetailをBlend してない方の画面を長時間眺めていたら、結構な3D酔いが起きました。脳が平面なのか立体なのか混乱するからでしょうか?兎に角、酔いました。

今度はRoughnessにDetailを追加します。

一番近そうなTextureを探してきました。

f:id:kazuhironagai77:20211024235754p:plain

これのB Channelを使用します。

f:id:kazuhironagai77:20211024235809p:plain

RoughnessにDetailを追加する場合は簡単で、以下に示した様にお互いの値を掛けるだけです。

f:id:kazuhironagai77:20211024235825p:plain

こんな感じになりました。

f:id:kazuhironagai77:20211024235839p:plain

何か銀でも含んでいるようなキラキラの粒が散在している岩になりました。

最後にColorとBlendする方法です。

このColorとBlendするためのTextureには条件があって以下に示した様に、

f:id:kazuhironagai77:20211024235852p:plain

値の大部分が‐0.5から0.5の間である必要があるそうです。

そんな事言われても、あるTextureで対応するしかないので、またこれで代用します。

f:id:kazuhironagai77:20211024235905p:plain

ColorのBlend方法だけ勉強出来ればまあOKとします。

ColorのBlendの仕方は以下に示した様にBlend_Overlayノードを使用します。

f:id:kazuhironagai77:20211024235919p:plain

Blend_Overlayノードは以下の解説が出て来ました。

f:id:kazuhironagai77:20211024235932p:plain

結果です。

f:id:kazuhironagai77:20211024235946p:plain

確かに岩の陰影が濃くなりました。

Materialに細部の表現を追加する時、Baseの色、Roughness、そしてNormalに細部のDataをBlendします。今回はその方法について学びました。

ただし、別に細部の情報は単純に足しても掛けてもある程度は表現出来る訳で、今回のやり方は今の所、コストと精度の関係から最もよく使用されているTechniqueと言うだけの事でもあります。

更にLandscapeとは違い、単なる岩のTextureにそこまで近づく理由もない訳で、今回の技術がどこまで実戦で必要になるかは疑問です。

今回の技術は、むしろ、あまり精度の良くないTexture2枚を使用して精度の高いMaterialを作成する時とかの方が役に立ちそうです。

以上です。

3.2 UE4 - Materials and UV Rotation [12] を勉強する

2021-10-03のBlogでTextureに対する加算と乗算を行いました。これは言い換えれば、Textureに対する移動と拡大・縮小です。となると後は回転があればTextureを自在に動かす事が出来ます。

そして今週のNiagaraの勉強中にTextureに対する回転も出来る事が分かりました。

f:id:kazuhironagai77:20211025000023p:plain

所が、この回転はTextureをずっと回転させています。私が欲しいのは一回だけ回転させる機能です。

そしたらgameDev Outpost氏のUE4 - Materials and UV Rotation [12]にそのものずばりがありました。

f:id:kazuhironagai77:20211025000040p:plain

ボっとこれを見てたんですが、これってひょっとしてOpenGLのZ軸回転に使用した行列のXYを計算しているだけじゃないの?と思って確認しました。

以下にLearn OpenGLのTransformation [13]にあるZ軸回転に使用する行列を示します。

f:id:kazuhironagai77:20211025000105p:plain

何かそんな気がします。

急遽ですが、これを確認する事にします。

このMaterialにRotationを実装します。

f:id:kazuhironagai77:20211025000120p:plain

こんな感じです。

f:id:kazuhironagai77:20211025000133p:plain

まず実装結果を示します。

f:id:kazuhironagai77:20211025000148p:plain

解説をします。

最初にTextureの中心をずらします。回転軸をTextureの中心に移動させます。ここは‐0.5を追加しているんですが、0.5が正しいんじゃないのかと思っています。後で詳しく検討します。

次が回転の実装です。これも後で詳しく検討します。

その次が、移動したTextureの中心を戻すための実装です。何故かUE4 - Materials and UV Rotation [12]では移動させた値をもう一回加算していました。足したら引くべきだと思います。結果は同じでした。

<回転について>

Learn OpenGLのTransformation [13]にあるZ軸回転に使用する行列をもう一回見ていると

f:id:kazuhironagai77:20211025000207p:plain

x軸の値は、

f:id:kazuhironagai77:20211025000220p:plain

です。Rotationの実装の計算は、

Cos θ*x + Sinθ*y

でした。

Y軸の値は、

f:id:kazuhironagai77:20211025000253p:plain

Cos θ*y-Sinθ*x

でした。

似てるけどちょっと違う。

うーん。ひょっとしてDirectXだから計算がちょっと違うとか?

DirectX Factor : 3D Transforms on 2D Bitmaps [14]をみると

f:id:kazuhironagai77:20211025000317p:plain

となっていました。

うーん。

これだと、Tutorialの計算と同じですが。

単純にこの行列が出て来たからと言って「はい。出来ました。」とは言えないです。何故かと言うとDirectXには詳しくないのですが、行列の計算がOpenGLと違ったような気がしていて、確か行と列が逆になった気がするからです。

これ行と列を逆にするとOpenGLと同じなんですよね。

この二つの行列、等価な気もして来ました。

Learn OpenGLのTransformation [13]にあるZ軸回転に使用する行列と同じ式で実装してみました。

f:id:kazuhironagai77:20211025000332p:plain

Degree = 0の時です。

f:id:kazuhironagai77:20211025000356p:plain

Degree = 60の時です。

f:id:kazuhironagai77:20211025000421p:plain

Degree = 90の時です。

f:id:kazuhironagai77:20211025000435p:plain

Degree = 120の時です。

f:id:kazuhironagai77:20211025000448p:plain

Degree = 180の時です。

f:id:kazuhironagai77:20211025000500p:plain

Degree = 240の時です。

f:id:kazuhironagai77:20211025000513p:plain

Degree = 300の時です。

f:id:kazuhironagai77:20211025000525p:plain

Degree = 360の時です。

f:id:kazuhironagai77:20211025000537p:plain

普通に回転しています。

あっ!

もう一回、Tutorialの式に戻して回転させます。

Degree = 0の時です。

f:id:kazuhironagai77:20211025000550p:plain

Degree = 60の時です。

f:id:kazuhironagai77:20211025000602p:plain

回転する方向が違う!!!

このTutorialのやり方だと時計回りに回転しますが、OpenGLの式だと反時計回りに回転しています。

ああ、Z軸の向きが違うと言う事か。

どっちの回転が正しいんでしょうか?

Rotatorノードを使用してTextureを回転させてみます。

f:id:kazuhironagai77:20211025000615p:plain

このノードが回転させる方向が正と考えて問題ないでしょう。

f:id:kazuhironagai77:20211025000827g:plain

反時計回りじゃないですか。

と言う事はOpenGLの回転の行列をそのまま適応できると言う事ですね。

ああ、4年。

約4年間もかかって、やっと一部ですがOpenGLの理論とUEの理論が繋がりました。長かった。

<中心の移動について>

これが納得出来ないんです。

なんで‐0.5を加えると絵の中心が軸になるんでしょう。0.5なら納得するんですが。

以下の実装で色々実験してみます。

f:id:kazuhironagai77:20211025000928p:plain

f:id:kazuhironagai77:20211025000934p:plain

0.5、0.5を追加します。

f:id:kazuhironagai77:20211025000946p:plain

はい。想定した通りです。

回転軸は左上にあるはずですから、これで回転させれば綺麗な回転をするはずです。

因みに‐0.5、‐0.5の場合は

f:id:kazuhironagai77:20211025001001p:plain

こうなります。

0.5、0.5の状態のまま回転させてみます。

Degree = 0

f:id:kazuhironagai77:20211025001016p:plain

Degree = 30

f:id:kazuhironagai77:20211025001029p:plain

え。

何で?

何でずれるの?

‐0.5、‐0.5の状態でテストします。

Degree = 90

f:id:kazuhironagai77:20211025001043p:plain

えー。

こんな回転してるんですか?

これについては1週間時間を置いてまた考えます。

考えるためのヒントとしてDegreeの代わりにTimeノードをつけた場合のScreen shotを残しておきます。

f:id:kazuhironagai77:20211025001110g:plain

4.NPCAIを作成するためのAIの復習の続き

公式のDocumentであるArtificial Intelligence [15]のAI Perceptionを勉強しようとしたら

f:id:kazuhironagai77:20211025001149p:plain

まだNavigation Systemの復習を一個もしてない事に気が付きました。

どうせ全部復習し直すのですから、Navigation Systemもきっちり勉強し直します。

と言う事で今週はNavigation System [16]の復習をします。

Navigation Systemを見たら以下に示した様に沢山のTutorialがありました。

f:id:kazuhironagai77:20211025001205p:plain

Basic Navigation [17]の勉強の前にNavigation System [16]で述べられていた重要そうなキーワードを書き残しておきます。

Navigation System には以下に示した3つのGeneration Modesがあるそうです。

  • Static,
  • Dynamic
  • Dynamic Modifiers Only

Navigation System は更にAgentを避ける為に二つのSystemを提供しているそうです。

  • Reciprocal Velocity Obstacles (RVO),
  • The Detour Crowd Manager

両方とも何の話をしているのか全く分かりませんね。

ここで紹介されているTutorialを勉強して行くうちに理解出来るでしょう。

4.1  Basic Navigation [17]の勉強

何と、このTutorial、Behavior Treeを使用していません。

先週まで、UE_AIは単なるIF節。しかしBehavior Treeを採用したから4つのクラスを使用しない非常に複雑な形になった。と断言して来たので、Behavior Treeを使用しないで作成するAIはとても興味深いです。

<Overview

Agentって何を指しているのかとおもったらAIにコントロールされるNPCの事でした。

簡単にまとめるとNavigation SystemはNPCが(障害物があっても)到達したい場所への行き方を見つける事を可能にします。と言っています。

<Goals

特に重要な事は言っていません。

<Objectives

このTutorialから学べる事がまとめられています。

私にとっては特に重要な事はないです。

<1 - Required Setup

このTutorial用の新しいProjectを作成しています。

勿論、私は前に作成したProjectを使用します。

ただし、新しいLevelだけは作成しました。

f:id:kazuhironagai77:20211025001309p:plain

<2 - Building the Navigation Mesh

Nav Mesh Bound Volumeを使用してNPCが移動出来る領域を作成します。

f:id:kazuhironagai77:20211025001330p:plain

この緑の領域はPを押すと表示されます。(知らなかった。)

以下に示したように緑が切れている箇所の直し方が解説されていました。

f:id:kazuhironagai77:20211025001344p:plain

Recast Nav Mesh – Defaultを選択します。

f:id:kazuhironagai77:20211025001357p:plain

Draw Offsetの値を増やします。

f:id:kazuhironagai77:20211025001410p:plain

私が自作した階段も緑が切れかけています。Draw Offsetの値を50に増やして直るか確認します。

f:id:kazuhironagai77:20211025001423p:plain

50にしました。

f:id:kazuhironagai77:20211025001436p:plain

以下の様になりました。

f:id:kazuhironagai77:20211025001449p:plain

こんな技術がある事すっかり忘れていました。

復習は大切ですね。

<3 - Visualizing the Navigation Mesh

緑の部分がどういうMeshで構成されているかを可視化するそうです。

正直言ってあんまり必要な技術ではない気がします。

以下に示したDraw Poly Edgesにチェックを入れると

f:id:kazuhironagai77:20211025001509p:plain

こんな感じに表示されました。

f:id:kazuhironagai77:20211025001522p:plain

<4 - Creating your First Agent

Third Person CharacterをCopyし以下の実装をしました。

f:id:kazuhironagai77:20211025001542p:plain

うーん。AI Controllerすら作成しないんですね。

ホントにこれで動くのか試したら普通に動きました。

f:id:kazuhironagai77:20211025001556p:plain

Basic Navigation [17]のまとめ>

初心者向けのTutorialですが、それなりに勉強になりました。

Draw Offsetの機能なんですっかり忘れていました。

それよりもこのTutorialが私の興味を引き付けるのは、私が主張している「UEのAIはBehavior Treeを採用したからこんな複雑な形になったしまったが、実際は単なるIF節である。」を強力にSupportする内容です。

Behavior Treeを使用しないで作成したAIで動くNPCはCharacterクラス内で全ての処理を実行しています。

非常に単純な実装で、Randomな場所に移動するという行為を実行しています。

私が作成するUEのAIのTutorialにこのBehavior Treeを使用しないAIは一個は追加したいです。

4.2 Modifying the Navigation Mesh [18]

何これ。中に更に二つに分かれています。

f:id:kazuhironagai77:20211025001620p:plain

あ。あの緑の部分の名前が分かりました。Navigation Meshと言うそうです。

ここではそのNavigation Meshの編集方法について習うそうです。

Modifying the Navigation Mesh Preparation Guide [19]

ここでは次のTutorialで使用するためのLevelを作成するようです。Navigation Meshの編集方法を習うための準備ですね。

f:id:kazuhironagai77:20211025001639p:plain

出来ました。

ここは単に初心者でどうやってLevelの作成をしたらいいのか分からない人向けに次のTutorialで使用するためのLevelの作成方法を教えるだけでした。

ただ、ここでもBehavior Treeを使用しないAIを作成してNPCをボールに向かって動かしています。

その点は面白かったです。

Modifying the Navigation Mesh [20]

<< Overview >>

特になしです。

<< Goals >>と<< Objectives >>

以下の使用方法を勉強します。

  • Navigation Modifier Volumesを使用してNav Meshの編集
  • Navigation Proxy Linksを使用して2つのNav Meshを繋げる
  • Smart Proxy Linksを使用してNPCが2つのエリアをジャンプして移動出来るようにする
  • ActorBPからRun Time中にNavigation Meshを再構成する方法

Navigation Modifier VolumesとNavigation Proxy Linksは一回位は使用した事がありますが、やり方はもう忘れました。Smart Proxy Linksについては全く覚えていません。

<< 1 - Required Setup>>

これはさっきやったところです。

<< 2 - Using Navigation Modifier Volumes>>

Navigation Modifier VolumeをNav Mesh内に配置しました。

f:id:kazuhironagai77:20211025001725p:plain

配置した所の緑が消えましたね。

更にもう一個Navigation Modifier Volumeを追加しました。

f:id:kazuhironagai77:20211025001739p:plain

この時点で本当にNPCがボールを追いかける事が出来るのかかなり疑問です。

それを確認します。

f:id:kazuhironagai77:20211025001753p:plain

階段を登ってボールにつきました。

f:id:kazuhironagai77:20211025001806p:plain

Navigation Modifier Volumeで出来た溝を避けてボールにつきました。

出来ています。

f:id:kazuhironagai77:20211025001827p:plain

これだけ出来ていませんでした。

橋の下を潜ろうとしていますがNPCの方が大きすぎて潜れません。

新しいNavigation Modifier Volumeを追加しました。

f:id:kazuhironagai77:20211025001840p:plain

今度の場所はArea ClassにNavArea_Obstacleをセットしました。

f:id:kazuhironagai77:20211025001853p:plain

Nav Area Obstacleはその場所を通らなければ目的地に到達できない場合のみにその場所を通るようにNPCに指定出来るそうです。

他の選択肢についても解説されていました。

f:id:kazuhironagai77:20211025001908p:plain

ここで気になるのは、NavArea_LowHeightです。

これってさっきの天井が低くて動けない時に、天井の下の部分に配置しておけば、NPCは自動的にこの下の部分は潜れないと判断して別なルートを選択するんでしょうか?

f:id:kazuhironagai77:20211025001923p:plain

これは後で調べる事にします。

後、Area ClassはUE4C++を使用すれが自作出来そうなんですが、Programmer向けのTutorialかなんかでそのやり方も別途説明してもらえると有り難かったです。

最後に全般的な感想ですが、初心者向けというより、作業者向けって感じで、自分で考えて問題を解決する箇所がないです。これがとてもTutorialを続行するのを辛くしています。

<< 3 - Using Navigation Link Proxies>>

以下に示した様にNav Link Proxyで二つのNav Meshを繋げました。

f:id:kazuhironagai77:20211025001941p:plain

Link DirectionをLeft to Rightにセットしました。

f:id:kazuhironagai77:20211025002040p:plain

同じモノを反対側に作成する時にこのNav Link ProxyをAltで複製しました。そしたらWorld Outlinerには表示されるのですがLevel上から認識出来ませんでした。

何でなんでしょう?

今度はJumpさせます。

f:id:kazuhironagai77:20211025002100p:plain

これでJumpしてくれるんでしょうか?

f:id:kazuhironagai77:20211025002128p:plain

はい。Jumpする少し前のScreen shotしか取れませんでしたがJumpしました。

<<<Using a Nav Link Proxy to Allow Your Agent to Jump to Its Goal>>>

今度はSmart Linkの使用方法について勉強します。

パッと読んだんですが良く分かりません。取りあえずやってみます。

Jumpするための場所を作成します。

f:id:kazuhironagai77:20211025002150p:plain

ここであえてJumpと言っているんですから、先程の飛び降りるのとは違うはずです。

つまり飛び降りる時より、一寸だけ高い所とか一寸だけ遠い所にたどり着けるはずです。

f:id:kazuhironagai77:20211025002204p:plain

ので少しだけ高い位置かつ

f:id:kazuhironagai77:20211025002219p:plain

遠い位置に作成しました。

Nav Link Proxy BPから新しいBPを作成します。

f:id:kazuhironagai77:20211025002232p:plain

BPを開いてEvent Receive Link Reachedノードを追加します。

f:id:kazuhironagai77:20211025002244p:plain

このノードの機能は大体想像付きますが、以下のような説明がありました。

f:id:kazuhironagai77:20211025002256p:plain

想像した通りでした。

以下に示した様な実装をしました。Tutorialと全く同じはずです。

f:id:kazuhironagai77:20211025002309p:plain

このBPをLevel内に配置して以下に示したように先程作成した板とつなぎます。

f:id:kazuhironagai77:20211025002322p:plain

Tutorialの次の指示でCopy End Points From Link to Smart Linkボタンを押せとあります。

f:id:kazuhironagai77:20211025002335p:plain

が私のNav Link Proxy BPにはそのボタンがありません。

多分、私のVersionが4.27だからだと思います。

試してみます。

f:id:kazuhironagai77:20211025002347p:plain

Jumpはしましたが届かないで落っこちてしまいました。

仕方ないので高さなどを微調整しました。

f:id:kazuhironagai77:20211025002405p:plain

あんまりJumpはしている感じはありませんが隣の床に飛び乗る事は出来るようになりました。

人数を増やすと見てるだけでも楽しいです。

f:id:kazuhironagai77:20211025002420p:plain

でも問題もあります。

この位置に来ると必ず動かなくなります。

f:id:kazuhironagai77:20211025002432p:plain

他の人もここに捕まるとどんどん詰まってしまいます。

f:id:kazuhironagai77:20211025002453p:plain

何か喧嘩が始まったみたいです。

f:id:kazuhironagai77:20211025002511p:plain

移動中に他のNPCとぶつかると動けなくなるみたいです。

f:id:kazuhironagai77:20211025002526p:plain

途中からまったく動かない一体が誕生しました。

f:id:kazuhironagai77:20211025002538p:plain

何なんでしょうかこいつは。

後、Jumpしないで落ちています。

f:id:kazuhironagai77:20211025002551p:plain

何故かScreen shotの絵はjumpしています。

Navは結構奥が深いですね。

<< 4 - Generating the Navigation Mesh at Runtime>>

ここは軽くやる事にします。

Action Gameを作成するならこの辺は厳しく追及しないといけないかもしれませんが、村人のAIを作るのにあんまり必要な技術とは思えませんから。

Tutorialの通りに設定を変更します。

f:id:kazuhironagai77:20211025002615p:plain

回転する板を追加しました。

f:id:kazuhironagai77:20211025002628p:plain

SimulateをしたらMeshだけ回転してます。

Nav Modifierを追加しました。

f:id:kazuhironagai77:20211025002641p:plain

板の回転に吊られてNav Meshの形状が変化しました。

f:id:kazuhironagai77:20211025002708p:plain

<<<Using the Runtime Generation (Dynamic)>>>

今度は、Dynamicを選択した場合のやり方でしょうか?

Tutorialの通りにBP_Moving Actorを作成しました。

f:id:kazuhironagai77:20211025002727p:plain

f:id:kazuhironagai77:20211025002731p:plain

ボールが動いていますが、Nav Meshは動きません。

f:id:kazuhironagai77:20211025002745p:plain

Project SettingのRuntime GenerationをDynamicに変更します。

f:id:kazuhironagai77:20211025002757p:plain

テストします。

f:id:kazuhironagai77:20211025002812p:plain

微妙ですがNav Meshは変化しています。

こんなにNavの復習に時間がかかるとは思ってなかったです。

と言うか復習じゃないて初めて知る内容も結構ありました。

今週のAIの勉強はこれでお終いです。

5.World CompositionによるMap1の作成(バグの直し)

今週やる事はこれだけです。

f:id:kazuhironagai77:20211025002836p:plain

この変なバグを直す。

5.1 Streaming Distanceの変更

一番簡単にStreaming Distanceをもう少し大きくしてみます。200mに変更しました。

f:id:kazuhironagai77:20211025002855p:plain

当然、変な山は現れません。

f:id:kazuhironagai77:20211025002911p:plain

直ったと言えば直りました。

他の場所もチェックします。

以下の赤丸の部分に同様のバグが見られます。

f:id:kazuhironagai77:20211025002926p:plain

が、あまり目立たない言えなくもないです。

こういう事をして大丈夫なのか分かりませんが、Sub Level1-2だけStreaming Distanceを500mに変更してみました。

f:id:kazuhironagai77:20211025002940p:plain

一瞬だけBugが見えますが、本当に一瞬だけです。

f:id:kazuhironagai77:20211025002954p:plain

山に登ってみましたが、僅かにバグが確認出来ます。

f:id:kazuhironagai77:20211025003007p:plain

UE5ならこのバグは自然と消えるので諦める事にします。

5.2 Alt Key + CursorでLoad されているSub Levelが分かる件

もう止める。と言ったんですが、Alt Key + CursorでLoad されているSub Levelが見れる事が分かりました。

こんな感じです。

f:id:kazuhironagai77:20211025003032p:plain

これ使ったらどのSub LevelがBugをおこしているのか分かります。

Cursorの位置が見えないので大体の場所を赤点で示しています。

f:id:kazuhironagai77:20211025003046p:plain

赤で四角に囲った部分が消えます。

f:id:kazuhironagai77:20211025003100p:plain

この重なっている部分がbugを引き起こしているんじゃないでしょうか?

ここだけ確認してみます。

f:id:kazuhironagai77:20211025003117p:plain

重なっているActorを小さくして移動させました。

テストします。

f:id:kazuhironagai77:20211025003131p:plain

全然、駄目でした。

5.3 Monsterなどの動的なActorの生成をWorld Compositionでする為の検討をする

今週は検討だけします。

現状ではItemやMonsterはLevel BPで動的に生成します。

f:id:kazuhironagai77:20211025003153p:plain

これをそれぞれのSub Levelでやれば良いだけのはずです。

そしてItemやMonsterのSpawn用のDataはGame Instanceで管理しています。

f:id:kazuhironagai77:20211025003207p:plain

f:id:kazuhironagai77:20211025003212p:plain

これもData Tableで管理してGame Instanceで管理するのはSpawnするかどうかだけの方が管理し易いですね。今回は直しませんが次回のGame 制作ではそうします。

これを見ただけでではどのSub Levelに属しているのか不明ですので、ここで示されているLocationに静的にItemやMonsterを配置して位置を確認します。

そして静的なMonsterやItemがUnload やLoadしても大丈夫な事を確認します。

それが終わったら、それぞれのSub Level様にItem Spawn Dataを作成します。

f:id:kazuhironagai77:20211025003243p:plain

BPの変数にはCategoryを指定する場所があるのでMap1を指定します。それで管理出来るはずです。

Sub LevelからMonster やItemをSpawnする実装を作成します。

この実装方法はSpawn Items関数やSpawn Monsters関数を見れば分かります。

f:id:kazuhironagai77:20211025003259p:plain

f:id:kazuhironagai77:20211025003307p:plain

Monsterの配置を知るのと、それぞれのSub Level用のSpawn Monsterのデータを作成するのが大変そうですが、それ以外は簡単そうです。

5.4 戦闘が終わってBattle Field Mapから帰還した時

今、気が付いたんですが、戦闘が終わって、戦闘Mapから帰還した時、World Compositionで作成されるMapはCharacterが生成されてから1秒か2秒経ってから生成されますよね。

そうすると今までの方法だと戦闘が終わって、元のMapに戻ると、Landscapeから落ちて死んでしまう可能性が高いです。

調べるとPlayerの操作するキャラはRPG Game Mode Base BP内で生成されています。

f:id:kazuhironagai77:20211025003327p:plain

最初、このキャラの発生時間を遅らせれば良いと考えましたが、LandscapeはPlayerの操作するキャラの位置を知ってからSub Levelを生成するのでそのやり方だと永遠にLandscapeが発生しない可能性があります。

このキャラが生成して3秒間位重力の影響を受けないで浮いているようにしないといけないかもしれませんね。

<重力を切る方法の検討>

以下の方法で試してみました。

f:id:kazuhironagai77:20211025003347p:plain

かなり3D酔いしますがキャラは空中に浮いていて落ちません。

f:id:kazuhironagai77:20211025003402p:plain

3D酔いする理由がわかりました。キャラを浮いた状態で移動させる事が出来るからです。

f:id:kazuhironagai77:20211025003416p:plain

しかもこの状態で移動すると、一回方向を入れるとずっとその方向に進みます。

これが気持ち悪さを引き起こしているです。

この問題はひとまず置いておいてEを押すとキャラの重力が戻る仕組みを実装します。

f:id:kazuhironagai77:20211025003430p:plain

試してみます。

f:id:kazuhironagai77:20211025003443p:plain

出来ていました。

今度はCustom Eventを追加して1.5秒後に地面に落下する様にしました。

f:id:kazuhironagai77:20211025003458p:plain

こんな感じです。

f:id:kazuhironagai77:20211025003510g:plain

あんまりスムーズに撮影出来ませんでした。

これも来週試します。

6.UE5におけるWorld Partitionの勉強の続き

今週はもう時間がなくなってしまったので、一個だけ確認します。それはLoading Rangeの確認です。Loading Range外のLandscapeはUnloadされているのかが知りたいです。

以下の条件でテストします。

f:id:kazuhironagai77:20211025003538p:plain

Playを押した後にwp.Runtime.ToggleDrawRuntimeHash2Dをcmdから入力しました。

f:id:kazuhironagai77:20211025003555p:plain

この白い円がLoading Rangeを示しているんでしょうか?

良く分かりませんね。

Loading Rangeを100mに変更しました。

f:id:kazuhironagai77:20211025003610p:plain

一マスが32mだとすると6マスと1/5マス位でしょうか。

32*6=92と1/5マス=6.4 なので98.4、まあ100mですね。

f:id:kazuhironagai77:20211025003642p:plain

Landscapeの端に来ました。

f:id:kazuhironagai77:20211025003659p:plain

黄色の線がLandscapeを表していると思ったんですが違いそうですね。円の中にある白い線がキャラが向いている方向を示してると思っていたんですが。この線は黒線のタイルに平行ですね。

このテストに使用しているLevelのLandscapeが2個重なっていました。

新しく作り直してもう一回テストします。

今、端っこにいます。

f:id:kazuhironagai77:20211025003722p:plain

中央に戻ります。

白い円の端が黒い線のマスの端と重なっています。

f:id:kazuhironagai77:20211025003746p:plain

最初に立っていた位置が、白い円の端になりました。

f:id:kazuhironagai77:20211025003804p:plain

山が消えました。

f:id:kazuhironagai77:20211025003825p:plain

4マスと半分位です。4.5*32=144mです。

円から外れたら消える訳ではないですね。

f:id:kazuhironagai77:20211025003847p:plain

今度は確認の為にActorを配置してみます。

f:id:kazuhironagai77:20211025003903p:plain

Actorが配置されているCellはまだ円の中にあります。

そしてActorも見えます。

f:id:kazuhironagai77:20211025003924p:plain

Actorは円の外に出ました。

Actorが配置されているCellはまだ円の中にあります。

Actorは表示されています。

f:id:kazuhironagai77:20211025003943p:plain

Actorが配置されているCellが円の外に出ました。

Actorは消えました。

これを見るとやっぱりWorld Partitionで設定出来るのは配置されているActorだけでLandscapeには何か別の基準が適応されているみたいです。

今週は時間がもうないのでまた来週、勉強する事にします。

7.まとめと感想

今週は、腰が痛くなってしまってあんまり集中出来なかったです。

結構、腰痛って集中力を削ぎますね。

まあ、こういう時のあると納得するしかないですね。結局、コツコツやってる方が最終的にはデカイ成果を出せる場合が多いですし。駄目な時は駄目なりに課題をこなしていくだけですね。

<参照(Reference)>

[1] Takeshi, A. (n.d.). What’s the difference between inner product, dot product and scalar product? Quora. Retrieved October 24, 2021, from https://www.quora.com/Whats-the-difference-between-inner-product-dot-product-and-scalar-product

[2] PDF file cannot be cited. It’s from http://ursula.chem.yale.edu/~batista/classes/vvv/v570.pdf

[3] Kzooma K. (2021, September 16). ドット積と内積の違い. note(ノート). Retrieved October 24, 2021, from https://note.com/kzooma/n/n65c4eff99610

[4] The NumPy community. (n.d.). numpy.dot — NumPy v1.21 Manual. NumPy. Retrieved October 24, 2021, from https://numpy.org/doc/stable/reference/generated/numpy.dot.html

[5] Epic Games [Unreal Engine]. (2020, May 27). Building advanced effects in Niagara | Unreal Engine [Video]. YouTube. https://www.youtube.com/watch?v=syVSRDQxrZU

[6] CGHOW. (2021, September 20). Disintegration in UE5 Niagara Tutorial | Download Files [Video]. YouTube. https://www.youtube.com/watch?v=4dYg4bvf4Rc

[7] UnrealCG. (2021, October 14). Time Distortion Effect - UE4 Tutorial [Video]. YouTube. https://www.youtube.com/watch?v=3ejuQVasl7w

[8] Cloward, B. [Ben Cloward]. (2019, December 12). Distortion Shader - UE4 Materials 101 - Episode 4 [Video]. YouTube. https://www.youtube.com/watch?v=gwx2NOZJ5CE

[9] LearnOpenGL - Coordinate Systems. (n.d.). LearnOpenGL. Retrieved October 24, 2021, from https://learnopengl.com/Getting-started/Coordinate-Systems

[10] Cloward, B. (2021, September 2). Detail Normal Mapping - Shader Graph Basics - Episode 13. YouTube. Retrieved October 24, 2021, from https://www.youtube.com/watch?v=SvtTx5jDjuQ&list=PL78XDi0TS4lEBWa2Hpzg2SRC5njCcKydl&index=13

[11] Epic Games. (n.d.-f). Vector Operation Expressions. Unreal Engine Documentation. Retrieved October 24, 2021, from https://docs.unrealengine.com/4.27/en-US/RenderingAndGraphics/Materials/ExpressionReference/VectorOps/#derivenormalz

[12] gameDev Outpost. (2020, May 4). UE4 - Materials and UV Rotation [Video]. YouTube. https://www.youtube.com/watch?v=4ITTsrm-MDo

[13] Vries, J. (n.d.). LearnOpenGL - Transformations. LearnOpenGL. Retrieved October 24, 2021, from https://learnopengl.com/Getting-started/Transformations

[14] Microsoft. (2015, July 1). DirectX Factor - 3D Transforms on 2D Bitmaps. Microsoft Docs. Retrieved October 24, 2021, from https://docs.microsoft.com/en-us/archive/msdn-magazine/2014/april/directx-factor-3d-transforms-on-2d-bitmaps

[15] Epic Games. (n.d.-a). Artificial Intelligence. Unreal Engine Documentation. Retrieved October 24, 2021, from https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/ArtificialIntelligence/

[16] Epic Games. (n.d.-e). Navigation System. Unreal Engine Documentation. Retrieved October 24, 2021, from https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/ArtificialIntelligence/NavigationSystem/

[17] Epic Games. (n.d.-b). Basic Navigation. Unreal Engine Documentation. Retrieved October 24, 2021, from https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/ArtificialIntelligence/NavigationSystem/BasicNavigation/

[18] Epic Games. (n.d.-c). Modifying the Navigation Mesh. Unreal Engine Documentation. Retrieved October 24, 2021, from https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/ArtificialIntelligence/NavigationSystem/ModifyingTheNavigationMesh/

[19] Epic Games. (n.d.-d). Modifying the Navigation Mesh Preparation Guide. Unreal Engine Documentation. Retrieved October 24, 2021, from https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/ArtificialIntelligence/NavigationSystem/ModifyingTheNavigationMesh/ModifyingtheNavigationSystemPreparationGuide/

[20] Epic Games. (n.d.-d). Modifying the Navigation Mesh. Unreal Engine Documentation. Retrieved October 24, 2021, from https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/ArtificialIntelligence/NavigationSystem/ModifyingTheNavigationMesh/ModifyingtheNavigationSystem/

「Unreal Engine 4.xを使用してRPGを作成する」の足りない部分を作成する 村人用のAIの開発3

f:id:kazuhironagai77:20211017214548p:plain

<前文>

前文には、日本人が誤解しているアメリカ、特に日本文化とキリスト教文化の違いから生じる誤解とその解決法について気が付く範囲ですが書いていきます。

これからのInternet社会において、多くの日本人は、望む、望まずに限らず生のアメリカ人との関係が最も重要になって来ます。

そして、私のこの前文には、どうやってアメリカ人と良好な関係を築けるのかのヒントが隠されていて、私が指摘している点を気を付けるだけでも、最悪の事態を避ける事は可能です。

ところで最近気が付いたんですが、日本のネットの意見って一般の日本人の意見と大分違うと言う事です。例えばネット上だとBLM運動の参加者に対して日本人全体が激しく差別的な発言を繰り返しているように見えましたが、実際の日本人の大多数はBLM運動の参加者に対して大変好意的だった事です。

ほとんどの日本人はネットの意見なんて信じていなかったんですね。

安心しました。

一応念のために言っておきますが、日本のネットの意見をそのままアメリカ人に伝えるとアメリカ人は見た事無い位、激怒しますよ。

激怒するだけじゃなくて場合によっては社会的、もしくは法的な罰を与えられます。会社の上司だったり、学校の先生だったりした場合、解雇されたり退学にさせられたりします。その激怒したアメリカ人が政府関係者だったらアメリカに入国禁止にされるかもしれません。その位の内容が日本のネットには書かれています。

この辺の話題こそ、私が前文に書いていくべき内容だったのかもしれません。

ネットの意見の中でも、誰が主張しているのか不明な意見には特に注意して下さい。あなたの意見になってしまうからです。政治家の○○さんの意見によれば、と言っておけばある程度は怒りの矛先をかわす事が出来るかもしれません。しかしあなたの意見であるとなったら解雇されたり、退学にされても文句も言えなくなります。

この前もニュースでやっていましたが、ネットで人種差別的な発言をしていたアメリカ人の高校生のHarvard大学の入学が取り消しになりました。アメリカでは発言の自由が保障されている代わりに発言の責任は自分で取る必要があります。彼は未成年であるにも関わらず、発言の責任を取らされた訳です。

ではどうすれば良いのかと言うと普段から英語のニュースを聞いておく事です。

そうする事でアメリカ人と会話する時の安全な話題と超えてはいけないLineが自然と身に付きます。

それでは今週の勉強を始めます。

<本文>

1.今週の予定

今週も先週の続きをやっていきます。

先週は最後の部分は時間が足りずにほとんど出来ませんでした。後、最近は勉強する方が主になってGameの作成の方はかなり少なくなってしまっています。

  • Niagara : 先週の続き
  • Material : Ben Cloward氏のTutorialを勉強する
  • NPCAIを作成するためのAIの復習の続き
  • World CompositionによるMap1の作成
  • UE5におけるWorld Partitionの勉強
  • Loading Screenの勉強の続き(Moduleについて)

この中で今のRPGの製作に全く関係のない純粋な勉強は、NiagaraとWorld Partitionです。今のGameは4.24で制作しているのでNiagaraは標準では使用出来ませんし、する気もありません。World Partitionに関してはUE5の機能なのでハナから使用するのは無理です。

でもNiagaraの勉強だけは止める気はありません。

何といっても3D Graphicsと直結している分野なのである程度理解したら私の3D Graphicsの専門知識がそのまま活用できる可能性が高いからです。

Materialの勉強も同じです。更にBen Cloward氏のTutorialで勉強する事でぐぐっとMaterialに対する理解が深まっています。これも止めるのは論外です。

World Partitionの勉強はあくまでもWorld Compositionをどの位勉強すべきかの査定をするためにやっている事なので今週で終りに出来ます。

World CompositionとNPCのAIの勉強はGameの作成に直結してるので中止する事は勿論出来ません。

となるとLoading Screenの勉強が一番弱いですね。Moduleの作成方法などの勉強は面白いですが、あまり適切なTutorialが存在しない事。Loading Screenそのものの作成は終わっている事の点から考えて中止すべきはこれでしょうね。

2.Niagara : 先週の続き

2.1  Disintegration in UE5 Niagara Tutorial | Download Files [1] の続き

先週途中まで勉強したCGHOW氏のDisintegration in UE5 Niagara Tutorial | Download Files [1] の続きをやっていきます。

f:id:kazuhironagai77:20211017214719p:plain

ParticleがEdgeの部分からのみ発生するようにします。

M_ParticleBodyの実装を以下に示した様に変更します。

f:id:kazuhironagai77:20211017214737p:plain

以下の様になりました。

f:id:kazuhironagai77:20211017214752p:plain

この方法だと発生したParticleが発生した位置から移動しないそうです。

その解決策として以下の事をしました。

まず、Niagara SystemのScratch Module内にあるDynamic Material Parameterを消します。

f:id:kazuhironagai77:20211017214811p:plain

すると以下の様にParticleの発生が変わります。

f:id:kazuhironagai77:20211017214826p:plain

更にParticleの発生用のMaterialの実装を以下のようにします。

f:id:kazuhironagai77:20211017214839p:plain

当然ですが全身からParticleが発生するようになりました。

f:id:kazuhironagai77:20211017214854p:plain

Curl Noiseを切るとこんな感じです。

f:id:kazuhironagai77:20211017214910p:plain

そしてParticle Update SectionでKill Particles In Volumeを使用します。

f:id:kazuhironagai77:20211017214924p:plain

f:id:kazuhironagai77:20211017214930p:plain

すると以下の様になります。

f:id:kazuhironagai77:20211017214949p:plain

更にもう一個同じModuleを以下の条件で追加すると

f:id:kazuhironagai77:20211017215003p:plain

f:id:kazuhironagai77:20211017215009p:plain

両方の条件を満たした箇所だけParticleが発生する事になります。

こんな感じになりました。

f:id:kazuhironagai77:20211017215024p:plain

おお、ParticleをEdgeだけから発生する事が出来ました。

しかしこの方法にも問題がありました。Curl Noiseを追加してもParticleが球のEdgeの範囲内でしか移動しません。

f:id:kazuhironagai77:20211017215040p:plain

その理由はKill Particle in Volume Module内でParticle Positionを使用しているからだそうです。

f:id:kazuhironagai77:20211017215055p:plain

うーん。何で?正直分からないと思ったら、次のノードを見たら分かりました。

f:id:kazuhironagai77:20211017215110p:plain

もしParticleのPositionが球の範囲から出た場合は消してしまうんです。成程分かりました。

これにそっくりなScratch Moduleを作成してこのPositionをInitial Position に変更します。

コピーしている間に新しいTechniqueを一個学びました。

以下に示した様に沢山のノードに繋がったPinはCtrl+マウスの左クリックで一辺に移動出来ます。

f:id:kazuhironagai77:20211017215124p:plain

f:id:kazuhironagai77:20211017215130p:plain

これをKill Particle in Volume Moduleの代わりに使用します。

f:id:kazuhironagai77:20211017215144p:plain

同じ結果が得られました。

f:id:kazuhironagai77:20211017215159p:plain

Particle Positionの部分をInput InPositionに変更しました。

f:id:kazuhironagai77:20211017215215p:plain

あれ?ここにInitial Positionを追加するんじゃなかったんでしょうか?

その後でInitial Positionを追加しました。

f:id:kazuhironagai77:20211017215229p:plain

うーん。いきなり入れたら駄目なんでしょうか?

この辺も後で検討します。

結果はこんな感じです。

f:id:kazuhironagai77:20211017215245p:plain

ここから最後の仕上げに入ります。

球のActorを用意してその球の動きに合わせてイスが消えてParticleが現れるようにします。

一回軽くTutorialを見たのですが、何でそうやるのか正直、意味不明な部分が有りました。

今は、Tutorial通りに再現出来る事に勤めて、後で何故そうやったら出来るのかは検討します。

Kill Particle in Volume Moduleの代わりに新しく作成したModuleのOrigin OffsetにRead from new User parameterを選択します。

f:id:kazuhironagai77:20211017215618p:plain

f:id:kazuhironagai77:20211017215624p:plain

初めてName SpaceがUserのParameterを作成しました。後Make Read from User Parameterも始めて使用します。

この辺についても後で調べます。

System SettingsのUser Parameter Moduleを選択すると

f:id:kazuhironagai77:20211017215641p:plain

Origin Offsetの変数が出来ていました。

f:id:kazuhironagai77:20211017215657p:plain

はあ。これがUserなんですね。

こっちにもOrigin Offsetが出来ていました。

f:id:kazuhironagai77:20211017215712p:plain

そう言う事ですか。成程。

今度はこのLevelのBPを開きます。

f:id:kazuhironagai77:20211017215727p:plain

何気にUE5のBPを使用するのは初めてです。

以下の様な実装をしました。

f:id:kazuhironagai77:20211017215742p:plain

更にLevel上に球を追加してその球の位置をSet Niagara Variable (vector3)のIn Valueに追加します。

f:id:kazuhironagai77:20211017215756p:plain

以下に示した様に追加しました。

f:id:kazuhironagai77:20211017215811p:plain

Playにして試したらParticleの発生の仕方がTutorialとちょっと違います。

f:id:kazuhironagai77:20211017215828p:plain

そうです。境界上に現れていません。

色々調べましたら良く分かりません。球の境界が良く分からないのでひょっとすると合っているのかもしれません。

後で又検討します。

先週作成したMaterial Parameter Collection であるMPCにVector Parameterを追加します。Parameter NameはLocationです。

f:id:kazuhironagai77:20211017215842p:plain

イスのMaterialに先程作成したMaterial Parameter Collection であるMPC 内のLocationを今まで使用していたLocationと交換します。

f:id:kazuhironagai77:20211017215857p:plain

そしてLevelのBPで以下の実装を追加します。

f:id:kazuhironagai77:20211017215911p:plain

やっぱりParticleの何かがずれていますね。

f:id:kazuhironagai77:20211017215926p:plain

調べたらParticle Update SectionのKill Particle in Volume Moduleの代わりに新しく作成したScratch ModuleのInPositionが外れていました。

f:id:kazuhironagai77:20211017215940p:plain

f:id:kazuhironagai77:20211017215946p:plain

これで試します。

f:id:kazuhironagai77:20211017220006p:plain

f:id:kazuhironagai77:20211017220015p:plain

f:id:kazuhironagai77:20211017220024p:plain

出来ていますね。

2.2  Disintegration in UE5 Niagara Tutorial | Download Files [1] で使用したModuleなどの調査

Disintegration in UE5 Niagara Tutorial | Download Files [1] で初めて使用したModuleなどの機能を調べます。

<Sample Static Mesh Module

この二つのModuleは椅子の形にParticleを発生させるのに使用しましたが結局は、Scratch Moduleで一から作成したModuleと交換しました。

f:id:kazuhironagai77:20211017220525p:plain

今回は試しに別なMeshを使用してみました。

f:id:kazuhironagai77:20211017220540p:plain

f:id:kazuhironagai77:20211017220546p:plain

解説を探したのですが公式のDocumentであるParticle Spawn Group [2] にちょっとだけ解説があっただけした。

f:id:kazuhironagai77:20211017220602p:plain

うーん。これだけじゃ何とも言えないです。

Static Mesh Location Moduleの変数であるSample Mesh NormalとSample Mesh Position にSample Static Mesh Moduleの変数であるMesh NormalとMesh Positionが使用されています。

f:id:kazuhironagai77:20211017220618p:plain

これが上記の言っているThose Sampled Valuesの事を指しているんでしょうか?

この二つの変数の値は、Sample Static Mesh ModuleのScriptを開いて見ると

f:id:kazuhironagai77:20211017220634p:plain

f:id:kazuhironagai77:20211017220639p:plain

何回も見たRandomに選んだMeshのPositionやNormalを示すノードです。

これさえパスすればStatic Mesh Location ModuleはMeshの形にParticleを生成するんでしょうか?

Scratch Pad Moduleで試してみます。

以下の実装を作成しました。

f:id:kazuhironagai77:20211017220654p:plain

このoutputしている変数、myPositionとmyNormalをStatic Mesh Location Moduleの変数であるSample Mesh NormalとSampled Mesh Positionにセットします。

f:id:kazuhironagai77:20211017220721p:plain

警告は表示されたままですが、以下に示した様にParticleを指定したMeshの形に生成する事が出来ました。

f:id:kazuhironagai77:20211017220739p:plain

大体何をやっているのか分かりましたね。

2021-09-06のBlogで以下の事を述べています。

f:id:kazuhironagai77:20211017220758p:plain

これは、Particle Spawn Group [2]をみると実際は以下の様になっています。

f:id:kazuhironagai77:20211017220816p:plain

それぞれのModuleのScriptを見てどう違っているのかを確認してみます。

<<Initialize Mesh Reproduction Sprite Module>>

Skeletal MeshのRandom Coordinateの値を変数であるMesh Tri Coordinateにセットしています。

f:id:kazuhironagai77:20211017220838p:plain

その値を元にしてSkeletal MeshのPositionを求めそれをOUTPUTかつModuleであるPositionにセットしています。

f:id:kazuhironagai77:20211017220852p:plain

OUTPUTもMODULEもどんなName Spaceなのかちょっと分からないですね。

最後にParticleであるPositionに値をセットしています。

f:id:kazuhironagai77:20211017220907p:plain

Initialize Mesh Reproduction Sprite ModuleではいきなりPositionに値をセットしてしまうんですね。

Normalの方はSprite Facingにその値をセットされていました。

f:id:kazuhironagai77:20211017220941p:plain

<<Sample Skeletal Mesh Skeleton>>

このModuleはUE5のNiagaraでは見つからなかったです。

f:id:kazuhironagai77:20211017221001p:plain

<<Sample Skeletal Mesh Surface>>

これも無かったです。

<<Sample Static Mesh>>

これはさっきやった奴です。

<<Update Mesh Reproduction Sprite Module

これは、Building advanced effects in Niagara | Unreal Engine [3]で使用したModuleでInitialize Mesh Reproduction Sprite ModuleとPairで使用します。

2021-09-12のBlogでちょっとだけ勉強しました。

<<ParticleをMeshに沿って発生させるModuleのまとめ>>

この結果だけみるとSkeletal Meshの場合は、Initialize Mesh Reproduction Sprite Moduleを使用し、Static Meshの場合はSample Static Meshを使用すると考えて良さそうです。

更に、Initialize Mesh Reproduction Sprite ModuleはUpdate Mesh Reproduction Sprite ModuleとPairで使用しSample Static Mesh ModuleはStatic Mesh Location ModuleとPairで使用します。

因みにContent ExamplesのこのSampleは

f:id:kazuhironagai77:20211017221051p:plain

Initialize Mesh Reproduction Sprite Moduleを使用していました。

f:id:kazuhironagai77:20211017221110p:plain

<Static Mesh Location

f:id:kazuhironagai77:20211017221131p:plain

もう大体、このModuleが何をやっているのか分かりますね。Sample Static Mesh ModuleでOutputされたPositionの値をParticle Positionにセットしている訳です。

Scriptを見るとNormalの方はOffsetを計算する時に使用しているようです。

これだけ分かれば十分です。

<Materialについて>

Disintegration in UE5 Niagara Tutorial | Download Files [1]ではStatic Mesh用のMaterialとParticle用のMaterialの2種類が使用されています。

<<Static Mesh用のMaterial>>

ここで大切な事はどうやってMeshの一部をMaterialを使用して消しているのかと言う事でMaterial全体の内容はあんまり重要ではありません。

そのMeshを消すためのPinがOpacity Maskです。

f:id:kazuhironagai77:20211017221640p:plain

このPinへの接続方法を理解しながら今回の実装について観察していきます。

f:id:kazuhironagai77:20211017221709p:plain

これだけです。

他のノードもありますが結局はSphere Maskノードが全部やっています。

Building advanced effects in Niagara | Unreal Engine [3]ではDitherTemoralAAノードを使用していました。

f:id:kazuhironagai77:20211017221729p:plain

こういうある意味特殊なノードがOpacity Mask専用であるのかもしれませんね。

このMaterialの勉強はこれで終わりでも良いんですが、先週

f:id:kazuhironagai77:20211017221758p:plain

と書き残していたので、3Color Blendノードについて調べます。

公式のDocumentであるImage Adjustment [4]に以下の説明がありました。

f:id:kazuhironagai77:20211017221816p:plain

いやいや、2つをGray Scaleで表すなら意味が分かりますが、3つの色をどうやってGray Scaleから割り振るの?

そしたら

f:id:kazuhironagai77:20211017221831p:plain

こうやって割り振るそうです。

試してみます。

f:id:kazuhironagai77:20211017221846p:plain

こんな結果になりました。

f:id:kazuhironagai77:20211017221900p:plain

説明の通りですね。でも緑の幅が大き過ぎる気がします。この割合は変化出来ないんでしょうか?

まあいいです。これだけ分かれば十分です。

ここからは今週やった内容の調査になります。本当は一週間熟成させてから調べた方が良いのかもしれませんが、量が少ないのでやってしまいます。

Niagara SystemのScratch Module内にあるDynamic Material Parameter

この変数の役割を調べようと思ったんですが、今の段階だと全て消してしまっています。ので調べようが無くなってしまいました。今回はPassします。

<Kill Particles In Volume

Particle Update SectionでKill Particles In Volumeを使用しています。

f:id:kazuhironagai77:20211017221923p:plain

このModuleについて調べます。

公式のDocumentであるParticle Update Group [5] には

f:id:kazuhironagai77:20211017221939p:plain

と解説されていました。

f:id:kazuhironagai77:20211017221953p:plain

Cursorを乗せた時と同じ解説でした。

この解説で言っている内容ではInterpolated Spawn が何を指しているのか分かりません。

それよりもGoogleでKill Particles In Volume UE4 Niagaraで検索しても

f:id:kazuhironagai77:20211017222009p:plain

f:id:kazuhironagai77:20211017222016p:plain

f:id:kazuhironagai77:20211017222023p:plain

公式のDocumentが表示されないんですけど。

関係ないKill Moduleの公式のDocumentは表示されていますが?

試しにBingで検索してみたら

f:id:kazuhironagai77:20211017222038p:plain

f:id:kazuhironagai77:20211017222044p:plain

f:id:kazuhironagai77:20211017222051p:plain

かなり下の方ですが一応 Particle Update Groupは検索に引っかかっています。

この場合はParticle Update Groupで検索するのが筋なのかもしれませんが、昔の方が検索の精度が良かった気がします。

<<Interpolated Spawning>>

Interpolated SpawningについてはEmitter Setting SectionのEmitter Properties Moduleにありました。

f:id:kazuhironagai77:20211017222112p:plain

f:id:kazuhironagai77:20211017222117p:plain

こんな説明がされていました。

f:id:kazuhironagai77:20211017222131p:plain

要するにこれを使用した方がスムーズなParticleの生成が出来るけどその分コストもかかります。と言う事ですね。

現状、Kill Particles in Volume Moduleを使用して以下の様な状態になっています。

f:id:kazuhironagai77:20211017222147p:plain

Interpolated Spawningのチェックを外します。

f:id:kazuhironagai77:20211017222349g:plain

おお、本来発生してはいけない場所からもParticleが生成されています。

解説の通りですね。

<Initial Position変数をMap Getノードにいきなり追加出来ないのか?>

f:id:kazuhironagai77:20211017222426p:plain

理由が分かりました。

以下に示した様にInitial PositionはMap Getノードからも

f:id:kazuhironagai77:20211017222440p:plain

Parameterからも選択出来ないです。

f:id:kazuhironagai77:20211017222453p:plain

だから先週、Transientを選んだ時と同じようなやり方をしてInitial Position変数をここにセットしたんでした。

はい。納得しました。

<BPを使用して球のActorの動きに合わせてParticleの発生を変化させる>

f:id:kazuhironagai77:20211017222530p:plain

これ、実際にやってみたら分からない所は無かったはずです。

しかしBPからNiagaraを操作する方法を覚えておくのは大切なのでキッチリ復習します。

まず全体像を以下に示します。

BP側です。

f:id:kazuhironagai77:20211017222551p:plain

Set Niagara Variableノードが使用されています。

このノードがNiagaraとBPを繋ぐ事を可能にしています。

Niagara側です。

f:id:kazuhironagai77:20211017222604p:plain

f:id:kazuhironagai77:20211017222610p:plain

敢えてUser ParameterをSystem Setting Sectionに作成しています。

このUser ParameterのみがBPからAccess出来る変数なのかは分かりません。その辺から調べます。

f:id:kazuhironagai77:20211017222624p:plain

これを読むとその通りみたいですね。

gameDev Outpost 氏のTutorialにそのものずばりUE4 - Niagara Blueprints and User Parameters [6] がありました。

これ見たら、やり方全部説明していますね。

後、User ParameterのみがBPからAccess出来る変数かどうかは分かなかったですが、Niagara からBPとやり取りする時はUser Parameterを通してするのが普通のようです。

以上です。

3.Material : Ben Cloward氏のTutorialを勉強する

3.1 Min, Max, Clamp, & Saturate - Shader Graph Basics - Episode 11 [7]を勉強する

取りあえず軽く全部見ました。今回はUnityを主に解説していました。UEは最後に復習のためのちょろっとやっただけです。

f:id:kazuhironagai77:20211017222652p:plain

流石にこれらのノードの使用方法は理解しています。と思ったらMinimumとMaximumの機能を反対に理解していました。

後、知らなかった事にSaturateと0と1をセットしたClampの違いがあります。Saturateを使用した場合はCostがFreeになりますが、Clampの場合は違うそうです。

実際にUE5を使用して試してみます。

MinとMaxをテストします。

f:id:kazuhironagai77:20211017222711p:plain

Maxが黒を灰色に変化させているのは良く分かりますが、Minが白を灰色に変化させているのはあんまり良く分からないですね。

実際にスポイトで色を調べたら230になっていました。

f:id:kazuhironagai77:20211017222725p:plain

255*0.8=204なのでLinearではないですが、Minが白の上限を設定しているのも確認出来ました。

次はSaturateの有り無しについてです。

無しの場合です。

f:id:kazuhironagai77:20211017222738p:plain

f:id:kazuhironagai77:20211017222744p:plain

有りの場合です。

f:id:kazuhironagai77:20211017222757p:plain

f:id:kazuhironagai77:20211017222803p:plain

うーん。正直分からん。

色をTutorialと同じにしてみます。

Saturate無しです。

f:id:kazuhironagai77:20211017222818p:plain

Saturate有りです。

f:id:kazuhironagai77:20211017222832p:plain

こっちの方が黄色味が薄いですね。

Unlitにしてみました。

Saturate無しです。

f:id:kazuhironagai77:20211017222845p:plain

Saturate有です。

f:id:kazuhironagai77:20211017222859p:plain

良く分かりません。

まあ理論的には-1の値をそのままLerpでPassすると変な色になってしまう時もある。と覚えておきます。

3.2 Blending Normal Maps - Shader Graph Basics - Episode 12 [8] を勉強する

最初にサラッと全部を見ました。このTutorialの内容を簡単にまとめます。

Normal MapについてとNormal Mapの混ぜ方についてです。Normal MapはTextureのVectorを保持しています。ので混合する時は色を混ぜるのと違って注意する点があります。更に混合方法を4つ紹介しています。四つの混ぜ方は、Simple、UDN、Whiteout、そしてRNMです。この講義ではそれぞれのCostについても説明しています。UnityのNormal Blendノードは設定によってWhiteout方式かRNM方式のBlendをします。UEのBlend Angle Corrected NormalノードはRNMと同じ役割をします。

それでは自分でもやってみます。

まずUnityとUnrealのNormal Mapの違いについてです。

f:id:kazuhironagai77:20211017222919p:plain

Greenの値がお互いにInverseになっているそうです。

確認しようとしてUE5のTextureを開いたらBが外せません。

f:id:kazuhironagai77:20211017222933p:plain

UE4でNormal mapを開いて見ました。

f:id:kazuhironagai77:20211017222947p:plain

これだけ見ても差は分かりませんね。

TextureのDetailsに以下の項目がありました。

f:id:kazuhironagai77:20211017223004p:plain

Unity用に作成されたTextureをUnrealで使用する際にはこの項目にCheckを入れるんですかね。

UE5でもこの項目はありました。

f:id:kazuhironagai77:20211017223018p:plain

こっちのサンプルにはチェックがついていないので最初からUnreal用に作成されたNormal Mapと思われます。

完全にTutorialと同じには出来ないですが以下の条件で

f:id:kazuhironagai77:20211017223031p:plain

こんなのを作成しました。

f:id:kazuhironagai77:20211017223045p:plain

これを使用してTutorialと同じようにBlendingしていきます。

Tutorialが言う所のSimple Blendingを作成しました。

f:id:kazuhironagai77:20211017223100p:plain

こんな結果になりました。

f:id:kazuhironagai77:20211017223113p:plain

何で青が1なのかというかNormal Mapが一般的に言って青いのかが分からないとこの計算の意味が分からないです。

青はTextureの面に対しての垂直方向の軸を表しているんです。

 Normal Mapにいくら凹凸があると言っても大体は平らなはずです。だから青いんです。

ただ、Textureの軸がどうなっているのか良く分かりません。

先週、勉強したTangent SpaceだとX軸が面に対して垂直に出ています。

f:id:kazuhironagai77:20211017223126p:plain

正し、その図とMaterialのPreviewを見るとY軸の向きが逆です。

f:id:kazuhironagai77:20211017223140p:plain

これらを見ると面に対して垂直に出ている軸はx軸で赤になります。がそしたらNormal Mapも赤くなる必要があります。のでWorld Spaceでいう所のXYZで言うとR = X、G = Y、B = Zとなっているはずです。

上記のMaterialのCoordinateだとZ = R, Y =G, X = Bになると考えられますが、ちょっとUV軸をZY軸に置き換えるのはあんまり聞いた事がないですので、保留しておきます。

兎に角、大体Normal Vectorは面に対して垂直なんだから青には1を入れとけば大体合っているわけです。

それがこのBlendingの本質です。

UDN方式のBlendingです。

f:id:kazuhironagai77:20211017223156p:plain

UDN方式のBlendingは前のSimple 方式のBlendingだと岩のゴツゴツ感が無くなってしまう。と言う人向けに1の代わりの規定のNormal MapのBの値を使用します。

f:id:kazuhironagai77:20211017223210p:plain

以下にSimple 方式でBlendした時のPreviewを示しておきます。

f:id:kazuhironagai77:20211017223224p:plain

UDN方式のBlendingの方がゴツゴツしていますね。

UDN方式のBlendingは最後にNormalization(正規化)をしています。これは逆に何でSimple 方式のBlendingではNormalizationをしていないのかが不思議です。

Whiteout方式のBlendingです。

f:id:kazuhironagai77:20211017223245p:plain

いやいや、それだったら規定のゴツゴツした岩だけじゃなくて小さい粒々だって考慮しますよ。

と言うのがこれです。

f:id:kazuhironagai77:20211017223259p:plain

以下に比較のためのUDN方式でBlendingした時のPreviewを置いておきます。

f:id:kazuhironagai77:20211017223311p:plain

確かに粒々もはっきりしています。

RNM方式によるBlendingについてです。

f:id:kazuhironagai77:20211017223326p:plain

Tutorialのまま、Copyしました。

Tutorialによると何でこういう計算をするのかについてはここでは説明しないので以下にLinkを貼っておくとありました。

多分、これ(Blending in Detail)と思いますが、ぱっと見た感じではRNMの説明は無いように見えました。

正確な計算や計算の理論はOpenGLなどの教科書を見れば載っているでしょう。ここは3D graphicsとUEのMaterialの理論が一致しているのが大切です。

今週も、もう一個Tutorialをやる時間は無くなってしまいました。ここでMaterialの勉強は終わりにします。

4.NPCAIを作成するためのAIの復習の続き

先週、終わらなかったDebug機能を使用したDecorator ノードのObserver Abortの機能の解説を行います。

4.1 Observer Abortの機能の解説のDebug

<None

Decorator ノードのObserver AbortがNoneにセットされている場合の変化をみます。

f:id:kazuhironagai77:20211017223357p:plain

Observer AbortがNoneにセットされているDecorator ノードであるBlackboard Based Conditionの条件が満たされているためPrint String1が実行されます。

f:id:kazuhironagai77:20211017223413p:plain

Print String1が実行されるとSuccessを返します。返された親ノードはSequenceであるから、Failが返ってくるまで子ノードを左から右へ実行します。

f:id:kazuhironagai77:20211017223428p:plain

のでPrint String1を実行します。

f:id:kazuhironagai77:20211017223443p:plain

Print String1の実行が終わるとSuccessを親クラスであるSequenceノードに返します。するとSequenceは全部の子ノードがSuccessを返したのでSuccessをその親ノードであるSelectorに返します。Successを一個でも返されたSelectorは子ノードの実行を中止してその親ノードであるRootへ返します。

これを何度も繰り返すだけですが、ある時Print String1を実行中にDecoratorの条件が変化してFalseになりました。

Decorator ノードのObserver Abortの設定によって、ここからの挙動が全く変化します。

f:id:kazuhironagai77:20211017223458p:plain

まずNoneにセットしていた場合です。

以下のPrint された文字を見れば分かりますが、Print Stringが実行され、Print String1が実行中にDecoratorの条件が変更されました。

f:id:kazuhironagai77:20211017223515p:plain

Print String1の内容は全て実行され、その後Rootにまで戻ります。

f:id:kazuhironagai77:20211017223531p:plain

Decoratorの条件が変わらなかった時と全く同じです。何事も無かったように行動します。

以下に示したPrint String1(Execute)がPrint String1を最後まで実行した事を示しています。

f:id:kazuhironagai77:20211017223545p:plain

そして次のTurnから新しい条件のDecoratorで実行されます。

f:id:kazuhironagai77:20211017223559p:plain

これがDecoratorのObserver Abortの設定をNoneにした場合です。

<Self

今度はSelfにセットした場合です。

f:id:kazuhironagai77:20211017223618p:plain

以下に示した様に、Print String1を実行している時にDecoratorの条件が変化してFailになりました。

f:id:kazuhironagai77:20211017223631p:plain

AIはPrint String1の実行をただちに中止します。

以下に示したようにPrint String 1ではAbortが実行されています。

f:id:kazuhironagai77:20211017223645p:plain

するとPrint String1はFailを親ノードであるSequenceに返します。

f:id:kazuhironagai77:20211017223700p:plain

SequenceはFailを受け取ったのでそれ以上の子ノードの実行を中止します。

更にSequenceの親ノードであるSelectorにFailを返します。

Failを受け取ったSelectorは次の子ノードを実行します。

これがSelfです。Noneとの違いは実行しているTaskを中止するかどうかです。

<もう一回Self

よしSelfとNoneの違いが分かった。と早とちりしないで下さい。以下の条件でもう一回テストします。

f:id:kazuhironagai77:20211017223719p:plain

今度は、最初はDecoratorの条件を満たしていないのに、Print String3を実行中にDecoratorの条件を満たした場合です。

f:id:kazuhironagai77:20211017223732p:plain

はい。Abortが発生していません。

Debugを見ても

f:id:kazuhironagai77:20211017223746p:plain

Abortが発生していません。

最後まで実行しています。

f:id:kazuhironagai77:20211017223759p:plain

その後、新しいturnに入ってからDecoratorの条件にそって別のTaskを実行してます。

f:id:kazuhironagai77:20211017223812p:plain

これってNoneと同じじゃないですか?

はい。

SelfがAbortを実行するのは、Decoratorがあるノードの子ノードに対してだけなんです。

Decoratorがあるノードと同じ親ノードを持っているがDecoratorがないノードを実行している時にDecoratorの条件が変化しても何も反応しません。Noneである場合と同じようにずっと定められた内容を実行します。

ではDecoratorがないノードを実行している時に、Decoratorの条件が変化したらAbortしてほしい時はどうしましょう。それを可能にするのがLower Priorityです。

<Lower Priority

今度は先程と同じ条件ですが、Decoratorの条件をLower Priorityに変更します。

Print String3を実行中にDecoratorの条件が満たされると、Print String 3の実行を中止してAbortを発します。

f:id:kazuhironagai77:20211017223835p:plain

Debugを見ると

f:id:kazuhironagai77:20211017223847p:plain

いきなり以下のように変化しています。

f:id:kazuhironagai77:20211017223903p:plain

ここでPrint String 3からSequenceそしてSelectorへの赤いlineが現れないのは良く分からないです。

<Both>

では何時でもDecoratorの条件が変わった時にはAbortしてほしい時にはどうしますか?

その時はBothを使用します。

4.2 応用編について

今回は、応用編は作成しないつもりでしたが、そうするとNPCのAIが作れないので、応用編も作成する事に変更しました。

応用編は

  • AI Perceptionについて
  • EOSについて

についてやるつもりでしたが、これだけだと不十分です。

もう少し基礎的な、例えばNav Mesh Bound Volumeの使用方法などの解説が必要です。

それで基礎編2、応用編1、応用編2に分割しようと思います。

それで、内容なんですが今までUE4_AIで勉強した

f:id:kazuhironagai77:20211017223952p:plain

の内容を基礎編2、応用編1、応用編2に分割して整理してまとめようと思っています。

Online LearningのIntroduction to AI with Blueprintsの内容に関しては、2021-02-01のBlogでそれぞれの講義を簡潔にまとめています。

因みに公式のDocumentであるArtificial Intelligence [11] では、以下に示した様にUE4のAIを5つの分野に分類して説明しています。

f:id:kazuhironagai77:20211017224011p:plain

ちょっとBehavior Treeだけ見てみます。

あ、

読んでいて何で私が敢えてAIのTutorialを自分で書き出したのかを思い出しました。

この公式のDocumentの説明でUEのAIの仕組みが理解出来なかったからでした。

逆に言うと私が作成した基礎編のTutorialさえ理解出来れば、後は、公式のDocumentやYouTubeにあるTutorialを見てUE4のAIについての見識を深める事が可能なので、これ以上私がTutorialを作成する意味はない訳です。

うーん。

良し。こうします。

オリジナルのTutorialを作成するしないに関わらず、NPCのAIの作成をするのに

の復習は必要です。

今週はこれらのTutorialの最初の部分を復習しながら、何で私がオリジナルのUE_AIのTutorialを作成しないといけなかったのかとか、何でそのTutorialの説明だと理解出来ないのかなどを解説しながらまとめたいと思います。

4.3 新しいUEのAIのTutorialが出ていないかチェックする

自分が知らない間に完全無欠なUEのAIのTutorialが発表されているかもしれません。それをちょっとだけ調査します。

LeafBranchGames氏のAI [12] がありました。

f:id:kazuhironagai77:20211017224052p:plain

最初のTutorialが発表されたのが2021年の8月です。出来立てほやほやです。

これもチェックする事にします。

公式のOnline Learningもチェックしましたが特に新しいTutorialが発表されたとかは無かったです。

5.UEAITutorialの勉強

今週はそれぞれのTutorialの最初の2、3個だけチェックします。

5.1 公式のDocumentであるArtificial Intelligence [11]の勉強

このPageを開いたAI初心者が最初に選ぶのはBehavior Treeだと思うのでBehavior Tree内のTutorialから試してみます。

f:id:kazuhironagai77:20211017224121p:plain

UE_AIをこのような分類にしているのはかなり正しいと思います。自分がUE_AIのTutorialの最初の部分をまとめた時、Navigation Systemが入り込む余地がなかったです。更にAI Perception

とEQSを分けているのも正しい分類と思います。AI Debuggingにおいては言語設定が違う時のDebugの仕方がきちんと解説されているのかが気になります。

今回は、最初のTutorialであるBehavior Treeを見て行きます。

Behavior Trees [13]の勉強

Remarkに以下の説明がありました。

f:id:kazuhironagai77:20211017224141p:plain

イキナリBehavior Treeの説明から入っているので、AIとBehavior Treeの関係が良く分かりません。

ビルの建設で一階を立てる前に、2階を建設しているような気分になります。

後、BlackboardをBehavior Treeの脳に当たると紹介していますが、これは間違っています。BlackboardはBehavior treeのために変数の値を保持する機能しか持っていません。勿論記憶するのは脳の大事な役割の一つですが、人間の脳には他の重要な役割も沢山あります。

こういう偽人的な例えは、AIらしさを強調するには役立ちますが、学習者がUE_AIを理解するためには大変な害になります。

ここははっきりと「UEのAIは単なるIF節である。」と言うべきです。

以下のTutorialに分かれていました。

勿論、今回は最初のBehavior Tree Quick Start Guide [14]をやってみます。

f:id:kazuhironagai77:20211017224156p:plain

<<Behavior Tree Quick Start Guide [14]を勉強する>>

以下に示したRemarkによると、いきなりPatrolやPlayerの操作するキャラの追跡をするAIを作成するみたいです。

f:id:kazuhironagai77:20211017224215p:plain

何で、前のPageでNavigation Systemを分けたのか全く分からない仕様になっていますね。

先に進みます。

このTutorialを勉強すると以下の事が理解出来るとあります。

f:id:kazuhironagai77:20211017224228p:plain

最初のBP云々は兎も角、この選択は素晴らしいです。私が作成したUEのAIのTutorialで解説している要素とほとんど同じです。

このTutorialではNPCが抜けています。

何故このTutorialを作成した人はNPCは重要でないと思ったんでしょうか?

その辺も行間から感じながら勉強していきます。

普通にNPCをThird Person Characterをcopyして作成しています。そこに新たに作成したControl AIをセットしています。

やり方を勉強するには非常に分かり易いです。しかしControl AIとThird Person Characterの関係性についての解説は一個もありません。作品は完成しますが、学習者が何も理解出来ない、AやってBやってCやってTutorialの典型です。

正し、このTutorialをやるだけで、Task内の実装や、Perceptionの実装のやり方まで勉強出来ます。そういう意味ではかなり優れたTutorialです。

UEのAIは理解していたけど何カ月も触ってなくてやり方を忘れてしまった人には非常に良いTutorialです。

今週は他のTutorialも見る必要があるので実際には試しませんが来週実際にやってみます。

Behavior Tree Quick Start Guide [14]にあった他のTutorialも見てみます。

<<Behavior Tree Overview [15] の勉強>>

軽く見ておきます。

f:id:kazuhironagai77:20211017224259p:plain

まず、全体的な感想ですが、UEのAIの基本を既に理解した人がBehavior Treeに関する知識を更に肉付けしたい時に読むには、とても良いです。

私が「この説明は納得。」とか「この解説は分かり易い。」と思う部分がそこかしこにありました。

いくつか例を挙げると

f:id:kazuhironagai77:20211017224313p:plain

青色の部分ですが、AIだってBPで作成出来るけど、Behavior Treeを使用してAIを作成するとこんな点で便利です。

と言外で言っているように私には読めました。

これは私のUEのAIのTutorialの思想と一致しているとも読めます。

f:id:kazuhironagai77:20211017224327p:plain

Blackboardの機能を情報を保持する事。とはっきり述べています。脳の働きなんで訳わからん事は言っていません。

f:id:kazuhironagai77:20211017224343p:plain

この辺なんか単なる読み物としても面白いです。

<< Behavior Tree User Guide [16] の勉強>>

このTutorialはBehavior TreeやUEのAIに関連したクラスの作成方法や使用方法を一個一個、細かく丁寧に解説していました。

これはこれで大切です。

Composite Decoratorについて解説してる箇所がありましたが、この機能は初めて知りました。

f:id:kazuhironagai77:20211017224407p:plain

<<Behavior Tree Node Reference [17] の勉強>>

UE4_C++でBehavior Treeに追加のコードを書く時には、必要な情報かもしれませんが、今のLevelでは必要ない情報です。

公式のDocumentであるArtificial Intelligence [11]の感想

今回は、この中のBehavior Trees [13]の勉強 のみをやりました。

やはり、公式のDocumentだけあってLevelが高く、読み応えがある内容が多かったです。

しかし私が提唱している「UEのAIは単なるIF節」という思想を明確に示している箇所はなく、UEのAIを全く勉強した事がない人がイキナリ読んでも途中で理解出来なくなる可能性は高いと思われます。

学習者が私のTutorialで勉強した後でこのDocumentを読むなら、大変役立つ内容に成っていると思いました。

5.2 Online LearningIntroduction to AI with Blueprintsの復習

Introduction to AI with Blueprintsをもう一回勉強します。

f:id:kazuhironagai77:20211017224451p:plain

2021-02-01のBlogに勉強した内容を簡潔にまとめてあるのでそれも参考にします。

さくっとですが2021-02-01のBlogにあるIntroduction to AI with Blueprintsの最初の2~3個の講義のまとめを見直しました。結構本格的なAIの解説が中心の講義をしているみたいです。

今回の話で特に関係しているのは以下の部分ですかね。

f:id:kazuhironagai77:20211017224505p:plain

みました。

5分で終わってしまいました。

なんでこんなに沢山の講義を一日で勉強出来たのか不思議だったんですが、一個の講義が短かったんですね。

内容に関しては前の感想と同じです。

後、びっくりしたのはこの講義、日本語の訳が付いていました。こんな所まで翻訳してあるんですね。

5.3 Mathew Wadstein氏のWTF Is? AI [10]

BPでノードの使用方法が分からない時に、いつもお世話になっているMathew Wadstein氏のAIのTutorialです。

f:id:kazuhironagai77:20211017224531p:plain

これは見た事がないですね。この構成から想像すると最初のSimple Move in Unreal Engine 4で公式のDocumentでいう所のBehavior Tree Quick Start Guide [14] をやっているみたいです。

その後、徹底的に基礎の解説をしていますね。

じっくり見てみます。

WTF Is? Simple Move in Unreal Engine 4 ( UE4 ) [18] の勉強>

全然、想像と違いました。以下に示しましたが、

f:id:kazuhironagai77:20211017224552p:plain

Behavior Treeを使用しないAIの作成を行っていました。

うーん。これは私の想像を超えてました。こっちからAIの勉強に入る方法もあるんですね。

ここで、AI ControllerとNav Meshについての解説を終えています。これはこれで凄いです。

WTF Is? AI: Blackboard in Unreal Engine 4 ( UE4 )[19] の勉強>

今度はBlackboardについてです。これだけは昔見た事があるみたいです。内容は全く覚えていませんが。

Videoが8分有ります。BlackboardなんでBlackboard key(変数)の作成方法とそれをBehavior Treeから呼び出す方法、もしくはAI ControllerなどのBPから呼び出す方法位しか勉強する事無いと思うんですが、何を8分も講義するんでしょうか?

見てみます。

最初はBlackboardがBehavior Treeのために値を保持するObjectであると説明しています。

これはその通りですが、Behavior Treeの説明もない状態で言われても初心者にはチンプンカンプンかもしれません。

それだけじゃなくて実際にBehavior Treeを開いてさらにSelector、Decorator、そしてServiceまで使用してBlackboardの使用方法について解説しています。

f:id:kazuhironagai77:20211017224615p:plain

これは結構、初心者にはきついかもしれませんね。Mathew Wadstein氏のTutorialは分かりやすく、いつもお世話になっていますが、ここはBehavior Treeを先にやった方がもっと分かり易かったと思いますね。

そんだけですね。

Blackboardの使用方法やBehavior TreeからBlackboard keyを呼び出す方法の説明はとても分かり易かったです。

WTF Is? AI: Behavior Tree in Unreal Engine 4 ( UE4 ) [20] を勉強する>

DecoratorやTask、Serviceなどの簡単な使い方を含めてBehavior Treeの仕組みを説明していました。

この中にSimple Parallelと言う知らないCompositeがありました。

f:id:kazuhironagai77:20211017224635p:plain

最後にこの後、Behavior Treeで使用する一つ一つのクラスの解説をこの後でそれぞれ独立して行い、それが終わったらまたBehavior Treeに戻ってもう一回全体の使用方法を解説するとありました。

物量作戦です。感服です。

5.4 Ryan Laley氏のAI [9] の勉強

Ryan Laley氏のAI [9]で今回、勉強しなければならないのは一番最初のTutorialだけです。何故なら2番目のTutorialはPerceptionの説明に入ってるからです。

Unreal Engine 4 Tutorial - AI - Part 1 The Behavior Tree [21] について>

結構しっかりと4つのクラスからAIを作成する方法を説明しています。

f:id:kazuhironagai77:20211017224708p:plain

良く考えたらこのTutorialでUEのAIについて勉強したんで、私のUEのAIに対する考え方がこのTutorialと似ているのは当たり前でした。

そんだけです。

5.5 LeafBranchGames氏の AI [12]について

LeafBranchGames氏の AI [12]は最初からPerceptionについての話題なので今回はパスします。

f:id:kazuhironagai77:20211017224728p:plain

来週見ます。

6.World CompositionによるMap1の作成

先週、やったMap1へのWorld Composition化を実際のゲームであるch4_3のMap1で行います。

6.1 Landscapeの作成

Enable World Compositionをチェックします。

f:id:kazuhironagai77:20211017224754p:plain

以下の注意が出て来ました。

f:id:kazuhironagai77:20211017224808p:plain

うえ。マジか!

一端、Cancelします。

Map1とmap1_BuildDataを別なFolderに移しました。

f:id:kazuhironagai77:20211017224822p:plain

もう一回、Enable World Compositionをチェックします。

f:id:kazuhironagai77:20211017224836p:plain

今度は警告されませんでした。

以下の様になりました。

f:id:kazuhironagai77:20211017224850p:plain

今のLandscapeの配置を見ると以下に示した様に少し中央からずれています。

f:id:kazuhironagai77:20211017224906p:plain

15マスと

f:id:kazuhironagai77:20211017224920p:plain

0.8マス

f:id:kazuhironagai77:20211017224936p:plain

下にずれています。

真ん中に64x64のLandscapeが配置されるとなると32mはみ出すのが正しいので、15.8mしかはみ出していないとも言えます。

新しく作成するLandscapeは16.2m上にずれる訳です。

今度は左右を見てみます。

f:id:kazuhironagai77:20211017224952p:plain

もう少し細かく見てみます。

f:id:kazuhironagai77:20211017225006p:plain

10マスにギリ足りません。

拡大します。

f:id:kazuhironagai77:20211017225020p:plain

0.7マスと

f:id:kazuhironagai77:20211017225034p:plain

0.04マス位でしょうか?

9.74m右にはみ出しています。

本来は32m右にはみ出さないといけないので22.26m左にずれているとも言えます。

ActorのLocationはcmが単位なはずです。

f:id:kazuhironagai77:20211017225047p:plain

Map1に存在する全てのActorをxに+2226、yに‐1620ずらせばぴったし合うはずです。

うーん。

何か間違っている気がします。

Y軸をもう一回確認します。

Actorを配置してそのActorの位置を測定する事にします。

f:id:kazuhironagai77:20211017225104p:plain

Y軸に対して1480でした。

f:id:kazuhironagai77:20211017225117p:plain

3200‐1480=1740です。

左右も同じ方法で測定します。

f:id:kazuhironagai77:20211017225132p:plain

9.74mずれています。

f:id:kazuhironagai77:20211017225145p:plain

こっちの計測は合ってましたね。

最初からこのやり方で計測すべきでした。

それではLandscapeを作成していきます。

計算値とは違うですが以下の値で設定する事にしました。

Landscape内の値。

f:id:kazuhironagai77:20211017225159p:plain

World SpaceにおけるこのLandscapeの値。

f:id:kazuhironagai77:20211017225212p:plain

さっきのActorにぴったし合わせたらこの値になりました。

f:id:kazuhironagai77:20211017225228p:plain

後、前回はこのLandscapeを作成する時に位置を指定しなかったから後で直せなかったんだと分かりました。

作成します。

f:id:kazuhironagai77:20211017225243p:plain

ああ、ずれています。

やり直します。

今度は計算値でやります。

f:id:kazuhironagai77:20211017225258p:plain

f:id:kazuhironagai77:20211017225306p:plain

X軸は合っていますが、Y軸はもう少し下です。

f:id:kazuhironagai77:20211017225320p:plain

色々試したら以下の値がもっとも合っていました。

f:id:kazuhironagai77:20211017225333p:plain

f:id:kazuhironagai77:20211017225338p:plain

f:id:kazuhironagai77:20211017225344p:plain

これでやってみます。

World Compositionを開くと以下の様になっていました。

f:id:kazuhironagai77:20211017225403p:plain

ただしこれはLevel1_1のLandscapeなので上に一個、左に4個ずらす必要があります。

f:id:kazuhironagai77:20211017225417p:plain

しました。

f:id:kazuhironagai77:20211017225430p:plain

前のLandscapeと合わせるとバッチし合っています。

これでいきます。

36個のSub Levelを追加しました。

f:id:kazuhironagai77:20211017225444p:plain

f:id:kazuhironagai77:20211017225450p:plain

前のLandscapeと位置が完全に一致しています。

f:id:kazuhironagai77:20211017225505p:plain

Height MapをImportしました。

f:id:kazuhironagai77:20211017225520p:plain

LandscapeのLandscape MaterialにMap1_instをセットします。

f:id:kazuhironagai77:20211017225534p:plain

LandscapeのPaintのLayersに以下に示した値をセットしました。

f:id:kazuhironagai77:20211017225554p:plain

36個のLandscape Streaming Proxyの

f:id:kazuhironagai77:20211017225607p:plain

Landscape MaterialにMap1_instをセットしました。

f:id:kazuhironagai77:20211017225623p:plain

こんな感じです。

f:id:kazuhironagai77:20211017225638p:plain

こんな感じです。

f:id:kazuhironagai77:20211017225654p:plain

まあいいんじゃないでしょうか。

SD_10Kを作成して全てのSub Levelをそこに移しました。

f:id:kazuhironagai77:20211017225709p:plain

今までのLandscapeは要らないので消してしまいます。

f:id:kazuhironagai77:20211017225723p:plain

Playして試してみます。

f:id:kazuhironagai77:20211017225739p:plain

落ちて死にました。

ひょっとしてLandscapeの高さって0じゃなかったんでしょうか?

うーん。

前のLandscapeはもう消してしまっています。

f:id:kazuhironagai77:20211017225754p:plain

Map1_testがありました。こっちの値を調べて見ます。

f:id:kazuhironagai77:20211017225808p:plain

100ですね。

成程、確かにみんな浮いています。

f:id:kazuhironagai77:20211017225823p:plain

浮いていますがこれ位の高さかならLandscapeが見えないのはおかしいです。

これはLandscapeが生成されていないように見えます。

逆にもう少し高くに発生させて確認します。

f:id:kazuhironagai77:20211017225838p:plain

にしました。

f:id:kazuhironagai77:20211017225853p:plain

落ちている間に地面が誕生しました。

f:id:kazuhironagai77:20211017225907p:plain

静的に配置されたActorが全て浮いています。

静的に配置されたActorの位置を全て100cm下げます。

f:id:kazuhironagai77:20211017225922p:plain

直しました。

後、Monsterなどの動的に生成するActorは生成しないようにしました。

f:id:kazuhironagai77:20211017225941p:plain

Itemもです。

f:id:kazuhironagai77:20211017225954p:plain

これでテストしてみます。

こんな感じです。

f:id:kazuhironagai77:20211017230009p:plain

奥のLandscapeが読み込まれます。

f:id:kazuhironagai77:20211017230024p:plain

色々な場所を散策しましたが結構PCは熱くなってるみたいでファンがうんうん言っていました。

6.2 ActorをそれぞれのSub Level内に分割して配置する

これも先週と同じやり方でやります。

出来たので試してみます。

大体良かったのですが変なLandscapeが表示されています。

f:id:kazuhironagai77:20211017230048p:plain

山が出来ると消えます。

f:id:kazuhironagai77:20211017230104p:plain

なぜこうなるのか分かりません。

f:id:kazuhironagai77:20211017230119p:plain

これはそのSub Levelに属するActorがはみ出している場合はLevelのサイズが変わるみたいで、バグではなさそうです。

更に以下の様になってゲームが始められなくなってしまいました。

f:id:kazuhironagai77:20211017230135p:plain

原因が分かりました。

World Compositionで読み込んだ場合、Landscapeが作成されるのが遅いんです。

f:id:kazuhironagai77:20211017230150p:plain

Planeを置いておいてCharacterが落ちないようにしないといけません。

色々遊んでみます。

6.3 World Composition来週以降の課題

まず以下に示した、変なTextureを伸ばした様な絵Landscapeが表示される時があります。

f:id:kazuhironagai77:20211017230209p:plain

これの直し方が分かりません。

World CompositionはLandscapeの読み込みが速いのが特徴ですが、以下に示した様にLandscapeの読み込みが始まる前に1秒程度の遅れが生じます。

f:id:kazuhironagai77:20211017230225p:plain

この二つは商用レベルのゲームではあってはならないバグですが、直し方が分かりませんでした。

来週、もう一度検討します。

7.UE5におけるWorld Partitionの勉強

7.1 公式DocumentWorld Partition [22] を勉強する

最初の導入部の文章で以下の解説がありました。

f:id:kazuhironagai77:20211017230249p:plain

この「手動でSub Levelを分割して、Level Streamingを使用してLandscapeをLoad したりUnloadしたりしていた。」と読めますが、World Compositionの事を指していない、つまり単なるStreaming Levelの事を述べてるように感じます。World Compositionを使用すれば、手動でLevel Streamingを組む必要がないからです。

SeamlessなLevelのLoadingは今のゲームではかなり重要なPointですが、この分野の教材はあまり整理されていないのかもしれません。

World Partitionは以下に示した4つ特徴があるそうです。

f:id:kazuhironagai77:20211017230303p:plain

それぞれが何を指しているのか全く想像出来ませんね。

<Enabling World Partition in Your World

最初の章です。

World Partitionの使用方法についての説明をしているみたいです。

これは先週勉強した内容と一致しているはずです。

復習を兼ねて読んでいきます。

World Partitionの使用方法の説明ではなく、World Partitionが使用可能になるための設定方法についての説明でした。

2つの方法が紹介されていました。

最初の方法は、Project Settingから設定する方法で、先週やったやり方と同じです。もう一つはCommand Promptから指定する方法でした。

Command Promptから指定する方法は、必要になった時に勉強する事にします。

<Using World Partition

今度こそWorld Partitionの使用方法の解説です。

と思ったら、最初はWorld Partitionの特徴を説明しています。

f:id:kazuhironagai77:20211017230327p:plain

最初の文ですが「PersistentなLevelが一個だけあってそれに沢山のSub Levelがあります。」と書かれています。でもこれってWorld Compositionでも同じですよね。特別、World Partitionだけの特徴とは言えない気がします。その後の解説であるConfigurable Runtime Gridを使用して、Persistent LevelをStreamable Grid Cellに分割してる所がWorld Partitionの特徴なんでしょうね。 

ここでは、Configurable Runtime Gridが何であるかの説明はありませんが、名前から察するとRun time中にSub Levelを指定する技術のようです。もしそうなら大変な技術革新です。Configurable Runtime Gridには注目していきます。

次の文では「Playerが見たり、干渉したりするSub LevelだけをLoadします。」と解説されています。これってLoadされるLevelは単にPlayerからの距離だけではなくPlayerから見えるSub Levelは遠くのLevelでもLoadされると言う事でしょうか?

もしそうならWorld Compositionよりだいぶ改良されていますね。この辺も注目していきたいです。

<<Actors in World Partition>>

World PartitionがEnableされた後は、配置されている全てのActorにGrid Placementの指定が出来る様になるらしいです。

試しに先週作成したWorld Partitionに配置されているActorを見たら以下のような設定が載っていました。

f:id:kazuhironagai77:20211017230346p:plain

f:id:kazuhironagai77:20211017230352p:plain

Grid PlacementがLocationに設定されています。

Documentの説明を読むと

f:id:kazuhironagai77:20211017230406p:plain

と書かれていました。

これを理解するのに、前提条件としてUE4のWorld CompositionではどのActorがどのSub Levelに属するかと手動で指定しています。

f:id:kazuhironagai77:20211017230421p:plain

この部分をUE5のWorld Partitionは自動でやってくれます。

正し、どのような方法でSub Levelに分類されるかはActor毎に指定出来る訳です。

その指定方法が、World PartitionのGrid Placementなんです。

f:id:kazuhironagai77:20211017230443p:plain

ここでLocationを指定すると

f:id:kazuhironagai77:20211017230458p:plain

という条件でActorは配置されるGrid Cellを選択出来ます。

ただしこの条件で言っているBounds Volumeが何を指しているのかが分かりません。

このBounds VolumeがActor内にあるのか、Grid Cell内にあるものなのかすら分かりません。しかもこのBounds Volume、Theirで修飾されています。ActorにしてもGrid Cellにしても単数です。

うーん。

あ、分かりました。「the Actor」とActorのAが大文字で書かれているから、これが複数を表しているんです。となるとContainsは3人称単数なので必然的に、The Grid Cellを指します。はい。

つまり、Actor内にBounds Volumeがあってその中心もある。まあ多分Actorの重心みたいなのがあるんでしょう。その点が配置されているGrid CellにそのActorも属する事になると言っているわけです。

上記のWorld Compositionの例で言えば、以下に示した岩、はこのSub Levelに部分的にしか入っていません。この岩をどのSub Levelに属するのかを決めるのは、手動でも結構悩みます。

f:id:kazuhironagai77:20211017230513p:plain

それをそのActorが持つBounds Volumeの中心(多分重心みたいなもの)が配置されているThe Grid Cell(UE4のSub Levelに当たるもの)に属すると決めるのがLocationなんです。

多分、この解釈で合っているでしょう。

確認のために他の選択肢も見てみます。

f:id:kazuhironagai77:20211017230530p:plain

はい。まず「All the grid cells that intersect…」とあります。つまりGrid Cellが沢山ある前提の話なんです。それは以下に示したようなActorがSub Level(UE5ではThe Grid Cell)の境界上に配置された場合について言っている訳です。

f:id:kazuhironagai77:20211017230548p:plain

この時点で、私のLocationに対する解釈はほぼ正しいと確信しました。

World PartitionのGrid PlacementはActorがGrid Cellの境界上に配置されていた時に、どこのGrid Cellに属するかを指定するためのものだったんです。

別にGrid Cellの境界上に無い場合はそのGrid Cellに属するのは当たり前なんです。だからそんな事は指定しない訳です。

何で今度は「its bounds volume」と単数形なんでしょうか?

でもこれでBounds VolumeがGrid Cellを指していない事はほぼ確実ですね。この文章ではGrid Cellsと複数形になっていますから。The Actorだから書き手の心に描いている状況によって複数だったり単数だったりするのかもしれません。

細かい点ではまだ不明な所がありますが、Boundsを選択した時は、このActorは全てのGrid Cellsに含まれると言う説明で間違いないでしょう。

どのGrid Cellが読み込まれてもこのActorは表示される訳です。

でもこれってあるActorが4つのGrid Cellにまたがって配置されていて、その内の一つのGrid Cellが読まれた場合は良いんですが、4つ全部のGrid Cellが読まれた場合はどうするんでしょうか?

勿論、そこは最新のTechnologyを有するEpic Games社が開発したWorld Partitionですから一個のActorしか読み込まれないんでしょうが、どうやっているのかとても不思議です。