UE4の勉強記録

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

「Unreal Engine 4.xを使用してRPGを作成する」の足りない部分を作成する 村人用のAIの開発ー今週から本当に作成します

f:id:kazuhironagai77:20211220010126p:plain

<前文>

<PS5とUE5

あんまりGameそのものには興味のない私はPS5が日本で全然流行ってない事を先週まで知りませんでした。

PS5 を買えない日本人(の貧乏?)がやばい。みたいな論調が日本では主流のようですが、私は逆にUE5の方が大変な事態じゃないのかなと思っています。

今週はそれについて解説します。

まず3D Graphics ProgrammingってGame会社が作っているんじゃないんです。大学、それもその筋の研究者が色んな大学から沢山集まってそれぞれの専門分野を作成しています。何が言いたいのかと言うと3D  Graphicsが成立するためには、とんでもないお金を掛けて基礎研究する必要があります。その成果がGPUになったりUE5のようなGame Engineになったりしています。だからその大量のお金を掛けて研究した基礎が無いと、GPUもGame Engineの様な華やかな部分も出来ないんです。

ところが、やっぱり大学で研究するとなると大学故の制約があるんです。

例えば、Global Illuminationの計算をもっと簡単で速くするとか、動的に歪みのある大量のVertexの処理を高速で行う。みたいな定量的な評価が出来かつ社会からのニーズがある分野はどんどん予算がついて研究されてます。しかしアニメ風のrenderingの仕方とか3Dで美人のModelを作成するための研究は、定量的な評価が出来ないどころか、美人であるとかアニメ風であるっていう事は客観的な評価すら出来ないので予算が付きません。

特にアニメはアメリカの大学では学問と見なされていません。だから例えば大学の芸術でアニメは勉強出来ないんです。これ凄いんですがGameや映画は学問として認めれられているんです。

でもアメリカ人は日本のアニメ風のGameがやりたくてしょうがないんです。

どれくらいアメリカ人が日本のアニメ風の文化が好きか、日本にいると体感出来ませんが物凄い好きです。

しかしアメリカの大学ではアニメ風のRenderingとかの研究の予算は非常につきにくいので、日本のアニメ風のGameをアメリカ人だけで作成する事は無理です。日本の力が必要なんです。

しかし日本人がPS5で遊べないとなると日本のGame会社もUE5でGameを作ろうとは思わなくなるでしょう。

結果的にアニメ風のGameはSwitch用にUnityで作成しようと言う雰囲気が生まれるんじゃないでしょうか?

確かに最新の3D Graphicsの技術を集めたUE5とPS5のGameをPlay出来ない日本のSoftware 技術はGameに関しても先進国から中進国位の衰退に直面するでしょう。それはそれで日本で暮らす我々は大変ですが、その結果、もっと大変になるのは最新鋭の技術を持ちながらアニメ風のGame が作られなくなるUE5の方な気がします。

だってアメリカ人、日本のアニメ風のGameが大好きですから。

Epic Games社側で、日本でUEを使用してアニメ風のRenderingを研究している個人やグループにMega Grantsを渡して、UEがアニメ風のGameに対して積極的に支援したり、日本にアニメ風のRenderingを研究するための施設を東大クラスの大学院と共同で作ったりしてアニメ風のRenderingに対してUEは真剣に取り組んでいると言う姿勢を日本で思いっきりアピールすれば別な展開が生まれるかもしれませんが、このままの状態だと結構、最悪な結果になる気がします。

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

<本文>

1.今週の予定

今週もいつも通りやっていきます。

  • Niagara: HLSL Triangle code to UE4 Material nodes Tutorialの続き
  • Material : Content Exampleを見るの続き
  • NPCAIを作成する
  • Game DesignポケモンHxHの念能力( 戦闘システムの作成)
  • Map1Bug直しの続き
  • UE5naniteの勉強

2.Niagara: HLSL Triangle code to UE4 Material nodes Tutorial [1] の続き

先週の続きでCGHOW氏のNiagara: HLSL Triangle code to UE4 Material nodes Tutorial [1] の残りをやっていきます。

2.1 ノードを改良して見た目を綺麗にする

<Fracノード>

f:id:kazuhironagai77:20211220010251p:plain

公式のDocumentのMath Expressions [2] にFracの解説がありました。

f:id:kazuhironagai77:20211220010324p:plain

Floorは単なる小数点の切り捨てです。xの値が1.5だった場合Floor(1.5) は1になります。1.5-1=0.5です。

f:id:kazuhironagai77:20211220010340p:plain

4で掛けているのでU軸、V軸ともに0から4になっています。それらの全ての数字にFracをかけると

f:id:kazuhironagai77:20211220010358p:plain

となります。

<Custom Rotator

f:id:kazuhironagai77:20211220010419p:plain

公式のDocumentのCustomRotator [3] はここです。

この公式のDocumentのCustomRotator [3]にはNodeにCursorを乗せてCtrl+Altからではたどり着ません。

f:id:kazuhironagai77:20211220010439p:plain

Material Functionと言う全く別の所に飛んでしまいます。

これは端に間違いだと思うんですが、違うんでしょうか?

f:id:kazuhironagai77:20211220010505p:plain

Rotation Centerが自作の回転と違い+になっています。後は特に解説する所はないです。

中を開くと以下の様な実装になっていました。

f:id:kazuhironagai77:20211220010522p:plain

こっちが自作した回転の実装です。

f:id:kazuhironagai77:20211220010535p:plain

比べると結構計算方法が結構違います。

まず回転の中心に関してですが、私が自作した回転は中心の移動は含んでいません。回転の外側で実装する必要があります。その場合もTextureの中心で回転させたい時はU軸に-0.5、V軸に-0.5ずらす必要があります。

Custom Rotatorノードの方を見るとInputした値に-1を掛けてTextureに足しています。

f:id:kazuhironagai77:20211220010550p:plain

計算方法は微妙に違いますが、結果は一緒になりますね。

ここでは-1を掛けて足していますが、これって単に引くよりもCostが低くなるんでしょうか?

興味深い所です。

回転の計算式で興味深い処が一点ありました。

f:id:kazuhironagai77:20211220010604p:plain

SinやCosに0~360度を0~1に変換して渡す場合、SinやCos のPeriodの設定が1になっているとSinやCos のPeriodの設定が6.28でSinやCosに0~360度の値を渡した場合と同じ結果に成ると言う事を示している箇所がありました。

f:id:kazuhironagai77:20211220010629p:plain

これは面白い発見ですのでテストして確認します。

f:id:kazuhironagai77:20211220010648p:plain

f:id:kazuhironagai77:20211220010658p:plain

テストします。

元の絵です。

f:id:kazuhironagai77:20211220010724p:plain

回転した後です。

f:id:kazuhironagai77:20211220010741p:plain

時計回りに回転してます。

SinノードとCosノードのPeriodを6.28に戻して

f:id:kazuhironagai77:20211220010759p:plain

90度回転させます。

f:id:kazuhironagai77:20211220010815p:plain

90度/360 度=0.25なので同じ結果になるはずです。

f:id:kazuhironagai77:20211220010831p:plain

なっていました。

残りはDotノードを使用したりしていますが計算の順番が違うだけで同じ事をしていました。

Dotノードについても細かく検討しようと思ったんですが、これ以上Custom Rotatorにこだわると粒度(Granularity)がバラバラになりそうなので今回はパスします。

<それぞれの三角をバラバラに回転する>

以下の計算でそれぞれの三角形に別々な値を作成しています。

f:id:kazuhironagai77:20211220011036p:plain

まずTexCoord[0]にMultiplyノードで4で掛けています。

f:id:kazuhironagai77:20211220011052p:plain

最大値が4になっています。勿論、上記のMultiplyノードの色は1以上は全て同じなのでImageからは分かりません。

Floorを掛けます。

f:id:kazuhironagai77:20211220011128p:plain

0~0.9999…が0になり1.00~1.9999…が1になり2.00~2.9999…が2になり3.00~3.9999…が3になります。

うーん。4は4ですよね。

最後の1Pixelは4があるんでしょうか?

4で割ります。

f:id:kazuhironagai77:20211220011147p:plain

0/4=0、1/4=0.25、2/4=0.5、3/4=0.75、4/4=1です。最後の1は1Pixel分だけとあるようには見えないですね。

気になるのでSmooth Stepノードをつけて確認してみます。

