<前文>
<三国志と英語力の関係について>
日本国内で、テストのためにしか英語の勉強をした事がない人には多分、永遠に分からない話ですが、英語圏の人に英語で発言する必要がある時にアジア人である我々日本人は普通にしゃべっていると知的とは思われません。
ほとんどの日本国内に住んでいる日本人には、アメリカ人などの英語圏の人から日本人が知的であると見なされない事に対して信じられないと思います。別にその事についてあーだこーだ言うつもりはありません。ご自由にとだけ言っておきます。
私がここで述べたいのは、何故、英語圏の人に英語で発言する必要がある時にアジア人であるだけで知的とはみなされないのか。と言う理由とその対策についてです。
まずアジア人であるだけで知的とはみなされないのか。と言う理由ですが、結局の所、英語圏におけるアジア人の地位は使用人なんです。
使用人に重要な仕事を任せますか?任せませんよね。
使用人に家族の重要な情報を教えますか?教えないですよね。
そして何か重要な決定をする時に使用人に相談しますか?しませんよね。
はい。
ほとんどの日本人は英語で発言する時に、外人からは使用人と思われているのに自分が賢者(guru)と思われていると勘違いして発言します。
そしてアホかと。思われます。
これは日本人の英語が通じない原因の一つでもあります。
アメリカ人、特にアメリカの支配階級である白人層にとってアジア人である日本人と話をする時というのは、何十人の使用人が働いている屋敷の主人がその使用人の一人に話しかける時と同じで、それは命令する時だけなんです。
それなのに話しかけられた日本人は、とうとう外人まで俺の頭の良さを理解して相談しに来たのか。しょうがないから俺の知性を貸してやるか。という気持ちで返答するから話がかみ合わないんです。
それで英語も通じなくなります。
しかしもっと重要な事は、日本語の情報というのは一部を除いて、英語圏の人が使用人に教えても良い話とか、使用人が仕事をするのに必要な話だけが翻訳して伝わっていると言う事なんです。
これホントに見事なほど、英語圏の人がこれは使用人には伝える必要がないと判断した情報は日本語に翻訳されないです。
だから日本語の情報だけを元に、英語で発言すると何か凄い頓珍漢な内容になります。
非英語圏の人と英語で会話する時は、これでも何とかなりますが、英語圏の人にとっては物凄い政治的な問題(中絶禁止とか銃の規制とか)に関しての会話を英語圏の人とする時には、単なる使用人としてではなく一人の人間とみなして会話して来ているのに、凄い頓珍漢な返答をして英語圏の人を唖然とさせてしまいます。
もっと、分かり易い例を思い付きました。
アメリカにいた時に日本人の友達とRestaurantに行った時ですがwaitressがサラダにするかスープにするか聞いて来たんです。そしたらその日本人の友達がYes. Pleaseって答えたんです。
その場にいたアメリカ人全員が、動物園の珍しい動物でも見るように、こっちを見て来ましたよ。質問して来たWaitressなんか、驚愕からか白人特有の大きな目を更に大きくして、顔の三分の一位が目になってこっちを見つめていました。
すっかりその事は忘れてしまっていたんですが、最近、日本のファミレスにいったらスープとサラダが一緒に出て来たんです。
思わず、その時一緒にいたアメリカ人の子に「日本ではスープとサラダって一緒に出て来るものなの?」って聞いちゃいましたよ。
それは兎も角としてアメリカではRestaurantで注文する時は、スープかサラダのどっちかを選ぶのが常識なんです。それに対してYes. Pleaseって答えたら、凄い頓珍漢な回答になります。
でもその日本人の友達からしたらそんなに変な回答じゃなかったんです。
だって、日本のファミレスではサラダとスープは一緒に出て来るものだから。
恐らく、その友達はwaitressの早口の英語のサラダとスープの部分だけ聞き取れて、きっとこのWaitressはサラダとスープ付きにしますかと聞いて来ているんだな。と推測してYes. Pleaseって回答したんです。
日本の常識から推測した場合、全然、頓珍漢な回答じゃなくてかなり鋭い回答だったんです。
このように日本語の情報だけを元に、英語で発言すると何か凄い頓珍漢な内容になりがちです。
それを回避するためには普段から英語圏のニュースやそれに対するコメント何かを注意深くチェックする必要があります。またReddit等のThreadには英語圏の本音が書かれているので、逆算して読むと英語圏の日本人からは見えない常識が分かったりします。
しかし最近、もっと凄い方法を見つけたんです。
それは三国志なんかの中国の古典物を読む事です。
これ、読み方にもよるんですが、どうやって君主に正しい情報を伝えないでその君主を騙すのかと、君主側がその騙しを見抜いて、更に本当の情報を得るためにはどうすれは良いか。だけが書かれているんです。古今東西のあらゆる正しい情報を伝えないで騙す手段とその対抗策がそこには書かれていました。
もうむさぼるように三国志なんかの中国の古典物を読んだり動画を見たりしています。
情報を伝えないって行為をした時点で、その行為自体が別の重大な情報を伝えていたなんて驚きです。
私が三国志関連の中国の古典物を読み終わった時、もっとアメリカやヨーロッパの本質が見えるようになると思います。そうなったら多分ですが、アメリカ人が質問して来た時の回答の内容が、知的産業で働いている平均的なアメリカ人が金払ってでも聞きたいレベルの質にまで自然に高まっていそうです。
それでは今週の勉強を始めます。
<本文>
1.今週の予定
今週もいつも通りやっていきます。
- Niagara: Flower Effect in UE4 Niagara Tutorialの続き
- Material : Content Exampleを見るの続き
- NPCのAIを作成する
- Game Design:ポケモン+HxHの念能力( 戦闘システムの作成)
- Map1のBug直し:武器屋で買える武器の設定の追加
- UE5:naniteの勉強
2.Niagara: Flower Effect in UE4 Niagara Tutorialの続き
CGHOW氏のFlower Effect in UE4 Niagara Tutorial [1] の検証の続きをやっていきます。
2.1 色々なVariationのFlower Effectを作成する
<Black Bodyノード>
黒体放射ってやつですね。量子力学の勉強の最初に出て来るやつです。
公式のDocumentであるUtility Expressions [2] には以下の例が紹介されています。
これを見ると指定された温度における黒体の発光を示していますね。
ネットで調べると大体の目安として4000Kで赤、6000Kで黄色、12000Kで青となっています。試してみます。
<<4000k>>
Utility Expressions [2] の例とほぼ同じ実装をしました。
結果です。
赤と言うかOrangeですね。
<<6000K>>
白い。黄色くはないです。
<<12000K>>
うーん。青くはないです。
でももしかするとこっちの計算結果の方が実際の見た目には近いのかもしれませんね。
例えば光子が錯乱する割合は波長によって変わって来ますし、恒星と違ってこんな近くで黒体放射を見たらこういう色なのかもしれません。
こうなると実際の計算を見て確認したいです。
うーん。見れない。
MaterialのノードもUE5のSource Codeから見ればどんな実装しているのか見れるんでしょうか?
その辺のやり方もこれから勉強していきます。
<Torus Location Moduleについて>
Niagaraの勉強と称してずっとMaterialの勉強をしていますが、今度は本当にNiagaraのModuleの勉強です。
Torus Location Moduleは何度か前に使用した事のあるModuleです。
Torusつまりドーナツ状にSpriteを発生させるModuleです。
<<Torus Knot>>
Torus Knotは良く知りません。
調べます。
うーん。調べたんですが分かり易い解説が見つからなかったです。
Torusの表面をなぞるように作成されるKnotのある形状でpとqの値を指定する事で形状を指定出来る事は分かったんですが、何かピンとしません。
大体のTorus Knotの形状は分かったのでそれで終りにします。
<<Ring/Disc>>
更に、Ring/Discもあります。ただしこれはTorus Location ModuleのTorus ModeではRingとなっています。
RingだったらTorusと同じ気がしますが、どう違うんでしょうか?
公式のDocumentで私が見つけられたTorus Location Moduleに関する説明はParticle Spawn Group [3]にある
だけでした。後は実際にTorus Location Moduleを使用している所から機能を推察するしかありませんね。
今回は先々週やった内容を復習してTorus Location Moduleの使用方法の一例を勉強したと形でまとめようと思います。
でもその前に先々週、意味が分からないので後で調べると言ったModuleの機能などを一通り調べておきます。
<<Torus Distribution Mode>>
これは端に値を完全に一定にしてるだけですね。
<<U PositionとReturn Normalized Exec Index>>
Torus Location Module のU PositionにReturn Normalized Exec Indexをセットしています。
U PositionについてはCursorを乗せたら以下の解説が出て来ました。
Large Radiusが何を指しているのか不明ですが、先程Torus Knotを調べていた時、Torusはドーナツの大きさである大きな円とそのドーナツの厚さを決める小さな円で定義されるみたいな話がありました。その大きな円の半径を指しているのかもしれません。
Return Normalized Exec Indexは前にも調べています。まずその復習からやります。
2021-11-08のBlogと2021-11-14のBlogでReturn Normalized Exec Indexについて勉強していますね。
まず2021-11-08のBlogですがDynamic Input Scriptを開いて
実際の実装を確認して、それぞれのParticleに発生順に番号を着け、更にその番号をNormalizeしているみたいだ。と結論づけています。
2021-11-14のBlogではReturn Normalized Exec Indexが「それぞれのParticleに発生順に番号を着け、更にその番号をNormalizeしている。」事を確認するために自分で実験方法を考えてその結果を見る限りにおいては「それぞれのParticleに発生順に番号を着け、更にその番号をNormalizeしている。」事が正しいみたいである。と結論づけていました。
勿論、個人でしかも短時間で考えた実験方法ですし、検証も所詮は個人の限界がありますが、自分で言うのもあれですが読んでて素晴らしいと思いました。
しかし、これやったの2021-11-14でたった一カ月前なのに全く覚えていません。
今、読み直して他人事のように感動しています。
うーん。
やっぱり復習は重要ですし、その復習が出来るようにBlogに記録として留めておくのは大切です。
それで元のTorus Location Module のU PositionにReturn Normalized Exec Indexをセットした機能ですが、それをする事で以下のようなSpriteをTorusの円周上に配置しています。
となるとU Positionは先程、考えていたTorusの半径の値を設定するのではなく
Torusの円周上のある位置を指定していると考えられます。
しかもこの位置はNormalizeされていて最初の位置が0、最後の位置が1になっています。
これは仮説ですが後で検証してみましょう。
<<TutorialにあるNormalized Index Scaleについて>>
先々週のBlogでTorus Location Module のU PositionにReturn Normalized Exec Indexをセットした時にTutorialではNormalize Index Scaleという項目があるのにも関わらず、自分のNiagaraにはその項目が表示されないと記録しています。
確かに今確認しても
自分のNiagaraにはNormalize Index Scaleという項目がありません。
でも前にReturn Normalized Exec Indexを使用した2021-11-08のBlogを見るとその時にはNormalize Index Scaleの項目があります。
実装を確認したらMap GetにNormalize Index Scaleの項目がありません。
2021-11-14のBlogでReturn Normalized Exec Indexの実装を確認した時には確かにNormalize Index Scaleの項目があったんですが、
これは、公式がReturn Normalized Exec IndexのParameterをあれから変更したのか、私が間違えてReturn Normalized Exec Indexの実装を上書きしちゃったのかのどちらかですね。
新しくUE5のProjectを制作したらどっちが正解なのかが分かるかもしれませんが、流石にそれだけのために新しいUE5のProjectを作成する気にはなりません。調査はここまでとします。
<Emitter Update SectionのEmitter State ModuleのLoop Durationについて>
Emitter Update SectionのEmitter State Moduleですが
これです。
Emitter Update Sectionって2つのModuleしか使用しませんが、その内の一つのModuleです。
結局、これって次のEmitterが起動するまでにどれぐらい休むかって事でしょう。
Cursorを合わせたらもっと詳しい解説が出て来ました。
Loop Durationに一回毎にRandomな値を指定したい時は、Recalculate Duration Each Loopにチェックを入れろとあります。
更に0を指定する事は出来ないので0をセットした場合は自動で0.016667に変更されるとあります。
Recalculate Duration Each LoopはLoop Durationの直ぐ下にありました。
<Torusの向きの直しについての検証>
TutorialではEmitter Setting SectionのEmitter Properties ModuleのLocal Spaceにチェックを入れる事で
Torusを回転させていましたが、実際はここにチェックを入れなくてもTorusは普通に回転しました。
この機能が本当は何を担当しているのかを検討します。
<<Emitter Settings SectionのEmitter Properties ModuleのLocal Spaceについて>>
Cursorを乗せると以下の様な説明が出て来ました。
うーん。
これは、私がずっと探し求めていた機能みたいですね。
これに限らないですが、CGHOW氏のNiagaraのTutorialってWorld Coordinateの原点を元に作成しています。実際に使用するために、例えばMonsterの攻撃に付属してNiagaraでEffectを追加しようとするとその辺の設定をどう変えればいいのかが分からなくなります。
これをcheckすれば全部Local 座標に変更するなら、Monsterの攻撃に付属してNiagaraでEffectを追加したい時もこれだけ変えれば良い気がします。
<Particle Spawn SectionにあるTorus Location ModuleのNormalized Angle Around Torus Axisについて>
Particleの発生位置に揺らぎを与える機能のようです。
先々週のBlogでは以下の様に書いています。
これです。
これ自体には特に疑問はないです。
機能も既に分かっていますし。
一応、以下にNormalized Angle Around Torus Axis にCursorを乗せた時の解説を示しておきます。
<<何故、Set Parameter Moduleを使用して値を設定しないといけないのか?>>
これは2021-11-14のBlogを読み直したら明白でした。
以下の例を見ると分かるようにEmit毎にSpriteの発生位置を微妙に変化させているからです。
Emit一回で生成されるそれぞれのParticle同士の位置は特に変わっていません。単にTutorialがそういう設定のEffectを作りたかったからです。
<Hue Shiftノードについて>
Hue Shiftノードは今回初めて使用したのでどんな機能なのか等を調べておきます。
一応、公式のDocumentであるImage Adjustment [4] にHue Shiftノードに関する記載を見つけました。しかしそれよりも普通のHSL・HSVの解説の方が分かり易いです。
要するにHueは色の事で0がRBGで言う255,0,0の赤に当たります。
HSL Calculator [5]でHueの色が分かるので
これを利用してHue ShiftノードのHueのShiftの割合について確認します。
以下の実装で試します。
0.5つまり50%、赤からHueをずらしました。
結果です。
HSL Calculator [5]でもHueの色を50%ずらしてみます。全部で360度になっているので180度を入力します。
同じ色になりました。
<25%>
これは微妙に色が違いますね。
<0.125>
他の色も色々試しましたが、微妙に色が違います。
実際に使用する時はOutputの色を確認しながら使用すべきかもしれません。
<新しいDynamic Parameterの追加方法について>
このやり方は既に先々週のBlogで解説しています。
初めて勉強したやり方なのでもう一回書いて置きます。
Materialの新しいDynamic Parameterを作成したら
Parameter Indexに1をセットします。
NiagaraのParticle Update SectionのDynamic Material Parameters Moduleの
Dynamic Parameter Index 1のWrite Parameter Index 1をチェックします。
2.2 Torus Location Moduleの使用方法に関するまとめ
Torus Location Moduleの使い方は複雑な上、公式のDocumentであるParticle Spawn Group [3]では
これしか解説がないので、今回は以下の様なSpriteの配置をするためのTorus Location Moduleの使い方のみに関してまとめます。
Spriteをこの様に配置するためにはTorus Location ModuleのU PositionにNormalized Exec Indexをセットする必要があります。
基本的にはこれだけです。
追加の情報として、前節でU Positionの機能について推測しましたが、この推測が当たっている事を示す証拠も見つけましたのでそれを示します。
Torus Location ModuleのU PositionにNormalized Exec Indexをセットする代わりにV PositionにReturn Normalized Exec Indexをセットします。
以下の結果になります。
これはTorusを定義するために必要な二つの円の小さな円の円周上にSpriteを配置しています。
と言う事は、前節で予測した
が正しい事が推測出来ます。
3.Material : Content Exampleを見るの続き
今週もContent Exampleの見学は延長してBen Cloward先生のTutorialを勉強する事にします。
3.1 Using Position Data - Shader Graph Basics [6] を勉強する
取りあえずパラパラ見ました。
今回は、理論的な説明は全部Unityでして実装方法もUnityを使用して説明しています。最後にUnityで示した実装方法をUnrealでも紹介しています。
<勉強方法について>
まず、Unrealで紹介されている実装方法を試してみます。
細かい点は兎も角、今回の勉強の中心であるLocal CoordinateとWorld Coordinateの違いは理解していますからそれだけでもそれなりの勉強にはなるはずです。
その上に理論の理解を深めるためにUnityの解説を聞いてまとめます。
<Unreal Engineにおける実装>
以下の3つが今回、メインで勉強するノードです。
Local PositionノードはそのTextureが使用されている場所のLocal Coordinateな位置を示すはずです。Absolute World PositionはWorld Coordinateの位置を示すはずです。Object Positionは多分そのObjectのWorld Coordinateの位置を返すんでしょう。Localな位置を返しても意味ないですから。
<<Objectの下側を暗くする>>
一番最初のLocal Positionノードの使用した例はObjectの下半分を暗くする方法です。
以下に示した例ではUnlitであるにも関わらず下半分に影が付いているように見えます。
Ben Cloward先生はこのTechniqueをStylized Renderingで良く使用されると解説されていましたがどうなんでしょうか?
Stylized Renderingって実際はアニメ調のRenderingの学問的な言い方です。
アニメ調のRendering方法については大学で研究は出来ない。しかしアニメ調のRendering方法について教えてほしいという要求は凄くある。と言うジレンマの中で、Stylized Renderingと言う事でぎりアニメ調のRenderingを研究、教育出来るようにした訳です。
でも実際のアニメで下半分を上記の球の様に暗くする事ってないですよね。
私はアニメの専門家ではないですが、上記の球の様に暗くすると汚く、もしくは寒く見える典型的な駄目な塗りに見えます。
まあ、Programmerは芸術家ではないので、アートの部分にまで責任はないでしょう。
以下に実装方法を示します。
まずLocal Positionを使用しているためObjectの中心が原点になります。
Maskする事でZ軸の値だけ取り出します。
球は原点を中心に配置されていますので、下半分の値がマイナス、上半分の値がプラスになります。
以下にMaskした結果を示します。
色が白と黒にくっきりと分かれている理由はUnreal Unitが1㎝にセットされているため、下半分の値が0から-100、上半分の値が0から100に変換されるためです。
Gradientを出すために100で割ります。
その結果です。
Gradientが現れました。
Gradientを強くするためにPowerを使用します。
結果です。
2乗する事による値の変化を下に示します。
全体的には黒くしているんですね。
実際にLevel上でこのMaterialを使用したら真っ黒になってしまいました。
この原因はTutorialのPivot Pointは球の一番下に位置していますが私の球はPivot Pointが真ん中に位置しているからです。
0.5 を足す事で調節します。
結果です。
Tutorialと同じように下半分に影がついたような黒味がかかっています。
<<Objectの位置を変える事でObjectの色を変化させる>>
今度はObject Positionノードの使用方法の例です。
以下の実装を作成しました。
結果を先に示します。
原点にいる時です。
少し移動します。
色が黒くなりました。
コードを見てみましょう。
まず0.01倍しています。
これはUnreal Uniteが1cmだからでしょう。
次に行きます。
3を掛けています。
うーん。この意味は分かりません。Unityにおける実装の説明を見る必要がありますね。
後回しにします。
この部分は単にObjectの位置と色の関係を簡単に表せるようにXYZの影響を一つにまとめただけでしょう。
そのままつないでx方向に変化した時は赤、y方向に変化した時は緑、z方向に変化した時は青にしても良かったかもしれません。
その次はSineノードを繋いでいます。
ここはTutorialでは説明はなかったんですがPeriodは6.28にセットするときれいな色の変化が見られました。
Sineノードを繋いだ理由は単純に色の変化を原点から100の位置までで終にしないで繰り返し変化するようにしたかっただけだと思います。
ここはsineノードの計算結果が-1から1の間なのでそれを0から1に変換しているだけです。
以上です。
<<Absolute World Positionを使用したTexture Projection>>
まず実装方法を示します。
結果です。
Projectionはしていますが何か歪んでいます。Tutorialによれば歪まない投影方法は次のTutorialで教えるそうです。
実装部を見てみましょう。
他の実装と同じように0.01をかけています。
これについての説明はもういらないでしょう。
MaskしてRGの値だけ取り出しています。XY軸の値とTextureのProjectionを繋げるためですね。
XY軸の値をUV値としてPassしています。
このやり方だとTextureのTiling Methodの設定が
でないと一回で切れてお終になるはずです。
幸いに私が選択したTextureはWrapでセットしていました。
CGHOW氏のTutorialで使用されていたFracノードを間にかませれば
TextureのTiling Methodの設定がClampでもWrapでも繰り返し表示されるようになるはずです。
録画するのが大変なので記録は残しませんが、一応確認したらその通りになりました。
<Unityにおけるこれらの実装の理論の解説のまとめ>
<<Objectの位置を変える事でObjectの色を変化させる>>
ここで知りたいのは、<<Objectの位置を変える事でObjectの色を変化させる>>で3を掛けた理由です。それから調べます。
11:50分の所でUnityにおけるObjectの位置を変える事でObjectの色を変化させる実装の3を掛ける所を解説しています。
しかし理由は何も言っていませんでした。
理由が分からないので1を掛けてみました。
結果です。
特に変わった所はないです。3を掛ける意味はなさそうですね。
<<残りのUnityの理論>>
一応全部見ましたが特に記録に残す内容はなかったです。
これで終わりにします。
4.NPCのAIを作成する
一応、先週の段階でそれなりにNPCが動くようになりました。
他にしたい事についてまとめます。
4.1 これからの課題
<夜には消える>
全部のNPCではありませんが、ほとんどのNPCは夜には消えるようにしたいです。
そのためには、
を追加する必要があります。
<NPCによってはその場に留まって欲しい>
歩き回らないでほしいNPCもあります。
そのためには
- Parameterを付けて、歩き回るどうかをそれぞれのNPCのInstanceから設定出来るようにする。
<Generic Anim Packの調査>
前に無料のAssetとしてGneric Anim Packを貰ったんですが
これにNPC用に使用出来るMotionがないのか調べます。
この一群のAnimationはどれも使えそうです。
壁を修理しているAnimationです。
これも何処かで使えそうです。
ここに4種類の会話中のAnimationがありました。
NPCと会話になった時に使用出来るかもしれません。
準備体操をしているAnimationです。
これはNPCが止まっている時のAnimationにぴったりです。
何かを打ち付けるAnimationです。
こういうのを見るだけで想像力が刺激されますね。
4.2 実際のNPCで検討する
思い付いたんですが、夜にキャラを消すだけなら静的に生成しても出来る気がします。
それも試してみます。
<NPCを動的に生成するための調査>
まずNPC Personを見ると
生成するためには以下の二つのParameterを指定する必要があります。
NPCを生成するのは、Monsterを生成した後が良さそうです。
Map1のLevel BPのEvent BeginPlayのMonster生成の実装部分を以下に示します。
実際に作成する時は、それぞれのSub Level上で生成する事になります。
<試しにNPCを一体だけ動的に作成してみる>
以下の実装を追加しました。
動的にActorを生成する場合、今までは場所の指定を以下に示した様にData Tableで数字で管理していました。
Target Point Actorを使用するとActorを生成する場所を一々数字で指定しなくても良い事を知ったので試しに使用してみます。
公式のDocumentのTarget Point Actors [7] の解説です。
特に記録しないといけないPointとかはないですね。敢えて言えばGet Actor Transform ()関数を使用する事でしょうか。
こんな感じに配置しました。
テストします。
出来てますけど、ModelがOldman用のModelじゃないですね。
成程。
OccupationでOldmanを指定しましたけど、meshの指定も個別にする必要がある訳ですね。
しました。
結果です。
今度は大きさが違いますね。
大きさも指定します。
結果です。
丁度良い大きさです。
会話も試してみます。
普通に出来ました。
<<動的にNPCを作成してみて>>
色々な知見が得られたので、それをここにまとめます。
- NPCのMeshは自動では変更されません。NPC_PersonにMeshの変更をする実装を追加するか、NPC_Personを作成した後でMeshを変更する必要があります。
- MeshのScaleを指定する必要があります。
- NPCを生成する位置を試しにTarget Point Actorで指定してみましたが、特にData Tableで管理した場合と比較して便利とは感じませんでした。
これらを考慮してNPCの動的な生成は今までのMonsterやItemの生成方法と同じやり方でやる事にします。
NPC_PersonにMeshの変更をする実装を追加するか、NPC_Personを作成した後でMeshを変更するかは来週決めます。
<NPCが昼だけ存在するようにする>
一応、NPCを動的に生成する事が出来る事が確認出来たのでNPCが昼だけ生成されるようにします。
取りあえず何でも良いので実装してみます。
以下の方法で夜になるとTrueを返す実装を作成しました。
これをEvent Tickに接続します。
夜になったら作成したNPCを破壊します。これは一回すれば良いのでDo Onceノードを使用しました。
更に朝になったら
NPCをもう一回作成します。
これで出来るはずです。
朝です。
夜です。
NPCが消えました。
また朝になりました。
NPCが現れました。
<<この実装方法の問題点>>
これだとTickのTriggerの度に昼か夜か計算して確認しているのでCostが大きいです。
以下のノードを見つけたんですがこれ使用したらTickの発信が一秒に一回になるんでしょうか?
これでコストが下げられるのならこのノードの使用を考えるのもアリですね。後でこのノードについて調べてみます。
更にNPCが一体の場合はこれでも出来ますが多数になった時に改良も必要になります。
うーん。
残りは来週考える事にします。
<静的に生成されたNPCを消す>
色々調べたんですが、ActorをKillした方が簡単みたいなのでこっちは止めます。
5.Game Design:ポケモン+HxHの念能力( 戦闘システムの作成)
5.1 MonsterのParameterについて
Monster同士の戦闘ですが、最初は単に戦闘力とHPだけでも良い気がしています。
Monsterの種類で、
- 戦闘力:大、HP:大
- 戦闘力:小、HP:大
- 戦闘力:大、HP:小
- 戦闘力:小、HP:小
この4種類のMonsterから3種類を選んで配置します。
もしくは、タイプのみにしてグー、チョキ、パーにします。
うーん。
グー、チョキ、パーで代用するのが良い気がして来ました。
いや両方あれば良いのか。
戦闘力:大の値は300、戦闘力:小の値は100にします。HP:大の値は300、HP:小の値は100にします。
ジャンケンに勝った方は戦闘力が2倍になります。
ここで大切なのは、
- 一番弱いParameter(戦闘力:小、HP:小)を持つモンスターは戦闘したら必ず死にますが、一番強いParameterを持つMonster(戦闘力:大、HP:大)にもダメージを与える事
- 一番弱いParameter(戦闘力:小、HP:小)を持つモンスターは例えジャンケンに勝ったとしても、一番強いParameterを持つMonster(戦闘力:大、HP:大)には勝てない事
の2点です。
この2つを保つ事で、このゲームで遊ぶ子供たちは近代科学とほぼ同意語であるquantitative(定量的)な概念を学べる訳で、他のゲームの様に時間を潰すだけで後で損したと感じなくて済みます。
5.2 MonsterのData Tableの作成
そうするとMonsterは以下に示した様に12体必要になります。
Monster用のData Tableを作成します。
以下の様に作成しました。
Row NameにMonsterの名前を入れても良かったんですが、Row Nameの変更方法は他の要素とやり方が違うので、ひょっとすると私の知らない何か特別な役目がRow Nameにはあるのかもと思い一応別枠でNameを作成しました。
Data Tableに使用したParameterの元のStructは以下の様に作成しました。
このStructの一要素であるMonster TypeはEnumで以下の様に作成しました。
5.3 それぞれのMonster にSkeletal Meshを割り当てる
最も強いMonsterにはDragonを当てます。
Four Evil Dragons HPから3体選びます。
紫のが他のDragonのデサインに比べてショボいので紫以外のDragonを使用します。
City of Brass Enemiesの3D Modelは戦闘力が高く、HPが低いMonsterに使用します。
この中から3体選びます。
戦闘力が低くHPが高いMonsterはSkeleton Crewから選びます。
戦闘力が低くHPも低いMonsterはToony_Tiny_RTS_Setから選ぶ事にします。
以下の様に振り分けました。
5.4 魔術師のParameterを決める
最初に幾つかのMonsterの名前に魔術師を使用していたのでMonsterの方は呪術師に変更します。
今の魔術師のParameterは以下の通りです。
召喚出来るMonster名一覧と使用出来る魔法名一覧が必要です。
魔法を使用するとMPが減るのか、無限に魔法が使用出来るのかについても考える必要があります。
最初に使用出来る魔法について考えます。
<魔術師の魔法について>
2021-12-13のBlogで述べていますが以下のような戦闘中に一発逆転出来るような戦術系の魔法の一覧を作成します。
ですが最初は最低限の魔法さえあれば良いので
- 味方のMonster一体を回復
- そのターンのMonsterの攻撃を禁止
- Monsterの位置の入れ替え
- 一体のMonsterの属性(ジャンケン)を変更(グー→チョキ→パー)
の4つのみにします。
属性の変更やMonsterのHPの回復の作成は簡単ですが、Monsterの位置の入れ替えはMonsterの戦闘位置の指定方法を良く考えてAlgorithmを実装しないと最終的にとんでもないSpaghetti Codeになってしまうか最悪作れなくなってしまいそうです。
先に魔法の種類について考えて良かったです。
<魔術師のParameterについて>
取りあえずは上の4つの魔法についてだけ使用出来れば良いのでMPはなしにします。
ので魔術師のParameterは
- HP
- 召喚出来るMonsterのリスト
- 使用出来る魔法のリスト
の3つになります。
Monsterと魔法のリストはStringの配列にするのかそれぞれのクラスを作成した後にそのクラスの配列にするのかは今は決められません。
よく考えたらまだMonsterのクラスも作成していませんでした。
5.5 Monsterクラスの作成
Actorクラスから作成しました。
以下のParameterを保持しています。
試しにDragonを配置してみたら滅茶苦茶大きかったです。
微調整が必要ですが今決定している事はこれだけですので、ここまでで一端中止します。
5.6 戦闘Phaseの直し
先週、戦闘Phaseを最後に少しだけ変更しました。
これを実装します。
Player用のMonsterを召喚するためのWidgetを作成します。
今、ここだけ細かい点まで作成してしまうと粒度(Granularity)がずれてしまうのでこの程度の精度にしておきます。
決定を押すと次のPhaseに移動します。
Monster側の魔術師がMonsterを召喚するためのWidgetです。
5秒経つと次のPhaseに移動します。
これらのWidgetを開くためにGame Mode BP内にEvent_PlayerSummonとEvent_MonsterSommonを作成しました。
これらのEventはFindFirstWidgetの
BPから呼ばれるようにしました。
ただし、Monsterを召喚するのは最初の一回だけなのでそれをチェックする実装も追加しています。
テストします。
開始ボタンを押します。
先攻後攻を決定します。
先攻に成りました。
Monsterの召喚画面が出て来ました。本来ならここで召喚するMonsterを選択しますが、今回はまだその辺りは実装していないので決定ボタンを押して終わりです。
相手の魔術師が召喚するMonsterを選択しています。
5秒たったので攻撃のPhaseに移ります。
この後、Monsterの攻撃がありました。5秒しかなくてScreen Shotは取れませんでした。
次のターンです。
また先攻です。
今度はMonster召喚のWidgetではなく使用する魔法を選択するWidgetが表示されました。
出来ています。
正しく実装されているようです。
この後、貴方の攻撃、Monsterの攻撃のWidgetが表示されました。
この後、何ターンかの攻撃をやり取りしてGame Overになりました。
Monsterの召喚をする実装部分のPhaseの追加の実装は出来た事が確認出来ました。
この後、何回かテストしましたがGame Overになる回数の方が多い気がします。どっかにバグがありそうですがこの辺の実装は後々外してしまうので無視します。
6.RPGのストーリーに関する勉強のまとめ
6.1 隠れたテーマについて
正月の間に物語の作成方法に関して少しだけ勉強したのでまとめておきます。
読者から支持される魅力のあるストーリーには必ず隠れたテーマがあるそうです。その隠れたテーマを描き切れるかどうかで読者が指示するかどうかが決まるそうなんです。
そこで成程と思い、色々なテーマについて考えてみたんです。例えば
- 世界平和
- 勉強して良い成績を取る。
- 勧善懲悪
でもつまらないんです。
そしたらある事に気が付いたんです。それは隠れたテーマが世の良識に即している場合は面白く無いです。
考えてみれば当たり前です。テーマが世の良識に即しているなら隠す必要なんてないですから。
隠れたテーマは必ず世の良識に反していないといけなかったんです。
上記の例で言えば、世界平和を願うのは世の良識に即しているから隠す必要なんてありません。でもこれが世界平和を保つために一カ月に一回、無実の人間を一人殺す必要があったらどうなりますか?
ここで世界平和の本当の価値を読者に問える訳です。
勉強して良い成績を取るマンガなんて面白くも何ともないですが、勉強しないで良い成績を取るマンガだったら面白い気がします。
勉強しないでいつも一番の成績を取る主人公と、勉強沢山するけどいつも2番の成績の主人公のライバル。
テストの後で、主人公がどうやって勉強をしないで一番を取ったのかの種明かしをしてしかもそれが理に適っていたら結構面白い話になりそうです。
勧善懲悪の物語もそうです。
大人になるとほとんどの人は正しさには必ずある種のうさん臭さがあり、悪にも一分の理がある気がしています。
だから勧善懲悪とは何ぞやとなってしまいます。
これを上手くやったのが鋼の錬金術師だと思います。
鋼の錬金術師は自分達の都合、弟の肉体を取り戻すと言う自己の目的を遂行するために悪を倒していきます。だから読者は主人公が戦う相手が本当に悪なのかあんまり考えなくなります。と言うか考えたくなくなります。しかしここで思い出してほしいのは、弟の肉体が無くなったのは自分達が禁止された錬金術を行ったからなんです。つまり自業自得なんです。だからある意味、弟の肉体を取り戻すと言うのは自分達の勝手なエゴなんです。しかしそのエゴは隠れたテーマなので読者からはオブラートに包まれて表示されます。
6.2 隠れたテーマを考える
今作成中のRPGの目的は金の切符を探す事にしました。でもそれは隠れたテーマではありません。ここに隠れたテーマを加える必要があります。
隠れたテーマは世の良識に反していないといけません。
村や町に行くと、
- 決闘している
- 奴隷がいる
- 革命の準備をしている
うーん。
これらは世の良識に反してはいますが、ピンと来ませんね。
思い付きません。来週までに考える事にします。
思い付きました。
隠れたテーマは良識に反しているだけでは駄目なんです。良識に反しているけど世の真実、少し割り引いても主人公たちにとっては真実を表していないといけないんです。
このRPGの隠れたテーマは「良識に反しているけど正しい選択」にします。
このRPGでは常にPlayerに選択を迫ります。そして正しい選択は良識に反している場合が多いようにします。
例えば、Playerが決闘を受けるかどうかの選択を迫られるとします。これは今の日本の良識に照らし合わせれば絶対に断るのが正しい選択でしょう。しかしこのRPGではPlayerが決闘を受けるのが正しい選択になるような条件を作成しておきます。そして決闘を受けた場合のみ次の展開が進むようにします。
となると、最初の赤い帽子の魔女のセリフも変わって来ますね。
例えば
「将来、貴方は人類全体にとって重大な変化を引き起こす可能性のある選択を強いられる事になります。
貴方の選択によっては人類全体が経験した事のない災害に襲われるかもしれません。ひょっとすると貴方の選択によって人類は滅ぶかもしれません。その選択から正しい答えを選ぶのは歴史上の賢者と呼ばれる人達でも難しく今の貴方が正しい選択を選べる可能性は0%です。
そこで我々は決断しました。貴方が人類全体にとって重大な結果を引き起こす選択を強いられる前に、貴方に我々が出来る最高の教育を施す事を。
貴方を幻想世界に送ります。
これは貴方を教育するためにです。その世界で貴方は金の切符を探すのです。そうすれば、貴方は、人類全体にとって重大な変化を引き起こす可能性のある選択を強いられる時に、正しい選択が出来る可能性が最高に高まる様な経験を積めるはずです。
良いですか。貴方は転送された新しい世界で金の切符を探すのです。」
こうなると、このGameに対しての興味も俄然湧いて来ます。どんな経験を幻想世界で積むのかにも興味が出て来ますし、Gameをクリアした後で、その経験から将来、人類全体にとって重大な変化を引き起こす可能性のある選択を強いられる時にどんな選択をするのかについても、みんなで議論したくなるかもしれません。
7.Map1のBug直し:武器屋で買える武器の設定の追加
7.1 先週のアイデア
武器屋が販売している武器・防具は全て表示されるが、クリックしても買う事は出来ないようにしようと思っていました。
しかし今は、単に職業を表示してその職業で買える武器を表示した方が良い気がしてきました。
UIデザインに関してですが、どのようにデザインするのがよいのかあまり分かっていません。
今週のアイデアで作成する事にします。
7.2 実装
出来ました。
うーん。
まあ。いいでしょう。
職業によって買える武器や防具が変わる事を会話で説明する事にします。
NPC Weapon Shop Dialogの
0 のセリフを「職業によって買える武器や防具が変わるよ!」に変更しました。
これで、NPC_Parent Widget の子クラスであるWeapon Shop Talk Widgetの
NPC Weapon Shop Dialogの
0 のセリフも「職業によって買える武器や防具が変わるよ!」に変更されました。
テストして確認します。
変わっていました。
武器屋などの店の会話の管理は、この教科書に書かれていた通りに作成しているのでNPCの会話の管理方法とは違います。
NPCの会話方法の管理の方法は自分で思い付いたやり方を実装しているんですが、正直そっちの方が管理し易いと思っています。
今回は直しませんが、次回作はNPCの会話方法の管理の方法でまとめる事にします。
武器屋に関してはこれでお終いです。
7.3 職業による見た目の変化
職業が変化した時にPlayer の操作するキャラの見た目が変化するようにします。
Third Person Character内に
Playerの操作するCharacterのSkeletal MeshをOccupationによって変更する関数を作成します。
その変数をEvent BeginPlayに実装します。
これで職業によってPlayerの操作するCharacterの外装が変化するはずです。
テストします。
狩人です。
戦士です。
騎士です。
魔術師です。
魔法戦士です。
武器を持たしてみます。
剣を握っていませんね。
これって直せるんでしょうか?
戦闘もしてみます。
流石に圧勝でした。
中々カッコイイです。
手と武器がずれているのが気になります。
他の武器を装備した場合もチェックします。
杖もずれていますね。
よく見たら最初からずれていました。
これって確か、元々、正しい位置にソケットをつけてあったのを知らないで自分で位置を変えてしまったからこうなってしまった記憶があります。
UE4_Mannequin_Skeletonを開いて
Hand_rSocketを選択して
剣の位置を少し外側に移動しました。
今度はしっかり剣を握っています。
魔法戦士の場合です。
うーん。
手の握りと剣の柄が微妙にずれていますがこれぐらいは仕方ないのかもしれません。
弓矢の装備も念のために確認しました。
問題ないですね。
7.4 転職用のアイテム
職業のSkeletal Meshを作成していて、Itemで職業が変えられるようにしたら面白いと思いました。
ので職業を変えるItemを作成します。
Data TableのItems
に転職石を追加しました。
イラストが無いので作成しました。
Widget Itemに
Change Occupation関数を作成します。
これで転職石を使用したらOccupationが変化するはずです。
この関数を実装します。
テストします。
転職石(魔術師)を使用します。
魔術師になりました。
他の転職石も試しましたが、全部、正しく機能しました。
よく考えたら、職業を変えるとキャラの見た目だけじゃなくてParameterの数値も変化します。
Parameterをどうするのか考えてなかったです。
7.5 転職後のParameterについての考察
転職をItemで出来るようにすると、色々な職業を行ったり来たりするかもしれません。そうすると狩人のLevel7で戦士になった後にもう一回狩人に戻ったらLevel1になってしまうのか、Level 7から始められるようにするのかを決めておく必要があります。
もう一つの考え方は、弟子でLevel 10 になったら転職石を使用して戦士のLevel 1に転職出来ると言う考え方です。
また別な考え方ですが、転職するためには今の職業でLevel 10 になる必要があり、転職したら次の職業では常にLevel 1から始める方法もあるかもしれません。これだと弱い雑魚Monsterが常に必要になってくる訳で、今までのRPGにない面白い展開が開けるかもしれません。
整理します。
<Idea 1>
色々な職業を行ったり来たりする。前の職業のLevelは保持され、その職業に戻った時はそのLevelから始められる。
<Idea 2>
次の職業になるにはその職業でLevel 10になる必要がある。そこで転職石を使用すると転職出来る。
弟子―>狩人―>戦士―>騎士―>魔術師―>魔法戦士
の順番で転職する。
<Idea 3>
Idea 1と2の中間。次の職業になるにはその職業でLevel 10になる必要があるが、次の職業は自由に選択できる。次の職業は必ずLevel 1から始まる。
他にも面白いIdeaが出で来るかもしれませんし、このIdeaのどれが一番面白く、簡単に実装出来るのかも考える必要があります。今週はここで一端中止します。
8.UE5:naniteの勉強
先週の続きで公式のDocumentであるNanite Virtualized Geometry [8] を読みます。
番号が先週と違うと混乱するので番号は先週の続きで書きます。
7.9 Data Size
Naniteを使用した時の実際のDataのサイズはHigh Polyと比べてどうなのかについて検証しています。
結論だけまとめるとHigh Polyと比較してDataのサイズは約8分の1になります。
<General Advice on Data Size and a Look to the Future>
以下の事について解説していますが、
Userにdataを送るのが一番の問題です。ってそのまま素直に読むとGameをDownloadする事を指していると思われます。
うーん。
それって別に時間かかっても問題じゃなくない?
寝てる時にDownloadすれば良いんじゃない。
別なLevelに移動する時のLoad時間の事を指してるのかもとも思いましたが、そうすると文章の辻褄が全く合わない気がします。例えば
と言っています。
これ別なLevelに移動する時のLoad時間には全く関係ないですよね。
ちょっと何が言いたいのか理解出来ないですね。この節は。
この節の題でGeneral Advice on Data Size…と言っているので、一般的な話として述べているのかもしれませんね。
最後の部分のこれからのNaniteは以下の分野に集中して開発していく
と言う事は理解出来ました。
ああ。分かりました。
これはFortniteのようなネット上でみんなで遊ぶGameの話をしていたんです。それならInternet Bandwidthが関係します。
もう一度、読み直します。
NaniteとVirtual Texturing System、更に速いSSDによってGeometryとTextureの“Runtimeの予算(この部分が具体的に何を指しているのかは不明。後で検証します。)”を気にする必要は少なくなりました。
それよりも最も大きな障害はこのDataをどうやってUserに届けるのかです。
素直に読むと大体こんな訳になると思います。
まずRuntimeの予算ですが、色々考えられますが、一個のMaterialでTextureが12枚(15枚?)しか使用出来ない事とか、GPUのCashに入れるTextureのDataの大きさなんかを指している気がします。と言うのかそういう箇所が現在Renderingで一番遅くなる工程だと聞いた気がするからです。特にTextureを取って来る時間はそのTextureの保持されてる箇所によって時間のかかり方が凄い違うと言う話は聞いた事があります。
ただし、その後で「現在の最も大きな障害はこのDataをUserに届ける事である。」と言っていますので、これからの話題はどうやってこのDataをUserに届けるかについて話すのでRuntimeの予算が具体的に何を指しているかが例え分からなくても文脈を掴むための大きな障害になる事はありません。
ここでこのDataが何を指しているのかが問題です。この文脈で考えればGeometryとTextureと思います。
うーん。
全然、ネットで対戦するGame には詳しくないんですが、Fortniteの様なネットで対戦するGameでもGeometryとTextureをServerとClientでやり取りする事は無い気がします。GeometryとTextureは既にClientのHD内に保存されている気がします。
となるとやっぱりこのDataって最初の解釈であるGameそのものを指しているのが正しい解釈になります。
仕方がない。
次の段落も全文、ここで検証します。
まず最初の
ですが、DiskにあるDataと言っていますから、Serverから送られてくるDataではないし、普通に考えればゲームそのもののDataです。
うーん。また最初の文章に戻りますが、
この文章における「このData(this data)」は、最初の解釈通りGameそのもののDataを指していますね。
となると最初の文でNaniteとVirtual Texturing SystemとGeometryとTextureのRuntimeの予算について語っているのに、次の文でGameそのもののDataをどうやってUserに送るのかについて語っているわけです。
粒度(granularity) が無茶苦茶でかなりの悪文です。
この節の題がGeneral Advice on Data Sizeなので、今までのNaniteの話と一般的なDataのSizeの問題と言う全然粒度(Granularity)の違う話を強引に繋げる必要があったんでしょうね。
納得しました。
これでこの次の段落では、一般的なData Sizeの問題について語る事に成る訳です。
次の段落に戻ります。
この最初の文は完全にGameのDownloadの方法について語っていますね。
Physical mediaはCDとかの事を指していてDownload Over the InternetはそのままGame をDownloadしてHDに保存した場合の事を指しているのでしょう。
そして「圧縮技術はある程度しか働かない。」と述べています。「圧縮技術はある程度しか働かない。」とわざわざここで言っていると言う事は、GameのDataが大きすぎて、Downloadするのに凄い時間がかかる事が問題であると暗に示しているんでしょうね。
うん。
これなら意味が理解出来ますね。
その次の文ですが、This DataがGameそのもののDataを指していると分かれば、何が言いたいのかすぐ理解出来ます。
UserのInternetの環境を含むPCの性能はショボいんでそれを考慮しないといけませんよ。と言っているだけです。
そして最期の文
GameそのもののDataをUserに(快適に!)Downloadさせるのは(UserのPCの性能は低いんで)結構大変な事だよ。と言っています。
うっせー。おおきなお世話だ。と言いたくなりますが、Epic Games社で開発している人達のInternetの環境とPCのスペックからすると単に事実を述べただけなんでしょう。
それで次の段落にいきます。
はい。ここではRendering highly detailed meshes efficientlyから始まっています。
Renderingの話です。前の段落とは話題が変わっているんです。ここも混乱する所だったんです。次の文で、Storage of its data on disk…と続くから前の段落の話の続きかと思うですが、実際は前の段落ではGameそのもののDataのDownloadについて、この段落ではHDに保存されているGameのDataとRenderingについての話になっているんです。話題が変わっています。
Naniteに関して言えば効果的に細かいMeshをRenderingする事についてはもう問題じゃないです。でもGameのDataがDisk上でどうやって保存されているのかは(例えば圧縮された状態で保存されているのかとか)はこれから非常に重要になって来ます。と言っています。
それはそうです。RenderingのためにあるTextureを取り出すとしたら、そのTextureがGPUのCashにあるのかMemoryにあるのか、それともHDにあるのか、しかもHD上で圧縮された状態であるのかでそのTextureを取り出す時間は天と地の差が起きるでしょう。
成程。
ここでNaniteが今までのBottle NeckであったRendering highly detailed meshesを解決したので、次のBottle NeckであるDiskからGeometryやTextureを取り出す部分について語り始めていたんです。
全然、GameのDownloadとは関係ない話になっています。この話の展開が追えないと意味が全く分からなくなってしまいます。
それで、Outside of compressionが続きます。その圧縮以外の話では、別な2つの技術の開発も必要です。といって2つの別な技術を紹介しています。
そして最期の段落につながります。
これからのTextureに関するNaniteの技術の発展は今まで開発されてきたTexture技術がNaniteに併合されるようになるでしょう。と締めくくっています。
やっと意味が通じました。
もう一回読み直します。
うーん。まだだいぶ間違えている様です。
一例を挙げると以下の部分ですが、
この一般人のInternetの環境を含むPCの性能はEpic Games社で働いている人が使用しているPCと比較してショボいと理解していてそれを以下の様に書いていましたが
今、読み直すと、InternetのBandwidthなどはHard DriveのBandwidthらと比較してショボいと言っています。別にEpic Games社で働いている人が使用しているPCと比較してショボいとはいっていませんでした。同じPC内で比較していました。
こういう細かい点の間違いかまだかなりあります。
でもこの節ってそんなに大切な内容でもないでしょうし、この辺で止めておきます。
本当は今週で全部読み切るつもりだったんですが時間が無くなってしまいました。
最後の節のVisualization Modesは来週読む事にします。
9.まとめと感想
今週は年始めなので軽くやってお終いにしました。来週以降から本格的にやる事にします。
10.参照(Reference)
[1] CGHOW. (2021, December 4). Flower Effect in UE4 Niagara Tutorial | Download Files [Video]. YouTube. https://www.youtube.com/watch?v=37g1J8mImjg
[2] Epic Games. (n.d.-e). Utility Expressions. Unreal Engine Documentation. Retrieved January 9, 2022, from https://docs.unrealengine.com/4.27/en-US/RenderingAndGraphics/Materials/ExpressionReference/Utility/#blackbody
[3] Epic Games. (n.d.-d). Particle Spawn Group. Unreal Engine Documentation. Retrieved January 9, 2022, from https://docs.unrealengine.com/4.27/en-US/RenderingAndGraphics/Niagara/EmitterReference/ParticleSpawn/
[4] Epic Games. (n.d.-a). Image Adjustment. Unreal Engine Documentation. Retrieved January 9, 2022, from https://docs.unrealengine.com/4.27/en-US/RenderingAndGraphics/Materials/Functions/Reference/ImageAdjustment/
[5] w3schools. (n.d.). Colors HSL. W3schools.Com. Retrieved January 9, 2022, from https://www.w3schools.com/colors/colors_hsl.asp
[6] Cloward, B. [Ben Cloward]. (2021, December 9). Using Position Data - Shader Graph Basics - Episode 26 [Video]. YouTube. https://www.youtube.com/watch?v=Rm4ubzc-6Q4&list=PL78XDi0TS4lEBWa2Hpzg2SRC5njCcKydl&index=26
[7] Epic Games. (n.d.-c). Particle Spawn Group. Unreal Engine Documentation. Retrieved January 9, 2022, from https://docs.unrealengine.com/4.27/en-US/RenderingAndGraphics/Niagara/EmitterReference/ParticleSpawn/
[8] Epic Games. (n.d.-b). Nanite Virtualized Geometry. Unreal Engine Documentation. Retrieved January 9, 2022, from https://docs.unrealengine.com/5.0/en-US/RenderingFeatures/Nanite/