UE4の勉強記録

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

「Unreal Engine 4.xを使用してRPGを作成する」の足りない部分を作成する。アニメレンダリングの勉強など 10

<前文>

<今週のDirectXの勉強>

今週も3つの本で勉強していきます。

先週、 C++ DirectX 12 Game Engine - [S01E01] - Creating Our First Window [1] でCreateWindow()関数を勉強したのでその辺りを勉強します。

<<DirectX 12の魔導書>>

ちょうど、CreateWindow()関数を使用するところです。

ただし、CreateWindow()関数を使用する前に、WindowProcedure()という関数を作成しています。

うーん。

これは何する関数何でしょう?

とりあえず、作ってみます。

Sample Codeを見たら以下の場所に作成していました。

同じ場所に作成します。

この関数は、Windowが破壊された後にでも呼び出すんでしょうか?

まあ、続きをやっていくうちに、この関数の役目もはっきりするでしょう。

次に

  • Window Classの生成&登録
  • Window Objectの表示
  • Window の表示

を行うそうです。

これは、 Code analysis says Inconsistent annotation for 'wWinMain' : this instance has no annotations [1]で勉強した

  • Creating Windows
  • Display our window

とほぼ同じですね。

まだWindowの表示は勉強していませんが、来週それを勉強するはずです。

ちなみにCode上のCommetではListen for Message Eventsとなっていました。

それではWindow Classの生成からやっていきます。

うーん。どこに書けばいいんだ?

Sample Codeを見たらWinMai()関数の後に書いていました。

同じ箇所に書きます。

まずWNDCLASSEX型のObjectを宣言しています。

これ、 Code analysis says Inconsistent annotation for 'wWinMain' : this instance has no annotations [1]では、

とやっています。

まったく同じですね。

次に WNDCLASSEX型のObjectであるwのcbSizeを指定しています。

Code analysis says Inconsistent annotation for 'wWinMain' : this instance has no annotations [1]では、以下の4つを一辺に指定しています。

CbSizeに関しては全く同じです。

次にlpfnWindProcを指定しています。

うーん。

ここでさっき作成した関数を使用するのか。

Code analysis says Inconsistent annotation for 'wWinMain' : this instance has no annotations [1]では、最後の方でこのParameterを指定していました。

このDefWindowProc、いきなり出てきてよく分からないまま使用しています。

これは、ひょっとして結構重要な箇所なのか。

うーん。

調べます。

公式サイトの WNDCLASSEXW structure (winuser.h) [2]に以下の様に書かれていました。

という事は、WNDPROC型のObjectを返しているのか。

うん。

Code analysis says Inconsistent annotation for 'wWinMain' : this instance has no annotations [1]で使用しているDefWindowProcは何を返すのでしょうか?

これ公式のサイトにありません。

公式にあるのはDefWindowProcAと DefWindowProcWだけです。

でも返し値はLRESULTのようです。

こっちはCastしてWNDPROCにもしていませんね。

うーん。

まあ、いいでしょう。次に行きます。

w.lpszClassNameを定義しています。

まず本に書かれているとおりに書いたらErrorになっています。

Sample Codeを参考にして<tchar.h>をIncludeしたらErrorが止まりました。

あれ、<tchar.h>をIncludeしろとは、本には一言も書いていませんね。

Code analysis says Inconsistent annotation for 'wWinMain' : this instance has no annotations [1]では

と定義していました。

これ、ものすごく丁寧に定義していたので、lpszClassNameを定義する時は絶対これしないとだめなのかと思ったんですが、 DirectX 12の魔導書 の定義を見るとそうでもないみたいですね。

次のParameterはhInstanceです。

Code analysis says Inconsistent annotation for 'wWinMain' : this instance has no annotations [1]では

と定義して

とセットしていました。

2つの例を比較するとなんか正解みたいなのが見えてきました。

最後に WNDCLASSEXをRegisterします。

Code analysis says Inconsistent annotation for 'wWinMain' : this instance has no annotations [1]でも同じように

していました。

今週はここまでにして他の本ではどうやっているのか確認します。

<HLSLシェーダーの魔導書>

この本は、Windowの作成については何も書いていないので、Sample Codeでどうやっているのか確認します。

以下のInitGame()関数内で処理しているみたいです。

見つけました。

System.cppにありました。

なんとこの中のInitWindow()関数で処理しています。

InitWindow()関数は同じSystem.cpp内にありました。

ほえ。

こういう方法で WNDCLASSEXのParameterを定義しても良いのか。

成程。

Direct3D 12 ゲームグラフィック実践ガイド>

先週、Projectの設定方法を勉強したところで終わりました。

今週は実際にProjectを作成してその設定に変更します。

Windowの設定の指定やWindowの作成は時間があったら勉強します。

<<Solutionの作成>>

以下に示した様に、新しいSolutionを作成しました。

名前はFrameworkです。

更にその中にProject、Frameworkを作成しました。

ProjectからPropertiesを開きます。

まず、Windows SDK Versionが最新になっている事を確認します。

これ、一番最新だと、Windows11対応になってしまうと思うんですが、それってWindows10でも動くんでしょうか?

Character SetもUicodeになっていました。

うーん。

Unicodeは日本語対応しているんでしたっけ?

忘れた。

最後にSource Filesにmain.cppを追加します。

あれ。

こんだけ。

これだけだとちょっと短いので次の実装もやります。

Wmain()って、Main()関数とは違うんでしょうか?

今週はやっぱりここで止めて残りは来週やる事にします。

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

<本文>

1.今週の勉強について

今週も以下の内容についてやって行きます。

  • Niagara: CGHOW氏のTutorialをやる
  • Materialの勉強
  • RPGPackagingについて
  • Open Worldの検証
  • Gaeaの勉強
  • 雪山のMapの作成
  • 報酬システムの研究
  • Anime Renderingの勉強
  • DirectX 12の勉強

2.Niagara: CGHOW氏のTutorialをやる

CGHOW氏のTutorialの勉強を暫くしていなかったので、今週はCGHOW氏のTutorialを勉強します。

Ribbon Trails in UE5 Niagara Tutorial | Download Files [3] を勉強します。

UE5.1 はRibbon RenderingがGPUで使用出来る様になったはずです。おそらくこのTutorialでそのやり方を解説しているはずです。

2.1 Ribbon Trails in UE5 Niagara Tutorial | Download Files [3] を勉強する

これです。

まず軽く全部見ます。

見ました。

6分程度の短いTutorialでした。

何と予想に反してRibbonGPUで使用していませんでした。CGHOW氏はこれ5.03で作成していました。

うーん。

何で?

まあ、実装する時は5.1で作成してGPUにしてみましょう。

以下に内容をまとめます。

いつも通りFountainを追加したNSを作成します。

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

このModuleは初めて使用します。どんな機能があるんでしょうか?

Update Mesh Reproduction Sprite ModuleのPreview MeshにThird Person Characterで使用しているSkeletal MeshであるSKM_Quinn_Simpleを追加します。

ここでFix Buttonを押すと

Particle Spawn SectionにInitialize Mesh Reproduction Sprite Moduleが追加されます。

このModuleも初めて使用します。Update Mesh Reproduction Sprite Moduleと対になっているのは分かりますが、どんな機能を持つModuleなんでしょうか?

CGHOW氏何も説明はしませんが、このInitialize Mesh Reproduction Sprite Moduleの位置をParticle Spawn Sectionの最後に移動しました。

これ、絶対必要なのか、もしそうなら何故必要なのかの説明が全くなかったです。

うーん。

自分で調べるしかなさそうです。

実装した時に調べる事にします。

現在のPreviewの状態です。

これらのParticleは一辺にSpawnされるべきです。

更に一度生成されたら、消える必要もありません。

Emitter Update SectionのSpawn Rate ModuleをSpawn Burst Instantaneous Moduleに変更します。

これで全てのParticle は一辺に生成されます。

次にEmitter Update SectionのEmitter State Moduleにある

Loop BehaviorをOnce に変更します。

Particle Update SectionのParticle State Moduleの

Kill Particle When Lifetime…のCheckを外します。

これで一度生成されたParticleは、寿命が来ても消えなくなりました。

Particleが確認し易いようにParticleの色を変えます。

Particle Spawn SectionのInitialize Particle Moduleの

Color の設定を以下のように変更しました。

結果です。

そんなに見易くなってはいませんね。

今度は、Third Person Characterを開きMesh(CharacterMesh0)にNiagara Systemを追加します。

そしてNiagara System Assetに先程作成したNSをセットします。

結果です。

新たにEmitterを追加します。

こっちでRibbonを作成します。

それぞれのEmitterの名前を変更します。

最初のEmitterをSource、今作成したEmitterをRibbonとします。

Ribbon EmitterのRender SectionのSprite Renderer ModuleをRibbon Renderer Moduleに変更します。

Ribbon Renderer ModuleのMaterialにm_Beamをセットします。

CGHOW氏によるとFlatな色なら何でも良いそうです。

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

Particle Update SectionにあるVelocityやAcceleration 関連のModuleを消しました。

Particle Spawn SectionのAdd Velocity Moduleの

Velocity ModeをFrom Pointに変更します。

結果です。

Particle Spawn SectionのShape Location Moduleを消します。

Ribbon が発生する箇所はSource Emitterで生成したParticleの位置になるので、Shape Location Moduleは要らない訳です。

次にParticle Spawn SectionのInitialize Particle Moduleの

Life time ModeをDirect Setにセットします。

これは絶対必要なのかは分かりませんね。

実装した時に確認しましょう。

Emitter Update SectionのSpawn Rate Moduleを消してSpawn Particles from Other Emitter Moduleを追加します。

Spawn Particles from Other Emitter ModuleのEmitter Nameに先程作成してEmitterの名前をセットします。

ここでGCHOW氏、もし5.1を使用しているならGPUに変更しても良いです。とサラッと流しています。

更にSpawn Particles from Other Emitter Moduleの設定が続きます。