f:id:kazuhironagai77:20211220011207p:plain

0.9以下は黒く、1以上は白く表示されるはずです。

f:id:kazuhironagai77:20211220011226p:plain

あれ。真っ黒ですね。

あ。

0から0.999とかまでで1は入っていないんですね。Floatの数え方を忘れていました。

解決です。

最後にPerlin NoiseのTextureに繋いでいます。

f:id:kazuhironagai77:20211220011300p:plain

f:id:kazuhironagai77:20211220011313p:plain

これはTextureの

(0, 0)、(0, 0.25)、(0, 0.5)、(0, 0.75)、

(0.25, 0)、(0.25, 0.25)、(0.25, 0.5)、(0.25, 0.75)、

(0.5, 0)、(0.5, 0.25)、(0.5, 0.5)、(0.5, 0.75)、

(0.75, 0)、(0.75, 0.25)、(0.75, 0.5)、(0.75, 0.75)、

の箇所の値を取っているだけで別にNoizeであるならPerlinである必要はないですね。

<時間で三角形を回転させる>

以下の部分ですね。

f:id:kazuhironagai77:20211220011351p:plain

ここは時間である値を-1から1の間で変化したい時、sinを使用する定番のヤツですね。

でもこれだと最後に0~1の間に変換した方が良い気がしますが。

試してみます。

f:id:kazuhironagai77:20211220011409p:plain

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

f:id:kazuhironagai77:20211220011429p:plain

前の状態です。

f:id:kazuhironagai77:20211220011445p:plain

うーん。どっちが良いか。

色の調節にはSaturateノードが使用されています。

f:id:kazuhironagai77:20211220011504p:plain

色に対しては-1~1で良い気がします。

f:id:kazuhironagai77:20211220011605p:plain

うーん。半分消えているのは多過ぎな気がしますね

f:id:kazuhironagai77:20211220011627p:plain

Saturateの前に0.5足しました。

f:id:kazuhironagai77:20211220011645p:plain

イイ感じです。

2.2 Flower Effect in UE4 Niagara Tutorial [4] を勉強する

CGHOW氏のFlower Effect in UE4 Niagara Tutorial [4] を勉強します。

f:id:kazuhironagai77:20211220011710p:plain

何かTextureをMaterial内で色々弄ってそうなのと単純に綺麗だからです。

まずぱらっと全部見ました。

自作が必要なMeshとかはなかったのでやっていきます。

<M_Patternの作成>

Radial Gradient Exponentialノードを使用します。

f:id:kazuhironagai77:20211220011731p:plain

Densityに7000をセットすると境界が非常にはっきりした円が描かれます。

f:id:kazuhironagai77:20211220011745p:plain

Radial Gradient Exponentialノードの実装についても検証したいですが、これは来週以降します。

f:id:kazuhironagai77:20211220011804p:plain

ここから中が空洞の円を作成します。

一つ目の方法は半径の少しだけ小さい円を同じ方法で作成してそれを引きます。

f:id:kazuhironagai77:20211220011818p:plain

こんな感じです。

f:id:kazuhironagai77:20211220011853p:plain

もう一つの方法は3ColorBlendノードを使用するやり方で

f:id:kazuhironagai77:20211220011914p:plain

黒がA、白がC、その間がBで使用した色で表示されます。

f:id:kazuhironagai77:20211220011935p:plain

なので以下の様な色を指定すると

f:id:kazuhironagai77:20211220011953p:plain

こうなります。

f:id:kazuhironagai77:20211220012009p:plain

更にResult ノードの設定を以下のようにして

f:id:kazuhironagai77:20211220012025p:plain

以下の様に実装します。

f:id:kazuhironagai77:20211220012042p:plain

バックが透明になりました。

f:id:kazuhironagai77:20211220012057p:plain

更にLerpを追加して色をつけます。

f:id:kazuhironagai77:20211220012114p:plain

取りあえずこんな色にしました。

f:id:kazuhironagai77:20211220012132p:plain

Opacityに5を掛けます。

f:id:kazuhironagai77:20211220012153p:plain

うーん。これは何が目的なんでしょう。この辺も来週以降考えます。

f:id:kazuhironagai77:20211220012236p:plain

<<円に歪みを加える>>

この円に歪みを追加します。

まずRadial Gradient ExponentialノードのUVsに以下の実装を追加します。

f:id:kazuhironagai77:20211220012300p:plain

Texture SampleのTextureは付属のPerlin Noizeを使用しました。

Radial Gradient Exponentialノードのイメージは以下に示したようになりました。

f:id:kazuhironagai77:20211220012318p:plain

Texture Sampleの値に0.15を掛けて値を小さくすると

f:id:kazuhironagai77:20211220012341p:plain

円に近い形に戻ります。

f:id:kazuhironagai77:20211220012358p:plain

しかしこの方法では円の中心も移動してしまいます。

ので以下の様な実装にします。

f:id:kazuhironagai77:20211220012416p:plain

なんでこれで中心が固定されるんでしょう。これも来週以降検証します。

更にTexture SampleにPannerノードを追加して動きを加えます。

f:id:kazuhironagai77:20211220012430p:plain

一寸、Tutorialよりも動きが速い感じがします。

f:id:kazuhironagai77:20211220012444g:plain

Noizeに使用しているTextureが違うので完全な一致は無理ですので許容範囲と見なして先に進みます。

色々な値を弄ってTutorialの感じに近づけました。

f:id:kazuhironagai77:20211220012513g:plain

これで一応、Materialの作成が終わりました。

Niagaraの作成>

今度はNiagaraを作成します。

Niagara SystemでFountainを追加します。

f:id:kazuhironagai77:20211220012535p:plain

Preview Scene Settingの設定を以下のようにして

f:id:kazuhironagai77:20211220012553p:plain

PreviewのBackgroundの色をこんな感じにしました。

f:id:kazuhironagai77:20211220012610p:plain

Renderer SectionのSprite Renderer ModuleのMaterialを先程作成したのと交換しました。

f:id:kazuhironagai77:20211220012628p:plain

更にSorting ModeをCustom Descendingに変更しました。

f:id:kazuhironagai77:20211220012647p:plain

Sorting Modeは初めて使用するParameterです。後でどんな機能なのかを検証します。

こんな感じです。

f:id:kazuhironagai77:20211220012706p:plain

Tutorialの例は以下の様に黒い淵がはっきりしています。

f:id:kazuhironagai77:20211220012724p:plain

以下の部分に1.2を掛ける事で黒い線の部分を太くしました。

f:id:kazuhironagai77:20211220012743p:plain

Ringの太さが

f:id:kazuhironagai77:20211220012759p:plain

1.2倍になっているはずです。

f:id:kazuhironagai77:20211220012816p:plain

結果です。

f:id:kazuhironagai77:20211220012831p:plain

前よりは黒い線がはっきりしています。

先程のLerpにParticle Colorを追加します。

f:id:kazuhironagai77:20211220012850p:plain

そしてParticle Spawn SectionのInitialize Particle Moduleから

f:id:kazuhironagai77:20211220013048p:plain

Colorをセットします。

f:id:kazuhironagai77:20211220013109p:plain

こんな感じです。

f:id:kazuhironagai77:20211220013130p:plain

Particle Spawn SectionのAdd Velocity in Corn Moduleを消してAdd Velocity From Point Moduleを追加しました。

f:id:kazuhironagai77:20211220013149p:plain

こんな感じです。

f:id:kazuhironagai77:20211220013209p:plain

Sizeを変化させます。

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

f:id:kazuhironagai77:20211220013229p:plain

Tutorialでは以下の様に設定していますが、

f:id:kazuhironagai77:20211220013250p:plain

私のScale Sprite Size Moduleは項目が少し違っているので以下の様にセットしました。

f:id:kazuhironagai77:20211220013312p:plain

よく見たらTutorialではUE4を使用していました。

結果は同じになるはずです。

結果です。

f:id:kazuhironagai77:20211220013331p:plain

サイズがSpriteの寿命によって変化しています。

色も変化させます。

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

f:id:kazuhironagai77:20211220013347p:plain

色の指定はこんな感じです。

f:id:kazuhironagai77:20211220013403p:plain

結果です。

f:id:kazuhironagai77:20211220013420p:plain

Niagara から操作しやすいようにMaterialのParameterをDynamic Parameter ノードを使用してまとめます。

