<前文>
<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 訳と打つと以下の検索結果が出て来ます。
まずはGoogle の訳です。
Weblioでは
点乗積と訳されています。
読み方はてんじょうせきだそうですが、てんじょうせきで変換しても点城跡や天井積しか表示されないと言う、本当に日本語として定着しているのか不思議な単語です。
最後に英ナビ!辞書ですが
点乗積と訳されています。
読み方はてんじょうせきだそうですが、てんじょうせきで変換しても点城跡や天井積しか表示されないと言う、本当に日本語として定着しているのか不思議な単語です。
最後に英ナビ!辞書ですが
なんとこの辞書には内積がDot Productの訳に入っています。しかも点乗積という聞いた事のない単語が入っていない所も特徴です。
何となくですが、英ナビ!辞書は、通訳や留学生などの実際に日本語と英語を翻訳する必要がある人達が使用している辞書って感じがします。理屈は良いから通じる単語を示せ。的な意思を感じます。
今度は、ドット積と内積の違いについて調べます。
これ見てまず感じたのが、日本の学者の専門用語に対しての不真面目感です。
日本中で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を勉強する
- NPCのAIを作成するための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を作成します。
その変数をSpawn Rateにセットします。
以下に示したようにFlake Amountの値をUE4のEditorからセット出来るようになりました。
<指定したStatic Meshの形状にParticle を発生させる>
今まで勉強したやり方の一つと同じ方法でやっています。
<EffectをStatic MeshにAttachする方法>
これが先週、新しく学んだことです。
以下に示したようにStatic MeshにComponentとしてEffectをAttach出来ます。
この時注意しないといけない事はStatic MeshのParameterであるAllow CPU Accessにチェックする必要がある事です。
これから調べて見ますか。
公式のDocumentであるbAllowCPUAccess [2] によると以下の解説がされていました。
これ読むとStatic MeshのGeometryのDataをCPUからGPUに移す時、普段はCPUの側のGeometryのDataは消してしまいますが、これにCheckを入れた場合は消さないで残しておくようです。
成程、先週、EffectのEmitter PropertiesのSim TargetをGPUにセットし直しましたが
この部分とは全く関係なかったんですね。
一寸だけ、GPUで計算しているのに何でCPU Access何だろうと思いました。
この部分で分からない所が、一個あります。
Sample Static Mesh ModuleではCubeでセットしているのに
ComponentとしてStatic Meshに追加するとそのStatic Meshの形にParticleを発生するところです。
これは後で調べます。
<Static Meshの色をParticleに追加する事とG Bufferについて>
Static Meshの色をParticleにパスする事はBuilding advanced effects in Niagara | Unreal Engine [3]で勉強しました。
今回はその時とは違いG Bufferを使用しています。
このG Bufferについて勉強します。
Learn OpenGLの Deferred Shading [4] に簡単な解説がありました。
これは実際に自分で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 ノードで変換しています。
これもG Bufferの意味を理解した後なら納得ですね。
ただScreen UVのCoordinateが-1から1なので0から1なのかは不明です。後、0から1の場合なら左上が原点であるのかも不明です。
その後で、Decode Base Color NodeでG buffer の指定した位置の色を取り出しています。
G-Bufferの他の値は取り出せないんでしょうか?
これ見ると結構色々な値がG Bufferに保持されているんですね。光のRenderingの計算は後ですると先程の説明でありましたが、ここにDiffuse ColorやSpecularの選択も出来ますね。Diffuse ColorやSpecularは先に計算しているみたいですね。
<Cameraとの距離によって発生するParticleの量を調整する>
これは2つの事を知る必要があります。
一つ目は、Spawn Rate ModuleにあるSpawn Probabilityです。
ここをチェックする事で発生するParticleの量を0から100%の割合で調節する事が出来ます。
この値とCameraとの距離を関連すければ良い訳です。
2つ目はCameraとの距離の計算方法です。以下にまとめました。
- Cameraの位置、ParticleのセットされたStatic Meshの位置をGetします。
- Particleを0~100%の間で表示したい距離を決めます。
- 2の値でCameraとStatic Meshの距離を割ります。
- 3の値をInverseします。
4の値をSpawn ProbabilityにセットすればCamera がStatic Meshにいる時に100%のParticleが発生します。そして指定した距離より離れた時はParticleの発生する数は0になります。
具体的には、Cameraの位置は、
から得ます。
公式DocumentのEmitter Update Group [5] によると
と書かれています。
Cameraに関する情報をNiagaraのModuleからaccess出来るようにする変数でしょうね。
Camera Queryから繋げられるノードを調べると以下の種類のノードが表示されます。
前回は、ここでCalculate Particle Distances CPUノードではなくGet Camera Properties CPU/GPUノードを使用しました。
多分、Calculate Particle Distance CPUノードはそれぞれのParticleとCamera の距離を返すので、Get Camera Properties CPU/GPUノードを使用したんでしょうね。
先週のBlogを読み返すと、何でCPU/GPUとあえて言っているのか不思議に思っていますがこの意味が分かりませんでした。
後、これは単なる推測ですが、
のForward Vector World、Up Vector World、そしてRight Vector Worldは
Camera の軸をWorld Spaceで表した値だと思います。
Particleの発生するStatic Meshの位置は
で得る事が出来ます。
Particleを表示する距離の指定はMap GetノードにFloat型の変数を追加する事で出来る様になります。
その後の計算は自分で計算しても良いですが、このTutorialではDistance Based Fall Offノードを使用しています。
以上です。
2.2 Niagara : Time Distortion Effect - UE4 Tutorial [1]の続きをやる
今度は床のEffectを作成します。
まず床のMaterialを作成します。
特に特徴のあるMaterialじゃないですね。
こんな感じです。
微調整しました。
また先程のMaterialに戻って以下の実装をします。
Sphere Maskノードはこの前のDisintegration in UE5 Niagara Tutorial | Download Files [6] の勉強で使用した時に勉強しました。
勉強したんですが、AとBの値の中間が球の中心になるのか忘れてしまいました。後で確認します。
この値をEmissive Colorに繋げます。
こんな感じになります。
あー。分かりました。この範囲の円を振動させるんですね。
以下の実装をしました。
結果です。
うーん。何でこんな感じになるのか今一理解出来ません。
この計算は色んな所で使用するので後でじっくり検証します。
Sineノードの計算結果は-1から1なので0から1に変更するために以下の実装をします。
でもこれって-1から1なので0から1に変更するためだけじゃないですよね。
この実装、Powerの部分が良く分からないんです。LerpのAlphaって結局0から1の範囲ですよね。折角sin値に1足して、0.5を掛けて値を0から1の範囲に変更したのに何でPowerをするんですかね?
この辺も後で検証します。
こんな感じになりました。
大体は良いんですが、
以下の状態の時、真ん中の円と最後の円の外側が全部選択されています。
この部分は余計なのでMaskして外します。
まず中心の円から消します。
こうなりました。
消えてますね。
ウーン。何で消えるのか分からない。いや消えるのは分かりますが、5乗する意味が不明です。
今度は円の外側を消します。
以下の実装を更に掛けます。
消えました。
これもSaturateを入れたり掛けたりしている部分が謎です。後でしっかり検証します。
今度はこの波紋に合わせて、Meshの波を起こします。
MaterialのTessellationの設定を以下の様に変更します。
これはWorld Displacementを使用するためのものです。
次に以下の実装をWorld Displacementに繋げます。
結果です。
MaterialのTessellationについてまだ勉強していないのでここは復習する時も軽くにしておきます。
床以外のActorにもこのMaterialを適用します。
今度はこのEffect(Materialですが)がCharacterに沿って起きる様にします。
Parameter Collectionからクラスを作成します。
Vector Parameterを一つ作成します。
今度はThird Person CharacterのBPを開いて以下の実装をします。
あまりConstruction Scriptを使用した事はないんですが、これってC++でいうConstructorのBP版であると理解しています。
と言う事はこの設定だとThird Person Characterが移動した後の位置の情報はパスされないんじゃないでしょうか?
更にMaterialのActor PositionノードをCollection Parameterノードと交換します。
はい。やっぱりTickにコードを足しました。
こんな感じです。
サイズが大きすぎてUpload出来なかったので画質を落としました。
残りの半分です。これも画質を落としています。
このEffectをこのMaterialに追加します。
Tessellationの部分を以下の様に変更して
World Displacementの部分を丸コピーします。
こんな感じです。
今度は床の光っている箇所に下記のTextureを混ぜてキラキラさせます。
こんな感じです。
こんな感じです。
この部分の実装はTextureのサイズを変更しているだけですね。TexCoordの代わりにAbsolute World Positionを使用した理由は分かりません。後で検証します。
この垂直の部分
は要らないので外します。
以下のコードを
Emissive ColorのLerpの前に掛けます。
はい。消えました。
Tutorialに何でこのやり方で垂直面の投影が消えるのかの解説がありましたが、後で自分で検証します。
今度は以下の部分のStatic Meshに先週作成したNiagara Effectを追加します。
この部分は微調整なので記録はスキップします。
今度はParticle のEffectをゆっくりにします。
これは単に以下の実装を追加しただけでした。
こんな感じです。
火のEffectがゆっくり動いています。
特に検証しなくてはならない箇所はないです。
今度はMaterialの最適化を行います。
ここで使用したMaterialはTessellationを使用しているためコストがかなり高いです。最適化をします。
一つ目の方法はLODを使用する方法です。
このCouchを使用して作成します。
CouchのStatic Meshを開いてMaterial Slotsを一個追加します。
以下に示した様に、元のMaterialをElement1にセットしてここで作成したMaterialをElement0にセットします。
そしてLOD PickerのCustomをCheckします。
更にLOD SettingsのNumber of LODsの値を2にします。
Apply Changesボタンを押します。
LOD1が現れるので、Materialに元のCouch用のMaterialをセットします。
LOD SettingsのAuto Compute LOD DistanceのCheckを外します。
LOD1のScreen Sizeに0.8をセットします。
テストします。
近づくとCouchもグネリますが、
離れると普通のCouchに戻ります。
むー。
初めてLODの設定を自分で変えました。LODにはこんな使い方もあるんですね。設定の詳細については後で検証します。
二つ目の方法はNiagaraの最適化です。
カメラが凄く遠く移動してParticleが何も生成しない状態でもEmitter Updateは常に働いています。それはDistance Check Moduleを動かす必要があるからです。
これを直します。
まずStatic MeshにAttachしたNSを選択します。
そしてAuto Activate のCheckを外します。
すると以下に示した様にBoxに近づいてもParticleは発生しません。
以下の方法でStatic MeshにAttachしたNiagara SystemをActivate出来るとありましたが
これをどう繋げるのかの説明はなかったです。これの使用方法についても後で検証します。
これでお終いです。
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の意味が良く分からないと言っていましたら
Ben Cloward氏がSine とCosineについてのTutorialを作成してくれていました。もうこれを勉強するしかないですよね。
まずぱっと全部見ました。
今回はUnityが主で解説していました。UEは最後にCodeを紹介するに留めていましたが、そこでUEのSinノードの結構重大な特徴を紹介していたりしてました。
全体の構成は
- 0:00~3:45 SineとCosineの定義について
- 3:45~6:50 Sineの計算結果を-1~1から0~1に変換する方法
- 6:50~9:49 Sineを使用して波紋を作成する方法
- 9:49~11:51 Sineを使用して位置を移動する方法
- 11:51~16: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は自分で実装する事にします。そして最期に答え合わせする事にします。
<SineとCosineの定義について>
この部分は特に記録する内容はないです。自明の事だけ説明していました。
Freya Holmér氏の作成した図がSineとCosineが可視化されていて直観的に理解しやすいです。
こういう図ってOpenGLでもProcessingでも何でも良いですが、作成しようと思えば簡単に出来ると思いますが、実際に作成した人はほとんどいないです。その辺をしっかり作成して講義で使用するところが、Freya Holmér氏の非凡な所なんでしょうね。
<Sineの計算結果を-1~1から0~1に変換する方法>
基本中の基本ですがしっかり復習します。
こんな感じです。
それでは検証していきます。
まず最初のsin(X)の値です。
-1から1の間で移動しています。
何かカクカクですがExcelに触るの久しぶりで滑らかな線の引き方を忘れてしまいました。
今度はその結果に0.5を掛けてみます。
値がSin(x)の半分になっています。
今度はそれに0.5を足します。
値が0~1の間になりました。
うーん。「houdiniとunreal engine 4で学ぶリアルタイムvfx」でノードの機能を一々グラフ化して説明していたんですが、それが大変分かり易かったです。
のでそれを真似したんですが、あんまり分かり易くないですね。
0以下がどこかパッと見で分からないからでしょうか?
図を少し改良してみました。
これ見て思ったんですが最初が0じゃないんですね。
試しにCosineで計算してみましたが、Cosineだと1から始まって1で終るんですね。
ひょっとするとCosineを使用した方が綺麗に見える可能性もありますね。
やっぱり何でも実際にやってみるものです。
<Sineを使用して波紋を作成する方法>
はい。これを知りたかった。
「2.2 Niagara : Time Distortion Effect - UE4 Tutorial [1]の続きをやる」で
にsineを掛けると
波紋が発生しますがこの理屈が今一分かっていません。ここでしっかり勉強します。
まずTutorial通りに実装しました。
こんな感じです。
一個ずつノードを見て行きます。
Fracは小数点以下の値のみを返すはずです。0から1の間の値が返されているのでしょうか?
ExcelでGraphにするのはあんまり分かり易くないのでPreviewを表示させる事にしました。
0~1の間の値が返っているのは間違いないみたいです。が数字でみたいですね。
調べたらDebug Floatノードを使用すれば数字が見れるみたいです。
Fracに繋いでみました。
以下の様な表示がされました。
0から1の間の値が返っています。
後、Fracの返し値は2Vectorじゃなかったです。でも同じ値を2個返してくれています。親切設計ですね。
今度は1を引いています。何でOne Minusノードを使用しなかったんでしょうね。
それは兎も角、Previewを見ると真っ黒です。
0~1の間の値から1を引いたら-1~0の値に変わるので当然ですね。Debug Floatノードを使用して数字も確認しておきます。
-0.9999から0の間の数字が表示されているみたいです。
それにGradientのTextureを足します。
すると円が大きくなるanimationがPreviewに表示されます。
録画したら平板全体が真っ白になる時があるんですが、Previewでは確認出来ません。カットしたかったんですがやり方が分かりません。
何で白い円が大きくなるのかの理由が分かりました。
-1をこのTextureに足したら、全部真っ黒になります。
-0.5を足したら半分だけ真っ黒くなります。
0を足したら円が全部表示されます。
そんだけの理由でした。
次は8を掛けています。
0から1の間の値だったのが0から8の間の値に変化しました。
これは白の色を濃くしています。
円内で真っ白な部分の割合が増えています。つまり白が濃くなっています。
次はClampしています。
正直Clampするなら0と1の間でいいんじゃないと思いますがどう違うんでしょうか。多分先の計算に影響するのだと思います。
これにPiを掛けています。
Sinノードに繋ぐのにPiを掛けておくと何か便利な事があるんでしょうか?
これも最後まで見ないと分からないですね。
はい。最後にSinノードにつながりました。
前にも表示しましたがこんな感じです。
Clampの値を1にしてみます。
輪の数が1個になりました。
Clampの値を2にしました。
輪の数は1個のままです。
Clampの値を3にしました。
輪の数は2個のままです。
これがClampノードの役割のようですね。
今度はPiノードを抜いてみました。
沢山あった輪が消えて一個の太い輪が表示されるようになりました。Piは輪の数をClampの値で調節するのに必要だったようです。
成程分かりました。
Sinで計算するので0から5の値も結局-1から1の間に変化するんです。それが輪を生み出しているです。
ちょっと遊んでみます。
まずsin()なので先程の実装と組み合わせて0~1の値に変換します。
なんと灰色のバックが生まれました。
何にもない所は0.5になるのか。うーん。
先程差のなかったClampの値が1と2の時です。
Clampの値が1
Clampの値が2
しっかり違いが出て来ます。
今度はSinの代わりにCosを使用してみます。
うーん。Cosは灰色の部分がちょっとしかないですね。
どうしてこんな違いが生じるのかは時間があるとき検討します。
<Sineを使用して位置を移動する方法>
以下の実装で
こんな動きしています。
World Position Offsetに繋いでいるのか。それなら納得です。Vertexの値を弄っている訳ですね。
ここはそれだけです。
<Sineを使用してTextureを回転させる方法>
はい。来ました。
以下の計算をしています。
Cos X + Sin Y
Cos X – Sin Y
ですね。
あれ?
先週の gameDev Outpost氏のUE4 - Materials and UV Rotation [9] と同じ計算してます。
うーん。でもUnityだと反時計回りに回ってますね。
分かりませんね。
座標軸が違うんでしょうか?
<UEでの実装方法の確認>
ここで大切な事はUEのSineノードのPeriodに
6.28を入れる必要がある事です。これがDefault値では1になっています。
3.2 UEのMaterialの回転の謎に迫る
先週、何で-0.5を足すと中心で回転するのか分からないと言っていました。
分かりました。
一週間かかってある仮説を思い付きました。
まず仮説をここに説明します。その後で実験して検証します。
その前に先週の計算を少し直しました。
DegreeからRadianの計算を追加して
SineとCosineのPeriodに6.28をセットしました。
これでDegreeとRadianの変換も正しいはずです。
一応テストしてみます。
前に計算したDegreeとRadianとSin(x)の表です。結果をこの表に足していきます。
0を入れます。
結果です。
大体同じ値なんですが90度の時だけ0が返っています。
Radianの値を調べたら
1.5707で計算値の1.571とほぼ一致しています。
試しに1.57をSinに入力してみると
1と正しい値が出て来ます。
でも元に戻すと
0って表示されます。
うーん。これは私のVideo Cardの問題かもしれません。Driverに問題が有って古いVersionをずっと使用していますので。
今回は90度の場合は見なかった事にして先へ進みます。
Texture Coordinateの座標がこれで正しいのかちょっと自信がないですがこれは後で調べます
0.5、0.5移動した時です。
-0.5、-0.5移動した時です。
で回転なんですがTextureの左上を中心に回転するんです。
こんな風に
これしか思いつかなかったです。
0度の時です。
90度の時です。
仮説と合います。
180度の時です。
あってます。
270度の時です。
これも合ってます。
それでは0.5、0.5ずらした時はどうでしょうか?
90度回転した時です。
画面から外れてしまいます。
外れています。
ずっと絵が写りません。
ぐるっと回して最初に移る時は口が写ります。
330度の時です。
実際の図も口が最初に写っています。
これだと実際の結果と合いますね。
でも単に座標軸が間違っているだけかもしれませんね。
後、OpenGLを勉強した時、座標軸を回転させると全部辻褄があった事を覚えているんです。この回転方法だと座標軸じゃなくて絵を回していますね。
来週も引き続き検討する事にします。
4.NPCのAIを作成するためのAIの復習の続き(Nav Meshの勉強の続き)
今週は、Navigation Systemの
を勉強します。
その前に今までのAIの勉強で何をやって来たのかとこれから何をする目的だったのかをもう一回確認しておきます。
目的ですが、村人のAIを作る事です。
そのためにMonsterのAIを復習しました。
その時のまとめが不十分だったのでまとめ直しました。
そのまとめ直した部分が私が作成したTutorialです。
その私が作成したTutorialはAIの基礎を学ぶ前に学ぶ内容をまとめたものですのでそれだけでは村人のAIは作れません。
その後に
を学ぶ必要があります。
まあ全部を学ばなくても村人のAIは作れそうですが、折角の機会なので勉強してしまいます。
4.1 Custom Navigation Areas and Query Filters Preparation Guide [10] をやる
ここは次のTutorialで使用するLevelを作成するためのTutorialなのでさっと作ってしまいます。
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を
Nav Mesh内に配置して、Area Classに
BP、Nav Areaから作成したクラスをセットします。
Nav Areaクラスは
そのAreaのコストとそのAreaの色を指定出来ます。
以下の様に配置した3つのNav Modifier Volumeに3つの別々のNav Areaをセットしました。
Tutorialを見るとここまで簡単にやっていますが、Nav Modifier Volumeを認識してくれなくて上記の赤や青の色が表示されなくて大変でした。
一端、UE4 Editorを再起動したら何か認識してくれました。
一応、原因を調べたらDefault Costが1にセットされていると認識されないみたいな説が出て来ました。
これだけ確認します。
白い部分ですが、新しいNav Modifier Volumeを作成してDefault Cost が1である新しいNav Areaをセットしました。
普通に認識しています。
良く分かりません。
Nav AreaのDefault Costを色々変えてテストしましたが、全ての場合で最適なルートを選んでいました。
上記の例だと、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クラスから新しいクラスを作成します。
以下の様にArea ClassにCostを上書き設定します。
AIが操作するキャラを選択して、以下に示したFilter Classに先程作成したNavigation Query Filterクラスをセットします。
これで完成です。
AIに操作されるキャラは新しいコストに基づいて最適なルートを作成します。
以上です。
Navigation Query Filterは想像していたのとは全く違っていましたね。でも使い方は覚えました。
4.3 Using Avoidance With the Navigation System [12]を勉強する
先週、話してたこれですね。
要するにAIが動いてるActorと衝突しないための機能です。
そう言えば、先週のテストでAIで操作されるNPC同士が衝突してお互いに動けなくなっている時がありました。
これを解消する訳ですね。
<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>
出来ました。
真ん中でにらみ合って全く動きません。
<4 - Adding Reciprocal Velocity Obstacles Avoidance to Your Agent>
CharacterのCharacter Movementを選択します。
Character Movement: AvoidanceにUse RVO Avoidanceがあるのでチェックします。
今度はお互いに避けて目的地につけました。
あれ。RVOは他のNPCの速度を計算するだけじゃなかったの?
これだけでも衝突を避ける事が出来るみたいですね。
<5 - Adding Detour Crowd Avoidance to Your Agent>
今度は、CharacterのAI Controller ClassにDetour Crowd AI Controllerをセットします。
これだけでした。
テストすると
スムーズな動きをして他のNPCの動きを躱して目的地に着きました。
これは凄いですがAI ControllerにDetour Crowd AI Controllerをセットする必要があります。
AI ControllerからBehavior Treeを呼び出す場合、Detour Crowd AI Controllerから呼び出せるのか、もしくはDetour Crowd AI Controllerの機能を丸コピー出来るようにする必要があります。
この辺の問題を解決する必要があります。
<まとめと感想>
最初、RVOとDetour Crowd Managerに対して以下の様な解釈をしていましたが全然違いましたね。
もう一回、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に以下の実装を追加しました。
Landscapeが生成されていませんが、キャラは浮いているので死ぬ事はありません。
設定は1.5秒間浮いています。その間にLandscapeが生成されて
重力が戻って落ちた時には地面の上に普通に着地しました。
Landscapeが生成される時間はもしかしたらPCの性能によって変わるかもしれません。その場合はEボタンを押したら重力が復活する。その代りEボタンを押さないと身動き出来ない。とかにすれば良いと思います。
5.2 静的に配置したMonsterと戦闘してみる。
Monsterの戦闘後に元のMapに戻って来る時は大丈夫なのかを試してみます。
Trapを静的に配置しました。この中に入ったらMonsterが発生します。
Monsterと戦闘しました。
落ちて死ぬ時とLandscapeの生成が間に合って助かる時の2パターンがあります。
重力の無い時間を3秒に変更します。
テストします。
3秒あったら大丈夫ですね。必ずLandscapeが生成されます。
しかし3秒は長いのでその間、何かのEffectを表示する必要がありますね。後で考えます。
闘技場の最初、3秒間浮いているのはかなり変です。ので闘技場のMapへ移動した時は重力は切らない事にします。
<闘技場Mapへの移動は重力を切らないようにする>
以下の実装を追加しました。
テストします。
戦闘画面に移動しました。
全く宙に浮かないで闘技場に落ちました。出来ています。
元のMapに戻って来る時は3秒間浮いています。
出来ました。
5.3 Monsterを一体だけ静的に配置してみる。
Monsterと戦闘しても無事に元のMapに戻ってこれる事が判明したので、一体Monsterを静的に配置してみます。
調べたい事は、
- LandscapeがLoadやUnloadされた時の影響
- 戦闘後の影響
などです。特にLandscapeがLoadされるよりも先にMonsterが生成されて地面から落ちる事がないのかを調べます。
こんな感じで配置しました。
テストします。
思いっきり落下しています。
Playerの操作するキャラと同じように重力を切ってみます。
効果なかったです。動的に生成する時はあるのかもしれませんね。
MonsterBPにStatic なPlaneを足してみました。
今度は落ちませんがMonsterが移動しなくなりました。
AIが全く効いていません。
どうしちゃったんでしょうか?
何か心配になって来ました。
Monster BPを壊しちゃったんでしょうか?
確認のためにMap1_Testを開いて見たら普通に歩いていました。
うーん。
謎ですね。
Nav Meshが効いていないのでしょうか?
一端、板をMonster BPから外してMap上に板を配置する事にします。
テストしましたが結果は同じでした。
何と、配置されていたMonster BPのCapsule ComponentがStaticになっていました。
直しました。
今度は普通に徘徊しています。
今度はMonster BPをSub LevelであるLevel 3-6に移しました。これでLoad やUnloadの影響を見ます。
一端Mapの端まで行って戻って来ましたが普通にMonsterは生成されました。
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の読み込みはかなりでっかい領域で使用すべきです。
私が考えていたような100mとかの範囲だと見た目が変な所が結構目立ちます。
それ以外にもゲームを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を動的に生成しています。
ここでMonsterを生成するのに使用しているのがGame InstanceのMonster Spawn Dataです。
先週の考えではこれを沢山作ればいい。と考えていましたが、Monsterを倒した時に以下のチェックを外します。
この実装がどうなっているのかを調べる必要がありました。
ありました。RPG Game Mode Base BP内の実装です。
ここでどのMapにおける戦闘だったのかを判断しています。
Map1なのでRemoved Defeated Monster from Map 1関数を使用します。
Removed Defeated Monster from Map 1関数の中身です。
Monsterの名前で消すMonsterを確認しています。
成程。
参考までにLandscape1のMonsterの生成方法も見てみます。
ああそうだ。Landscape1ではそれそれのBlockで発生するMonsterを分割してDataにまとめたんでした。
うーん。
これを作成した時はSub Levelについて知らなかったのでこの部分はもう一回、設計し直したいですね。
ただこの部分で実装したやり方は今のSub Level上でのMonsterの動的な生成の参考にはなります。
Monster Territory Numberを使用してどのBlockのMonster dataからMonsterを消すのかを判明してます。
よし分かりました。
このMonster Territory Numberの代わりにどのSub Levelにいるのかが分かる関数があれば、Dataをバラバラにしても大丈夫なはずです。
その関数があるかどうかをまず探します。
なさそうです。
UE4 Answer HubのHow To Get Current Sub Level Name [13] に
Sub Level毎のTrigger boxを作成してどのSub Levelに入っているのかを記録する方法が紹介されていました。
これやるならMonster のData を管理しているMonster Spawn Dataの項目に新しくSub Level Nameを追加した方が楽な気がします。
しかし前に、何気なく追加したらこのStructを使用して管理していたDataが全部消えてしまった記憶があります。
こっちはなるだけ触りたくありません。
妥協案としてMonsterが発生するSub LevelにだけTrigger Boxを生成します。
こんな感じにします。
Map1でMonsterが発生するSub Levelの一つは以下に示したようにSub LevelであるLevel 3-6です。
なので以下の部分にTrigger boxをセットします。
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の以下の部分が表示されない時は、
一回そのLevelを閉じて別なLevelを開き、もう一回そのLevelを開くと現れるそうです。
試してみます。
新しいLevelを作成してLandscapeを追加しました。
World Partition Setupには何も表示されません。
別なMapを開きもう一度このMapを開くと以下の様にWorld Partition Setup内にRun Time Settingの表示が現れました。
しかしLandscapeが表示されていません。
そこでもう一つの重要な話です。
もう一つはUE4で言う所のSub LevelのLoadの仕方です。
World Partitionを表示します。
Load Selected Cellsを選択します。
これを試してみます。
LandscapeがLoad出来ました。
はい。
これだけ知っていれば十分な気がします。来週はWorld Partition を使用してLandscapeを実際に作成します。
7.まとめと感想
今週はホントに予定通りに終わらないと思っていたら何とか終わりました。
TextureのCoordinateはひょっとすると以下の絵で言う
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/