Particle ID Sampling にApply Sampled ID as Ribbon IDをセットします。

これはSource Emitterで生成されたそれぞれのParticleのIDをそのままRibbonのIDに使用すると言う意味でしょう。

Source Emitterに戻ってPropertiesを選択し

Requires Persistent IDsにCheckを入れます。

これはNiagaraの基礎のEventの勉強で散々やったIDをPersistentにするやつです。

そう言えばこのやり方、従来のEventの設定方法とは微妙に違いますね。

Particle Spawn SectionのAdd Velocity Moduleの位置をSample Particles from Other Emitter Moduleの後に移動します。

PreviewのImageが

から

に変化しました。

うーん。Source Emitterで作成したParticleからRibbonが出ているのでしょうか?

良く分かりませんね。

出てました。

Velocityの中心は以下の赤丸で囲った箇所です。

これをThird Person Characterの中心に移動します。

Particle Spawn SectionのAdd Velocity Moduleの

Origin Offsetのzの値を0から100に変更します。

結果です。

これは微妙な調整ですが、見た目は結構変わりますね。

こういう技を使用するかしないかで見た目の印象って凄く変わるのかもしれませんね。

まだ微調整は続きます。

今度はAdd velocity ModuleのVelocity SpeedのMaximumの設定を以下のように変更しました。

以上だそうです。

微調整して見た目を良くしました。

最後にSource EmitterにLight を追加しています。

以下の設定に変更しています。

結果です。

床が光っています。

以上だそうです。

<感想>

成程。

大体、理解しました。最後にLight Renderingを追加したからGPUの使用は止めたんですね。

というかRibbon EmitterでGPUを使用しないといけない状況ってあんまり思い付きません。

今回のこのEffectはRibbon EmitterをGPUで使うには最適な例だと思ったんですが、Particleの生成した数がこれ位だとCPUでも楽に処理出来ちゃうんですね。

兎に角、実装してみます。

2.2 Ribbon Trails in UE5 Niagara Tutorial | Download Files [3] を実装する

今回は当然、5.1で実装します。

まずNiagara Systemを作成しました。

開きます。

Emitter StackのParticle Update SectionにUpdate Mesh Preproduction Sprite Moduleを追加します。

まず最初にUpdate Mesh Reproduction Sprite ModuleのPreview Meshに、Third Person Character のSkeletal MeshにセットされているSKM_Quinn_Sampleをセットします。

以下のErrorが表示されています。

なるほどね。

Fix issueを押します。

Particle Spawn SectionにInitialize Mesh Reproduction Sprite Moduleが追加されました。

先程の Update Mesh Reproduction Sprite Moduleに戻りますが、まだ以下のErrorが表示されています。

TutorialではこれらのErrorは表示されていないみたいです。

取りあえず、このままにしておいて先に行きます。

今度はInitialize Mesh Reproduction Sprite Moduleの設定を変更します。

まず位置をAdd Velocity Moduleの後にします。

更に、Preview Meshに先程のSkeletal Meshをセットします。

こっちのModuleでも先程の Update Mesh Reproduction Sprite Moduleと同じErrorが表示されています。

Tutorialを見ると、このようなErrorは表示されていません。

うーん。

分からん。

Fix Nowを押します。

両方のModuleに表示されていた警告が消えました。

これらのModuleについて調査すると前節で書きましたので、少しだけ調べることにします。

公式サイトの Particle Spawn Group [4]の Mesh ModulesにRemarkがありました。

Initialize Mesh Reproduction Sprite ModuleのRemarkです。

最初の文章は、Particleの生成位置がRandomにSkeletal Meshから選択される事を説明しています。

その後に、Meshの表面に正しく整列するためには、Sprite Render ModuleのRender Alignment に Custom Alignemntを、Facing ModeにCusom Facingを、Custom Facing Vector Maskに1,1,1をセットするようにと書かれています。

これはこのTutorialでは確かやっていないはずです。

一応、Sprite Render ModuleにこれらのAttributeがあるか確認します。

まずRender Alignmentですが、これでしょうか?

単にAlignmentと表記されていました。

次のFacing ModeですがAlignmentの下にありました。

Custom Facing Vector Maskですが、

ないですね。

もしかしたらFacing ModeにCustom Facing をセットしたら現れるのかもしれません。

AlignmentにCustom Alignment、Facing ModeにCustom Facing をセットします。

なんと、Fadcing ModeにCustom Facingはありません。

Custom Facing Vectorはあるので代わりにそれを選択しました。

なんか新しく表示されました。

おお、これが Custom Facing Vector Maskかと思ったら、Default Pivot in UV Spaceでした。

うーん。分からん。

念のために公式のDocumentのVersionを確認したら4.26でした。

あれ、そのせいか。

5.1に直しました。

でも書いてあることは一緒でした。

うーん。

これ以上はよく分からないので一端先に行きます。

Attributeの値はDefault値に戻しておきます。

Remarkでは、その次の文章で、MeshがAnimatedしない場合についての解説をしていますが、今回の勉強には関係ないのでSkipします。

Update Mesh Reproduction Sprite Moduleについてです。

こっちでも、Sprite Render Moduleの設定について語っています。

こっちでは、Facing Mode にセットするのはCustom Facing Vectorと書かれていました。

これ同じPageのわずか10行程度しか離れていない箇所で、 Facing Mode にセットするのが、Custom FacingからCustom Facing Vectorに変化しています。

あんまり信用し過ぎるのはいけない文章かもしれません。

次に行きます。

VelocityやAccelerationに関するModuleを消します。

更にShape Location Moduleも消します。

今度はParticleの生成方法を変更します。

これらのParticleを一斉に生成するようにします。

更に一度生成されたら、消える必要もありません。

まずParticleの生成方法から直します。

Emitter Update SectionのSpawn Rate Moduleを消してSpawn Burst Instantaneous Moduleを追加します。

Spawn Countは100にセットしました。

後で、GPUで生成するように変更する時は、この値を10000ぐらいにしてみます。

今は、Tutorial通りに実装します。

今度は生成したParticleが二度と消えないようにします。

Emitter Update SectionのEmitter State Moduleの

Loop BehaviorをOnceにします。

更にParticle Update SectionのParticle State Moduleの

Kill Particle When Lifetime Has ElapseをOffにします。

今度はThird Person Character BPにこのNiagara Systemを追加します。

これを開きMesh(character Mesh 0)にNiagara (Niagara Particle System Component) を追加します。

そしてNiagara System Assetに、今作成中のNSをセットします。

こんな感じです。

Level 状でPlayしてみました。

よく分かりません。

Tutorialのははっきりしています。

Scale Color Moduleを消すのを忘れていました。

この後も色々工夫しましたがTutorialのようには光りませんでした。

このくらいで妥協します。

今度はRibbonを生成するEmitterを実装します。

名前を変更しました。

Ribbon Emitter StackのRender SecitionにあるSprite Renderer Moduleを消して代わりにRibbon Renderer Moduleを追加します。

Ribbon Renderer ModuleのMaterialには以下のMaterialが付いていたのでそのまま使用する事にしました。

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

そしてSpawn Particles from Other Emitter Moduleを追加します。

Emitter NameにSourceを追加して

Fix Errorを押します。

更にParticle Spawn SectionのSample Particles from Other Emitter Moduleを選択し

Particle ID Sampling にApplay Sampled ID as Ribbon  IDとします。

今度はSource Emitter StackのRequires Persistent IDsにCheckを入れます。

まだRibbon Emitter Stackに戻って、Particle Spawn SectionにあるInitialize Particle Moduleの

Lifetime ModeをDirect Set、そしてLifetimeを1にします。

そしてParticle Spawn SectionのAdd Velocity ModuleをSample Particles from Other Emitter Moduleの後に移動します。

結果です。

すっげえー。

更にAttributeの値を微調整しました。

結果です。

一応できたんですが、想像していたのとは一寸違いました。

このように普通に走らせると前が見えません。

それではGPU Modeにしてみます。

Source EmitterのPropertiesとRibbon Emitter のPropertiesの以下のAttributeをGPUに変更しました。

更にCalculated Bounds ModeをFIxedに変更しました。

Ribbonを細くしたら、Particleみたいになってしまいました。

元に戻しました。

せっかくGPUにしたので数を増やしてみます。

Source EmitterのSpawn Countの数を10,000に増やしました。

わけわからない結果になりました。

やっぱりRibbonGPUで使う必要はない気がします。

一応、RibbonGPUで使用出来たので今度は逆にリボンの数を少なくしてみました。

こっちの方がRibbonらしいです。

更に改良して以下の様にしました。

2.4 色々試してみる

前にRibbonで色々、作成しました。

2021-07-04のBlogRibbon Effectで色々実験していますが、似たような事をします。

その時に使用したTextureを探してきました。

最後には元のMaterialに戻すので記録のために元のMaterialのScreenshotをここに残しておきます。

まずはMaterialの作成をします。

Textureの設定で黒と透明を分ける方法があったはず。

しかし覚えていません。

うーん。

これでも同じ効果が出るでしょう。

結果です。

何だこれ。

微調整しました。

もう少し顔が見えるといいかもしれません。

走るとこんな感じです。

呪いに追いかけられているみたいです。

他のMaterialも試してみます。

丸です。

炎の字を書いたTextureです。

色々やって分かりましたが、Textureの模様はあんまり関係ないです。

色だけが問題でした。

Textureが横にものすごく伸ばされていると考えると分かりやすいです。

後、真っ黒なTextureはLevel上が暗くなると全く見えなくなります。

あんまりIdeaが出てこないので今週のNiagaraの勉強はこれで終わりにします。

3.Materialの勉強

今週はVHS Filter Seriesの3番目のTutorialであるPixelation Filter - Shader Graph Basics - Episode 61 [4]を勉強します。

3.1 Pixelation Filter - Shader Graph Basics - Episode 61 [4]を勉強する

まず軽く全部見ます。