f:id:kazuhironagai77:20211220013438p:plain

ParameterのDistortとTileをDynamic Parameterにまとめました。

Dynamic Parameterと普通のParameterの違いはわかりません。これは来週調べます。

NiagaraのParticle Update SectionにDynamic Material Parameters Moduleを追加します。

f:id:kazuhironagai77:20211220013457p:plain

TileとDistortの値をRandomにします。

f:id:kazuhironagai77:20211220013524p:plain

結果です。

f:id:kazuhironagai77:20211220013543p:plain

Level上に配置してみます。

f:id:kazuhironagai77:20211220013604g:plain

<色々なVariationのFlower Effectを作成する>

作成したNiagara EffectとMaterialを複製します。

f:id:kazuhironagai77:20211220013635p:plain

新しいFlower EffectはEdgeの色もControl出来るようにします。

LerpノードのBにParticle ColorとDynamic Inputを掛けた値を繋げます。

f:id:kazuhironagai77:20211220013655p:plain

これだと色をControlするんじゃなくて色の輝きの強さをControlしますね。

Dynamic ParameterのEdgeの値に140をセットします。

f:id:kazuhironagai77:20211220013717p:plain

こんな感じです。

f:id:kazuhironagai77:20211220013734p:plain

ちなみにEdgeにNegativeな値を入れると

f:id:kazuhironagai77:20211220013755p:plain

こんな結果になります。

f:id:kazuhironagai77:20211220013813p:plain

Edgeが黒くなりますね。

Particle Update SectionのColor ModuleのScale Colorの値を下げる事で色を暗くします。

f:id:kazuhironagai77:20211220013832p:plain

f:id:kazuhironagai77:20211220013841p:plain

こんな感じです。

f:id:kazuhironagai77:20211220013904p:plain

これが2個目のFlowerのEffectです。

f:id:kazuhironagai77:20211220013923p:plain

<<三番目のFlower Effect>>

三番目のFlower Effectを作成します。

f:id:kazuhironagai77:20211220013945p:plain

Black BodyノードをParticle Colorの代わりに使用します。

f:id:kazuhironagai77:20211220014010p:plain

BlackBody ノードは黒体放射を表すノードだと思うんですがこれも後で調べます。

BlackBodyノードで色を決定するのでNiagaraのParticle Update SectionにあるColor関係のModuleは必要ないです。

消します。

更にDynamic Parameterで

f:id:kazuhironagai77:20211220014024p:plain

温度を指定します。

f:id:kazuhironagai77:20211220014040p:plain

結果です。

f:id:kazuhironagai77:20211220014057p:plain

こんな感じです。

f:id:kazuhironagai77:20211220014118p:plain

<<四番目のFlower Effect>>

Particle Spawn SectionのSphere Location Moduleを消し更にAdd Velocity From Point Moduleを外して、Torus Location Moduleを追加します。

f:id:kazuhironagai77:20211220014138p:plain

Torus Location ModuleのTorus Distribution ModeはDirectになります。

f:id:kazuhironagai77:20211220014156p:plain

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

f:id:kazuhironagai77:20211220014222p:plain

Spawn Burst Instantaneous ModuleのSpawn Countに10をセットします。

f:id:kazuhironagai77:20211220014303p:plain

またParticle Spawn SectionのParticle Spawn Sectionに戻り

f:id:kazuhironagai77:20211220014327p:plain

U PositionにReturn Normalized Exec Indexをセットします。

f:id:kazuhironagai77:20211220014350p:plain

Tutorialの方ではNormalized Index Scaleという項目が存在してます。

f:id:kazuhironagai77:20211220014421p:plain

UPositionにReturn Normalized Exec Indexを追加した方法が違っているのかもしれません。これも後で検証します。

結果です。

f:id:kazuhironagai77:20211220014451p:plain

微調整をした後で、Particle Spawn SectionのAdd Velocity From Point Moduleを起動します。

f:id:kazuhironagai77:20211220014510p:plain

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

f:id:kazuhironagai77:20211220014550g:plain

Emitter Update SectionのEmitter State Moduleの

f:id:kazuhironagai77:20211220014607p:plain

Loop Durationの値を0.2にセットします。

f:id:kazuhironagai77:20211220014628p:plain

すると

f:id:kazuhironagai77:20211220014644g:plain

となります。

Level上に配置します。

f:id:kazuhironagai77:20211220014703p:plain

するとTorus は上向きに作成されているので上記のような配置になってしまいます。

Tutorialではこれを直すためにEmitter Settings SectionのEmitter Properties Moduleに

f:id:kazuhironagai77:20211220014719p:plain

Local SpaceにCheckを入れて

f:id:kazuhironagai77:20211220014736p:plain

回転させています。

f:id:kazuhironagai77:20211220014752p:plain

こんな感じになります。

f:id:kazuhironagai77:20211220014814p:plain

しかしEmitter Settings SectionのEmitter Properties ModuleのLocal SpaceのCheckを外しても同じ事が出来ます。

f:id:kazuhironagai77:20211220014827p:plain

結果です。

f:id:kazuhironagai77:20211220014844p:plain

全く同じ様に出来ました。

Emitter Settings SectionのEmitter Properties ModuleのLocal Spaceの機能については後で調べます。

<<5番目のFlower Effectを作成します>>

Emitter Update SectionのSpawn Burst Instantaneous Moduleの

f:id:kazuhironagai77:20211220014914p:plain

Spawn Countの値を10に下げます。

f:id:kazuhironagai77:20211220014930p:plain

以下のようになります。

f:id:kazuhironagai77:20211220015007p:plain

この結果を見ると明らかですが、Spriteの位置が毎回、正確に同じ場所から誕生しています。これに揺らぎを加えます。

それを可能にするのがParticle Spawn SectionにあるTorus Location ModuleのNormalized Angle Around Torus Axisです。

f:id:kazuhironagai77:20211220015030p:plain

Normalized Angle Around Torus Axisに0.2を入れてみます。

f:id:kazuhironagai77:20211220015045p:plain

以下の様な結果になりました。

f:id:kazuhironagai77:20211220015104p:plain

うーん。

Spriteの発生位置にブレが出来ているのか分かりません。

しかしTutorialの本筋はそこではなくて、これをEmitter一回毎にセットし直さないといけないそうです。

その方法について解説していますのでそれを行います。

まずFloat型のEmitter Name Spaceの変数を作成します。

Particle Spawn Section にSet Parameters Moduleを追加します。

f:id:kazuhironagai77:20211220015127p:plain

Set Parameter内でFloat型のEmitter Name Spaceの変数を作成します。

名前はRot_Offsetです。

f:id:kazuhironagai77:20211220015148p:plain

次にこの変数を先程のParticle Spawn SectionにあるTorus Location ModuleのNormalized Angle Around Torus Axisにセットします。

f:id:kazuhironagai77:20211220015209p:plain

最後にParticle Spawn Section のSet Parameter Module内でRot_Offset変数の値にRandom Range Floatをセットします。

f:id:kazuhironagai77:20211220015233p:plain

結果です。

f:id:kazuhironagai77:20211220015251p:plain

Spriteの位置が微妙にずれています。

これで完成ですが、更に良くするためにMaterialも改良します。

LerpとEmissive Colorの間にHue Shiftノードを追加します。

f:id:kazuhironagai77:20211220015314p:plain

Hue Shiftノードについては後で調べます。

Hue ShiftノードのHue Shift Percentage (s) ResultにDynamic Parameterを繋ぎます。

しかしDynamic Parameterの四つの要素は既に使用されています。

f:id:kazuhironagai77:20211220015333p:plain

そこで新しいDynamic Parameterの使用が必要になるんですが、それは

f:id:kazuhironagai77:20211220015349p:plain

Parameter Indexの値を0から1に変化すれば良いようです。

Niagaraに戻り、Particle Update SectionのDynamic Material Parametersの

f:id:kazuhironagai77:20211220015407p:plain

Write Parameter Index1にcheckを入れて

f:id:kazuhironagai77:20211220015426p:plain

HueにRot_Offsetをセットします。

その結果、

f:id:kazuhironagai77:20211220015450g:plain

になりました。

Level上に配置するとこんな感じになります。

f:id:kazuhironagai77:20211220015512p:plain

今週はここまでです。

知らないノードの機能などについては来週検討します。

3.Material : Content Exampleを見るの続き

