<前文>
前文には日本人が誤解しているアメリカ、特に日本文化とキリスト教文化の違いから生じる誤解とその解決法について気が付く範囲ですが書いておきます。
何でも欧米の文化が日本より上と思っている日本人って結構います。私が悲しいのは英語の勉強が好きな人達や欧米に留学した人達にそういう傾向が多い事です。実際は、西洋文化に内側から触れると日本より良い部分も多い反面、日本より全然駄目な部分も沢山あります。
アメリカで十年暮らした私が欧米の文化の中で日本の文化と比べて最も駄目だと思う部分について今回は語ります。
それは欧米人が焚書を悪い事と思っていない事です。
彼等は簡単に本を燃やします。単に燃やすだけじゃなくてその本に書かれた事実もついでに無かった事にします。
日本人にとって一番簡単な例が教会の絵です。昔は裸で書かれていた天使の絵を、後からふしだらと言う理由で服を着せたり、人物ごと消したりします。
アステカ文明とか西洋に完全に滅ぼされた文明の記録なんか全て燃やされてしまいました。残っているのが彼らが生贄を捧げていた残虐な民族であるというキリスト教にとって有利かつCheapな情報だけでアステカ文明という人類の文明にとって欠かせない遺産が現在に全く伝わってない結果になってしまっています。
当時の宣教師たちは大変な知識階級だったわけで「こんな大切な人類の遺産を消す訳にはいかない。」と思って例えそれが大きな罪に問われる事になっても、燃やす前にどこかにコピーを隠したりする人が一人位はいるべきだろうと、日本人なら感じますが実際は当時の宣教師たちの間には全くいなかったわけです。
これが日本の話になると、例えば、私の家の近所には、高野長英が東北に逃げる時に幕府に内緒で匿った家があるんです。
その当時そんな事したら打ち首獄門な訳ですよ。そしてその時は村社会だから村の人はみんなその事を知っている訳です。知らないフリしているけど知っている訳です。
村全体が罰せられるかも知れないんですが、みんな黙っていたんです。
そのせいかどうか知りませんが、未だにその家の人達は、高野長英が東北に逃げるのを助けた○○さんって影で言われています。
でもそういう人達がいたお陰で日本は西洋の科学技術を他のアジアの国と違って素早く吸収する事が出来た訳です。
所が、西洋人にはそういう文化はないんです。本なんか聖書以外は、自分達の直接の利益にならなければ燃やしたって全然OKなんです。
これが西洋人の本に対する普通の感覚なんです。
これを理解した上でないと、なんでユダヤ人があんなにホロコーストに否定的な意見に対して激怒して攻撃しているくるのかも理解出来ないです。
ユダヤ人がああやって怒っていないとホロコースト関連の資料なんか全部燃やされて、西洋社会ではあっという間に無かった事にされてしまうからです。
日本の歴史の例で言えば、戦国時代の日本人奴隷の存在や、長崎の原爆がカソリック教会に落とされた事など、現在はほとんどなかった事にされてしまっています。
そして私が危惧しているのがKindle独占状態における電子書籍化です。電子書籍に関しては私は大賛成です。しかし西洋社会では書籍はちり紙のように軽く扱われます。いつ日本語の本が発禁にされてもオカシクありません。
こういう事実を理解しておけば、日本語の本を西洋人に管理させてはならない。と言う事と、いつ発禁処分にされても大丈夫なようにBlock Chain技術で管理しなければならないと言う結論に自ずと達します。
それでは今週の勉強を開始します。
<本文>
1.今週の予定
今週は先週、終わらなかった事を中心にやっていきます。
- Niagara : 先週の復習とExample Contentsの勉強
- Material : 先週の復習など
- AIの復習の続き
- World CompositionによるMap1の作成
- Loading Screenの勉強の続き(Moduleについて)
2.Niagara : 先週の復習とExample Contentsの勉強
2.1 Transient Physics Drag変数についての補足
先週、Local Name SpaceとTransient Name Space の違いについて以下の2つの解説を見せました。
このTransientの解説は良いんですが、
Localの方です。
ここでTransient Valueと言っているのはLocal Valueの間違いですよね。
後、最初の文でSingle Module内でしか使用出来ないと言っているのだから、Frame 間やEmitterからParticle、Spawn Section からUpdate Sectionへの変数の値のパスは勿論出来ません。2番目の文の説明いるんでしょうか?
このLocalの説明は間違ってTransientの説明を載せていて、それをCheckした人がAny ModuleからSingle Moduleの所だけ直した可能性はないでしょうか?
何かとても不自然な文章です。
2.2 Bugs in UE4.27 Niagara Tutorial | Download Files [1] で新しく学んだModuleなどを復習する
<Add Velocity From Point Module>
まず解説から読んでいきます。
最初の文はこのModuleの機能を説明していると思われます。
2番目のUses the vector…が何を言っているのか分かりませんね。
UsesとSが付いていると言う事は命令形じゃなくて「このModuleは」と言う主語が隠れていると言う事でしょうか?となると「このModuleはVelocity Vectorを計算するのにVelocity originとParticles PositionからのVectorを使用します。」と言う事になるんでしょうか?
Scriptを開いて確認してみましょう。
Map GetノードにVelocity originとParticles Positionらしい変数を見つけました。
Default Positionの方はParticles Position変数の値をパスされていました。
と言う事はVelocity originとParticles Positionに間違いないですね。
ただVelocity originって具体的に何を指しているのか良く分からないですね。
調べたらDefault Position変数、Velocity origin変数共にSelectionでどんな値を代入するのかを指定されていました。
Dynamic Inputなので当たり前だったんですが気が付かなかったです。
これを見るとVelocity origin変数はSimulation Positionをパスされています。
Simulation Positionを調べます。
<<Simulation Position>>
Engine.Owner.Positionの値かLocal Spaceにチェックがある場合は0を返すそうです。
あれ、これ前にも使用しましたっけ。
ぱっと確認したら2021-07-11のBlogと2021-09-06そして2021-09-12のBlog内でこのDynamic Inputについて述べています。2021-07-11のBlogではSimulation Position をRibbon の作成に使用しています。2021-09-06、そして2021-09-12のBlogではBuilding advanced effects in Niagara | Unreal Engine [2]内で使用されていました。
Engine.Owner.Positionの値を使用していますが、この値はEmitterの原点を示しているはずです。
以下の図Curl Noise Force Moduleを切った状態ですが、Emitterの原点からそれぞれのParticleのPositionが放射状に広がっています。これは繋げたVectorを初速度のVectorとして使用しているからです。
またScriptを見てもVelocityの値にVelocity origin変数とParticles Position変数から計算したNormalized Vector Between Positionsと(ifノードに繋がっている)Velocity Strength変数の値を掛けたものをセットしています。
これも先程の訳と同じ事を表しています。
はい。分かりました。
このAdd Velocity From Point ModuleはそれぞれのParticleに速度を与えるModuleです。速度の方向はEmitterの原点とParticleの発生位置を繋げたVectorから計算します。
その後の解説で
もしEmitterの原点とParticleの発生位置が同じ時はどうするのか?とか、
最も正確な結果がほしい時はLocation Moduleの下にこのModuleを配置しろとか説明されています。
完全に理解しました。
<Curl Noise Force Module>
Curl Noiseは流体の動きを表現するのに便利なNoiseです。2021-08-23のBlogでCurl Noiseについて調べています。その時に以下の仮説を述べています。
Noise Strengthがベクトル場の大きさを表して、Noise Frequencyがベクトル場の複雑さを表してると言う仮説です。
今までこれを証明する方法がありませんでしたが、前回Curl Noise Forceを追加したParticleを平面上に飛ばすやり方を教わりました。この技術を使用したらNoise Frequencyとベクトル場の複雑さの関係の確認は出来るはずです。それを試してみます。
<<Velocity変数>>
その前にCurl Noise Forceを追加したParticleを平面上に飛ばすやり方で使用しているVelocity変数について復習します。
これです。
Velocity 変数そのものについては先程のAdd Velocity From Point Module内でも出て来ましたがParticleの速度を管理する変数です。
今回はその変数を直接、Particle Update SectionにModuleとして追加しています。
そして以下の計算を行っています。
Velocity = Velocity * (1,1,0)
をです。
このやり方は覚えておきます。色々な個所で使用出来るはずです。
<<Noise Frequencyとベクトル場の複雑さの関係>>
Noise Frequencyが20の時です。
Noise Frequencyが100の時です。
うねりが全く無くなってしまいました。
これはCurl NoiseでHigh Frequencyの時に黒と白の部分が細かくなっていくのに一致した結果と思われます
Noise Frequencyが100の時、particleは回転しているはずです。ただしその渦が上記のHigh Frequencyの時のように非常に小さくなってパッと見には回転してないように見えていると考えられます。
Noise Frequencyが10の時です。
Particleの動きがNoise Frequencyが20の時よりも大きいです。これもCurl Noiseでlow Frequencyの時に黒と白の部分が大きくなっていくのに一致した結果となっています。
この結果から推測するとCurl Noise Force ModuleのDynamic InputであるNoise FrequencyはCurl Noiseでいう所のFrequencyと同じであると言えます。
<Spawn Particle From Other Emitter Module>
このModuleは使い方の復習をします。
このModule、何回か使用したはずですが、Blogの検索に引っかかりません。
仕方ないので先週のBlogの記録を持っていきました。
Sample Particles From Other Emitter ModuleをParticle Spawn Sectionに追加する事がPointですね。
<RibbonのRendering方法の復習>
あれだけ勉強したRibbonのRenderingの方法を忘れてしまっていました。復習します。
<<Ribbonの理論>>
まずRibbon Renderingの理論ですが、2021-07-04のBlogによくまとまっています。
簡単にまとめると
Ribbonは以下の様に生成されます。
緑の菱型の数がSpawn Rateで指定した数に当たります。
それぞれの緑の菱型は
Lifetimeで指定した時間だけ存在します。
後、Ribbonの幅はParticle Spawn Section のInitialize Ribbon ModuleのRibbon Width で指定します。
<<Ribbonの作り方>>
前のBlogにおけるRibbonの作成方法も読んだんですが分かりにくい。
私が新しく「Ribbonの作り方Tutorial」をここに作ります。
Niagara SystemからEmpty Templateを追加して新しいEffectを作成します。
Emitter Update SectionにSpawn Rateを追加します。
Particle Update SectionにGravity Forceを追加します。
こんな感じになりました。
このSpriteをRibbonに変換します。
まずRender sectionのSprite Render Moduleを消してRibbon Renderer Moduleを追加します。
Ribbon Renderer ModuleのMaterialにDefault Ribbon Materialを追加します。
こんな感じになります。
次にParticle Spawn SectionにInitialize Ribbon Moduleを追加します。Initialize Ribbon ModuleはInitialize Particleの後にセットします。
こんな感じです。
Ribbon出来ました。
少しだけ微調整します。
Particle Spawn SectionのInitialize Ribbon ModuleのRibbon Widthの値を50に変更して
Ribbon の幅を太くしました。
更にInitialize Ribbon ModuleのLife timeの値を1.5にしてRibbonを長くしました。
以上です。
一つ疑問ですがParticle Spawn SectionのInitialize Particle Moduleは要らない気がしています。
試しに外して見ましたが、Effectに変化は見られなかったです。
<Scale Ribbon Width Module>
このModule自体よりもRibbonのサイズを管理している変数は何かに興味があります。
Initialize Ribbon ModuleのDynamic InputであるRibbon Widthの値はParticle のRibbon Width変数にパスされていました。
と言う事はParticle のRibbon WidthがRibbonのサイズを管理する変数と言う事なんでしょうか?
そのようですね。
Scale Ribbon Width Module内でもRibbonのサイズを変更する時は、Ribbon Widthの値を変更しています。
以上でしょうか?
2.3 Disintegration in UE5 Niagara Tutorial | Download Files [3]を勉強する
Disintegration Skeletal Mesh FX in U5 Niagara Tutorial [4] をやろうとしたら、
このTutorialで使用しているMaterialはDisintegration in UE5 Niagara Tutorial | Download Files [3]で作成したヤツだからそっちを参考にしてと言っていました。
なのでDisintegration in UE5 Niagara Tutorial | Download Files [3]を勉強する事にします。
どっちもBuilding advanced effects in Niagara | Unreal Engine [4] の派生ですね。
ParticleをCurl Noise で飛ばすかParticleにSpriteを貼り付けて炎のEffectを出している違いだけです。
ただCGHOW氏の方はActorの足がParticle化していないんです。こっちのやり方の方が精錬されています。
Content ExampleのNiagara_ Advancedにも同様のTechniqueが紹介されています。
こっちは一回NSの実装を見たけど途中で理解出来ない部分があり、中止しています。
そう言えばUE5で制作中のGame、Black Myth: WukongのTrailerでも似たようなEffectが使用されていました。
Black Myth: Wukong - Official Unreal Engine 5 Gameplay Trailer [6] より
Meshがparticle化するEffectはかなり基本的な技術のようです。
良し。今回はこの技術の習得を目指して勉強します。
前、Building advanced effects in Niagara | Unreal Engine [4]を勉強した時は、CGHOW氏のTutorialをやっても再現も出来なければやっている内容の意味も分からないLevelだったので、CGHOW氏のTutorialと比較してBuilding advanced effects in Niagara | Unreal Engine [4]がどれだけ分かり易いがが焦点でした。
のでMeshが消えてその代りにParticleをMeshに沿って生成させる技術の理解はニの次でした。実際、どうやってそれを実現させたのかは分かっていません。
今回は、その辺の技術に注目して勉強しようと思います。
- Meshが消える技術
- ParticleをMeshに沿って発生させる技術
- 発生したParticleを動かす技術
などについてです。
2.4 Building advanced effects in Niagara | Unreal Engine [4] の復習
Disintegration in UE5 Niagara Tutorial | Download Files [3]を勉強する前にBuilding advanced effects in Niagara | Unreal Engine [4] の復習をやっておきます。特に
- Meshが消える技術
- ParticleをMeshに沿って発生させる技術
- 発生したParticleを動かす技術
についてどうやったのかを復習しておきます。
調べるとBuilding advanced effects in Niagara | Unreal Engine [4] の勉強は2021-09-06のBlogから開始しています。
<ParticleをMeshに沿って発生させる技術>
Initialize Mesh Reproduction Sprite Moduleを使用しています。
ただこのModuleが指定されたMeshに沿ってSpriteを発生する以外の機能については分かっていないと書かれています。
Meshに沿ってSpriteを発生させるModuleは以下に示したように沢山あるじゃないの?
と書かれていました。
この辺は今回の勉強でも注目します。今回、勉強するTutorialでもInitialize Mesh Reproduction Sprite Moduleを使用するのか?するならばその理由は何なのか?などが注目するPointになるでしょう。
<発生したParticleをMeshの動きに追随させる技術>
Particleを発生させる事が出来てもそのParticleはMeshの動きには追随しません。
それを直すために以下の事をしています。
今回のTutorialはStatic Meshに対してなのでこの技術が使用されるかどうかは分かりません。その次に行うDisintegration in UE5 Niagara Tutorial | Download Files [3]では注目すべき個所です。
<発生するParticleの色をMeshのMaterialの色と同じにする>
これは以下に示したように出来なかったんです。
最新のCrunchは沢山のMaterialを使用していてTutorialで使用されているCrunchは一個のMaterialしか使用していませんでした。Meshが一個のMaterialしか使用していない時のやり方はTutorialから理解出来ましたが、Meshが複数個のMaterialを使用していた場合のやり方が分からなかったです。
今回のTutorialはMeshにあるMaterialと同じ色を発生する必要はないのでこの技術は謎のままです。
<Spriteが四角な事、Spriteが常にカメラを向いている事>
うーん。こんな事も勉強していたんですね。
すっかり忘れていました。
カメラの向きは以下の方法で直します。
ただこの方法で直せるのは以下の理由があるからだそうです。
成程と書いていますが、その理由が書いていません。
今考えると、Custom Facing Vectorが一個一個のNormal Vectorを指しているはずです。Meshは動きますが一個一個のNormal VectorはUpdate Mesh Reproduction Sprite Moduleで常に最新の状態にUpdateされます。
多分、こう考えて成程と書いたんだと思います。
Spriteを丸くするのは以下の方法でやっています。
PointはRadial Gradient Exponential ノードを使用してる所です。
ここからは2021-09-12のBlogになります。
<CrunchがObjectに触ったらCrunchのMaterialが消える方法>
この部分はあんまり丁寧に書かれていなくて良く分からない部分もありました。
分かった範囲で書くと
以下の実装をMaterialのOpacity Maskに追加すると
以下の様にParticleが発生する箇所のMeshのMaterialが消えます。
この部分の実装に関しては2021-09-19のブログで詳しく解説されています。
簡単に説明するとDitherTemoralAAノードはMaterialを透明にするノードです。
例えば以下の実装だと
こんな感じにMaterialを消します。
このTutorialで使用した実装を元にした以下の例では
Subtract ノードとDivideノードの値によって以下のような変化を示します。
これでMaterialを消している訳です。
ただしこの方法だと発生したParticleはバラバラになって移動しません。
そのためには以下のような新しいModuleを作成して
色々やっているんですが何をやっているのかが良く分かりません。
実際の記録でも
と書いてありました。
この辺が何をやっているのかを理論のレベルから理解するのも今回の課題にします。
<Building advanced effects in Niagara | Unreal Engine [4] の復習まとめ>
復習した事で以下のPointで重要な情報が得られました。
<<ParticleをMeshに沿って発生させる方法>>
Building advanced effects in Niagara | Unreal Engine [4]ではParticle Spawn SectionでInitialize Mesh Reproduction Sprite Moduleを使用する事で可能にしています。
<<Meshを消す方法>>
Material内でDither Temporal AA ノードを使用する事で可能にしています。
<<発生したParticleを動かす方法>>
この部分はどうやっているのか分かっていません。
2.5 Disintegration in UE5 Niagara Tutorial | Download Files [3]の勉強の続き
ぱっと一回見ましたが結構違う方法でやっています。
取りあえず今週はやれる所までやってみて、検討は来週以降します。
Fountain Templateを追加したNiagara Systemを作成しました。
要らないModuleを全部消した後、Particle がMeshに沿って発生するためにSample Static Mesh ModuleとStatic Mesh Location Moduleを使用しました。
Sample Static Mesh ModuleのPreview MeshとDefault MeshにはSM_Chairをセットしました。
こんな感じです。
Materialを作成します。
SM_Chairに適応しました。
Emitter Properties ModuleのSim TargetをGPUに変更してSpawn Rateを10000に変更しました。
イスが見えます。
このParticle がMeshのMaterialを侵食して発生するようにします。
イスをLevel上に配置します。
Materialに以下の実装をします。
上記のMaterialのInstanceを作成してそれをイスのMaterialに適応します。
適切な値を選択すると以下の様にイスのMaterialがある部分だけ消滅します。
Materialを消すのにSphere Maskノードを使用しています。後でこのノードについては調べます。
今度はこの球に境界線を追加します。
以下の実装をMaterialに追加しました。
3ColorBlendノードの機能が良く分かりません。後で調べます。
こんな結果になりました。
このMaterialを使用すると以下の様に椅子の消えた部分との境目に境界線が現れました。
今度は消えた部分からParticleを発生させます。
まず以下の先程作成したModuleを消します。
えー。何で?
折角新しいModuleを習ったと思ったらもう消すそうです。
理由がColorがVertexの Colorを使用しているからだそうです。MaterialのColorを使用したいそうです。
以下の部分がそうみたいです。
これだけ見るとVertexのColorの値をPassしているのかどうかは分かりませんね。これも後で検討します。
消したSample Static Mesh ModuleとStatic Mesh Location Moduleの代わりに以下のModuleをScratch Pad Moduleを使用して作成します。
Dynamic Material Parameterが何をしているのか不明です。
この変数は何を管理しているんでしょうか?
UV値をパスしていると言う事はTexture関連の変数なんでしょうか?
今度は先程作成したMaterialをDuplicateします。新しい方のMaterialの名前をM_ParticleBodyと名付けます。そして以下のコードを追加します。
先程のScratch Moduleで使用したDynamic Material ParameterはこのMaterial内で使用しているDynamic Parameterとlinkしているんでしょうか?
そうすると理屈が通りそうですね。
この部分の意味は分かりましたがこのMaterialをどうすんでしょうか?
Render SectionのSprite Renderer ModuleのMaterialにセットしました。
うーん。これってどういう事?
これってParticleをMeshがある部分だけ生成すると言う事でしょうか?
何も生成していません。
Particleが生成する箇所を逆にするために1-xノードを消しました。
こんな感じです。
そしてNSそのものをMeshに重ねています。
所が私のNSは
全部Particleになっています。しかも移動してくれません。がっちりCenterに位置しています。
理由が分かりました。
このMeshが消える球が原点に位置しています。NSもMeshも原点に置かないと消滅したりParticleになったりする位置が変わってしまいます。
両方を原点に設置したら以下の様になりました。
そう言う訳で出来てはいました。この原点から移動出来ない理由は後で調べます。
今度はParticleの位置とMeshの位置を手動でコントロール出来るようにします。
Material Functionを作成します。
ここにFloat型のParameterであるRadiusを作成します。
これを先程作成した二つのMaterialのRadiusと交換します。
これでMaterial Functionを使用してMeshとParticleの位置が自由に移動出来るようになりました。
今度はParticleに速度を与えて動かします。
Particle Update SectionにCurl Noise Force Moduleを追加します。
値を色々微調整して
今度は境界線の部分だけParticleが発生するようにします。
流石に疲れて集中力が切れてきました。残りは、来週やる事にします。
3.Material : 先週の復習など
今週もBen Cloward氏のShader Graph Basics [7]の勉強をしていきます。
先週のBlogのMaterialの箇所を読み直しましたが特に復習しなければならない箇所はないように思えます。
先週のBlogを読み返した感想としては習った基礎の応用方法を忘れないようにしたいです。
3.1 Input Vectors - Shader Graph Basics - Episode 9 [8] を勉強する
正直、集中力が切れてしまっているのでゆっくりやります。
最初の疑問ですがInput Vectorって何を指しているんでしょうか?
これが調べたんですが良く分からない。ならこのTutorialを見た方が早いと兎に角、最初から見る事にしました。
Tutorialでは以下の3つがInput Vectorとして紹介されていました。
<Surface Normal >
まあ当然ですね。Normal Vectorの事ですね。
既にNormalization(正規化)された状態で保存されています。
<Camera Vector>
カメラから物体に当たるまでの距離と角度を保存しているVectorだそうです。このVectorはPixel一個一個が保持しているんでしょうか?
Normalization (正規化)はされていないそうです。
<Light Vector>
光源からその光が当たる物質との角度と距離を示すVectorです。
Normalization (正規化)はされていないそうです。
UEではlightの計算は後で行う(Deferred)からMaterial内で使用する事は出来ないそうです。このRenderingの方法をDeferred Renderingと言うそうです。
<Vertex Normal WSノードなどについて>
Vertex Normal WSノードは公式のDocumentであるCoordinates Expressions [9] には
と説明されています。
TutorialではWorld Spaceについては後でしっかり解説するので今は計算するVectorが同じSpaceにいる事だけを確認しておけば大丈夫といっています。
そこは当然と思ったんですが、SpaceにはWorld Spaceの他にObject Space、Tangent Spaceがあるそうです。
World SpaceってWorld Coordinateと同じと思っていましたが違うのかもしれません。
Vertex Normal WSを使用して以下の実装を組みました。
こんな結果になりました。
これだけではLightの影響が分からないので以下の場合も試しました。
こんな感じです。
思ったより明るいですね。(0,1,0)と垂直になる球の中央が白いのはわかりますが、先週の例のような黒さは出てないです。
設定をUnlitにしたら以下の様になりました。設定の問題でした。
Tutorialによると以下の実装でも同じ効果が得られるそうです。
確かに計算結果は同じですね。
<Camera Vectorなどについて>
まずCamera VectorとVertex Normal WSで以下の様にDot Productを実装します。
結果です。
今度はCamera Vector はNormalize(正規化)されていないのでNormalizeノードを追加します。
こんな結果になりました。
あれ、同じ?
実はUEのCamera Vectorは最初からNormalize(正規化)されているそうです。
今度はPowerノードを実装します。
Power = 2の時です。(Powerとは乗数の事です。)
Power = 3の時です。
Power = 5の時です。
One Minusを使用して白黒を逆にする事も出来ます。
こんな感じです。Fresnel Reflectionと同じ効果になります。
Normalize(正規化)されていないCamera Vectorを使用したい時もあります。
例えばCameraから写っているActorへの距離を知りたいときです。
そんな時は以下の実装でNormalize(正規化)されていないCamera Vectorを得る事が出来るそうです。
うん。と言う事は以下の関係が成り立つと考えられるので
Absolute World PositionはActorの位置を指していると思われます。
この実装を使用してCameraから写っているActorへの距離を計算するには以下のようになります。
しかし実際の実装を見ると以下の様にその後にSubtractノードとDivideノードが追加されています。
これらの働きは何なのでしょうか?
まずSubtractですが、上記の例だと500 cm つまり5mの距離内にあるActorは全て真っ黒(0)になると言う意味です。Offsetと同じです。
次のDivideですが、5000cmになっています。つまり50mです。この50mの間で真っ暗から真っ白、0から1に変化すると言う事です。50m以上離れたActorは真っ白になります。Mask Lengthと同じです。
と解説されていました。
これは分かり易いです。この説明でやっと意味が分かりました。
Tutorialでやっていたのと同様のテストも試してみます。
カメラに近い時です。
球は真っ黒です。
球をカメラから放すと色が薄くなりました。
球をもっと放すと白くなりました。
<Light Vectorノードについて>
以下に示したようにLight VectorノードとVertex Normal WS ノードでDotした値をBase Colorに繋ぐとErrorになります。
以下の様な説明がされていました。
UEではDeferred Rendering方式を採用しているのでLightの計算はMaterialの計算をした後で行うそうです。なのでこのErrorの説明はMaterial内でLight Vectorを使用する事は出来ないと言っている訳だそうです。
ウオー。
こういう事を知りたかった。
と言う事はLight FunctionやDeferred Decal MaterialはLightのRenderingが終わった後でやる特殊なMaterialと言う事も同時に理解出来ました。
Light VectorノードとVertex Normal WS ノードでDotした値をBase Colorに繋ぐのは単にDiffuse Lightingの計算でPreviewをLitで見れば、Diffuse Lightingは既にEngine側で計算されているのも分かります。
成程。
後、このDiffuse Lightingの計算はG-buffer内で行われるとありました。
そう言えば、Disintegration in UE5 Niagara Tutorial | Download Files [3]で、CGHOW氏が「○○さんはUEで同じTechniqueを作成していますが、彼はG-bufferを使用して作成しました。私のNSはG-bufferは使用していません。」と言っていた気がします。
G-bufferやDeferred RenderingそのものについてはDeferred Shading [10] で詳しく解説されています。これは後で勉強します。
Tutorialはこの後はUnityの場合の解説でした。
同じ事をUnityでやってるだけですが結構実装方法に違いがあって面白いです。
UEでVertex Normal WSノードにMaskをしてDot Productと同じ効果を出すやり方をUnityでやっています。
この部分です。
この計算が以下と同じと言う奴です。
所がUnityの場合はG(1)が上下の軸を表してるだそうです。
だから以下のようなImageになるそうです。
Unityの公式のDocumentのTransforms [11] には以下の説明図が載っていました。
そう言えば、昔UE4の軸がオカシイと何回も計算した記憶があります。
調べたら2019-05-05のBlogでした。
z軸の回転方向が一般の場合と逆だ。と書いてありました。Unityの軸とは関係なかったです。
次はUnityにおけるFresnel Reflectionの実装です。
ここで大切なのがUEにおけるCamera VectorとUnityのCamera Directionは向きが逆で、Unityの場合はNegateノードを使用する必要がある事だそうです。
UnityにおけるCameraから写っているActorへの距離の計算です。
ここでもCamera PositionとPositionからNormalize していないCamera Vectorを計算して使用しています。Camera VectorがNormalizeしてないと言った最初のコメントは何だったんでしょうか?
後、Unityでは単位がmだそうです。上記のSubtractで9.5が代入されていますが、9.5mの事だそうです。
3.2 View, World, Object, & Tangent Space - Shader Graph Basics - Episode 10 [12] を勉強する
知らなかった事を記録しておきます。
View SpaceはZ軸がカメラの見ている方向になっています。
Tangent Spaceについてです。
Vertices一つ一つが持つCoordinateの事のようです。
赤がそのVertexのNormal、青と緑がUVを表しているそうです。
ここからはCoordinateが違うVector同士の計算方法についてです。
<Spherical Coordinate>
Spherical Coordinateは別名をMat Cap Reflectionsと言うそうです。
Spherical Coordinate用のTextureを手に入れます。
Tutorialと同じモノにしました。
このTextureをそのまま使用すると
こうなります。
Vertex Normal WSを直接繋げた場合は
こうなります。
この二つを上手く使ってTextureが球の反射をしているかのように表現します。
以下の様に実装します。
結果です。
ここで使用した重要なノードであるTransform Vectorノードについて解説します。
以下の様にセットする事でWorld SpaceをView Spaceに変換します。
それがどういう事かを示すために以下の実装で試すと
以下の結果が表示されます。
Vertex Normal WSのみとの違いは幾らObjectを動かしても色が変化しない事です。
この値をTexture Coordinateとして使用するそうです。
そのまま使用した場合は
こうなります。
4つのTextureが表示されていると言う事はUVの両方を0.5倍すれば1個のTextureが表示されるはずです。
Vが‐0.5なのは向きを上下逆にするためだそうです。UEのCoordinateのY軸が下に向かって+だからでしょうか?
結果です。
Textureの中心がずれています。UV両方に0.5を足します。
結果です。
<Tangent Space to World Space>
以下の実装をします。
こんな感じです。
ここに苔を生やします。
もし単純に苔のTextureを使用すると
以下のようになり、全然作成したいImageと違うものになります。
今度はLerpを使用してBlendします。
半々でBlendします。
緑がかった石になりました。
今度はVertex Normal WSを利用します。以下の実装をすると
以下の様になります。
これをLerpに使用すると以下の様な実装になり
こんな結果になります。
前よりはかなりマシですがそれでも変です。
何が変かと言うと岩のゴツゴツが苔の生えている部分にはないんです。
じゃあ、岩のNormalをLerpのAlphaに使用したらいいんじゃないでしょうか?
所が、岩のNormal MapはTangent SpaceなのでWorld Spaceとは繋げないんです。
はい。
Transform Vector ノードを使用します。
以下の様にです。
Tutorialによると岩のTextureをTransform Vectorノードを使用してWorld Spaceに変更した後は必ずSaturateをして‐の値を消す必要があるそうです。
後は一緒です。
こんな感じになりました。
このやり方の凄い所がTutorialで説明されていました。
このMaterialを使用した岩を下に示します。
この岩を回転させると
それでも苔は岩の上だけに生えています。
はあー。凄いです。
これならこのMaterialを使用すれば岩を色々な角度に配置するだけで凄いリアルな岩山が作成出来ます。
私のRPGのこの岩山のMaterialに使用したいです。
99%はこのMaterialの方が良いですが、極稀に岩を転がす場合が存在します。
その時に苔が常に上に移動したら変です。その場合の対策をこれからやります。
Transform VectorノードのDestinationの値をWorld SpaceからLocal Spaceに変更します。
以上です。
Object SpaceはどうやらUEでいうLocal Spaceの事だったようです。
ここでUEは終でUnityのMaterialに変わります。
やっている内容は全く同じなので特に記録したい事はなかったです。
以下にUnityで作成した苔の生えた岩のPreviewを示します。
言ってはアレですがUEに比べるとかなりショボいです。
これは使用しているTextureの差が大きいように思えます。
Quixelの超高品質のTextureがそのまま使用出来るUEはGraphicsに関してはUnityを完全に制圧していますね。
もう一個Tutorialをやる予定だったですが、結構疲れてしまいましたので、ここでMaterialの勉強は終了します。
Ben Cloward氏のTutorialは質が高くてかつ親切で分かり易いです。来週もこのTutorialで勉強します。
4.AIの復習の続き
4.1 先週の復習
先週、NPCにAIを追加してもっと人間らしい動きを再現しようとしたのですが、UE4_AIのやり方をほとんど全部忘れていました。のでMonsterのAIを作成した時のBlogを見直してUE4_AIの復習をする事にしました。
Blogを読み直すと、何を言っているのか分からない箇所が多々ありました。これは半分は私のUE4_AIの知識がその当時程無くなってしまったためですが、残り半分はBlogの書き方が悪いからです。
そこでUE4_AIについて書かれた箇所を、もう一回まとめ直す事にしました。
以下の様にまとめ直す事にしました。
<基礎編>
- UE4_AIは単なるIF節!
- UE4_AIを構成する4つのクラスとその繋ぎ方
- Task BPとService BPそしてDecorator BPについて
- Task BPのAbort関数、Execute 関数、そしてTick関数
- Task BPのFinish Execute ノードとFinish Abortノード
- SequenceとSelector
- Debugのやり方
- Observer Abortの機能について
<応用編>
- AI Perceptionについて
- EOSについて
しかし量が多すぎたのでまとめきらないで先週は終わってしまいました。今週はその続きをやります。
番号が先週と全く変わってしまうと、後から見た時に訳分からなくなるので、番号を先週の続きから始める事にします。
5.AIの復習の続き Part 2
先週、途中までやったUE4_AIのまとめの続きを行います。
番号が先週と全く変わってしまうと、後から見た時に訳分からなくなるので、番号を先週の続きから始める事にします。
5.6 Task BP、Service BPそしてDecorator BPについて
そうだ。思い出しました。今までUE4のAIは単なるIF節です。しかしBehavior Treeシステムを採用しているので単なるIF節を書くのに4つのクラスを使用する必要があるんです。
と説明していたら、Behavior Treeを作成するのにTask BPと言うクラスが必要だと判明して、整合性が取れなくなってしまったんです。
実際、Behavior Treeを作成するためにはTask BPだけでなくService BPとDecorator BPも必要です。
しかもこのService BPとDecorator BPの機能について全く覚えていません。その復習をまずやります。
分かりました。
2021-02-01のBlogでTaskですべき内容とServiceですべき内容について熱く語っていますが、
UE_AIを通常のAIに当てはめて考えるから色々矛盾が出て来る訳で、単なるIF節と考えれば何の問題もありません。
If節の“何かの条件を指定“する為のクラスが、Decorator BPです。
そして“実行する内容”を指定するのが、Task BPとService BPです。
Task BPとService BP の違いはBehavior Treeの最後のノードで実行する内容を指定する場合はTaskノードが使用され、Behavior Treeの途中で実行する内容を指定する場合はService BPが使用されます。
先週作成したテスト用のBehavior TreeだとSequenceノード内に“実行する内容”を指定する場合はService BPが使用されます。
では試しにService BPを作成して試してみましょう。
<Service BP>
Behavior TreeのNew ServiceからBTService_BlueprintBaseを選択します。
するとBTService_BlueprintBaseが開きます。
Browseボタンを押してこのクラスが作成された箇所に飛びます。
名前を変更します。FirstServiceとします。
名前を変更したらFirstServiceのBP内に戻ります。
そこに以下のコードを追加します。
今度はBehavior Treeに戻り、Sequenceノードに先程作成したFirst Serviceを追加します。
こんな感じになります。
実行してみます。
First Serviceの内容が実行されました。
では最後のif 節の条件を指定するDecorator BPについて解説します。
<Decorator BP>
実はDecorator BPはService BPやTask BPと比較すると使用方法を理解するのが比較的難しいんです。
その理由ですが、IF節の条件は以下に示したように
X = 0
「Xのような変数の値が0の時は…」と言う指定の仕方をするからです。
そしてUEのBehavior Treeは変数の値を保持する事が出来ないんです。だからBehavior TreeはBlackboard クラスのInstanceを利用して値を保持します。このBlackboardクラスの使用方法を先に理解する必要があるんです。
と言う訳でDecorator BPの使い方を理解する前にBlackboard クラスの使用方法を勉強します。
<Blackboard クラスの使用方法>
今まで何回もBlackboardクラスはBehavior Treeのために変数の値を保持しますと言いました。
どうやって保持するのでしょうか?
それをここで解説します。
まずBlackboardクラスを開きます。すると以下の様になっています。
以下に示した様にNew Keyを押すと変数が作成出来ます。
今回は一番簡単そうなBoolean型を選択します。名前はFirstBB_Variableとしました。
以上です。
え。
いやいや、作成したBoolean型である変数に値をセットしていないじゃないですか?
Behavior Treeの変数の値を保持するのがBlackboardクラスの役目なのにBlackboardに作成した変数の値を指定しないのってオカシイじゃないですか?
はい。
その通りです。
しかしBlackboardクラスの役目はあくまで変数の値を保持する事なのでBlackboardクラスからはBlackboardクラス内の変数の値ですら指定する事は出来ないんです。
それが出来るのはBehavior Treeなんです。
<<Behavior TreeからBlackboardクラスの変数の値を指定する>>
もう色々なクラスを行ったり来たりして頭が大分こんがらがって来てると思います。
今の状況を簡単に整理します。
Behavior Treeの使用方法を理解するためには3つのクラスの使用方法を勉強する必要がありました。その内の2つTask BPとService BPについて勉強しました。残りのDecorator BPの使用方法を理解するためには、Blackboardクラスの使用方法を理解する必要があり、Blackboardクラスにおける変数の値を指定するためには、Behavior Treeから指定する必要があると分かりました。
Behavior Treeの使用方法を理解するためにはBehavior Treeを使用する必要があると言う地獄のような状況です。
はい。
でも大丈夫です。
Blackboardクラスにおける変数の値を指定するためにBehavior Treeで使用するのは、今まで勉強したTask BPとService BPのどちからで可能だからです。
現在、Behavior Treeは以下の様になってます。
First TaskにDecorator BPを追加して、先程Blackboardクラスで作成したBoolean型である変数、FirstBB_VariableがTrueだったらFirst Taskを実行するように設定したいです。
そうなるとBlackboardクラスのFirstBB_Variable変数の値は、その前のSequenceにあるService、FirstService内で指定するのがよさそうです。
FirstServiceのBPを開きます。
最後のノードであるPrint StringにBlackboardクラスに値をセットするためのノードを繋げます。
そのノードの名前は、Set blackboard Value…です。そのものズバリの名前ですね。
今回はBlackboardのBoolean変数に値をセットするのでSet blackboard Value as Boolを選択します。
すると以下の様なノードが表示されます。
ここでValueの意味は直ぐに分かります。この値がBlackboardクラスのFirstBB_Variable変数にセットされるはずです。Trueにしておきます。
残りのKeyですが、これは何を指定するでしょうか?
はい。
ちなみにKeyを指定しないとErrorになります。
それでは答えから先に言います。
Blackboard内の変数は今はBoolean型が一つしかありませんが、後々、2つ3つと増えていきます。この時にどのBoolean変数を指しているのかを指定する必要があります。
Blackboard内のどのBoolean変数の値をセットするのかをKeyで指定する必要があります。
ただしこのやり方がまたちょっと複雑になります。
それはServiceクラスであるFirstServiceは直接はBlackboardクラスとやり取りする事が出来ないからです。Behavior Treeを通してしかやり取り出来ません。
ではそのやり方を指定します。
まずService BP内で新しい変数を作成します。取りあえず名前はFirstBB_Keyにしました。
目をクリックしてPublicにします。なぜこれをしないといけないのかについては後で説明します。
この変数のタイプをBlackboard Keyにします。
この作成した変数、FirstBB_KeyをSet Blackboard Value as BoolのKeyに繋げます。
はい出来ました。
ここでCompileするとErrorも消えます。
いやいや、ちょっと待って下さい。まだBlackboardクラスのFirstBB_Variable変数にこの値をセットして下さいって指定していませんよね。
はい。
それをこれからやるんです。
正しそれはService BPであるFirstServiceでは行いません。Behavior Tree内で行います。
Behavior Classに戻ってFirst Serviceを選択すると、以下に示したように先程作成した変数であるFirst BB Keyが表示されています。
ここにBlackboardクラスのBoolean型の変数であるFirst BB Keyをセットします。
これでやっとBlackboardクラスに作成した変数に値をセット出来ました。
最後にFirst Service内の変数であるFirstBB_KeyをPublicにしないといけないのかについて説明します。
Privateに戻しました。
するとBehavior TreeからFirst Serviceを選択してもFirstBB_Keyが表示されません。
なのでFirst Service内の変数であるFirstBB_KeyはPublicにする必要があります。
<Decorator BP の使い方 Part 2>
はい。とうとうBlackboard クラスの変数、FirstBB_Keyの値がセットされました。
なのでDecorator BPで
If( FirstBB_Key == True)
を実装します。
実はDecoratorには既にBlackboardの値に対応しているモノがあります。
Blackboardです。折角あるのでこれをそのまま使用する事にします。
こんな感じになりました。
そしてBlackboard Based ConditionのBlackboard KeyにFirstBB_Variableをセットします。
これだけです。
テストしてみます。
Blackboard Based ConditionがTrueなのでFirst Taskが実行されました。
今度は、First Service 内のSet Blackboard Value as BoolのvalueをFalseにします。
今度はFirst Taskは実行されません。
はい。やっとUEのAIにおける
を曲りなりにも作成出来ました。
しかし実は、工程を分かり易くするために、やってはいけない事とか、もっと詳しく知らないといけない事とかを全部省いてここまでやりました。
その補正をこれからやっていきます。
5.7 SequenceとSelectorについてとTask BPのFinish Execute ノードについて
先週、SequenceノードとSelectorノードについての違いを解説しないまま、先に進んでしまいました。
のでSequenceノードとSelectorノードについての違いから始めたいと思います。
SequenceノードとSelectorノードについての違いは以下の様に説明されています。
このChildのノードが成功とか失敗とはどういう意味なのかを含めてSelectorとSequenceの違いを解説します。
先程作成したBehavior Treeを以下に示したように簡単にします。
First Taskの中身も以下の様に変更します。
Taskを後3つ程増やします。
First TaskをDuplicateしました。
Printする内容を少しだけ変更します。
これを以下の様に接続します。
ここで結果を予測します。
SequenceはChildrenの内一つが失敗を返すまで左から右へとそれぞれのChildを実行するとあります。
そこから予測すると
First Task、First Task 1、First Task 2、First Task 3とPrintされると予測されます。
実行すると
First TaskしかPrintされません。
え。じゃ最初のTaskが失敗を返してるの?
と思うかもしれません。
もしそうならSequenceノードの代わりにSelectorノードを使用したら、先程の予想のようにFirst Task、First Task 1、First Task 2、First Task 3が返されるはずです。
なぜなら、SelectorノードははSequenceノードとは逆にChildrenが成功を返すまで次のChildを実行するからです。
以下の実装で試してみます。
ところが、今回もFirst Taskしか実行されません。
何でしょう?
実は、First Taskは成功(success)も失敗(fail) も返していないんです。そればかりか、First Taskの実行は終了すらしていません。
<Finish Execute ノードについて>
Taskの実行を終了させるためにはFinish ExecuteノードをEvent Receive Executeの最後につける必要があります。
ただし、これはEvent Receive Executeで始まっているからで、
他のEventの場合は、別なFinish ノードを使用する必要がありますが、それについては又後で説明します。
First TaskにだけFinish Executeノードを追加してSuccessをチェックします。
更に、Sequenceノードに戻します。
これでテストします。
今度も結果を先に予測します。
まずFirst Taskが実行されますので、First TaskがPrintされます。その後Finish Executeノードが実行されSuccessが返されます。SequenceはFailが返るまで次々とChildrenを実行するので次のFirst Task1が実行されます。しかしFirst Task1にはFinish Executeノードが繋がっていないので、そこでずっと実行した状態になります。
のでFirst Task、First Task 1がprintされます。
想像した通りの結果になりました。
では今度は、全部のTaskにFinish ExecuteノードをつけてしかもSuccessにチェックを入れたとします。
結果はどうなるでしょうか?
今までの理論から考えれば、First Task、First Task 1、First Task 2、First Task 3とPrintされるはずです。
試してみましょう。
何と、First Task、First Task 1、First Task 2、First Task 3を繰り返してPrintしています。
はい。実はRootノードからの実行の指令は、Tick関数のように何度も何度も送られて来ていたんです。
それが今では、Task内でFinish Executeノードを使用していなかったためTask内の実行がいつまでたっても終わっていない状態になっていたんです。
<この節のまとめ>
SequenceノードはそのChildがFailを返すまで、SelectorノードはそのChildがSuccessを返すまで左から右へと次々にChildを実行していきます。
正しTaskがSuccessやFailをその親ノードに返すためにはFinish Executeノードを使用する必要があります。
Finish Executeノードが使用されていないTaskはずっと実行中の状態になり、そこでAIの作業は停止してしまいます。
5.9 Task BPのAbort関数、Execute 関数、そしてTick関数とFinish Abortノードについて
Task BPを開くとReceive ExecuteだけじゃなくてReceive AbortとかReceive Tickとかがあります。
これらはReceive Executeとどう違うのでしょうか?
まずTick関数から説明します。
<Event Receive Tickノードについて>
Receive Tickノードの機能について説明するためにBehavior Treeを以下の様に変更します。
ここでFirst Task BPの中身を以下の様に変更します。
Finish ExecuteノードがないのでこのTaskはずっと実行されます。
Executeノードの時は、一回だけ実行されてその後は何も起きませんでしたが、Tick関数だったらどうでしょうか?
このTaskが実行されている限り、ずっと実行されるはずです。
試してみましょう。
予想通りの結果になりました。
今度はEvent Receive Abortノードについてです。
<Event Receive Abortノードについて>
今度はEvent Receive Abortノードについてです。
このノードはこのTaskを実行中に何らかの事情で、このTaskの実行が中止になったら実行されます。
以下の実装をTaskに組みます。
Playを押してゲームを開始しても何も表示されません。
Escキーを押してゲームを中止します。
するとPrintされました。
この機能は後で勉強するDecoratorクラスのObserver abortsに関係してくるのでその時に更に詳しく説明します。
5.10 Debugのやり方
UE_AIのDebugのやり方ですが覚えていません。
これが出来ないと次のObserver abortsの検証も出来ないので、一端、勉強し直します。
2021-02-01のブログにDebugのやり方が簡潔にまとめられていました。
もうそのままやればDebug出来ます。
一応、まとめの練習としてここにもDebugのやり方をまとめておきます。
まずBehavior Treeを開いたままPlayボタンを押してゲームを始めます。
都合の良い所でPauseをします。
Behavior Treeに戻ると以下の図のように今どのTaskが実行されているのかが記されています。
記されていない時は以下の赤く囲った箇所に調べたいAI Controllerの名前をセットして下さい。
そうすれば表示されます。
この状態でBack:IntoかBack:Overをクリックすると
一手前にどんなTaskが実行されたとかが一目瞭然になります。
更に、10手位、遡って
を使用するとどんな手順でTaskが実行されているのかが一手ずつ順番に示されます。
以上です。
Debugにはもう一つ、以下に示した方法があります。
どちらかと言えばこっちの方が大切なんですが、今回はNav Mesh Bound Volumeの説明まで行かないのでこのDebugについては応用編を作成する時に説明する事にします。
5.11 Observer Abortの機能について
基礎編の最後にDecorator BPのObserver abortsのNone、Self、Lower Priority、そしてBothについて解説します。
公式のDocumentであるBehavior Tree Node Reference: Decorators [13] によると
と説明されていますが実際にどういう事なのかを解説します。
2021-02-07のブログに詳しいテストのやり方が説明されていました。
ただこのテストと同様の物を作成するとなるとAI ControllerからBlackboard の変数の値をセットする方法を使う必要があります。
ので今週は口だけで説明します。
<None>
以下の図でPrintString2が実行されている時に、Blackboard Based Conditionの条件を満たした場合、このBehavior Treeは
PrintString3を実行します。そしてPrintString3の実行が終わった後でSelectorに戻り、Blackboard Based Conditionの条件をチェックして満たしている事を確認します。そしてPrintStringを実行します。
<Self>
以下の図でPrintStringが実行されている時に、Blackboard Based Conditionの条件を満たさなくなった場合、このBehavior Treeは
PrintString1の実行をAbortしてSelectorに戻り、Print String 2を実行します。その後、Print String 3を実行します。
<Lower Priority>
PrintString2が実行されている時に、Blackboard Based Conditionの条件を満たした場合、このBehavior Treeは
Print String 3の実行をAbortしてSelectorに戻り、Print Stringを実行します。その後Print String1を実行します。
<Both>
BothはSelfとLower Priorityの混合です。
以下の例はLower Priorityと同じ行動をしています。
以下の例ではSelfと同じ挙動を示してます。
このテスト用のBehavior Treeの作成方法とDebugによるDecoratorの結果が変わった時のBehavior treeの挙動の可視化も来週やります。
6.World CompositionによるMap1の作成
6.1 Actorの追加
今週は先週作成したWorld Compositionを使用したMap1に岩や家などを追加します。
本来ならばMap1にあるActorをそのまま使用したいのですが、方法が分かりません。
色々考えましたが、前にImportしたMap1を最初の状態に戻して、World Compositionを使用可能にして新しくLandscapeを作成した方が速い気がします。
しかもこのやり方が上手く行けば、Ch4_3のMap1を修正する時も、新しいMapを作成してその上でMap1を全部作り直すのではなく、元のMap1をほとんどそのまま使用出来ます。
この方法を試してみます。
Sub Levelに移したActorなどを全部Persistent Levelに移します。
Sub Levelを消します。
上手く出来たみたいです。
今度は、Landscapeを全部消します。
そしてWorld CompositionにCheckを入れます。
消したはずのSub LevelのDataがまだ残っているみたいであーだこーだ言っていますが、無視して先に進みます。
Sub Level、Level1_1を作成します。
先週、Landscapeの作成に使用したDataを見ると以下のようになっています。
同じ設定にしてLevel1_1 にLandscapeを作成します。
Landscapeの位置を自由に決められません。
仕方ないので最も近い場所に配置しました。
先週と同じように36個のSub Levelを追加しました。
Map1のHeight mapを追加します。
ここでLandscapeを移動させたいのですが何をやっても移動してくれません。
仕方ないのでPersistent LevelにあるActorを全選択してLandscape側に移動させました。
これでもまだズレていますね。
微調整しました。
こんな感じです。
移動した時に失敗したのか最初の神殿が二つ出来ていました。
これはこれで面白いです。
どれくらいLandscapeから離れるとUnloadされるのかを設定します。
10,000にセットしました。名前はMap1_10Kとしました。
作成したLandscapeを全部選択してAssign LayerからMap1_10Kを選択します。
テストします。
左奥に山が現れました。出来ています。
何なんでしょか?このLandscapeの残りは?
前に作成したLandscapeのDataが残っているでしょうか?
分からないのでほって置きます。
本番ではこんなへんなモノは現れない事を祈ります。
LandscapeにPaintします。
Landscapeを選択してLandscape MaterialにMap1_Instをセットします。
Landscape Streaming Proxyにも同様にMap1_Instをセットします。
こんな感じです。
PaintのTarget Layersを以下のようにセットします。
以下の様な感じでPaintしました。
こんな感じです。
後、Mapに残っていた前のSub Levelのdataを消しました。
するとPlay時に現れる変なLandscapeも消滅しました。
はい。
これで準備が出来ました。
ここからActorをそれぞれのSub Levelに紐づけします。
以下の様にActorが乗っているLandscapeに紐づけしました。
36枚のSub Level全てやりました。
テストします。
何故か夜に?
Good Skyが5つに増えていました。
消します。
もう一回テストします。
今度は昼になったり夜になったりしました。
空を見上げるだけで山が消えたり現れたりします。
かなり変です。
でも一応は出来ました。
6.2 Map1のLandscapeをWorld Compositionに変更する事について
Sub Level内のLandscapeがある一定の場所にしか配置出来ないのが難点です。今回は全部のActorの位置を移動させましたが、そんな事をすれば、色々な新しい問題が発生してその直しにもっと時間がかかってしまいます。
Map1のLandscapeは4x9だから中心にLandscapeがあるとずれます。5x9で新しいLandscapeを作ってしまうのはどうでしょうか?
Map1のHeight Mapの高さは253pixelです。4で割ると63.25なので326か327pixelの大きさに改良した新しいHeight Mapを作成してそれをImportするのはどうでしょうか?
試しにMap1のHeight Mapを5x9のLandscapeに広げて見ました。
出来る事は出来るみたいです。
Ch4_3のLandscapeの位置を確認してみます。
これは上から2段目の5番目のComponentが真ん中にくるようになっていますね。
そういうつもりで最初からLandscapeを作成したら動かす必要も無かったかもしれませんね。
兎に角、World CompositionはUE4までにしかない機能なのでそんなに頑張って勉強する価値は無いので適当に済ましておきます。
6.3 Unreal Engine 5 | Open World Tutorial Using World Partition [14] の勉強
よくよく考えたらNiagaraのような小さいEffectならともかく、Landscapeのような大きなものが今の私のPCでUE5が完全に動く訳ないので見るだけにします。
こんな風にUE5だと変わるのかと言う事を理解すればOKにします。
軽く一回だけ見ましたが、これなら私のPCでも出来そうなので試してみます。
まず一番最初にしなければならない事は、World Partitionを使用可能にする事です。
Project SettingからWorld PartitionのEnable World Partitionにチェックを入れます。
TutorialではWorld SettingにあるWorld Partition SetupのEnable World PartitionからはCheckが出来ないと言っていましたが、それも試してみました。
出来ませんでした。
ProjectをRestartしました。
新しいLevelをTime Of Dayから作成しました。
この名前から推測するにこのTemplateだと太陽の動きも自然に表してくれてるみたいです。
良く分からないのですがこのLevelを一回Re-Openしろと言っています。
しました。
これでWorld Partitionが使用出来る状態になったそうです。
確かにWorld SettingのWorld Partition Setupを見ると以下の様に変化していました。
うーん。結構、面倒くさいですね。
Landscapeを作成します。
どうせなんで、Map1と同じ大きさにしました。
Map1のLandscapeのDataです。
こんな感じのLandscapeが出来ました。
次にWorld Partition SetupのWorld PartitionをクリックしまくってGridsまで開きます。
Cell SizeはUE4で言うComponentもしくはSectionに当たるのでしょうか?
Loading RangeはWorld Compositionでいう所のStreaming Distance
に当たる部分でしょうか?
後は分かりませんね。
Preview Gridにチェックを入れます。
すると以下のようにGridsが表示されます。
ここでTutorialはStreamingが効いている事を示すためにFoliageを使用して木をPaintしました。
代わりにLandscapeをデコボコにしました。多分これでも十分でしょう。
テストします。
奥に山が生成されています。
Commandでws.Runtime.ToggleDrawRuntimeHash3Dと打ちます。すると以下に示したようなGridが表示されます。
更に高い所でFlyと打ち込むとその高さから落ちないで移動出来ます。
でもこれ良く見ると円柱のRangeからはみ出ているLandscape消えてないですね。
真ん中にある球が消えました。
これはLandscapeは関係なくてActorとかFoliageとかにだけ影響するのかもしれませんね。
公式のDocumentであるWorld Partition [15] に簡潔な解説がありました。
こっちを先にやった方が良かったかもしれません。
今週はここまでにして来週はDocumentであるWorld Partition [15]を先に読みます。
7.Loading Screenの勉強の続き(Moduleについて)
時間が無くなってしまったので来週やります。
8.まとめと感想
時間が無くなってしまったので今週はなしにします。
9.参照(Reference)
[1] CGHOW. (2021, August 22). Bugs in UE4.27 Niagara Tutorial | Download Files [Video]. YouTube. https://www.youtube.com/watch?v=Jfxh_hqcZKY
[2] Epic Games [Unreal Engine]. (2020, May 27). Building advanced effects in Niagara | Unreal Engine [Video]. YouTube. https://www.youtube.com/watch?v=syVSRDQxrZU
[3] CGHOW. (2021b, September 20). Disintegration in UE5 Niagara Tutorial | Download Files [Video]. YouTube. https://www.youtube.com/watch?v=4dYg4bvf4Rc
[4] CGHOW. (2021c, September 21). Disintegration Skeletal Mesh FX in U5 Niagara Tutorial | Download Files [Video]. YouTube. https://www.youtube.com/watch?v=72TSg5Tv5Ik
[5] Epic Games [Unreal Engine]. (2020b, May 27). Building advanced effects in Niagara | Unreal Engine [Video]. YouTube. https://www.youtube.com/watch?v=syVSRDQxrZU
[6] IGN. (2021, August 20). Black Myth: Wukong - Official Unreal Engine 5 Gameplay Trailer [Video]. YouTube. https://www.youtube.com/watch?v=nOMIwsupy9k
[7] Cloward, B. (n.d.). Shader Graph Basics. YouTube. Retrieved October 10, 2021, from https://www.youtube.com/playlist?list=PL78XDi0TS4lEBWa2Hpzg2SRC5njCcKydl
[8] Ben Cloward. (2021, August 5). Input Vectors - Shader Graph Basics - Episode 9 [Video]. YouTube. https://www.youtube.com/watch?v=lrc-j7ub28U&list=PL78XDi0TS4lEBWa2Hpzg2SRC5njCcKydl&index=9
[9] Epic Games. (n.d.-b). Coordinates Expressions. Unreal Engine Documentation. Retrieved October 10, 2021, from https://docs.unrealengine.com/4.27/en-US/RenderingAndGraphics/Materials/ExpressionReference/Coordinates/#vertexnormalws
[10] VRIES, J. (n.d.). LearnOpenGL - Deferred Shading. Learn OpenGL. Retrieved October 10, 2021, from https://learnopengl.com/Advanced-Lighting/Deferred-Shading
[11] Unity3d.com. (n.d.). Unity - Manual: Transforms. Unity-Manual. Retrieved October 10, 2021, from https://docs.unity3d.com/550/Documentation/Manual/Transforms.html
[12] Cloward, B. [Ben Cloward]. (2021, August 12). View, World, Object, & Tangent Space - Shader Graph Basics - Episode 10 [Video]. YouTube. https://www.youtube.com/watch?v=E6Srr-HaicI&list=PL78XDi0TS4lEBWa2Hpzg2SRC5njCcKydl&index=10
[13] Epic Games. (n.d.-a). Behavior Tree Node Reference: Decorators. Unreal Engine Documentation. Retrieved October 10, 2021, from https://docs.unrealengine.com/4.26/en-US/InteractiveExperiences/ArtificialIntelligence/BehaviorTrees/BehaviorTreeNodeReference/BehaviorTreeNodeReferenceDecorators/
[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.-c). World Partition. Unreal Engine Documentation. Retrieved October 8, 2021, from https://docs.unrealengine.com/5.0/en-US/WorldFeatures/WorldPartition/