今回はVHS Filterとは関係無くて、箸休めの回だそうです。

まあ、そう言う回があっても良いと思います。

Unreal Engineの実装だけ見ました。

非常に簡単な実装でした。

後、Ben Cloward先生、Material Instanceを使用する事でParameterをLevel上から操作出来る事を知りませんでした。

それだけです。

以下にUEにおける実装を簡単にまとめます。

以上でした。

うーん。

これBen Cloward先生のTutorialで勉強したのかどうかは、覚えていませんが、このやり方前に勉強しています。

一寸だけそれぞれの工程が何故必要なのか自分で考えて見ます。

<Add(,0.5)ノード>

この実装の後で、Scalingを行うので、Image全体が均等にScalingされるためには、TexCoord[0]をImageの中心に移動する必要があります。

それをこのNodeが行っています。

<Multiplyノード>

ここでTextureのScalingを行います。

ScalingはBの値が1より大きければ、Imageは小さくなります。逆に0~1の間の値ならば、Imageは大きくなります。

これについては、過去のBlogで散々、TexCoord[0]ノードはCameraの役割をしていて、それを考えるとその操作とその結果は全部辻褄があう。という説で説明しているのでここでは説明し直しません。

と思ったんですが、こういうのを何回も説明する事で私の説明する力が向上するそうです。

ので今回も、TexCoord[0]ノードに掛け算をすると言う行為が、実際はどんな事をやっているのかについて解説します。

TexCoord[0]ノードに掛け算をすると言う行為の本質を理解するためには、まずTexCoord[0]ノード並びにTextureにおける前提を理解する必要があります。

前提は以下の3つです。

  • 座標軸、
  • Textureの位置、
  • TexCoord[0]Cameraである

これだけ聞いたんでは、訳わからないと思いますので以下に簡単な解説を追加します。

まず座標軸から説明します。

TexCoord[0]ノード並びにTextureで使用されている座標軸は、普段使用される座標軸と違い、上下が逆になっています。

左右は同じです。

この座標軸に沿ってTextureやTexCoord[0]の計算は実行されます。

なんだ!そんな事か。と思うかもしれませんが、座標軸を間違って理解していると、幾ら計算を追っても理論と実際の計算の結果は一致しません。

何年もUEを使用しているにも関わらず、TexCoord[0]の使い方を理解出来ない人達がいますが、その原因の一つがこの座標軸を理解していない事です。

次はTextureの位置です。

Textureは今説明した座標軸を使用して以下の位置に配置されます。

左上が(0,0)、右上が(1,0)、左下が(0.1)、右下が(1,1)になります。

これは元のTextureのサイズがどんなに大きくても、サイズ比が1:1でなくても変わりません。もしサイズ比がHDのような1920:1080でも左上が(0,0)、右上が(1,0)、左下が(0.1)、右下が(1,1)になるように配置されます。

そしてこれが秘伝級の内容になります。

この配置されたTextureは移動したり、回転したり、収縮拡大する事は一切しません。未来永劫この位置に留まっています。

はい。Texture自体は決して動きません。

これが秘伝の内容です。

前提条件の2番目の意味は、

  • Textureは前提条件1で説明された座標軸内で、元のTextureの寸法に関係なく、左上が(0,0)、右上が(1,0)、左下が(0.1)、右下が(1,1)に配置されている。
  • Textureを移動、回転、拡大縮小と、皆が皆言いますが、そんな事は実際は起きていません。Textureはいつでも同じ場所に同じ大きさで存在している。

の2つです。

最後に「TexCoord[0]はCameraである。」について説明します。

これは文字通りの意味でTexCoord[0]がCameraとなってTextureが存在している上記の座標軸内で撮影している事を説明しています。

最初TexCoord[0]は以下に示した位置にカメラを配置しています。

このCameraが、先程説明した座標軸上で移動、回転、拡大縮小を行います。

Textureは移動、回転、拡大縮小を行う事は絶対にないです。Textureは最初から最後まで同じ位置にいます。

これは実際の計算を見れば、Texture Sampleノードに四則計算しているのではなく、TexCoord[0]ノードに対して四則計算しているのですから、ある意味明白です。

しかし、現実ではあらゆるUEのTutorialでTextureの移動、回転、拡大縮小と表現されています。

Textureはこの座標軸の中では、移動も回転も拡大縮小も行いません。

このTextureを含めたこの座標空間を撮影しているCameraであるTexCoord[0]が移動、回転、そして拡大縮小を行っているんです。

後、一寸だけ話はそれますが、このTexCoord[0]は一個のカメラではなく、昆虫の複眼のように沢山の小さなカメラが集合した状態なんです。しかしそれは今回は考えなくていいです。もっと高度なTexCoord[0]の操作をする時に、その事を理解する必要が出て来ますが、今回はそれは要りません。

この3つが前提条件です。

では次に実際にTexCoord[0]がTextureをどう撮影しているのか確認します。

当然ですが、最初の段階では、以下のようにTexCoord[0]はこの座標軸の空間を撮影しています。

実際にUEで試してみます。

以下のMaterialを作成しました。

Previewの結果です。

はい、当然ですが予測と全く同じ結果になりましたね。

TexCoord[0]に(0.5, 0.5)を追加するとどうなるでしょうか?

当然、Cameraはx軸方向に0.5、y軸方向に0.5移動し、以下の様な位置を撮影します。

以下の様な結果になるはずです。

実際のMaterialで試してみましょう。

先程のMaterialの実装にAddノードを追加しました。

AddノードでTexCoord[0]のXとYの両方に0.5を足しています。

結果です。

はい。

「予測と同じ結果になってないじゃないか。」と思う人もいるかもしれませんが、実はこれ予測と全く同じ結果になっています。

使用しているTextureを開いてDetailにあるTiling Methodの設定を見てみます。

Wrapと設定されています。

これは、以下に示したように先程の座標空間に、Textureを繰り返し貼った状態と見なしてください。と言う意味なんです。

この状態で、もう一回、先程のTexCoord[0]の撮影を行うと、以下のようになります。

そして撮影されたImageは以下のようになります。

先程の実際の結果と比較してみましょう。

実際のTextureのImageには枠線はないのと白のBackground Colorはここでは黒く処理されている事を考慮すると、全く同じImageになります。

あれ?

この位置でサイズを変更して良いのか?

間違ってない?

一寸、前のBlogを読み直して確認します。

2022-05-30のBlogの「3.3  Moving, Rotating, and Scaling UVs - Shader Graph Basics - Episode 43 [4]の検証をする」に拡大縮小に関する操作がまとめられていました。

簡単に説明すると、このTexCoord[0]のCameraの枠の4つの角の値にMultiplyのBの値を掛ければ、正しい拡大縮小の計算になります。

それで結論から言うと、このTexCoord[0]の移動は間違ってはいませんが必要でもありませんでした。

それについては後から説明します。

次は拡大縮小を行います。

これはTexCoord[0]の4角の点にMultiplyノードのBの値を掛けるだけです。

実際の実装ではMultiplyノードのBの値は以下の計算で決まっていますのではっきりした値を出す事は出来ません。

しかし1より大きな値である事は間違いないです。

Materialの計算においては、1以下か1以上かが大事で、1以上である事さえ分かれば、大体の予想は当たります。

ここではMultiplyノードのB を10にして計算してみましょう。

まず以下の4つの点ですが、

(0.5 , 0.5)(1.5, 0.5)

(0.5, 1.5)(1.5, 1.5)

となっています。

これらの点を10倍にすると、

(5 , 5)(15, 5)

(5, 15)(15, 15)

となります。

つまり以下のようなカメラの配置になりました。

実際の実装で確認します。

結果です。

何でImageが見えるのか?という質問に対しての解答は、前に説明したようにTextureの設定がWrapだからです。

はい。

ここで最初の質問に戻ります。

Textureに1より大きい数字を掛けたら、普通ならTextureは大きくなります。しかしMaterialではTextureは小さくなります。

これが何故かと言うと、ScalingはTextureを大きくしているのでは無くて、Cameraを大きくしているからです。

ここまでの解説でこの事がすんなり理解出来たと思います。

<Floorノード>

Floorノードは小数点以下を切り下げて整数にする機能です。

先程の計算の例だと、最初のSmileが表示されている箇所は(5,5)の位置にありますが、実際は5.1、5.2、5.3の位置でSmileのそれぞれの部分部分のImageを撮影しています。

だから最終的に以下の様なImageになります。

所がここでFloorにすると、5.1、5.2、5.3の位置で撮影していたそれぞれのCameraに5.0の位置で撮影して下さいと命令したのと同じになります。

つまりみんなして以下の部分を撮影する事になります。

全体で言うと以下のようになります。

あ、これさっき言ったTexCoord[0]のCameraは実際には昆虫の複眼みたく構成されていると言う話です。

これに関しては今回はあまり詳しくは説明しません。しても混乱するからです。

ので簡単に説明しました。

<Divideノード>

ここで先程Multiplyノードで掛けた値と同じ値で割ります。

先程の例だと、

が、

に変化します。

つまりPixel化します。

流石にこれは何だかわからないので、30で掛ける事にしました。

Pixel化しています。

<Subtractノード>

最後にAddノードで移動した分を元に戻します。

以下の位置に有ったTexCoord[0]が

以下の位置に戻ります。

結果、

MaterialのImageは

から

になります。

ここで最初のAddノードは要らないと言う話に戻ります。

以下のようにAddノードとSubtractノードを外しても

同じ結果になります。

うーん。

頑張ってTexCoord[0]とTextureの関係を説明しましたが、あんまり上手く説明出来ませんでした。

最初からTexCoord[0]が複眼になっている事も説明した方が、Floorノードの説明が分かり易くなった気がします。

というか、このTutorial自体がTexCoord[0]とTextureの関係を説明するのに、あんまり相応しくなかったです。

必要のないTexCoord[0]の中心の移動とかしていますし。