ここの所、Ben Cloward先生のTutorialから離れていたのでContent Exampleは今週はお休みしてBen Cloward先生のSwizzle & Channel Manipulation - Shader Graph Basics - Episode 25 [5] をやる事にします。

3.1 Swizzle & Channel Manipulation - Shader Graph Basics - Episode 25 [5]を勉強する

一応全部見たんですが、超簡単に言えば、以下のNodeの使用方法についての説明です。

f:id:kazuhironagai77:20211220015535p:plain

まずChannelとは、以下の例で言えば、

f:id:kazuhironagai77:20211220015555p:plain

R、G、B、AがそれぞれのChannelに当たります。

そしてChannel Manipulationとは、これらのChannelの数を減らしたり増やしたり順番を入れ替えたりする事を指します。

それでですね。

一応、ここで説明された内容は全部、知っている事でした。でしたが、初心者に自分で説明する気になって勉強してみます。

<Channel Manipulationに関する3つの事>

<<Channel Manipulationに使用する以下のノードのCostはfreeである>>

f:id:kazuhironagai77:20211220015618p:plain

つまり、RGBAの内、Rだけ計算する必要がある場合、RGBAからRのみを分離して計算してその後で、残りのGBAと計算したR’の値でRGBAに戻した方が、RGBA全てに計算するよりもCostが少なくてすみます。

<<Channel Manipulationのやり方はUnityUnrealではかなり違う>>

これは、まあどうでも良いです。

<<それぞれのChannelを表すのにRGBAやXYZWなどの違う表示が使用されるが名前が違うだけで中身は一緒である>>

XYZとRGBは交換して使用する事も出来きます。

RPGは色に関するDataに使用されます。XYZは座標に関するDataに使用されます。更にTexture座標に関してはUVが使用されます。これらは単に名前が違うだけでChannel Manipulationに関しては同じものとして扱う事が可能です。

この辺は初心者は結構、迷う箇所かもしれません。特にTexture座標がUVで呼ばれる事に関しては???でしょう。

<Task1:Texture SampleのRGBAのAを除いてRGBにする>

これはUnityではそれなりの手順が必要ですがUnrealではTexture Sampleノードに標準でついている機能です。

f:id:kazuhironagai77:20211220015654p:plain

それ以外の、例えばComponent 4 VectorノードのRGBの値だけ取り出す時は、Maskノードを使用します。

f:id:kazuhironagai77:20211220015711p:plain

MaskノードはMaskと打っても表示されません。

f:id:kazuhironagai77:20211220015727p:plain

ComponentMaskと打つ必要があります。

f:id:kazuhironagai77:20211220015744p:plain

更に、MaskはDefaultでは

f:id:kazuhironagai77:20211220015801p:plain

RGのみOutputする仕様になっているのでBにCheckを入れる必要があります。

<RGBとAを合わせてRGBAを作成する>

RGBとAを合わせてRGBAのような4つのChannelを持つノードを作成する事とAppendすると言います。

UEではそのものずばりAppendノードを使用します。

f:id:kazuhironagai77:20211220015822p:plain

Append ノードの正式な名称はAppend Vectorです。

f:id:kazuhironagai77:20211220015839p:plain

これは間違えてAppendしか打たなくても出て来るのでAppendノードが見つからない事はないでしょう。

<RGBの値のうちRとGを交換したい>

これはSwizzleノードを使用すると出来ます。

f:id:kazuhironagai77:20211220015902p:plain

後Swizzleノードは、XYの値を交換してYXにする事も出来ます。

f:id:kazuhironagai77:20211220015918p:plain

しかし場合によってはSwizzleノードで対応出来ないRとBを交換したいとかRとAを交換したいとかをする必要があります。

その場合は、Append Manyノードを使用します。

f:id:kazuhironagai77:20211220015940p:plain

Append Manyノードならばどんな組み合わせも可能です。

Texture SampleノードはRGBAが全部分かれていますが、Constant 4 Vectorノードの場合はRGBAは分かれていません。

f:id:kazuhironagai77:20211220020000p:plain

その場合はSplit Componentノードを使用します。

f:id:kazuhironagai77:20211220020030p:plain

ただしこのノードFloat3 を分解してそれぞれのChannelに移すだけなのでAの値がないです。

RとAの値を交換したい場合、以下のような実装をする必要があります。

f:id:kazuhironagai77:20211220020047p:plain

以上です。

3.2 TexCoord[0]と計算だけで三角形を作成する

2021-12-13のBlogでTexCoord[0]と計算だけで三角形を作成する位は、私だって出来ます。と言って出来ませんでした。

f:id:kazuhironagai77:20211220020124p:plain

これが出来たとしても何かCostが低くなるとかがあるのかは分からないですが、MaterialのMatrixの計算の理解と手段を自分の物にするための練習にはうってつけなのでもう少し頑張ってみました。

今週の結果は以下のようになりました。

f:id:kazuhironagai77:20211220020140p:plain

実装方法は以下に示します。

f:id:kazuhironagai77:20211220020200p:plain

やっぱり三角形は真ん中が中心で正三角形にしたいですね。

もう少し考えてみます。

4.NPCAIを作成する

4.1 NPC用のAIのための4つのクラスを作成する

まずはUEのAIを作成するために必要な4つのクラスのうち、既に作成されているCharacterクラス以外の3つのクラスを作成します。

f:id:kazuhironagai77:20211220020226p:plain

4つのクラスを繋げます。

CharacterクラスであるNPC_PersonのBPのAIに先程作成したAI_Controllerをセットします。

f:id:kazuhironagai77:20211220020245p:plain

MyNPC_AIControllerのBPを開きBehavior Treeを実行するために以下の実装をします。

f:id:kazuhironagai77:20211220020304p:plain

実行するBehavior Treeは勿論、先程作成したMyNPC_BehaviorTreeです。

最後にMyNPC_BehaviorTreeを開いてBlackboard Assetから仕様するBlackboardを指定します。

f:id:kazuhironagai77:20211220020321p:plain

指定するBlackboardクラスは勿論、先程作成したMyNPC_Blackboardです。

テストします。

まずBlackboardクラスにBoolean変数を作成します。

f:id:kazuhironagai77:20211220020402p:plain

次にBehavior TreeでそのBool変数がTrueになったら文字を表示する実装を組みます。

f:id:kazuhironagai77:20211220020419p:plain

Task、PrintStringTaskの実装は以下の様になっています。

f:id:kazuhironagai77:20211220020436p:plain

実行されると“I see you”がPrintされます。

先程作成したAI ControllerクラスであるMyNPC_AIControllerのBPにこのBlackboardクラスの変数であるCanSeePlayerの値をTrueに変更するためのEventを実装します。

f:id:kazuhironagai77:20211220020451p:plain

このEventをCharacterクラスであるNPC_Personからある条件の時に呼び出します。

f:id:kazuhironagai77:20211220020509p:plain

結果です。

f:id:kazuhironagai77:20211220020526p:plain

I see youがprintされています。

NPC用のAIは機能していますね。

4.2 BehaviorTree を作成する

Behavior Treeの内容ですが、普段はMonsterのように一定の範囲を歩き回ったり止まったりします。

Playerの操作するキャラがTrigger Box内に入ると、立ち止まってPlayerの操作するキャラを見るようにします。

MonsterのBehavior Treeです。

f:id:kazuhironagai77:20211220020552p:plain

これをそのまま利用します。

こんな感じで作成しました。

f:id:kazuhironagai77:20211220020605p:plain

NPCの最初の位置を以下の方法で取得しようとしていますが、出来るのか不明です。

f:id:kazuhironagai77:20211220020623p:plain

ちょっとテストしてみます。

f:id:kazuhironagai77:20211220020636p:plain

駄目みたいです。

うーん。AI ControllerからそのAIを使用しているCharacterを呼び出すノードが有った気がしますが覚えていません。

探したんですが見つかりません。

以下の方法で代用しました。

まずMYNPC_AIControllerにVector型の変数FirstPlaceを作成します。

f:id:kazuhironagai77:20211220020657p:plain

更にBlackboardクラスのVector型の変数であるFirstPlaceにMYNPC_AIControllerの変数であるFirstPlaceの値をCopyするEventを作成します。

f:id:kazuhironagai77:20211220020722p:plain

NPC_PersonのBPでMYNPC_AIController のFirstPlaceにNPCの位置をセットします。