3.2 TexCoord[0]の説明があんまり上手く出来なかった件について

よくよく考えたら、TexCoord[0]とTextureの関係で、みんなが頭を悩ますのは回転の計算をする時です。

その時なら、私の説明はSliver Bulletになるはずです。

今回のようなFloorノードを使用する場合は、TexCoord[0]のCameraは昆虫の複眼のようになっていて、それぞれのCameraには、座標が保持されていてその座標の位置のImageを撮影すると言う事がもっとも重要でした。

しかしその事に気が付いたのはもう説明の大半を終えた時で、もうすでに遅しという感じになってしまっていました。

しかも何故か、Tutorialでは+の方向に0.5ずつTexCoord[0]をずらしており、それは拡大する時もTexCoord[0]を軸の中心からする必要があるため。と私もずっと思っていました。

Nodeの計算によるTexCoord[0]の移動や変形を逐一追っていたら、AddノードとSubtractノードの作用は実際は全く必要ないものである事にその時になって初めて気が付きました。

TexCoord[0]を軸の中心で回転させるためには、TexCoord[0]を-の方向に0.5ずつ移動させる必要があります。しかしTexCoord[0]を拡大させるためにTexCoord[0]を移動させる必要は無いです。

それなのに、最初のAddノードにおけるTexCoord[0]の移動について滅茶苦茶細かく説明していました。これが全くの無駄になってしまいました。

これがTexCoord[0]が‐0.5に移動して、その後、回転が来ていたら話は違っていました。

それでもTextureの座標軸の仕組みや、Texture自体は移動も回転も拡大もしない事、TexCoord[0]が実際はCameraの役目を果たしている事についてはかなり分かり易く説明出来たとは思います。

しかしその説明の前後で、説明つかない事態が、完全に説明つくように変化した事を理解出来る様な例を提供出来なかったので、この説明を聞いた人達は、どの程度役に立つ内容なのかを判断出来ないのでその大切さは全く分からないです。

そう言う意味では、今回の説明は失敗です。

<どうやったらもっと上手く説明出来るのか?>

このTexCoord[0]とTextureの関係が「TexCoord[0]がCameraと考えると全部上手く説明出来る。」というのは、100%私が発見した内容で、世界の誰も言っていません。

説と言っていますが、ほぼ間違いなく正しいです。

自分で試せる範囲が限定されているので説と言っていますが、今までどんな複雑なTexCoord[0]の計算(Animationが入ったりNormal Vectorを表示したりする場合でも)でも、この考え方に基づいてTexCoord[0]を計算通りに操作した場合、実際にMaterialとして表示されるTextureの結果と一致しています。

この説が、世間一般に受け入れられるかどうかは、私の説明の上手さに掛っています。

しかし今回の説明を後から自分で読んでみると、残念ながら分かり易い説明とは言えません。

どうしたらもっとみんなの興味を引けるように説明出来るか、考える事にします。

初めてTexCoord[0]ノードを使用する時に「あれ?このNodeよく意味分からない。けど、使用出来てるし、まあいいか。」という感じで、ほとんどの人がサラッと流してしまいます。

そしてその後、何年間も分からないままで、何となく使ってしまって、まあそれでも何とかなっているし、まあ良いか。となってしまう方が大半だと思います。

良いIdeaを思い付きました。

現場猫の力を借りるんです。

Textureの変換をあんまり理解しないで使用してると現場猫みたくなるぞ。と暗に示して

簡単なTexCoord[0]の計算を追加した後でTexture SampleノードのUVにパスした場合の結果を予測させます。

これは、私の編み出したTexCoord[0]をCameraに例える方法を知っていれば、結果を予測するのは可能ですが、そうではない場合、かなり難しいです。

そして、まあ今までも出来なくても何とかなったし、今更勉強しなくてもいいよね。と考えている所へ

これです。

今度TexCoord[0]とTextureの関係を説明する時は、現場猫にも手伝ってもらいます。

3.3 Screen Resolutionノードと以下の実装について

この部分の説明を忘れていました。

これは、Screen Resolutionを基準にして掛け算、割り算をするため、Play画面のサイズに影響されないでPixelのサイズを一定に出来ます。

例えば、画面のサイズが1920x1080だったとします。

1920/16 = 120

1080/16 = 67.5

です。

これを、1920が1になっているTexCoord[0]に掛けます。例として0.5を使用します。

0.5 x 120 =60

です。

61になるまでの値がFloorによって60に変換されます。

61/120 = 0.50833333333

です。

大体0.83%です。

これをpixel数に直すと1920 * 0.0083 = 15.936になりました。

同じ計算を画面のサイズが4Kの場合で試してみます。3,840 x 2,160です。

3,840/16 = 240

0.5 x 240 = 120

121/240 = 0.50416666666

大体、0. 416%です。

これをPixelに直すと、3,840* 0.00416 = 15.9744になりました。

このように、画面のサイズが変化してもPixelのサイズは一定のままになります。

3.4 Pixelation Filter - Shader Graph Basics - Episode 61 [4]を実装する

一応実装もします。

結果です。

Parameterの値を11ぐらいに設定すると以下の様になります。

以上です。

4.RPGPackagingについて

先週作成したch4_3のCloneが動くのか確認します。

Renaming Projects | Tips & Tricks | Unreal Engine [5]では、Cloneした後に色々しないといけないみたいな事が書かれていましたが、どうなんでしょう。

普通に開けましたが。

一応、Renaming Projects | Tips & Tricks | Unreal Engine [5]を見て確認します。

これ見てたらComment欄に何でC++のRenamingの方法は教えてくれないんだ。とか書かれていてその後で

Open World Server (OWS) - How to Rename your Project [6]が紹介されていました。

これを見たんですが、このやり方でやったら出来そうです。

やっぱり動画は実際に動いているのが確認出来るので、Blogと違って出来そうな感じが凄いします。

今週はこの2つのTutorialのやり方をまとめて来週実際に挑戦する事にします。

4.1 Renaming Projects | Tips & Tricks | Unreal Engine [5]を勉強する

これ、Comment欄の文句が凄いです。

企業のAccountだから動画の製作者が勝手にComment欄を消す事は出来ないのかもしれないけど、あんまり信用出来ない内容なのかもしれません。

例えば、

とかです。

と言うかCloneを作成する時に、新しいProjectの名前を選択出来るのでそれをした場合はどうなんでしょうか?

その場合もここで説明している事をやる必要があるのでしょうか?

その辺も確認しながら動画を見る事にします。

後、C++付きのProjectの名前の変更方法については説明しません。と言う事を4分の動画の内の1分を使って説明するくらいなら、その時間でC++付きのProjectの名前の変更方法も説明しろ。とは思いました。

Projectの入っているFolderを開いてProject名を変更しています。

先週、Cloneした私のProjectを見るとProject名は既に変更されています。

うーん。

次ですが、Config Folder内にあるDefault.iniを開き

を追加しています。

私のDefault.iniを開くと

既に追加されていました。

Projectの入っているFolderの名前を変更しました。

これも最初から変更されていました。

これで終わりでした。

うーん。

ProjectをCloneする時にProject名に別な名前を入れれば全部、自動でやってくれるみたいですね。

4.2 Open World Server (OWS) - How to Rename your Project [6]を勉強する

まず軽く全部見ました。

大体は、前に勉強した2つのTutorial、

と同じ内容でしたが、新たな知見も得られました。

まずProject Nameは変えても変えなくても関係ないそうです。

次にDefaultEngine.iniの以下の部分の設定を正しく書かないとBPが全部Crashして2度とそのProjectは使用出来なくなるそうです。

これだわ。

前のProjectの名前の変更はこの部分を間違えてやっていたんですわ。

他にも重要な事を言っていたかもしれません。

以下に全部まとめ直します。

まずProjectのCopyを作成します。

最初に名前の変更を行う時は、失敗する可能性が高いので絶対Copyしとけ。と言っています。

このTutorialが作成されたのが2年前なので、その当時はまだCloneの機能に不安があったのかもしれません。コピペで作成していました。

Copyした方のfolderの名前を変更しました。

今度はFolderを開いてuprojectの名前を変更しました。

この辺はCloneで作成すれば自動でやってくれますね。

今度は.uprojectを開いて中のProject名を変更しています。

Cloneした場合はこの辺はどうなっているんでしょうか?

確認します。

前の名前のままでした。これは後で変更します。

Tutorialでは次に以下のFileを直しています。

私のProjectにはこのFileは無いのでこの部分は無視します。

次はConfig Fileです。

DefaultEngine.iniの

GameNameの名前を直しました。

そして以下のCodeを追加しました。

Tutorialの解説によると、これを追加する事で、全てのBlueprintが新しいProjectにPointするそうです。

しかもこれを間違ってしてしまうと、BPが駄目になってそのProjectが2度と使用出来なくなる可能性もあるそうです。

マジ?

先にそう言う大事な事は教えてほしかった。

私のProjectのDefaultEngine.iniのこの部分を見ると以下のように書かれていました。

恐らくですが、このch4_3を作成した時の最初のProject名はThirdPersonだったんでしょう。それを後でch4_3に変更したんでしょう。

だから上記のような記述が追加されていたんでしょう。

この部分にあるch4_3をCh5_1に変更すれば良いだけな気がして来ました。

前回、やった時はこの部分は、

あれ?

しっかり直していました。

一寸Blogを見て確認します。

2022-11-28のBlogに詳しく前回のProjectの名前の変更で何をやったのかが書かれていました。

それを見ると、この部分は全く直さないで、一回BuildしたらErrorが出たので、この部分を上記のように直してもう一回BuildしたらErrorが消えてBuildは出来た。しかしVisual Studioから実行してUEのEditorを開こうとしたらExceptionが投げられて止まった。と書かれていました。

これはこのTutorialが今、ここで説明した「この部分を失敗するとBPがCrashしてそのProjectは2度と使用出来なくなる。」をやってしまった可能性がありますね。

最初からこの部分をしっかり直してもう一回、Testする価値は十分ありそうです。

次に行きます。

今度はDefaultGame.iniです。

Project Nameの変更ですが、これやらなくても良いと言っていました。

これでConfigの変更は終わりでした。

次は要らないFolderを消します。

Binaries、Intermediate、そしてSavedを消しました。

あれVSのSolutionは消さないの?と思ったらTutorialにはそれが最初から存在していませんでした。

この後Server Folder内を直していますが、このFolderは私のProjectには無いのでこの部分はSkipします。

次はSource Fileです。

全部名前を変更しています。

ここは基本的には全部の名前を変更すべきと思っています。

此処で私が知りたいのは

のような. Generated.hは消すべきなのかどうかです。

これについてはこのTutorialも何も言っていません。

後、.Build.cs Fileの以下の箇所にGameplayAbilities Moduleを追加していました。

私のBuild.cs Fileは以下のようになっていました。

GameplayAbilities Moduleは追加されていませんね。

これは追加する必要があるのかもしれません。

Source FileからProject名のFileを開くと以下のようになっています。

私のProjectは以下のようになっていてTutorialのFileとは一緒ではありませんが、

取りあえず話しを聞きます。

この中のPublic Folderを開いてAPIの前の名前を変更します。

私のProjectにはPublic Folder自体がないです。

のでPrivate Folder以外のFileを開くと

以下に示したように、APIは付いていませんが、旧Project名がついているClassがそれなりにありました。

前回の、Project名の変更の時はこの辺はしっかり直したんでしょうか?

確認します。

確認した所、全部しっかりと直っていました。

Generated.hについては何もしていませんでした。

ただしこれを見るとそもそもGenerated.hの名前に旧Project名が入っていません。

この辺が私のProjectとTutorialのProjectと根本的に違う処で、なんでこうなっているのか全く覚えていません。

これでお終いでした。

その後で、VSのSolutionを作成してBuildして実行して普通にUEのEditorを開いていました。

以上です。

4.3 今回直すべき改良点のまとめ

Open World Server (OWS) - How to Rename your Project [6]はそれなりの新しい知見が得られました。

それに基づいて、前回の名前の変更が失敗した理由を考えると、

  • iniActiveGameNameRedirectsの設定を、最初間違えたためBPCrashしてしまった。
  • .Build.cs Fileの特定の箇所にGameplayAbilities Moduleを追加していなかった。

の2つの可能性が考えられます。

しかし、私のProject、Class名がこれらのTutorialと違い、_APIが付いていません。これが何故起きているのかは不明ですが、このせいでProjectの名前の変更が失敗に終わっている可能性もあります。

今Cloneで作成したC++の方の名前は全く弄っていないProjectが普通に起動するならそれを使用してPackagingをするのも有りな気がしてきました。

来週はその辺を検証する事にします。

5.Open Worldの検証

今週は、ドアの開閉機能を建物に追加します。

Naniteの勉強は、うーん。FoliageのNaniteでも試してみますか。

5.1 How To Open And Close A Door In Unreal Engine 5 | Efficient Methods And An In-Depth Explanation [9]で実装する

先週、見たTutorialの中で一番すぐれていたHow To Open And Close A Door In Unreal Engine 5 | Efficient Methods And An In-Depth Explanation [9]のやり方で建物のドアに開閉機能を追加します。

まずBlueprint Interfaceを作成します。

名前はInteract Interfaceとしました。

中を開き、Functionの名前をInteractに変更します。

今度はThird Person Character BPを開き、

いやその前に、Project Settingを開き、Action MappingsにInteractを追加します。

Third Person Character BPを開き、今作成したInteractを追加します。

以下のCodeを追加します。

Fを押すたびにOverlapしているActorを調べる訳ですね。

そしてそのOverlapしているActorがInterfaceを持っているかDoes Implement Interfaceノードで調べます。

勿論、調べるInterfaceは先程、作成したInteract Interfaceです。

もしTrueだった場合はInteract (Message )ノードに繋ぎます。

これって敢えて調べないとErrorになるんでしょうか?

Interfaceってこういうの調べなくても使用出来るのが強みだと思っていたんですが。

まあ、そういう事は後で自分で調べることにします。

後、TutorialではInteract (Message)ノードがInteractorというInputがありますが、

私のにはなかったので、この部分は無視して先に行きます。

あ。分かった。

InteractInterface内に

Interactを作成しましたが

Tutorialではそこで以下のParameterを追加していました。

別に使用しないけど一応追加しておきます。

なんて言っていたので、使用しないなら作らなくてもいいと思って、これらのParameterは追加しませんでした。

追加します。

Third Person Character BPに戻ってInteractノードをRefleshさせると

Tutorialと全く同じになりました。

更に以下の様に実装します。

Trueを返した時は、BranchしてBreakに繋ぎます。

これ必要なんでしょうか?

今回はInterface初心者なんで、一応Tutorial通りにやりますが、

これでThird Person Character BPの実装は終わりみたいです。

今度は

の実装をやります。

まずDoorを追加しました。

更にBox Collisionを追加します。

ここでInterfaceを追加します。

Event Graphに移りClass Settingを選択します。

そしてInterfacesの項目にあるImplemented Interfacesに先程作成したInterfaceであるInteract Interfaceを追加します。

Compileすると以下の箇所にInteractが表示されます。

これを開くと以下の様になっています。

まずVariableにIsOpen?を追加します。

以下の実装を組みます。

こんなん組むんだったら最初からBooleanをIs Closeにしておけば良いと思いますが。

今度は以下のVariableを追加しました。

これはドアの開閉にかかる時間を指定するためのParameterですね。

これらの値はInstance毎に指定するので、当然Instance Editableです。

ここでTimelineノードを追加します。

所が、Interface内ではこのNodeを使用する事は出来ません。

これはFunction内ではLatencyに関係する一切のNodeを使用する事が出来ない使用になっているからです。

そして InterfaceがFunctionの一種であります。

これから、Interface内でTimelineノードを使用しないけど、使用したのと同じ効果を発揮するための実装を行います。

まずEvent Graph内にTimelineノードを追加します。

名前をOpenDoor_Tとしました。

Custom Event、OpenDoorとCloseDoorを作成して以下の様にTimelineノードに繋げます。

これでInterfaceに戻ります。

すると

先程作成したTimelineノードを

変数として呼び出せるようになります。

うそ!

これは結構勉強になりました。

これから関数内でLatencyに関するNodeを使用したい時は、このやり方を真似る事にします。

そして以下の実装を追加します。

Set Play RateノードのNew Rateには1/Time to Openをセットする必要があるんですね。

Rateだから単位は/sになっているわけですね。

同様にDoorが閉まる場合も作成します。

当然、この後に先程作成したEvent、OpenDoorとCloseDoorを呼び出します。

そしてReturn Nodeに以下に示した様に繋ぎます。

これBoolean要らないですね。

まあ、Interfaceの勉強という事でこれはこのままにしておきます。

今度はTimelineノードの設定をします。

TimelineノードをDouble Clickして

以下に示したTimeline Editorを開きます。

更にTrackをClickしてAdd Float Trackを選択します。

以下の様になりました。

名前はDoorTrackに変更しています。

Lenghを1に変更しました。

こういう時、Tutorialが動画なのは本当に助かります。見逃したら戻って見直せばいいだけですので。

Graph内で右Clickして以下のBoxを表示します。

Add key to CurveFloat_0を選択します。

結果以下のような2つのkeyを追加しました。

この辺は他のCurveの操作と全く同じなので細かいStepはSkipしました。

これでTimelineノードの設定は終わりだそうです。

Event Graphに戻ります。

LerpノードのAlphaにTimelineノードのDoor Trackを繋げます。

うーん。

これは何をするのか分かりませんね。

今度はDoor のZ軸の値を示すVariableを作成しています。

あ、分かりました。

これをLerpノードのAとBに繋げるんですわ。

まずTutorialでやっている通りDoorが開いた状態をセットします。

この時のRotationのZの値は

です。

これを

のDefault値にセットします。

そして先程のLerpノードのAとBにセットしました。

DoorのRotationの値につなげてます。

うん。

最後にIs Open?ノードの値をセットします。

これで終わりです。

うん。

Collisionの設定はやっていないのでは?

うーん。

Third PersonがOverlapしていればいいので、別になにもセットしなくてもいいのかもしれませんね。

これは自分で実装を考えるときは少し改造するかもしれません。Box CollisionのEventを全く使用しないのは一寸もったいない気がします。

テストします。

Fを押しましたがDoorは開きません。

以下のParameterをセットするのを忘れていました。

もう一回テストします。

空きました。

もう一回Fを押すと

Doorは閉じました。

これが完成したらどうしても試したい事がありました。

以下の様にDoorに密着した状態でDoor開けたらどうなるんでしょうか?

試します。

Doorに押し飛ばされました。

5.2 Naniteの勉強

Doorの開閉の実装が思っていたより3倍位時間が掛かったのでNaniteの勉強をする時間が無くなってしまいました。来週やります。

6.Gaeaの勉強

今週はGaeaの勉強は沢山やる事があります。

まず、先週の続きですが以下の方法について調査します。

更にGaeaにはPaintして望みの地形を作成した後で、Noiseを追加する機能がある事を発見しました。これについて勉強します。

6.1 GaeaでPaintする

まず簡単に出来るこちらからやっていきます。

Gaea 1.2 Tutorial | Drawing custom shapes with the Draw Node [10]です。

これ見るとDrawノードを使用していますが、

私のGaeaにはDrawノードがありません。

うーん。

これは想像していませんでした。

どうしようかな。

何とComment欄に以下の質問が書かれていました。

これが学習Communityの強さなんです。

これに対してTutorialの製作者であるAndrea Cantelli氏が以下のように回答していました。

これをまずやってみます。

Maskノードを追加しました。

Edit Maskを押して

Zの文字を書きました。