f:id:kazuhironagai77:20211220020746p:plain

セットが終わったら先程作成したEventを呼びます。

これで代用します。

最終的にはNPCも動的にSpawnさせる事になるはずなので、結局これは仮の処置になりますので、今回はこれで行きます。

テストします。

f:id:kazuhironagai77:20211220020839p:plain

それぞれのNPCがそれぞれが配置された場所を保持しているのが確認とれました。

NPCが移動する所を確認する>

Nav Mesh Volume Boundを置いてNPCが移動するか確認します。

f:id:kazuhironagai77:20211220020903p:plain

全然移動しません。

f:id:kazuhironagai77:20211220020920p:plain

Debugします。

f:id:kazuhironagai77:20211220020942p:plain

Decoratorである“Is Random Place”の変数を作成していませんでした。

直しました。

テストします。

f:id:kazuhironagai77:20211220020958p:plain

移動はしますが、地面をSlideしています。

NPCのAnimationを作成していなかったです。

先に、PlayerがNPCと会話出来る距離に近づいた場合、Playerの方を見て待つ部分の実装をします。

以下の部分です。

f:id:kazuhironagai77:20211220021015p:plain

Blackboardクラスに新しい変数、PlayerCharacterを作成します。

f:id:kazuhironagai77:20211220021033p:plain

Find Player Serviceの

f:id:kazuhironagai77:20211220021051p:plain

Player ObjectにPlayerCharacterをセットします。

f:id:kazuhironagai77:20211220021108p:plain

更にRotate to Face BB entry の

f:id:kazuhironagai77:20211220021128p:plain

Blackboard KeyにPlayerCharacterをセットします。

f:id:kazuhironagai77:20211220021147p:plain

テストします。

f:id:kazuhironagai77:20211220021216p:plain

近づくと王様はこっちを振り返って見つめて来ました。

f:id:kazuhironagai77:20211220021239p:plain

出来ています。

NPCが散歩中にPlayerと遭遇したら散歩を中止してPlayerの方を見るか確認します>

今、NPCが散歩しています。

f:id:kazuhironagai77:20211220021306p:plain

途中でPlayerの操作するキャラが近づいてきました。

散歩を中止してPlayerの操作するキャラを見るTaskを実行し始めました。

f:id:kazuhironagai77:20211220021321p:plain

出来ています。

4.3 Animationを追加する

何と、NPCのAnimationの作成方法をすっかり忘れてしまいました。

f:id:kazuhironagai77:20211220021343p:plain

これです。

f:id:kazuhironagai77:20211220021400p:plain

うーん。Animationの勉強もしないといけないんでしょうが、今回は付け刃ですましたい。適当に調べて作成します。

5.NPCAnimation BPを作成する

5.1 復習します。

取りあえずMonsterのAnimation BPをみて復習します。

これです。

f:id:kazuhironagai77:20211220021425p:plain

しかし自分で作成しているにもかかわらず、何で全く覚えていないんでしょうか?

AnimGraphを開きました。

f:id:kazuhironagai77:20211220021444p:plain

Defaultを開きます。

f:id:kazuhironagai77:20211220021520p:plain

SPawnを開きます。

f:id:kazuhironagai77:20211220021538p:plain

おお、段々思いだしてきました。このPlay Skeleton_Swordman_SpawnがAnimationを担当しているはずです。

f:id:kazuhironagai77:20211220021555p:plain

やっぱりそうでした。以下のAnimation_squenceが呼ばれていました。

f:id:kazuhironagai77:20211220021610p:plain

しかしNPC用のAnimation_squenceは以下のヤツが一個あるだけです。

f:id:kazuhironagai77:20211220021628p:plain

これをどうやって作ったのかを調べる必要があります。

NPC用のAnimation_squenceの作成方法>

NPC用のAnimation_squence は2021-09-12のBlogで作成しています。

NPC用のThirdPersonIdleの作成方法を以下に整理します。

<<Third Person Idleの作成方法>>

f:id:kazuhironagai77:20211220021655p:plain

を選んでRetarget Anim Assetsを選びます。

f:id:kazuhironagai77:20211220021712p:plain

多分、これですね。

すると以下の様なWindowが開きます。

f:id:kazuhironagai77:20211220021731p:plain

ここで、UE4_Mannequin_Skeletonのポーズを以下の様に変更します。

f:id:kazuhironagai77:20211220021745p:plain

Retargetボタンを押します。

これでNPC用のAnimation_squenceが出来るそうです。

思い出して来ました。

これはどこかのTutorialを見ながらやったんです。2021-09-12のBlogをよく探したらありました。Skeleton Assets: Anim Retargeting Different Skeletons | 03 | v4.8 Tutorial Series | Unreal Engine [6] です。

ぱっと見ましたが、前回これらの設定は行っているはずなので多分ほとんどの事はやらなくて良いはずです。

5.2 Third Person WalkからNPC用のAnimation_squenceを作成する

f:id:kazuhironagai77:20211220021811p:plain

Retarget Anim Assetsを選択します。

f:id:kazuhironagai77:20211220021829p:plain

思った通り全部設定されています。

前回やったようにRetargetをクリックします。

出来ました。

f:id:kazuhironagai77:20211220021844p:plain

こんな感じです。

f:id:kazuhironagai77:20211220021900p:plain

NPC用のAnimation_Sequenceはこの二つで十分なはずです。

5.3 NPCのAnimation BPを作成します

Animation BPからSK_Character_Fantasy_Skeletonを選択して

f:id:kazuhironagai77:20211220021920p:plain

NPC_AnimationBPを作成します。

f:id:kazuhironagai77:20211220021940p:plain

NPC_AnimationBPのAnimGraphを開いてState Machineを追加します。

f:id:kazuhironagai77:20211220022002p:plain

名前はMonsterのAnimation BPの時と同じ、Defaultにしました。

Defaultの内部はMonsterのAnimation BPのIdle/Runだけが必要なので

f:id:kazuhironagai77:20211220022020p:plain

以下の様に作成しました。

f:id:kazuhironagai77:20211220022038p:plain

MonsterのAnimation BPのIdle/Runを開くと以下の様な実装がされています。

f:id:kazuhironagai77:20211220022057p:plain

変数のSpeedの値ですが、MonsterのAnimation BPのEvent Graphを開くと以下の様な実装で指定されています。

f:id:kazuhironagai77:20211220022113p:plain

SkelSword1D1ですが、

f:id:kazuhironagai77:20211220022127p:plain

BlendSpace1Dから作成されています。

これにSpeed変数をパスする方法が良く分からないです。

中を開くと横軸がSpeedになっているので

f:id:kazuhironagai77:20211220022142p:plain

これが入力値になっているのでしょうか?

うん。

多分そうでしょう。

良しこれを真似てNPC様に同じものを作成します。

NPC用の走っているAnimation_squenceを作成しました。

f:id:kazuhironagai77:20211220022205p:plain

多分、NPCが走る事はないと思いますが、折角、BlendSpace1Dから作成するので走るAnimationも追加しておきます。

BlendSpace1DからNPC用のIdle/Runを作成しました。

f:id:kazuhironagai77:20211220022220p:plain

Axisの設定はMonsterのAnimationで使用されているSkelSword1D1と全く同じです。

f:id:kazuhironagai77:20211220022237p:plain

それぞれのAnimationをGraph上に配置しました。

f:id:kazuhironagai77:20211220022302p:plain

これでNPC用のIdle/Run用のAnimationは完成ですね。

こんな簡単でしたっけ。

前やった時はえらい苦労した記憶がありますが。

まあ、私の実力が向上したと考えて先に行きます。

NPC_AnimationBPのIdle/Walk Stateを開いて

f:id:kazuhironagai77:20211220022325p:plain

以下の実装をします。

f:id:kazuhironagai77:20211220022341p:plain

更にNPC_AnimationBPのEvent Graphを開いてSpeed変数に値をセットします。

f:id:kazuhironagai77:20211220022400p:plain

Monsterでやったやり方と全く同じです。

NPC_Person BPに戻ってAnimationの設定を行いました。

f:id:kazuhironagai77:20211220022416p:plain

これで全部出来たはずです。

5.4 NPCのAnimation BPのテストとDebug

テストします。

結果のScreenshotです。

f:id:kazuhironagai77:20211220022440p:plain

移動する時にきちんと指定したAnimationで移動しています。

そこは大成功です。