Fxノードにつなげます。

LvとClmpをEnableします。

Clampを少しDownしろと書かれていますが違いが不明です。無視して先に行きます。

Fxを右ClickしてShow asからTerrainを選びます。

以下の様な表示に切り替わりました。

これ横から見ると明白ですが、高さがありません。

あ、Clampをここで使用するのかも。

試します。

ClampのMaxを18%にしてみました。

結果です。

厚みが出来ました。

うーん。

でも想像していたのとは一寸違いますね。

一寸だけ加工してみます。

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

結果です。

いいんじゃないでしょうか。

こんなに簡単に望みのTerrainが作成出来るなんて一寸驚きです。

6.2 Buildする時の正しい設定について

以下の部分の設定方法についてです。

Resolutionが1009なのは正しいのは分かっていますが他の設定の正しい値が分かりません。

これを調べます。

2022-06-26のBlogにGaeaのBuildingのSettingについての勉強の記録がありました。

これを読むとKlaus氏のGaea Beginner Tutorial Series : Part 5 - Build And Export [11]で勉強したみたいです。

ここに書かれている事をまとめます。

<Method

つまりFree版を使用している限りNormal Buildしか選択出来ないわけです。

はい。

一個解決しました。

<Range

これについては詳しくまとめてありました。ありましたがこれをまとめた2022-06-26のBlogを書いた時点では実際の意味は理解しておらず、結論としては良く分からないとまとめていました。

今、そのまとめを読み直したら非常に良くまとまっていましたので、以下にまとめ直します。

まずRangeが何を指定してるかと言うとTerrainの高さです。Terrainの高さをExportするに当たってどうやって指定するのかについて決定するのがRangeの役目です。

<<Raw>>

Nodeの高さを無視して以下の値を使用します。

<<Proportional>>

歪みが生じるので使用しない方が良いそうです。

<<Normalized>>

こちらはNodeの高さをそのまま使用するそうです。

<<Remapped>>

以下の箇所で指定し直します。

成程。

ただし全部完璧に分かった訳ではないです。

例えばNodeの実際の高さとかはどうやって調べるのか分からないとNormalized は使用出来ません。

RemappedにしてもMaxの単位が分からないと指定の仕方が分かりません。

でも大まかな意味は分かりました。

6.3 UEでImportする時の条件について

これは以下の条件についてですね。

これで分からないのは、Section Sizeとかの設定です。

調べます。

2022-08-01のBlogに以下のようにまとめられていました。

となるとこの設定のままでOKみたいです。

6.4 Layer同士がBlendしている時は、両方のLayerがBlendするのではなく、後のLayerが100%上書きするような設定について

これは何処で調べれば良いのか分かりません。

後で、思い付くかもしれないので来週また考える事にします。

6.5 Layerを選んでそのLayerだけにFoliageをPaintする方法

これはあの人のTutorialに書いてありました。

うーん。

Dither Temporal AAノードの使用方法を解説したTutorialを作った人です。

PrismaticaDev氏でした。

2022-03-14のBlogで勉強していました。

元のTutorialはLandscape Grass | 5-Minute Materials [UE4][12]でした。

こんな簡単な方法でLayerを分けてPaint出来たとは。

6.6 Foliageで生成した岩とCollisionする方法

本来はPaintで生成されたFoliageはCollisionするはずです。

何故、先週の岩はCollisionが無いのかが分かりません。

以下に思い付いた原因になる可能性を示しておきます。

使用した岩には元々Collisionが無かったです。後から追加したんですが、それが原因かもしれません。

後、考えらえるのはFoliageに使用した岩にはNaniteを使用しています。これが何かの影響を与えた可能性もあります。

後は単純にFoliageの設定の項目とかでしょうか。

この辺については来週調べる事にします。

6.7 ポケモンの新作の批判がすごい件について(Landscapeに関係するのでここに書きます。)

アメリカでは新作のポケモンのGraphicsがしょぼい事で結構な批判が巻き起こっています。これについて述べたい事がありますが、今週はもうまとめている時間がありません。来週やります。

と思ったんですが、一寸だけ時間が空いたので簡単にですが、以下に言いたい事だけまとめておきます。

まず私はGameはしません。

Gameのように主体的に何かしなければならない娯楽があんまり好きではないんです。私が好きな娯楽は、映画とかアニメを見たり、漫画や小説を読んだりする受動的な事です。

こればっかりは持って生まれた気質だから変わる事は無いと思います。

しかしそんな私でも、唯一はまったGameがPokemon GOです。

Pokemonを整理するのに5分だけと思って、1時間も費やしてしまった後、勉強に費やすべき時間と後、体力を、娯楽に消費してしまった。と焦った記憶があります。

そのくらい面白かったので、今回ポケモンの新作が、アメリカでかなり辛辣な批判を浴びているのを聞いて、かなりびっくりしました。

そしてそれについて私がどう思っているのかをまとめたいと思います。

実際、この事件が起きて初めて新作のPokemonのゲーム画面を(YouTube上ですが)見ましたが、そんなにUserが激怒するほどGraphicsが悪いのかと疑問に思いました。

Landscapeに関して言えば、確かにGaea やWorld MachineのようなTerrainを専門に生成するSoftを使用してNoiseから自動で生成したLandscapeを使用している様には見えませんでした。しかし別にPhoto-realisiticなLandscapeを作成するのが目的ではないですから、それは作品の方向性の問題でしょう。

それよりも地面を見るとTilingも起きてないし、うっすらとMacro Variationを使用しているのも確認出来ました。

それなりにしっかり作り込まれていると思いました。

後、Switchの性能が悪いと言う意見もありました。

これも調べましたが、SwitchのGraphic Cardの性能は大体、GTX 1650と同程度だそうです。

たしかSteamか何処かが出した調査結果で、一番Graphicsにうるさいと言われているPC Gamerの中で最も使用されているGraphic CardがGTX 1650だったはずです。

これ、本当にSwitchの性能が悪いと言えるんでしょうか?

正直、娯楽だけが目的の場合、Graphic CardにGTX 1650以上の値段を出せる人はあまりいないんじゃないでしょうか?

そう言う意味では、Switchの性能は庶民が許せる範囲での最高の性能と言ってもいいかもしれません。

簡便な調査ですが、このような結果が出てくると、辛辣な批判が本当に根拠のあるものなのか、言いがかりなのか一寸判断しかねる感じがします。

更にこのかなり強烈な批判は、暫くするとポケモンのGraphicsについては声を潜めて、Bugが多いとかFrame Rateが落ちるとかを言うようになりました。

この時点で、少なくとも私には、Gameに対してのUserからの苦情というより、クレーマーからのイチャモンに思えました。

苦情の内容が二転三転するなんて、典型的なクレーマーでしょう。

それで思ったのが、アメリカのそういうイチャモンを付けるのが専門の団体からポケモンは目を付けられたんじゃないのかと言う事です。

なんせ奴隷制のあった国なので、アメリカ人は人からモノを奪う事に対して良心が痛む事がないんです。

そう言う国のイチャモンを真に受けて対応したら、本当に骨までしゃぶられてしまいます。

ポケモンの会社は、こういう言いがかりには、毅然と対応して欲しいです。

というか毅然と対応出来ない場合、最悪倒産まで追い込まれると思います。

アメリカはそう言う文化なんです。いじめっ子が悪い。と考えるのではなく、いじめられっ子がいじめを許しているのが悪い。と考える文化なんです。

だから弱い奴とか馬鹿な奴には何しても良いと考えています。

そう言う文化の国で、イチャモンや言いがかりを受けた時に毅然と対応出来ないと、本当に最悪の事態を迎える事になります。

これがこの件についての私の結論です。

後、もう一つ。

今回の件を調査するに当たってYouTubeなどでポケモンの新作をPlayしている動画(英語圏のだけ)を見たんですが、その時のPlayer達が一番、文句言っていたのが、Playしている女の子のCharacterにスカートを着せられない事でした。

これは私には、本当に衝撃でした。本当にGameをやっている人達の不満は、そういうイチャモンを付けるのが専門の人達からは決して聞けない内容だったんです。

これは勉強になりました。

7.雪山のMapの作成

今週もVolumetric Cloudの勉強をやっていきます。

今週は、先週述べたように、Paint Cloudで作成した雲をSaveしたりLoadしたりする機能がないのか調査します。

9.1 Materialを変更してみる

まず試したのが、以下のMaterialの内一個ぐらいWidgetが正しく表示されるのがないか?という事です。

現在、Paint CloudをPlayすると以下のWidgetが表示されますが、

数字が全部N/Aになっています。

これがMaterialのせいなら、正しいMaterialを使用したらWidgetが正常に動いて、LoadボタンやSave機能も正常に働き、描いた雲のDataをSaveする事も可能になるかもしれません。

試します。

全部だめでした。

うーん。

これは究極的には出来るかもしれませんが、かなり大変かもしれません。

もう一つ、先週Volumetric Cloudの勉強をしていて気が付いたことがあります。

それはZero Conditional氏のVolumetric CloudのTutorialが、ほとんどすべてのVolumetric CloudのTutorialの源になっている事です。

彼が作ったVolumetric CloudのTutorialを元にして、あらゆるVolumetric CloudのTutorialは作成されている感じがします。

と言う訳で彼のTutorialを見て、何をすべきか考える事にします。

9.2 Zero Conditional氏のVolumetric CloudのTutorialを見る

まず Beginners Intro to Volumetric Clouds in Unreal Engine 4.26 [13]を見ます。

このTutorialはZero Conditional氏が最初に作成したVolumetric CloudのTutorialです。今回初めて見ます。

最初は軽く見始めたんですが、とても貴重な情報の塊です。

章を分けてこのTutorialだけでまとめる事にします。

9.3 Zero Conditional氏の Beginners Intro to Volumetric Clouds in Unreal Engine 4.26 [13]を勉強する

このTutorial、UEのVolumetric Cloudの勉強に必要な貴重な情報が詰まっています。

ただし作成されたのが、一年以上前で、使用しているUEのVersionも4.26ですので、今のUEの機能とは若干違う部分もあります。

その辺は端折りつつ、重要だと思う内容を抽出して以下にまとめます。

<Introduction

特に重要な内容はないです。

Lets get started

ここではBlankのLevelから、

以下に示したEnvironment Light Mixerを使用して空を生成する方法を解説しています。

このTutorialが作成された時は、まだこの機能が完成されていなかったみたいで、追加したActorのParameterをいろいろ調節しないと空が出来ないみたいです。

そのParameterの調整方法などについて詳しく説明しています。

今のUE5は、これを押すだけで空が完璧に作成出来るので、Environment Light Mixerがある事さえ知っていれば問題ないのかな。と思っています。

UE4 Documentation

Volumetric Cloudに関しての公式のDocumentについてです。

ああ。

これ調べるの忘れていました。

当然、公式のサイトにVolumetric Cloudについての説明が載っていますよね。

すっかり調べるの忘れていました。

後で、見る事にします。

<Cloud Shadow Parameter

Directional LightにあるParameterのAtmosphere and Cloudについて解説しています。

Volumetric Cloud に限りませんが、私このParameterの機能を覚えるの凄い苦手で勉強しても必ず忘れてしまいます。

Ben Cloward先生のTutorialでVolumetric Cloud関連のParameterを何個か勉強しましたが、このParameterを勉強したかどうか全く覚えていません。

一応、Blogに検索かけて調べてみます。

調べたら2022-07-12のBlog2022-07-18 のBlogで、 Atmosphere and Cloudについて勉強していました。

2022-07-12のBlogでは World Level Design社のTutorialであるUE4: Analysis of Volumetric Clouds and How to Use Them [14]を勉強していてその過程で、

Atmosphere and CloudにあるParameterの値が変更出来ないで困っています。

Cast Cloud ShadowsにCheckを入れるとParameterの値が変更できると書いてありました。

これはこれで貴重な情報です。

2022-07-18 のBlogでは、Ben Cloward先生の

Volumetric Clouds - Building Worlds In Unreal - Episode 32 [15]を勉強しています。

この中で

という事について説明していました。

それでは、Beginners Intro to Volumetric Clouds in Unreal Engine 4.26[13]における Atmosphere and Cloudの説明をみます。

Cast Cloud Shadowsについてです。

これは雲の影を追加します。

Onの時です。

比較のためのOffの状態も示しました。

雲が凄くRealになる代わりに、地面が真っ黒になっています。

次にこの影の強さの調整を以下のParameterからします。

この中のCloud Shadow on Surface Strengthの値を下げると

地面が見えるようになります。

これ自分でも試してみたんですが、まず地面が暗くなりません。

色々試して分かったんですが、まず雲が大量にないとそもそも影を投影しません。

次にSky Lightが効いている限り、地面が真っ黒になる事はありません。

それ以外は、このTutorial通りでした。

以下に私が試した例を載せます。

Cast Cloud ShadowsにCheckを入れました。

地面は少しだけ暗くなりました。

Cloud Shadow on Surface Strenghの値を1から以下の値に下げました。

地面が明るくなりました。

これをSky Lightがない状態で行うと

になります。

ただし、私のこの例だとVolumetric Cloud自体がしょぼくて敢えてCast Cloud Shadowを行うMerit自体があまりないです。

更に、すべてのVolumetric CloudのTutorialが参考にしているVolumetric Cloudの元のTutorialを作成したZero Conditional氏のTutorialで、そんなあいまいな話をするのかなとも思います。

ので、もっとVolumetric Cloudがはっきりしている例でもう一回テストしてみます。

以下の例を用意しました。

これならTutorialの例にかなり似た状態です。

Cast Cloud ShadowsにCheckを入れました。

結果です。

まず雲の陰影がはっきりしました。

そして地面が真っ黒までは行きませんが、かなり黒くなりました。

ここで

Cloud Shaow on Surface Strenghの値を1から0.752に下げました。

すると以下に示した様に、雲の陰影の濃さを保ったまま地面の影を、 Cast Cloud Shadowsを使用する前のように薄くする事に成功しました。

Tutorialがやっていた事をやっと再現できました。

次はCloud Shaow Map Resolution Scaleについてです。

空を注意深く見ると薄く層になっているのが見えます。

これが、Cloud Shaodow Map Resolution Scaleの値を2にすると

う、うん。

ここからのTutorialの説明が一寸混乱します。

もう一回、この部分の説明を見直します。

分かりました。

この空に層が出来ているのはCloud Shadow MapのResolutionのせいだそうです。

それがDefaultでは512にセットされていますが、 Cloud Shaodow Map Resolution Scaleの値を2にすると1024になるのかどうか、不明だと述べていました。

それで空の層が消えたかというと

消えてない気がします。

そしたら以下のCloud Shaode on Atmosphere Strenghの値を下げていました。

その結果、

空の層が消えました。

これも自分で試してみたいんですが、私の今見てるMapでは空の層が見えません。

次にCloud Shadow Extentについてです。

どこまで影が行くのかを管理しているそうです。

このShadow Mapがどんな仕組みなのか不明なので、よく理解出来ないです。

ここで時間が尽きてしまいました。

残りは来週勉強します。

8.報酬システムの研究

今週もDialogue Systemの勉強をします。

今週も先週の続きをやっていきます。

まず先週、どこまでWidgetの実装を読んだのかすっかり忘れてしまったので、復習します。

間違って読んでいるところを発見しました。

ここで

と述べています。

でもBreakしたってCompletedの実装は実行するはずです。

その場合、Found ValidがTrueになっているので何もしない。という結果になります。

つまりFound Valid変数は絶対必要な変数だったって事です。

全部、読み終わりました。

大体先週何をしたのか理解しました。

Constructorの実装にあるTo NPC Replyノードの実装を読んでいたら

その中にDisplay NPC ノードがあり、その実装を読んでいたら、最後に

Display Repliesノードがあって

この実装は来週読むことにしようとなって終了しました。

まず、 Display NPC ノードの実装にある

このNodeの機能が分かりません。

これやっぱりDialogueがNPCかどうかを確認していますね。

そういう機能でした。

まずWidgetを開くと以下のように既にNPCのDialogue、Playerの3つの選択、そしてNPCの名前が表示されています。

これらのDialogueはConstructorで読み込んでいます。

つまり先週、勉強した箇所で読み込んでいます。

まず NPCのDialogueですが、以下に示した Display Npc Node内のSet TextノードでDialogueがセットされています。

次がPlayerの3つの選択肢です。

うーん。大体、この辺の実装でやっているのは理解できますが、機能がよく分からないNodeが何個かあります。

まずこれです。Get Next Nodeノードです。

これ、次のノードだけ掴んでくるんでしょうか?

例えばDialogueのNodeが以下の様になっていた場合、

現在、1のNodeに居たとしたら、 Get Next Nodeノードが返すのは2のノードだけなんでしようか?

それとも2以降にあるすべてのNodeをArrayとして返してくるのでしょうか?

次に、現在2のNodeに居たとしたら、Get Next Nodeノードが返すのは3,4,5のNodeになると思いますが、順番はどうなっているんでしょうか?

実験して確認しないと分かりませんね。

やってみます。

以下のWidgetを組みました。

更に以下のDialogueも作成しました。

このwidgetを呼び出します。

1だけPrintされています。

つまり次のNodeだけ呼ばれています。

次にDialougeを以下の様に変更します。

現行のNodeを1に変更した後、同じWidgetを呼び出した。

はい。

予測した通りです。

Dialogueをセットする仕組みは大体理解出来ました。

後、分からないのは

の機能です。

これ最初は、

NPCの時にTrueを返しています。

しかし次に使用している箇所では、Playerの時にTrueを返しています。

このNodeの機能は本当に謎です。

一寸短いですが、一応Diaogueの表示の仕組みは理解出来たのでここまでとします。

8.2 Dialogue Pluginを勉強してみて

もう今週は時間がないのでまとめませんが、Dialogue Pluginを勉強する前に

Not Yet Dialogueを勉強していました。

2021-03-15のBlogにこのNot Yet: Dialogue Plugin Systemの使い方もまとめてあります。

しかも自分でDialogue Systemを自作しています。

以下に私が自分で考えたDialogue Sytemで表記したDialogueを示します。

何故、こんな無駄な事をしてしまったのか。

Landscapeに例えるなら、UEのLandscapeの使用方法を勉強して、World Machineの使用方法を勉強して、更にGaeaのLandscapeの作成方法を勉強する。と言っているのと同じです。

別にDialogue Systemで天下取る野望がある訳ではないので、一個使えれば十分です。

何故、こんな間違いを犯してしまったのかについて検証・考察する必要があります。

9.Anime Renderingの勉強

今週で、アニメレンダリングの勉強などはPart 10 を迎えました。ここで一端区切りにして来週、Anime Renderingの総括をします。

9.1 Vroidで作成したModelUEImportするの続き

今週はVRM4U [16]のMaterialで学んだ

を使用して自分で影付きのMaterialを作成してみようと思います。

まず以下のMaterialを作成しました。

当然Unlitです。

こんな感じです。

影(陰の方)は完全になくなりました。

Materialの実装をDirectional Lightノードを使用して改良します。

以下のように実装しました。

説明します。

IfノードのAの実装です。

VRM4U [16]のMaterialで学んだLight Direction ノードとNormalをDot Productします。

これLight DirectionとNormalが垂直に交わるときに0、水平に交わるときに1になるように設定すべきなんですが、その計算方法がこれであっているのか調べるのが面倒なので調べていません。

実験結果と比較して後で調整します。

IfノードのBの値です。

閾値を設定します。

この値より大きいと影(陰)、小さいと普通の色になるようにします。

うーん。逆か?

まあ、後で結果を見て調整します。

色を指定しました。