Debugする必要はなさそうです。

しかし思いっきり走っています。ここはNPCなのでゆっくり歩いてほしいんです。これは来週直します。

今週のNPCのAIの作成はここまでです。

6.Game DesignポケモンHxHの念能力( 戦闘システムの作成)

先週、考えてた戦闘システムのプロトタイプを作成します。

f:id:kazuhironagai77:20211220022511p:plain

6.1 ターン制の戦闘システムの構築

f:id:kazuhironagai77:20211220022534p:plain

に載っている通りの戦闘システムを作成する事も考えたんですが、試作段階にUE4C++ばかりか普通のC++まで使用するのはオーバーキルな気がします。のでこの本で紹介されているターン制の戦闘システムの構造だけはそのままにして全部BPで作成します。

この本では戦闘システムを複雑な方法で作成していますが、結論で言えばターン制の戦闘は以下の5つの状態で構成されています。

f:id:kazuhironagai77:20211220022600p:plain

最初の状態である行動を決定する状態、2番目の状態である決定した行動を実行する状態、それによる結果(勝利、敗北、逃走)です。

これに敵と自分のターンが加わります。

ので、以下の様に改良します。

  1. 先攻後攻を決める
  2. 先攻が次のターンの行動を決める。
  3. 後攻が次のターンの行動を決める。
  4. 先攻が1で決めた行動を実行する。
  5. 後攻が2で決めた行動を実行する。
  6. 勝負がつくまで15を繰り返す。
  7. 勝利、敗北、逃走のどれかになる。

これで試しに作成する事にします。

<先攻後攻を決める>

これは端にRandom で決定して良いでしょう。試作ですし。

対戦型にして2人で戦うのか?AIと戦うのかについても考える必要があります。取りあえずはAIと戦うようにします。

<先攻が次のターンの行動を決める>

先攻がAIの場合と人の場合があります。この行動を決定するのは先攻か後攻かより、AIかそうでないかが重要ですね。

<<先攻がPlayerの場合>>

盤上に存在する全ての見方の行動を決定する必要があります。

<<<魔術師の場合>>>

魔術師の場合は、先週考えた通り、

f:id:kazuhironagai77:20211220022653p:plain

の魔法から選択する事になります。

<<<召喚したモンスターの場合>>>

取りあえず召喚したモンスターがとれる選択は魔法攻撃、通常攻撃、魔法防御、通常防御位にします。Monsterは戦闘が開始するまでに勝敗が決定する戦略的な戦闘を担当するので、戦闘時の選択で勝敗が決定する要素はなるだけ避けたいです。

<<先攻がAIの場合>>

先攻がAIの場合は、Monsterのみが存在している場合と魔術師が存在している場合で違います。

Monsterのみが存在している場合は、Monsterが魔法攻撃、通常攻撃、魔法防御、通常防御のどれかを選択します。

魔術師が存在している場合は、Playerの選択と全く同じです。

<後攻が次のターンの行動を決める>

先攻で話した内容と全く同じ事をします。

<先攻が1で決めた行動を実行する>

魔術師がMonsterを召喚したり、召喚されたMonsterが攻撃をしたりします。

<後攻が2で決めた行動を実行する>

先攻で決めた内容と同じ事をします。

<勝負がつくまで1~5を繰り返す>

魔術師のHPを1500としてそれが無くなったら敗北にします。敵がMonsterしかいない場合は、敵のMonsterを全滅したら勝ちにします。

<勝利、敗北、逃走のどれかになる>

勝利の時は、報酬が貰え、敗北の時はGame Overです。逃走はGame Overにはならないですが報酬はもらえません。

6.2 魔術師やMonsterのParameterの作成

「6.1 ターン制の戦闘システムの構築」のみを決定したらすぐに試作品の作成に入れると思ったら、戦闘の勝敗を決定するためには魔術師やMonsterのParameterを考える必要がありました。

<MonsterのParameterについて>

HPとタイプが必要です。後、戦闘力もです。この3つがあれば最低限の戦闘が可能と考えています。

  • タイプ
  • HP
  • 戦闘力

<魔術師のParameterについて>

魔術師は魔法を使用するのでMPが必要です。Monsterと違い直接戦う事はないのでタイプと戦闘力は要りません。

  • MP
  • HP

6.3試作について

取りあえずこれだけ決定しておけば戦闘システムの試作は出来そうです。一週間、このアイデアを寝かせて来週から試作品の作成にかかります。

7.Map1Bug直しの続き

7.1 最初の村で買える武器や道具の種類を減らす

村や町は行ったり来たりする予定なのでどの村の武器屋でもどんな武器でも買えるが買う為には資格が要る形にした方が良いと思っています。

職業によって買える武器が変わるのは現実的です。

Playerの操作するキャラのParameterの一つにOccupationがあります。

f:id:kazuhironagai77:20211220022856p:plain

現在、Playerの操作するキャラのParameterの初期値を管理しているData TableであるYour Hero Classesには

f:id:kazuhironagai77:20211220022914p:plain

一個しかデータがありません。

f:id:kazuhironagai77:20211220022932p:plain

Playerの操作するキャラの3D モデルに使用しようしているModular RPG Heroes Poly artには以下のモデルが存在しています。

f:id:kazuhironagai77:20211220022950p:plain

これらを整理して職業を決定します。

そしてそれらの職業に対応してこれらの武器の使用権限も決定する事にします。

f:id:kazuhironagai77:20211220023004p:plain

こういうGame Designをある程度最初に決めておかないと何をProgrammingすれば良いのかも決まらなくて堂々巡りしてしまう訳ですね。

Game Designに関しては普通のProgrammerは勉強した事はないですし、どう勉強すれば良いのかも分かりません。

Game Designを担当する人達はGame Plannerと言うらしいですが、Game Planerが書かれた日本語の本を何冊か読みましたが、とても教科書として読める内容ではなかったです。これは英語の本でもそんなに変わらないみたいです。ただ全ての教材が駄目と決まったわけではなく中には凄い本がある可能性はあります。

私が言える事が一つあるとすればGame Designは必ずAlgorithmに変換する必要があります。それが出来ないとProgrammerはどうCodeに落とせば良いのか分かりません。だからGame Plannerは実際にCodeを書く必要はないですが、Game Plannerが作成するGame Designは必ずAlgorithmに変換できる必要があります。

ここでProgrammingを書いた事が無い人が作ったGame DesignがAlgorithm化出来る訳ないだろうと言う当然の帰結が判明します。

つまり、現在の風潮であるGame PlannerはGameを沢山Playした人で、DesignやProgrammingが出来なくても良い。みたいなのは完全に間違っています。

7.2 武器の種類を整理する

<弓矢>

弓矢は女子にも扱える強力な武器です。狩人が獲物を捕らえる時にも使用します。

f:id:kazuhironagai77:20211220023024p:plain

f:id:kazuhironagai77:20211220023030p:plain

<剣と盾>

剣と盾は沢山の種類があります。

f:id:kazuhironagai77:20211220023059p:plain

f:id:kazuhironagai77:20211220023108p:plain

木の盾や短剣は誰でも買える、鉄の剣や鉄の盾は騎士だけが買える、魔法の盾や魔法の剣は魔法戦士だけが買えると言うような分類が出来ると思います。

<杖>

杖は当然、魔術師のみが装備出来ます。

f:id:kazuhironagai77:20211220023131p:plain

<斧、Hammer

斧やハンマーは力が強くて強健な戦士が使用する専用の武器のイメージがあります。

f:id:kazuhironagai77:20211220023152p:plain

f:id:kazuhironagai77:20211220023204p:plain

以上です。

7.3 職業を決める

上記の武器、防具の関係から必要な職業が大体判明しました。

<初級者>

初級者が使用出来る武器は以下の2つです。短剣(小)と短剣(大)です。

f:id:kazuhironagai77:20211220023233p:plain

さらに以下の2種類の木の盾が使用出来ます。

f:id:kazuhironagai77:20211220023253p:plain

初心者の見た目は、

f:id:kazuhironagai77:20211220023309p:plain

です。

<狩人>

狩人が使用出来る武器は弓と矢です。

f:id:kazuhironagai77:20211220023334p:plain

弓と矢は強力な武器なので狩人の資格がある人だけが装備出来ます。

以下の3Dモデルが狩人っぽいです。

f:id:kazuhironagai77:20211220023355p:plain