分かり易いように黒と赤にしました。

結果です。

あれ?

イキナリ上手く行ってない?

ParameterであるShadow Sizeを変更してみます。

結果です。

ああ。

出来ている。

細かい数学の計算の辻褄はあって無いかもしれませんが、Unlitなのに影(陰)が出来ていますね。

念のため今度はDirectional Lightの向きを変えてみます。

にしました。

結果です。

しっかりとDirectional Lightにつられて影の位置も変化しています。

色を以下のように変更してVroidの顔のMaterialに使用してみます。

以下の顔の部分に使用します。

結果です。

逆ですね。

首の部分の影と向きが逆になっています。

以下の部分を逆にしました。

結果です。

Shadow Sizeの値を調整します。

結果です。

顔の回りはかなりデコボコしていますが、前と比較するとかなりマシです。

Directional Lightを動かしてみました。

角度によってはかなり良い感じです。

これに法線転写を追加したいですね。

一寸調べます。

法線転写は以下の実装をNormalに繋いでいますが、これをEmitterの計算に追加する必要がありますね。

更にNormal Vectorの空間をTangent SpaceからWorld Spaceに変換する必要もあります。

あ。

これ考えるの忘れていた。

これは簡単には出来ませんね。来週考える事にします。

今週はここまでです。

9.2 公式のDocumentStylized Rendering [17]の勉強

今週もWorld Aligned Blendノードの勉強をします。

先週、以下の事を今週やると言って終わりました。

こんなの全部やるのは無理です。

「World Aligned Blendノードの返し値であるAlpha、w/Vertex Normal、そしてw/Explicit Normalの違いについて」だけ調べる事にします。

先週作成したLandscapeで比較します。

alpha値です。

With Vertex Normals値です。

With Explicit Normal値です。

あるような、ないような。良く分かりません。

もう少し近づいてみます。

Alphaです。

With Vertex Normals値です。

違いあるんでしょうか?

完全に一致しています。

With Explicit Normal値です。

分からないですね。

実装から見てみます。

Alpha値です。

Alpha値ではPixel Normal WSノードとInput World VectorをDot Productしています。

With Vertex Normals値では

Vertex Normal WSノードとInput World VectorをDot Projectしています。

最後にWith Explicit Normal値では

Input Explicit NormalノードとInput World VectorをDot Projectしています。

これが3つの違いでした。

分かりました。

With Explicit Normalは兎も角として、AlphaとWith Vertex Normalsの違いは、PixelのNormalを使用するか、VertexのNormalを使用するかの違いだけでした。

これでは私のLandscape用のMaterialでは差が出ないのも納得です。

VertexとPixelのNormalで凄い差の有る場合はこの違いがみられるんでしょうね。

以上です。

10.DirectX 12の勉強

今週は、C++ DirectX 12 Game Engine - [S01E01] - Creating Our First Window [18]のMessage Loopを勉強します。

今の状態で既に完成はしているそうです。

ただし今の状態で実行すると一瞬だけ画面が光って終だそうでです。

今週勉強する実装は、その一瞬で終わる実行を永続さえるためのものだそうです。

何だ、単なるWhile構文の追加か。と思ったらそれをMessage Listenerを使用して以下の箇所に作成するそうです。

あれ。

この部分、ひょっとして結構難しい?

Message Listener は複雑なので最初に実装を全部コピぺして、その実際の実装を見ながら機能を説明するそうです。

うーん。

Tutorialの説明を見る前に、自分で読んでみます。

まずMSG ClassのObjectであるmsgを宣言しています。

そしてWhile構文です。

これはmsgがWM_QUITにならない限り永続して行います。

どうやらmsgはEnum型みたいですね。その中の一つがWM_QUITなんでしょう。

While構文内を見ます。

If節があります。

Peek Message()関数が使用されています。

名前通りの解釈をするならMessageをのぞく機能を持っている関数でしょう。

するとmsgをのぞいてその中身がPM_REMOVEだったら以下の実装を実行して。とで言っているんでしょうね。

実行する関数は以下の2つでした。

  • TranslateMessage()
  • DispatchMessaget()

この二つの関数の役割は良く分かりませんね。

まあ、これくらい理解していれば予習は十分でしょう。

Tutorialの説明を見ます。

まず

についてです。

これは予測の通り、Message Classでした。

Message Eventを開始させ、そのEventに対して、色々なCommandを指示するそうです。

Eventを実装するためのCommandを保持するClassなんでしょうか?

今一、説明が理解出来ません。

調べるか。

公式のwin32 のDocumentのMSG structure (winuser.h) [19]に以下の説明がありました。

更に、以下の構造をしたStructだそうです。

うん。Classじゃなかったのか。

この中にMessageというParameterはありますが、その単位はUINTですね。

以下のような実装は可能ですが、条件は限定されますね。

例えばWM_QUITがMacroでその中身が1とかのUINTである場合です。

これなら可能でしょうね。

あとEnumも、一番目の要素は0、2番目の要素は1に対応しているはずです。そういう事なんでしょうか。

これ見ると単なるStructです。あんまり深く考える必要な無いみたいです。

次に行きます。

Whileです。

ここは特に記録すべき内容の説明は無かったです。

PeekMessageについてです。

PeekMessageはNon-Blockingというやや高度な技術を使用して作成されているそうです。

これを使用しなくてもMessage Eventは作成する事は出来るそうです。

Tutorialの説明を聞いている、多分ですがPeekMessageはMulti-Threadで動くんでしょうね。

TranslateMessageとDispatchMessage()です。

この二つはMessageをTranslateして、Windowに送るそうです。

うーん。

分かったような分からんような説明です。

まあ、それくらいの理解でもいいのかもしれません。

最後にWindowを表示さえて終わっています。

はい。

この部分はまあ、はっきり言ってしまうと、丸Copyでもいいのかもしれません。

実装は来週行おうと思ったんですが、どうせCopyするだけなのでやってしまいます。

全部、コピペで済ませました。

実行します。

以下のWindowが表示されました。

出来てますね。

今週のDirect Xの勉強はここまでです。

11.まとめと感想

先週、気合いが入り過ぎたので、今週は一寸抑えて勉強しました。

Anime Renderingの勉強は今週を持ってPart10を迎えましたが、それなりの成果が出て来ました。

これについては来週まとめます。

12.参照Reference

[1] OlympusMonsTutorials. (2021, February 17). C++ DirectX 12 Game Engine - [S01E01] - Creating Our First Window. YouTube. https://www.youtube.com/watch?v=2vrEIhAajhM

[2] (2022, July 28). WNDCLASSEXW (winuser.h) - Win32 apps. Microsoft Learn. https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassexw

[3] CGHOW. (2022, October 31). Ribbon Trails in UE5 Niagara Tutorial | Download Files [Video]. YouTube. https://www.youtube.com/watch?v=spONYYja09E

[4] Ben Cloward. (2022d, September 15). Pixelation Filter - Shader Graph Basics - Episode 61 [Video]. YouTube. https://www.youtube.com/watch?v=x95xhWCxBb4

[5] Unreal Engine. (2022, July 13). Renaming Projects | Tips & Tricks | Unreal Engine [Video]. YouTube. https://www.youtube.com/watch?v=HzQhO8nxeI8

[6] SabreDartStudios. (2020, April 25). Open World Server (OWS) - How to Rename your Project [Video]. YouTube. https://www.youtube.com/watch?v=yCYGXw127oQ

[7] Unreal Engine. (2022, July 13). Renaming Projects | Tips & Tricks | Unreal Engine [Video]. YouTube. https://www.youtube.com/watch?v=HzQhO8nxeI8

[8] Moiz, M. (2021, January 7). Rename Your Unreal Engine 4 Project (Blueprints and C++) | Unrealistic. https://unrealistic.dev/posts/rename-your-project-including-code

[9] Matt Aspland. (2022, April 15). How To Open And Close A Door In Unreal Engine 5 | Efficient Methods And An In-Depth Explanation [Video]. YouTube. https://www.youtube.com/watch?v=Eakt2hBd3YY

[10] Andrea Cantelli. (2021, February 7). Gaea 1.2 Tutorial | Drawing custom shapes with the Draw Node. YouTube. https://www.youtube.com/watch?v=EjpBFzP7enw

[11] Klaus. (2022, January 23). Gaea Beginner Tutorial Series : Part 5 - Build And Export [Video]. YouTube. https://www.youtube.com/watch?v=PpaRzdT_Qx4

[12] PrismaticaDev. (2021, June 4). Landscape Grass | 5-Minute Materials [UE4]. YouTube. https://www.youtube.com/watch?v=uUOcs20Dkcc

[13] Zero Conditional. (2020, December 22). Beginners Intro to Volumetric Clouds in Unreal Engine 4.26 [Video]. YouTube. https://www.youtube.com/watch?v=M2rOitk_I9g

[14] WorldofLevelDesign. (2021, February 9). UE4: Analysis of Volumetric Clouds and How to Use Them [Video]. YouTube. https://www.youtube.com/watch?v=8XjEk-CP-kQ

[15] Ben Cloward. (2021, May 27). Volumetric Clouds - Building Worlds In Unreal - Episode 32 [Video]. YouTube. https://www.youtube.com/watch?v=dolfk2z4LDo

[16] Harube, R. (n.d.). VRM4U. VRM4U. https://ruyo.github.io/VRM4U/

[17] Stylized Rendering. (n.d.). Unreal Engine 4.27 Documentation. https://docs.unrealengine.com/4.27/en-US/Resources/Showcases/Stylized/

[18] OlympusMonsTutorials. (2021, February 17). C++ DirectX 12 Game Engine - [S01E01] - Creating Our First Window. YouTube. https://www.youtube.com/watch?v=2vrEIhAajhM

[19] Jwmsft. (n.d.). MSG (winuser.h) - win32 apps. MSG (winuser.h) - Win32 apps | Microsoft Learn. Retrieved December 3, 2022, from https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-msg