f:id:kazuhironagai77:20211220023407p:plain

<戦士>

戦士は力が強く、戦闘の専門家です。普通の人には扱えない重たい武器を使用してMonsterと戦います。

使用出来る武器はAxeやHammerです。

f:id:kazuhironagai77:20211220023432p:plain

AxeやHammerは重いので両手で扱う事にします。丁度両手用のMotionもありますし。

f:id:kazuhironagai77:20211220023449p:plain

3Dモデルは以下のHeavy Knight SKを使用します。

f:id:kazuhironagai77:20211220023502p:plain

f:id:kazuhironagai77:20211220023515p:plain

<騎士>

騎士は位が高く、鉄の武器を携帯する事が許されています。以下の武器を装備する事が出来ます。

f:id:kazuhironagai77:20211220023539p:plain

f:id:kazuhironagai77:20211220023549p:plain

うーん。最後の剣と盾を魔法戦士用に残しておくと盾が一個余ってしまいますね。

Shield 03SMは戦士用の盾にした方がバランスが良いかもしれません。

見た目は以下のModelを使用します。

f:id:kazuhironagai77:20211220023609p:plain

f:id:kazuhironagai77:20211220023619p:plain

どことなく高貴な雰囲気がします。

<魔術師>

魔術師の装備は杖のみです。

f:id:kazuhironagai77:20211220023650p:plain

杖のMotionは以下の物を使用します。

f:id:kazuhironagai77:20211220023707p:plain

見た目は

f:id:kazuhironagai77:20211220023722p:plain

f:id:kazuhironagai77:20211220023744p:plain

にします。

魔法戦士

魔法戦士は魔法の剣と魔法の盾を使用出来る最上級の職業です。

f:id:kazuhironagai77:20211220023811p:plain

f:id:kazuhironagai77:20211220023828p:plain

見た目は以下の3Dモデルを使用します。

f:id:kazuhironagai77:20211220023848p:plain

f:id:kazuhironagai77:20211220023858p:plain

これで売れる武器の分類が出来ました。

7.4 職業のDataを追加する

以下の様に職業を追加しました。

f:id:kazuhironagai77:20211220023922p:plain

このDataを読み込む箇所を全部抜き出します。

このGame CharacterクラスのCreateYourHero()関数で使用しています。

f:id:kazuhironagai77:20211220023938p:plain

ここで大切なのはPlayerRowNameを使用してこのDataTableのRowを読んでいる所です。

f:id:kazuhironagai77:20211220023951p:plain

そしてそのPlayerRowNameにはS1が使用されています。

f:id:kazuhironagai77:20211220024004p:plain

ここでも使用されています。

f:id:kazuhironagai77:20211220024018p:plain

DataTableのRow Nameは変更していないのでこれらの実装で破綻が生じる事は無いと思います。

検索で引っかかったのはこれだけでした。

このGameInstanceクラスのInit()関数はGameを開始した時の読み込みに使用するだけのようです。もうこっちの仕組みはすっかり忘れてしまいました。

転職の仕組みは後で考えるとしてテストしています。

何の問題もなくYourHeroClassesのDataTableのDataが読まれています。

f:id:kazuhironagai77:20211220024035p:plain

それより大変なバグを発見してしまいました。

道具袋では以下の様に表示されていますが、

f:id:kazuhironagai77:20211220024100p:plain

装備品では以下の様に日本語で表示されています。

f:id:kazuhironagai77:20211220024126p:plain

後、職業はどこにも表示されていませんね。

7.5 Pause画面の直し

これも直します。

Pause画面ではPlayerの操作するキャラのParameterは全部表示されるようにします。

f:id:kazuhironagai77:20211220024150p:plain

以下のParameterです。

f:id:kazuhironagai77:20211220024211p:plain

このGoldだけは使用していないので、他のParameterは全て表示するようにします。

まずこれらの日本語の名称を考えます。そしてそれらを統一して表示するようにします。

<Player Name

「名前」にします。

<Occupation

「職業」にします。

MHP

「最大生命値」にします。

<MMP

「最大魔力値」にします。

<HP

「生命値」にします。

<MP

「魔力値」にします。

<ATK

「攻撃値」にします。

<DEF

「防御値」にします。

<LUCK

「幸運値」にします。

<XP

当然「経験値」にします。

<LV

「レベル」にします。

直しました。

f:id:kazuhironagai77:20211220024235p:plain

Backの絵が歪んでいます。別な絵に変更しました。

f:id:kazuhironagai77:20211220024258p:plain

うーん。後ろの絵がこの作品のイメージに合わないです。

f:id:kazuhironagai77:20211220024317p:plain

道具袋や装備品も直します。

f:id:kazuhironagai77:20211220024338p:plain

装備品は取りあえずこのままにしておきます。

f:id:kazuhironagai77:20211220024357p:plain

キリが良いので残りは来週やる事にします。

8.UE5naniteの勉強

先週の続きで公式のDocumentであるNanite Virtualized Geometry [7] を読みます。

番号が先週と違うと混乱するので番号は先週の続きで書きます。

7.3 How does Nanite work?

ここでは2つの状態におけるNaniteの働きについて解説しています。その2つとはMeshをUE5にImportする時とRenderingする時です。

<Importing Mesh

このDocumentによるとMeshをUE5にImportする時に三角の塊に分解するそうです。

元々、Meshって三角の塊じゃないのと思うんですが、どう違うんでしょうか?

後、これ読むとMeshをImportする時にNaniteを使用するための何かをする必要がありそうです。

<Rendering

Play中のmesh内の三角の塊はカメラからの距離に比例して色々なサイズのLODに変更されるそうです。

これはDemo画面でも見ました。

以下に示したような画面表示に変更されて

f:id:kazuhironagai77:20211220024436p:plain

点々の部分のサイズがカメラが近づくと変化していくやつです。

多分これの事を言っているんでしょう。でもこの点々、三角形には見えない気がします。三角形の塊が色で表されているんでしょうか。

この後で、

  • この三角形の塊はカメラからの距離によって形を変化させるにもかかわらず常に回りの三角形の塊と滑らかに繋がるとか
  • On DemandDataが流れて来るのでCameraに写っているLevelの細かさをRenderingするのに必要なDataしかMemoryに保持していない。

などのNaniteの特徴が説明されています。

これらの事が可能になっているのはNaniteが今までのDraw Callとは全く別のRendering方法を採用しているからだそうです。

おお。

UE5でNaniteを扱うのにNaniteのRendering方法を勉強する必要はないと思いますが、単純に興味があります。その辺の情報も少し提供してほしいです。

例えばGlobal Illuminationとかだと関連する沢山の論文が発表されているじゃないですか。そういうのってNaniteのRenderingにもあると思うんです。その辺の情報がほしいです。

7.4 What Types of Meshes Should Nanite Be Used For?

はい。

Rigの入っている歪みが出来るSkeletal MeshにはNaniteは使えません。

と思ったら全然別な話が書かれていました。

ここではSkeletal Meshに関する話はなくてどんなMeshに対してもNaniteは使えるけど特に以下の3つの場合に特に使えます。みたいな話が書かれていました。それぞれの場合について考察します。

f:id:kazuhironagai77:20211220024519p:plain

成程。Z-Brushなんかで作成したMeshは非常に細かいMeshがあちこちに存在してそうです。

そういう3d ModelをそのままUEにImportすると細かいMeshの部分のCostも大きなMeshと同じ位のCostがかかって見た目以上の重さになっていた訳ですね。それをNaniteが解消してくれる訳ですね。

f:id:kazuhironagai77:20211220024539p:plain

先週のBlogで

f:id:kazuhironagai77:20211220024556p:plain

と書きましたが、Hierarchical Instanced Static Mesh Component を使用してMeshのInstanceをVideo Card内で複製すると滅茶苦茶Costが低く出来、何万個のInstanceを生成してもそんなにCostがかからないそうなんです。

NaniteのRenderingはこれを同じ事を自動でやっているんじゃないでしょうか?それならInstanceを沢山配置してもCostがほとんど無料みたいになってもオカシクはないです。

ただ現実のLevel Designで岩とかの配置は良いんですが、木はどうなんでしょうか?

木は風が吹くと歪みます。Naniteの適用範囲外な気がします。

そういえばUE5のDemoも木のない砂漠で行われていました。この辺のNaniteが適応出来る境界についてはしっかり理解しておくべきですね。Naniteが効くと思って木を何万本も配置したら駄目でしたってなったら大変ですから。

f:id:kazuhironagai77:20211220024613p:plain

このOccluderの意味が分かりません。

OccluderってGoogleで検索すると以下の様な視力検査に使用する目を隠す棒が出て来ます。

f:id:kazuhironagai77:20211220024639p:plain

当然ですがこの文脈においては、この視力検査の棒の意味では使用されていません。

Occluderの元になっていると思われる単語、Occludeは止める、とか流れをブロックするみたいな意味の動詞です。

更に3D Graphicsで良く使用されるAmbient OcclusionのOcclusionも止める、とか流れをブロックするみたいな意味があり、こっちは名詞です。ただしAmbient Occlusionのように3D Graphicsの世界で使用された場合、Occlusionは特に光の進行をBlockすると言う意味に限定して使用されている気がします。

これらの事を考慮するとこの文章におけるOccluderの意味は「遮蔽物」ぐらいが適当だと思われます。

ただ何を遮蔽するのかが分かりません。単純に考えればDataの読み込む流れを遮蔽する、もっとも複雑な形で大量のDataを持つMeshを指していると考えられます。しかし3D Graphicsの世界ではOcclusionは特に光の遮蔽に関する事に使用されるのでひょっとすると光を遮蔽するMeshに対して言っているのかもしれません。あるいは全く別にCameraに対しての遮蔽物を指している可能性もあります。

この節の感想は以上になります。

7.5 Enabling Nanite Support on Meshes

ここでは具体的にMeshをUE5にImportする時にどうすればNaniteが使用されるMeshに変換されるのかについての解説がされています。

<Importing a Static Mesh

やり方は公式のDocumentのこの項を見ればわかるので敢えてもう一回ここに書く事はしませんが、Documentで見るだけだと結構不安です。やっぱりこういうのは動画でみたいです。

<Batch Selection and Individual Assets

こっちは何を解説してるのかと思ったら、既にImportしたMeshでNaniteにしなかったヤツをNaniteに変換する方法についてでした。

実際にNaniteを使用するとしたらこっちが主流になりそうです。

7.6 Supported Features of Nanite

ここで(現状の)Naniteが使用出来る場合と出来ない場合についての詳しい解説がされています。

<Geometry

(現状の)Naniteが使用できるMeshは以下の4つだそうです。

f:id:kazuhironagai77:20211220024713p:plain

Hierarchical Instanced Static Meshがしっかり入っていますね。Geometry Collectionが何なのかは分かりません。

その下にしっかり解説されていました。現状、Naniteが使用出来るのはRigidなMeshだけでDeformationするMeshに関しては静的、動的に関わらず使用出来ないと。

次の文が一寸意味不明です。

f:id:kazuhironagai77:20211220024814p:plain

直訳するとこうなります。

これはNaniteのMeshの位置(情報)は、ある意味、Mesh全体の位置に対して一個の4x3の行列を掛けただけで表せる位置(情報)より複雑であると言う事です。

普通、頂点の位置を表す行列は(x,y,z,w)でxyzで三次元状の位置を表し、うろ覚えですがWは位置なら0、Vectorなら1を指定しているはずです。この位置を移動するのに行列を掛ける訳です。

これは最近、散々勉強しているMaterialのTextureの回転なんかもそうです。2021-10-31のBlogを見ると、頂点(vertex)を回転させるためには、以下の行列を掛けています。

f:id:kazuhironagai77:20211220024842p:plain

あれ、この例だとWに1が入っていますね。Wの値は位置なら1、Vectorなら0だったかもしれません。

兎に角、こういう行列を掛けてMeshの位置に移動、回転、拡大縮小などの干渉をする訳です。

この事を言っているのかと思って読んでいると、4x3の行列を掛けてと言っています。上記の様にMeshの位置に移動、回転、拡大縮小などの干渉をするは4x4なんです。

しかもここでa single …と「一個の…」とわざわざ強調しています。

更に前の文章との繋がりも不明になります。

前の文章で、現状、Naniteが使用出来るのはRigidなMeshだけでDeformationするMeshに関しては静的、動的に関わらず使用出来ないと言っています。ので当然次の文ではその説明が来るはずです。

この文に対する説明が、

これはNaniteのMeshの位置(情報)は、ある意味、Mesh全体の位置に対して一個の4x3の行列を掛けただけで表せる位置(情報)より複雑であると言う事です。

だとするとNaniteの位置情報は、普通のMeshと違って、一個の4x3の行列を掛けただけで表せる位置(情報)より複雑だからDeformationするMeshに関しては静的、動的に関わらず使用出来ないんです。となります。

この解釈が合っているのか間違っているのか判断出来る情報は全くないです。

まあでも間違っていると断定出来る情報もないですし、意味が分からないとしか言いようがないですね。

今度は以下の物にはNaniteは使えません。と説明されています。

f:id:kazuhironagai77:20211220024909p:plain

Skeletal AnimationとMorph Targetsは前から聞いていた通りです。World Position Offsetを使用しているMaterialに対しても使用出来ないのはびっくりです。使用するMaterialによってはNaniteが使えなくなるんですね。Normal Mapはどうなんでしょうか?最後のSpline Meshは何の事を言っているのか分かりません。いや正確に言えばContent Exampleの展示のどこかで見た記憶はあるんですが、何を指しているのかまでは思い出せません。

Skeletal AnimationとMorph Targetsに関しては将来的にはSupport出来るようになるんでしょうか?それともNaniteの構造上、歪みを生じるMeshには元から効かないんでしょうか?その辺が知りたいです。

更に現状のNaniteでは以下の2つに対しても効かないそうです。

f:id:kazuhironagai77:20211220024932p:plain

まあ、これは近い将来に解決されるみたいなのでどうでも良いです。

<Materials

以下のMaterialの機能を使用した場合、Nanaiteは使用出来ないそうです。

f:id:kazuhironagai77:20211220024957p:plain

ほとんど全部じゃねーか。

いやでもそうでもないですか。

Two Sideが使用出来ないのはきついかもしれませんね。木の葉なんかTwo SideとMaskの両方を使用してそうですが、木や草は無理って事ですね。

<Rendering

色々なRenderingに対してこれらのRenderingにはNaniteは使用できません。とありますがそこに登場しているほとんどのRenderingが初めて聞くものです。

後で色々なRenderingを使用する時になった時に確認する事にします。

<Supported Platforms

Naniteが使用出来るPlatform一覧です。

f:id:kazuhironagai77:20211220025028p:plain

やっぱりPS5が入っていますね。

今週のNaniteの勉強はここまでとします。

やっぱり木や草の作成にNaniteは使用出来なそうですね。

9.まとめと感想

今週はRPGの作成が結構進みました。本当のGame Designと単なる空想の違いが分かって来ました。

10.参照(Reference

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

[2] Epic Games. (n.d.-a). Math Expressions. Unreal Engine Documentation. Retrieved December 19, 2021, from https://docs.unrealengine.com/4.27/en-US/RenderingAndGraphics/Materials/ExpressionReference/Math/#frac

[3] Epic Games. (n.d.-c). Texturing. Unreal Engine Documentation. Retrieved December 19, 2021, from https://docs.unrealengine.com/4.27/en-US/RenderingAndGraphics/Materials/Functions/Reference/Texturing/

[4] CGHOW. (2021b, December 4). Flower Effect in UE4 Niagara Tutorial | Download Files [Video]. YouTube. https://www.youtube.com/watch?v=37g1J8mImjg

[5] Cloward, B. [Ben Cloward]. (2021, December 2). Swizzle & Channel Manipulation - Shader Graph Basics - Episode 25 [Video]. YouTube. https://www.youtube.com/watch?v=hxIl52S-hzM&list=PL78XDi0TS4lEBWa2Hpzg2SRC5njCcKydl&index=25

[6] Epic Games [Unreal Engine]. (2015, September 28). Skeleton Assets: Anim Retargeting Different Skeletons | 03 | v4.8 Tutorial Series | Unreal Engine [Video]. YouTube. https://www.youtube.com/watch?v=xy9aLbZLdeA

[7] Epic Games. (n.d.-b). Nanite Virtualized Geometry. Unreal Engine Documentation. Retrieved December 19, 2021, from https://docs.unrealengine.com/5.0/en-US/RenderingFeatures/Nanite/