UE4の勉強記録

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

UE5の勉強 -LandscapeのみのGameを作成する-

1.今週の予定

<LandscapeのみのGameを作成する>

以下の事を行います。

Niagaraの勉強>

CGHOW氏のRibbon Fire in Unreal Engine 5.2 Niagara Tutorial[2]を勉強します。

<Materialの勉強>

Ben Cloward先生のAdvance Material Tutorialを勉強します。

<戦闘システムの続きを作成する>

効果音をもっと検証します。

<Gaeaの勉強>

RenderBucket氏のTutorialを勉強します。

<Houdiniの勉強>

FOUNDATIONS | OVERVIEW [1]の続きを勉強します。

Unreal Engine For Fortniteの勉強>

Fortnite Sensei氏のTutorialを実装してみます。

DirectXの勉強>

 C++ DirectX 12 Game Engine - [S01E03] - Creating A Game Engine [2]のFinishing Touchesを勉強します。

2. LandscapeのみのGameを作成する

2.1 Improve GPU Performance in Unreal Engine 5 by Allocating Maximum VRAM for Texture Streaming [1]を勉強する

このTutorialに書かれている内容がLandscapeの計算Costを下げる事に繋がるのかを確認します。

Tutorialを軽く見ます。

見ました。

たった2分の動画なのですぐに見終わりました。

先週まとめた内容で大体あっています。

以下の事をしているだけです。

Pool Size VRAM Percentageは、TextureのDataに対してVRAMをどれくらい使用するのかを指定しているみたいです。

試してみます。

あ、先週FoliageだけでなくLandscape用のMaterialまで外していました。

うーん。

こっちはこっちでTest様に取っておきたい。

新しいLevelを作成します。

しました。My Landscape 9と名付けました。

以下の位置にPlayer StartとBookmark1をセットしました。

現状ではVRAMは5.1GB使用しています。

ではPool Size VRAM Percentageの値を変更してみます。

一端、UE5を閉じます。

から

WindowsEngine.iniを開きます。

PoolSizeVRAMPercentageがありました。

ここにPoolSizeVRAMPercentageの機能が説明されていました。

Tutorialの説明と同じです。

0にします。

UE5を起動します。

Taskを開いてVRAMの使用率を調べます。

ええ、こんなに下がるの!

Shader complexityも見てみます。

こっちは赤いままです。

2.2 Landscapeの境界を調べる

この状態で岩をFoliageで配置します。

そしてFoliageを大量に配置した場合、Landscapeの切り替わりの場所で、Playerが引っかかる現象を調査します。

岩を配置しました。

岩の数は4000個程で

Playerの周りだけ配置しています。

これで引っかかりが起きなかったら、もっと増やします。

テストします。

起きない。

ひっかかりが起きない!

と驚いたんですが、いつもテストしている場所じゃなかったです。この場所。

Testし直します。

以下の条件で組み直しました。

岩の数は5万個です。

これでテストしてみます。

山の麓まで来ましたが引っかかる所はありませんでした。

VRAMの使用率は以下の様になっています。

もう一回テストします。

以下の様に今回はLandscapeの境界に岩を配置して分かり易くします。

前回、テストした時は岩を17万個配置していました。

ので今回も同じぐらい岩を配置します。

島中をPaintして14万まで増やしました。

VRAMの使用量も4.4GBまで増えています。

これでテストします。

引っかかります。

思いっきり遅くなりました。

Play中のVRAM使用量です。

うーん。

まあ、引っかかってもそんなに問題ないかもしれませんが。

引っかかるのは起きますね。

これVRAMの使用量を見ると後の方が少しだけ下がっているんですね。

VRAMの使用量とLandscapeの引っかかりは関係ないのかもしれません。

Cull Distanceを指定して変化があるか確認します。

以下に示した様に岩が消えています。

Play画面です。

え、こんなに岩が生成されるの?

VRAM使用率です。

あんまり変わってないですね。

あれ、

あんな山の奥にまで岩が生成されています。

Cullingが効いてないみたいです。

Playを切ると以下のような岩の表示になります。

うーん。

こっちはCullingがしっかり効いていますね。

何で?

何やっても消えません。

Playすると全部表示されます。

仕方ないのでもう一回Paintし直しました。

以下の様に一見岩が無いように見えますが

実際は15万個の岩が配置されています。

Playします。

今度は岩が消えています。

VRAMの使用量です。

それではテストします。

引っかかります。

Cullingで数を減らしても意味ないみたいです。

今度はFoliageの数を減らしてみます。

7万まで減らしました。

正し減らしたのは島の裏側の岩です。

今のVRAM使用量です。

Playします。

全く引っかかりません。

因みにPlay時におけるVRAMの使用量は

です。

かなり高いです。

にもかかわらず引っかかりません。

今度は以下のテストを行います。

Rockを以下のLandscapeの境界内にだけ配置してみました。

Rockの数は3万です。

Sub Levelは全部で16個あります。のでRockの数は3万ですが、もしこの数は全部のSub Levelに敷き詰めたら48万個のRockを敷きつめたのと同じになります。

現状、VRAMは以下のような消費量になっています。

Playします。

全く詰まりません。

これから推測するとFoliageには最適な数が存在していて、それは数万個までではないかという事です。

数万個を超えるFoliageを配置するとLandscapeの境界でPCの動きが重くなるのかもしれません。

Foliageを数万個程度しか配置出来ないのでは、私の望むLandscapeは作成出来ません。

ひょっとしたらFoliageの1種類に対して数万個が限界なのかもしれません。

以下の様に2つの種類のFoliageを配置してテストしてみます。

Playしました。

全く引っかかりません。

あ、でもこれTotalでも7万位のFoliageしか使用していません。

どの程度の数のFoliageを使用するとLandscapeの境界で引っかかるのかを先に調べる必要がありました。

単一のFoliageで7万個配置してみました。

これでテストします。

一瞬だけ重くなりました。

うーん。

これは、ひょっとすると単一のFoliageは3万位までしか使用してはいけないのかもしれません。

今度は5万個で試してみます。

Playします。

5万でも引っかかります。

今度は確認のために3万で試して見ます。

なんせPCなんでMemoryの管理とかどうなっているのか完全なBlack Boxです。

これで引っかかったら再現性の薄い実験結果になりますが、引っかからなかったら3万個は一つの目安になります。

Playしてテストします。

極僅かですが引っかかりました。

うーん。

まあ、気にならないLevelではあります。

よし、

これらの実験結果から一種類のFoliageの数は3万位までが限界である可能性が高いとの結論になりました。

2.3 UE5.2 でこのProjectをPackagingしてWater SystemのRiverが追加されているのかを確認

これは先週、試しにUE5.2でWater Systemの川を作成してPackagingしたら以下に示した様に普通に川が表示されていました。

もう何か月も前の話ですが、以下LandscapeをPackagingしたら

こんな風に川が消えてしまいます。

2023-01-30のBlogに詳しくまとめられています。

このProjectをUE5.2で開いてPackagingをしたら川が表示されるのかどうかを調査します。

UE5.2で開こうとしたらDataが失われる可能性があるのでCloneしてそっちでやって下さい。と表示されました。

のでCloneを作成したら失敗しました。

うーん。

生でCopyして複製Projectを作成します。

あ、これだと名前の変更が面倒だったんだ。

うーん。

UE5.2で新しいProjectにLandscapeを作成してテストします。

取りあえず島だけ作成しました。

ここまでは目瞑っても出来たんですが、この後のWater Systemの追加が分かりません。

2023-01-22のBlogを読み直してWater Systemを追加します。

更に海と湖も追加しました。

これだけで良いみたいですね。

はい。

Packagingの設定を調整してPackagingします。

出来ました。

Exe.fileから起動します。

川をCheckします。

普通にありました。

凄い!

一応、湖も出来ている事を確認します。

これはもうUE5.2に移るべきですね。

来週からUE5.2でLandscapeを作成する事にします。

2.4 LandscapeをNanite化してもLayerを指定する方法があるのかを調査

これは2023-03-06のBlogにまとめてありますが、

LandscapeをNaniteに変換するとLayerのあるMaterialが乗らなくなってしまいます。

のでLandscapeをNaniteにするのは諦めたんですが、Render Bucket氏のGaeaのTutorialを見てるとLandscapeをNaniteにしそうなんです。

しかもそれでLayer用のMaskも作成しています。

うーん。

これはひょっとするとLandscapeをNaniteにしてもLayerを使用する方法があるのかもしれません。

それを調査します。

調べても昔読んだ資料しか出てこないので自分でテストする事にします。

UE5.2で作成したLandscapeを

Naniteにします。

なりました。

あれ

LandscapeのMaterialは普通に表示されています。

Playしてテストしてみます。

なんの問題もなくPlayできました。

確認しましたが、この場所のLandscapeもNaniteがしっかり効いています。

VRAMの使用率は一寸だけ高いですね。

あ、これはUE5.2ではPool Size VRAM Percentageの値がまだDefault値のままだからです。

まあこれは来週直す事にします。

今週は、UE5.2なら何の問題もなくLandscapeをNaniteにしてかつLandscape用のMaterialを使用出来る事が判明したので、これで十分です。

しかも見てください。

Shader Complexityの結果です。

Nanite化する前は真っ赤だったLandscapeが緑色になっています。

これはGraphic Cardにも優しい作りになっています。

2.5 LandscapeのMaterialを調整する

これは遠距離のMaterialはTextureを使用しないで色で代用したら負担が減るのではないのかと思ったのがきっかけです。

実際、遠くのMaterialのTextureに以下のような精密なTextureを使用する必要は無いです。

これで十分です。

まずCliff Layerだけ試してみます。

せっかくですのでUE5.2で試験します。

まずLandscape用のMaterialのCopyを作成し

更にそこで使用されているCliff用のLayerのMaterial FunctionのCopyを作成します。

このCopyしたCliff用のMaterial FunctionのFar Distanceの実装を全部変更します。

Far DistanceのTextureは使用しないでColorで代用します。

RoughnessとAmbient Occlusionは0で代用します。

Normal Mapは(0, 0, 1)で代用します。

これでテストします。

結果です。

全く問題ありません。

Shader Complexityです。

まだこの時点では何とも言えないですが、緑でも少し明るい緑にはなっています。

同様に以下の5つのMaterial FunctionもDuplicateして改造します。

出来ました。

これでテストしてみます。

まずLayerを指定します。

この状態で、Shader Complexityを見ます。

ああ。

僅かですが奥に行くほど緑が明るくなっています。

非常に微妙な効果ですが効果が確認できます。

VRAMの使用量は以下の様になっています。

結構高いですね。

Pool Size VRAM Percentageの値も今変更しますか。

はい。

のPool Size VRAM Percentageの値も0に変更しました。

UE5を再起動します。

結果です。

うーん。

思ったよりは下がらなかったですね。

あ。

もしかしてVRAM内にも前のProjectのDataが残っているのかも。

一回PC事再起動してみます。

まで落ちました。

Chromeを閉じたら

まで落ちました。

あー。これBackgroundで動いているAppの影響は全く考えていませんでした。

このVRAMの使用量の性格な計測方法も勉強する必要がありますね。

まあ今週のLandscapeの作成はこの位にしておきます。

2.6 今週のLandscapeの作成のまとめ

今週はLandscapeを作成するに当たって、結構新しく貴重な知見が得られました。

忘れないように以下にまとめておきます。

  • Pool Size VRAM Percentageの値を下げるとVRAMの使用率は必ず下がる。
  • Landscapeの境界でPlayerが引っかかる現象が起きるのは、Landscape全体のFoliageの数が多いと起きる。大体5万個以上だと引っかかるようになる。
  • Foliageの数はその種類にも影響していると思われる。一種類で5万語のFoliageを使用すると引っかかるようになるが、2種類のFoliageでそれぞれ3万個にした場合は引っかからなかった。
  • Landscapeの境界の引っかかりはCullingでは直せない。Cullingで表示されるFoliageの数を調整しても引っかかりは全く変わらなかった。
  • 2でPackagingした場合、Layerを使用したLandscapeを使用した場合でもUE5.1 では消えてしまうWater SystemのRiverが普通に表示される事が確認出来た。
  • 1ではLandscapeをNanite化するとLayerのあるMaterialの使用が出来なくなったが、UE5.2では普通に使用出来る事が確認出来た。
  • Materialを簡素化し、使用しているTextureを減らしたMaterialをLandscapeに使用した。Shader Complexityでは改善が認められた。

2.7 来週の予定

来週は、まずUE5.2でLandscapeを作成し直します。

今週、途中まで作成したので続きから作成します。

Water SystemのOceanやRiverを完成させます。

その後で、Foliageの岩を配置して、UE5.2でもLandscapeの境界で引っかかりが起きるのか確認します。

時間があったらFoliageで木も配置してみます。

後、今までのLandscapeの作成でやった内容を復習します。

結構、沢山やったのでまとめて簡潔に表示するようにします。

3. Niagaraの勉強

3.1 Ribbon Fire in Unreal Engine 5.2 Niagara Tutorial[2]を勉強します

CGHOW氏のRibbon Fire in Unreal Engine 5.2 Niagara Tutorial[2]を勉強します。

これです。

これは先週も書きましたが、昔、Ribbonを引っ張ると以外に綺麗なEffectになる事を昔偶然発見したんですが、それをどうやってEffectとして利用したら良いのか分からなかったんです。

その私が分からなかったEffectとしての利用方法を説明したTutorialがこれです。

やっとこのTutorialを勉強できます。

何とこのTutorial、節で分けられています。

節ごとにまとめます。

特に、どうやってRibbonをSkeletal Meshに繋げているのかに注目してまとめます。

<Intro>

今、気が付きましたがUE5.2で作成しています。

いつも通りFountainをTemplateとして追加したNiagara Systemを作成しています。

<Create Niagara Particle>

まずThird Person Blueprintを開きます。

MeshにNiagaraを追加します。

この辺の操作はあんまりやった事が無いです。

このNiagaraのDetailにあるNiagara System Assetに

先程作成したNiagara SystemであるNS_Ribbon_Fireをセットします。

以下の様になりました。

今度はNSの改造です。

Particle SystemにあるShape Location Moduleを消し

いつも通り要らない他のModuleも消しました。

Particle Update SystemにSample Skeletal Mesh Moduleを追加します。

うーん。Update Sectionの方に追加するって事は、Third Personが動きまくってもParticleはついて動くようになるって意味だと思います。

Sample Skeletal Mesh ModuleのMesh Sampling Typeの設定をSurface(Triangles)に変更します。

更にParticle Spawn SectionのInitialize Particle Moduleの

Mass ModeをUnset(Mass of 1)に変更して

Sprite Size Modeの値をUniformにセットしUniform Sprite Sizeの値を1.0にセットします。

結果です。

あれ、Third PersonのSkeletal Meshの形状になっていません。

CGHOW氏、いろいろ弄って最終的に以下の実装にしました。

まず、先程Particle Update Systemに追加したSample Skeletal Mesh Moduleを消しました。

はい。

消しました。

もう、えーですよ。

先程、成程、Third Personの動きに合わせてNiagara Systemを発生するためにはParticle Update SystemにSample Skeletal Mesh Moduleを追加すればいいのか。と感動したばかりなのに。

そしてParticle Spawn SectionにSkeletal Mesh Location Moduleを追加し、

そのPreview Meshに以下に示した

Third PersonのMeshをセットしました。

結果です。

今度はThird PersonのSkeletal Meshの形状にSpriteが表示されるようになりました。

Particle Spawn SectionのSkeletal Mesh Location ModuleのMesh Sampling Typesの値をSurface(Triangle)に変更します。

Previewが以下の様になりました。

最後にSkeletal Mesh Location ModuleをParticle Update Sectionに移動させます。

TutorialではこれでSpriteがSnap to the characterと言っています。

これContextからEffectがThird Personが動いても付いていくと言う意味であるのは明白ですが、Snapにそんな意味が有るんでしょうか?

一寸調べます。

うーん。

なさそう。

Stick toを聞き間違えたんかもしれません。

次にEmitter Update SectionにあるSpawn Rate Moduleを消して、代わりにSpawn Burst Instantaneous Moduleを追加します。

そしてSpawn Burst Instantaneous Module のSpawn Countに200をセットします。

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

Loop BehaviorをOnceにします。

更に

Particle Update SectionのParticle State Moduleの

Kill Particle When LifetimeをOffにします。

これらの手順は、Particleを一回生成したらずっと残しておく時にCGHOW氏がいつも行う方法です。

このやり方で生成したSpriteが残るのは分かりますが、Third Personが移動した時にSpriteが同じ様に移動してくれるんでしょうか?

あ、

これをしているからSpriteも移動するのか。

うーん。

一応納得しましたが、実際に試すまでは100%は信じられないですね。

Particle Spawn SectionにあるInitialize Particle Moduleの

Colorの設定を以下の様にします。

Spriteが赤く光り始めました。

Third Personの方でも以下の様に光っています。

はい。

ここまで見れば、どうやってRibbonをSkeletal Meshに繋げるのかが分かりました。

Eventですね。

2つのEmitterを作成して、片方をSourceにしてもう片方をRibbonにします。Sourceの方でここでやったようにSkeletal Meshの表面にParticleを発生させ、その位置にRibbonを繋げる訳です。

<Mesh Location>

ここでPlayして確認しています。

SpriteがThird Personの動きにくっついて移動しています。

ここでSkeletal Mesh Location ModuleをParticle Spawn Selectionに移動すると

Spriteは最初に生成された位置に残ります。

はい。

まあ予測した通りでした。

このParticleはSourceとして使用しますのでSpriteとして表示する必要はないです。

Render SectionにあるSprite Renderer Moduleも消します。

Emitterの名前をSourceに変更します。

新しいEmitterを追加し名前をRibbonとします。

このEmitterはいつも通りFountainをTemplateとしています。

Render SectionにあるStrite Renderer Moduleを消してRibbon Renderer Moduleを追加します。

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

Eventってこうやって作成したんでしたっけ。

もう完全にやり方を忘れています。

Eventのやり方を軽く復習します。

いろんな所でEventは勉強していますが、今回は一番最初にEventを勉強した2022-02-06のBlogを読み直した。

特に理由はないです。

調べたらこれが最初に出てきたからです。

あれ、全然違う。

2022-02-06のBlogを読んだら思い出して来ました。

Eventの作成方法ってここでやっているやり方とは全くちがいます。

ああ、分かった。

Spawn Particle from Other Emitter ModuleってParticle Attribute Readerを使用したModuleだったはずです。

前に調べた気がします。

ありました。

2023-02-06のBlogで調べていました。

やっぱりAttribute Readerを使用しています。

今回は、このNodeを使いこなせれば十分なのでAttribute Readerについての復習はまたの機会にする事にします。

そしてEmitter NameにSourceを追加し

Error表示の所にあるFix Issueを押します。

するとParticle Spawn Sectionに以下に示した様にSample Particles from Other Emitter Moduleが追加され

Errorが消えます。

今度はこのRibbon Emitterにある要らないModuleを消します。

消したModuleはShape Location Module、Gravity Force Module、そしてDrag Moduleです。

そしてAdd Velocity Moduleの

Velocity ModeをLinearに変更します。

結果です。

何か変です。

Particle Spawn SectionにあるSample Particles from Other Emitter Moduleを選択して

Particle ID Samplingの値を「Apply Sampled ID as Ribbon ID」

にします。

Source EmitterのPropertiesを選択して

Requires Persistent IDsにCheckを入れます。

ここはEventの設定の基本通りです。

特にCommentを入れる必要も無いです。

するとPreviewのImageか以下のように変化します。

更にParticle Spawn SectionにあるInitialized Particle Moduleの

Lifetime ModeをDirect SetにしてLifetimeを1.0にします。

結果です。

単に微調整しているだけです。

Third PersonのImageです。

RibbonがThird Personの表面から生成されています。

Level上のThird PersonのImageです。

良い感じですが、

以下に示した様にThird Personが走ると

Third PersonとRibbonの間に大きな隙間が発生します。

この問題を解決するためにEmitter Update SectionにあるSpawn Particles from Other Emitters Moduleの

Spawn RateとSpawn Rate Per Particleの値を10倍にして

以下の様に隙間を埋めても

この後にCurl Noiseを使用すると

Ribbonの形状が以下の様になってしまいます。

これ、原因がよく分からないです。

何でSpawn Rateの割合を上げるとCurl Noiseにこんな影響を与えるようになるんでしょう。

まあ良いです。考えても分からないかもしれないですね。

Tutorialの続きをやります。

そこで以下の方法を採用します。

<Solve Mesh Gap>

Particle Update SectionにScratch Padを追加します。

Map Set Nodeに[PARTICLE]Positionを追加します。

以下に示したSelect Nodeを追加します。

次にMap Getノードに[PARTICLE]Ageを追加します。

更に[INPUT]Floatを追加して名前をNumber of Particlesに変更しName SpaceをEmitterに変更します。

その値で1を割ります。

この値が[PARTILCE]Ageより大きいかどうかをGreater Than Nodeで調べます。

もし大きければPositionはそのまま、小さければ[INPUT]Niagara Positionに変更します。

うーん。

まだ何を計算しているのかよく分かりません。

何でAgeとParticleの数の逆数の関係がParticleの位置を決定する要因になるの?

Applyを押して完成です。

更にNSに戻ってNiagara Positionの値に[PARTICLE][INITIAL]Positionをセットします。

これでScratch Padの設定は終わりです。

Emitter Update SectionのSpawn Particles from Other Emitters Moduleの

Spawn Rateの値を50.0に変更します。

ここでScratch Padの以下の箇所の

Name SpaceをInputに変更して

以下に示した様にNSからNumber of Particlesの値を指定出来るようにするようにします。

以下の様に隙間が無くなりました。

うーん。

Scratch Padの実装について一寸考えてみます。

[PARTILCE]Ageが入っているという事はRibbonが生成されてからの時間が関係しているんでしょうね。

時間が経つと新しいPositionに移動するような設定しょうね。

あ、そういう事ですね。

時間が経ったら新しいThird Person表面上のSourceの位置にRibbonを移動する。という事でしょうね。

<Strach Velocity>

ここではParameterの微調整をしただけです。

Particle Spawn SectionにあるInitialize Particle Moduleの

Lifetimeを0.2にしたり

Ribbon Attributesの設定を以下の様にしたり

Particle Spawn SectionにあるAdd Velocity Moduleにある

Velocityのzの値を100に上げたりしています。

以下の様にしています。

<Fire Texture>

今度はFire用のMaterialを作成します。

何でこの項の題がTextureなんでしょうね。Fire Materialが正しいと思います。

以下の実装を組みました。

Ribbonは左から右へ移動するのでPannerノードのSpeedのXの値はNegativeにします。

Radial Gradient ExponentialノードのCenter Positionに以下の値を追加します。

その結果、以下のImageを作成しました。

これを先程のNoiseとBlend Color Burnノードを使用して混合します。

結果です。

更に炎っぽくするために以下の実装を追加しました。

結果です。

更に以下の実装を追加します。

以下のような結果になります。

Mainノードの設定を以下の様に変更します。

Opacityは以下の様に実装しました。

Previewでは以下の様になっていました。

これが炎になるんでしょうか?

<Effects>

作成したMaterialをNiagara SystemのEffectで使用します。

Ribbon EffectのRender SectionにあるRibbon Renderer Moduleの

Materialに先程作成したM_Fireをセットします。

Particle Update SectionにDynamic Material Parameters Moduleを追加し

値を以下の様にセットします。

これはBlackbodyのTempの値ですね。

Blackbodyと言っているのに、温度に対する発色はBlackbodyと全然違うNodeです。

こんな結果になりました。

こんな感じです。

全然、炎に見えません。

TempにCurveを代入して

以下のようなCurveを指定しました。

Particle Spawn SectionにあるAdd Velocity Moduleの

VelocityのZの値の2倍にしました。

Particle Spawn SectionにあるInitialize Particle Moduleの

Ribbon AttributesのRibbon Widthの値も2倍にしました。

以下の様になりました。

炎がCharacterの内側で発生しているようです。

<Camera Offsets>

炎をCharacterの外側で発生するようにします。

ここは単純にParticle Update SectionにCamera Offset Moduleを追加します。

Camera Offset Amountに30をセットします。

あまり変化がないので200にしました。

それでも変化が無いです。

これってRibbon EmitterじゃなくてSource EmitterでCamera Offset Moduleを使用したら効果あったんじゃないでしょうか?

自分で実装する時は試してみます。

ので今度はParticle Spawn SectionのInitialize Particle Moduleの

Lifetimeを0.5に増加しました。

結果です。

<Randomize>

炎の形状が全部同じです。それぞれの炎によって形状を変化させます。

まずRibbon EmitterのMaterialに使用したM_fireを開きPannerに以下の実装を追加します。

MultiplyノードのBにはDynamic Material Parametersノードの2番目のInputの値を繋ぎます。

Dynamic Material Parametersノードの2番目のInputの名前はPanにしました。

そしてNiagara Systemに戻ります。

以下の様にParticle Update SectionのDynamic Material Parameters Module のPanにLerpをセットします。

このAlphaの値はParticle Spawn SectionにあるSample Particle from Other Emitter Moduleの

以下のParameterを使用します。

しかしこのParameterはNiagara IDなので変更する事が出来ません。

のでParameterを自作して使用します。

まずNew Scratch Dynamic Inputを選択します。

New Scratch Dynamic Input を開いてMap Getノードに[INPUT]Niagara IDを追加します。

そしてその結果をOutput Dynamic Inputノードに繋げます。

New Scratch Dynamic Inputはほとんど実装した事ないです。

ぱっと見にはScratch Pad Moduleと同じに見えます。

Niagara Systemに戻ります。

先程のParticle Update SectionのDynamic Material Parameters Module のPanのLerpのAlphaに以下の様にセットします。

あ。成程。

こうすると[Sample Particle from Other Emitter] Niagara IDの値も使用する事が出来るようになる訳ですね。

うーん。

これって単にNiagara IDのTypeがNiagara IDだったからFloatのAlphaにセット出来なかっただけじゃない?

そんな気がします。

PanのBの値を調整します。

結果です。

炎が下向きになっている気がするのでLerpのAとBの値をNegativeにします。

結果です。

炎の向き云々はよく分かりませんが、かなり良いんじゃないでしょうか?

今度はSource EmitterのRender SectionにLight Renderer Moduleを追加します。

このLight Renderer ModuleのColor Addの値を以下の様にします。

結果です。

Color Addの値を調整しています。

結果です。

なんとここでCGHOW氏、先程あれほど一生懸命作成したParticle Update SectionにあるDynamic Material Parameters Moduleの

Alphaの値に直接、以下の

[PARTICLE][SAMPLE PARTICLES FROM OTHER EMITTER] Sampled Indexを追加しています。

うーん。

何で?

更にLerpのAとBの値も変更しました。

結果です。

このTutorialは一寸長いので、今週はここまでとします。

残りは来週、勉強します。

4. Materialの勉強

先週のBlogを読み直していたらSub Surface Profile Methodの勉強が、Sub Surface Profileにセット出来るAssetが無いために出来ないで終わっていました。

しかも公式のDocumentであるSubsurface Profile Shading Model [3]にこのAssetの作成方法があるので来週勉強します。と書いていました。

これは勉強する必要がありますね。まずこれからやる事にします。

4.1 Subsurface Profile Shading Model [3]のSub Surface Profileの作成方法を勉強する

まずサラッと全部読みます。

Sub Surface Profileの設定方法の説明は無かったです。これで本当に作成出来るのかは分かりません。

とりあえず書かれている通りに出来る所までやる事にします。

以下の箇所からSubsurface Profileを作成します。

出来ました。

Defaultである程度の設定はされているんでしょうか?

中身を見ます。

以下の様になっていました。

うーん。

これって Subsurface Scattering - Advanced Materials - Episode 8 [4]で使用されているSub Surface Profileの設定と

全く同じですね。

という事はこれを使用すれば先週のTutorialの最後の部分は出来るという事です。

今やります。

先週作成したSubsurface Profile用のMaterialを開き

今、作成したSubsurface Profileをセットしました。

結果です。

3つ並べました。

うーん。

よく分からん。

先週のBlogを読み直したら違いが分かりました。

これです。Transmitted Lightの違いを見ればいいんです。

となるとDirectional Lightだけの方が分かり易いと思います。

Directional Lightだけで比較します。

右端がSubsurface Profileです。

真っ黒です。

全然想像していたのと違います。

向きを変えるとこんな感じです。

境目はかなり赤くなっていますね。

それ以上は分かりません。

色々な角度から観察しましたが、以下の状態で何とかTransmitted Lightの影響が少しだけ確認出来るかどうかって感じです。

Tutorialがやっていたように

World Unit Scaleの値を1.0に変更します。

結果です。

うーん。

汚い。

計算Costはどうでしょうか?

少しだけ濃い緑色になっていました。

横からみた状態です。

これはかなりマシです。

真後ろから見た時です。

一番、真っ黒です。

側面からみた場合です。

これはかなり良いですね。

影の部分がしっかりピンク色になっています。

もっと赤くしてみました。

結果です。

うーん。よく分かりません。

通常のLevelにおいてみました。

色々値を弄ったら以下の様になりました。

まあ、慣れたら悪くは無いのかもしれません。

後は計算Costがどれくらいかかるのかですね。

一応今のSubsurface Profileの値も示しておきます。

Materialの方の値も少しだけ弄りました。

<勉強した感想>

一応、3つの皮膚をRenderingする方法を理解出来ました。

こういう技術ってGameに利用するとなるとどうなんでしょう?

Subsurface Profileなんか実際のGameに使用しようとしたら、何個かの難題を乗り越える必要がありそうです。

今回は3つの皮膚のRendering方法を理解出来たのでそれでよしとします。

4.2 Car Paint Shader - Advanced Materials - Episode 9 [5]を勉強する

まずTutorialを全部見ます。

今回はUnityが最初に説明されていました。

UEの方だけ見ました。

4つのCar PaintのMaterialの作成方法について説明していました。

以下にその方法をまとめます。

最初のCar Paintです。

実装です。

Fresnelノードを使用しています。

FresnelのExponentInには0.2がセットされて以下の様な結果になっています。

UEはUnityのようなGradientは無いのでLerpで代用します。

以下の様に組む事でLerpノードでGradientを再現します。

指定する色を変える事で以下のような色合いを出す事も可能です。

Tutorialでは以下の色を使用して上記の色合いを出しています。

Tutorialではこの色合いの事をChameleon Paintと呼んでいます。

この呼び方が一般的なのかは分かりません。

調べたら一般的見たいです。

Chameleon Paintで以下の検索結果が出て来ました。

今度はこのCar PaintにSparkleを追加します。

Roughnessに以下の実装を追加します。

これだとどんなTextureを使用しているのか不明です。

結果です。

これはかなり車のPaint感があります。

使用しているTextureの説明がありました。

以下のTextureを使用しています。

Voronoi NoiseをTextureにして使用しているそうです。

Voronoi NoiseをNetで検索したら以下のImageが出て来ました。

あんまりと言うか全然TutorialのTextureのImageと似ていません。

まあ、実装する時は似たImageを探して使用します。

次はClear Coatを使用した場合です。

Clear Coatって何の事かと思ったらMain NodeのShading Modelの値の一つでした。

Shading ModelにClear Coatをセットすると以下に示した様に

Clear CoatとClear Coat Roughnessが使用出来るようになります。

因みにClear Coatを使用した結果を以下に示します。

これが出来てどうなんだろう?

あんまり違い無い気がします。

と思っていたらTutorialで違いを見せてくれました。

以下のPreviewがClear Coatが無い状態です。

Clear CoatがあるとObjectの表面をWaxで塗ってピカピカにしたような効果があります。

はい。

分かりました。

後、実装ですが以下に示した通りLerpノードが追加されていました。

今度はCarbon Fiberです。

ふーん。

これ最初に作成した人が、喝采を受けたでしょうね。すごいRenderingです。

これは実装が今までのとは全然違うので以下に示しておきます。

何故か実装の全体像を映した場面がないので以下に残りの実装を示します。

Base Colorの結果です。

以下の結果ですが実はClear Coatは使用してないそうです。

その証拠にClear Coatの値が0になっています。

ここでClear Coatの特別な機能を見せてくれるそうです。

Roughnessの値を0.7、Clear Coatの値を1にセットします。

そしてProject Settingを開きClear Coat Enable Second NormalをEnableします。

すると以下に示したClear Coat Bottom Normalノードが使用出来るようになります。

これは先程のBase Colorで示した部分のNormalを指定する機能だそうです。

このClear Coat Bottom Normalノードに以下の実装を追加する事で

下層の部分のNormalを指定します。

この場合は以下に示した様にBase Colorには何も繋ぐ必要がないそうです。

この場合の結果も以下に示しておきます。

先程と全く同じ結果になっています。

これで終わりでした。

ここで使用されているTextureが分かりません。

Unityの方で説明されているかもしれません。

調べます。

以下のTextureが使用されているそうです。

説明を聞くとCarbon FiberのNormal Mapだそうです。

Carbon Fiber、Normal Mapで検索したら以下に示した様に大量の同じようなImageが表示されました。

こんだけあったら実装する時は何とかなるでしょう。

今週のMaterialの勉強はここまでとします。Car Paintの実装は来週やる事にします。

5. 戦闘システムの続きを作成する

先週は突然、病院に行く必要があり、ゾンビ族の効果音の追加を途中までやった所で中止したんでした。

今週はまずゾンビ族の効果音の追加を最後までやります。

5.1 ゾンビ族に効果を追加するの続きをやる

ゾンビ族が攻撃された時の効果音をゾンビ族が死んだときの効果音を追加します。

<攻撃された時の効果音>

以下の3つのNodeがゾンビ族のDamageを受けた時のAnimationを管理しています。

Animationを見るとDownloadしたAssetのAnimationをそのまま使用しています。

このAnimationをDuplicateして、そのDuplicateした方にDamage音を追加します。

まずDuplicateしました。

これを開き、Notify TrackとNotify、Play Soundを追加します。

Play Soundには他のMonsterのDamage音で使用されている以下の音源を使用します。

良い感じで効果音が追加されました。

最後にこのAnimationを先程のNodeにセットして終了です。

残りのゾンビ族のMonsterのAnimationにも同じ事をします。

ゾンビ弓士です。

ゾンビ剣士です。

テストします。

全部のゾンビ族で攻撃された時にDamage音が聞こえました。

Damage音自体の評価に関してですが、まずDamage音はその場の雰囲気にあっていました。

更にDamage音がMonsterが攻撃された事、そしてその攻撃が効いている事を暗に示すような音になっていました。

一応、合格とします。

<死んだ時の効果音>

ゾンビ族が死んだときの効果音も追加していきます。

Level BPにあるDefeat Animation()関数の以下の実装がゾンビ族が死んだときのAnimationを管理しています。

これもAssetのAnimationをそのまま使用しているのでDuplicateしたのに効果音を追加します。

DuplicateしたAnime SequenceにSoundを追加します。

Play AnimationノードにSound付きのAnimation Sequenceをセットします。

同様に残りの2つのゾンビ族のAnimationにも効果音を追加します。

Testします。

勝てない!

ゾンビ族3体と戦うのはきつ過ぎます。

こっちの召喚するMonsterをもっと強力にします。

調べると以下のWidgetでMonsterの召喚を管理していました。

更に詳しく見ると以下の部分の実装でPlayerが召喚出来るMonsterを指定しています。

召喚出来るMonsterのData Tableがありました。

ここで例えばDragonだけのData Tableを作成したらDragonでも召喚出来るんでしょうか?

うーん。

Dragonを味方として召喚した場合、作ってない部分が結構ありそうです。

今回は単純に妖精族の攻撃力を上げる変更を追加するだけにします。

当然、これはテスト用なので後で直します。

妖精族の攻撃力を300に変更しました。

これでテストします。

あれ、Damageが100しか入っていません。

何とMonster Data Tableが以下に示した様に4つもありました。

これはDataの管理と言う面から言うと最悪の作り方ですね。

まあ、元々このGameは「補助魔法の存在こそが戦闘の面白さにつながる」という推測を確認するために作成した試作品ですので、効率は度外視しています。

Monster Data Tableが実際のMonsterの攻撃力を管理しているみたいです。

こっちの値も変更しました。

今度は300ずつ減っています。

全部のゾンビ族の死亡時のAnimationを確認しました。しっかり音が出ていました。

設定を元に戻します。

妖精族の攻撃力が元に戻っているかを確認します。

攻撃力も元に戻りました。

5.2 Dragon族の効果音を追加する

最後に残ったMonster族であるDragonに効果音を追加します。

<Dragon族の攻撃Animationに効果音を追加する>

Dragon族の攻撃時の効果音は亡霊族と同じにします。これはどちらも攻撃時のAnimationが同じだからです。

以下にDragon族の攻撃Animationを管理しているNodeを示します。

以下のAnimationに効果音を追加します。

しました。

同様に他の2種類のDragonの攻撃Animationにも効果音を追加します。

テストします。

確認しました。

氷攻撃の効果音は迫力に欠けます。

それ以外は迫力満点です。

<DamageのAnimationに効果音を追加する>

これは全部のMonsterで同じ音を使用しています。

Dragon族も同じ音を使用します。

以下のNodeがDragon族のDamageのAnimationを管理しています。

まずDragon地面のDamage Animationに効果音を追加します。

これはAssetについてきたAnimationをそのまま使用しているのでDuplicateしてそちらに効果音を追加します。

追加しました。

このAnimation Sequenceを先程のNodeにSetします。

残りの2つのDragonのDamage時のAnimationも同じようにします。

しました。

テストします。

普通のDamage音です。

そんだけです。

特にBugも無かったです。

<Dragonが死亡した時の効果音を追加する>

以下にDragonが死亡した時のAnimationを管理しているNodeを示します。

ここに死亡時の効果音を追加します。

やり方は前と全く同じなので結果だけ示します。

テストします。

Dragonを倒す必要があるので今だけ妖精族の攻撃力を1000に変更しました。

3体全部のDragonが死亡した時の効果音を確認しました。

普通に鳴っています。

音自体はあんまり良くないです。

後で品質を向上させる時は直します。

妖精族の攻撃力を元に戻します。

更にStage1で召喚されるMonsterの種類も元に戻します。

確認のためStage 1だけPlayし直しました。

直っています。

これで今週やろうとしていた内容は終わりました。

もう大体完成しています。

来週からはBGMを追加します。

6.YouTubeのネタ

時間が余ったので本当は先週やりたかったYouTubeのSub Channel用のネタを如何にまとめます。

日本に帰って来てもう数年経ってかなり日本の内情に詳しくなりました。

それで気が付いたんですが、日本のNewsって英語圏で最も話題になっている問題を一寸しか流さなかったり、全く触れなかったりします。

しかもそのNewsを訳知り顔で解説する人達がかなり偏った意見を言ったり、もしくは物凄い見当違いな話をしたりします。

その辺をドヤ顔で指摘して、その後で少しだけ解説を加えるというYouTubeのChannelを作ろうと思っています。

6.1 アメリカ国内で画像AIの著作権がどう考えられているのかについて

本当はTennessee州の議員が除名されたNewsについて話したかったんですが、これ英語圏で一番熱いNewsなのに日本で全く報道されていません。

私が調査した結果(Googleで検索しただけ)ですが、日本語で書かれた記事でこの話題を取り上げたのはBBCの日本語版だけでした。

いや、びっくりして早速この話題をまとめようとしたんですが、これだけ日本で話題になってないと日本語しか出来ない人から全く興味持たれない可能性大な気がしてきました。

そしてそういうみんなが興味の無い話題は取り上げない(少なくとも最初の頃は)方が無難と言う結論に至りました。

ので今回は「アメリカ国内で画像AIの著作権がどう考えられているのかについて」をここにまとめます。

これは話題性、凄いあるでしょう。

なんせみんながイラストを発表するSNSを運営する会社のほとんどはアメリカに本社があります。つまりアメリカの法律が適応されるわけです。

となるとアメリカで画像AIの著作権がどう考えられているのかは単に興味のある話題であるだけでなく、イラスト関連で飯食っている人達全員が知っておくべき話題です。

まずこの分野は誕生したばかりで全く判例がなく、現状の法律をどう適用するのかもまったく未知な状態であるので、こうだろう。とは言えても現実にそうなるかどうかは全く分からないそうです。

そういうあやふやな状態である事を認識した上で、今のアメリカでは以下のような考え方が知的エリートの間で主流になって来ています。

  • AIが描いた絵に著作権は無い。
  • 著作権で守られている絵を使用してAIが学習してもFair Useの範囲
  • AIが勝手に作成した絵でもその絵が著作権で守られている物を侵害している場合は、その絵をUploadした人が賠償する責任を負う
  • AIであるイラストレーターの画風そっくりのイラストを生成しても著作権で訴える事は出来ない。

これらについて詳しく解説します。

<AIが描いた絵に著作権は無い>

これ、一番、重要な内容だと思うんですが、日本で全く聞いたことが無いんです。

まず理由から話しますが、AIに人権はないからです。

これ、理解するのにある重大な裁判の判決があります。

それについての説明を以下にします。

あるサルが観光客か写真家かわかりませんが、誰かのCameraのシャッターをふざけて押したんです。

そしたらその写真が偶然、凄い芸術的な写真になったんです。シャッターを押してるサルが写っているんですが、凄い楽しそうなそのサルの顔が写っているんです。

で、その写真の著作権が誰のものかで凄い揉めて、最後はとうとう裁判になりました。

結論は、サルがシャッターを押したからその写真の著作権はない。と言う判決でした。

何故なら、サルは人間ではないからサルが作ったものに著作権は付かないからです。

この判例の考え方はそのままAIの作成物にも適用される。と大方の知的エリートのアメリカ人は考えています。

AIはサルと同じで人間ではありません。

つまり、AIが作成したものに著作権は存在しません。

これがどういう事かと言うと、AIで生成したイラストを誰かが勝手に使用しても著作権違反だと訴える事は出来ないという事です。

誰かがAIでイラストを作成したとします。

それを他の誰かが丸コピーして販売したとしても、その元のイラストを(AIで)作成した人は、丸コピーした人を著作権違反で訴える事は出来ないと言う訳です。

だってそのイラストを作成したのはAIですから。

これって凄い重大な内容だと思うんですが、まだ日本ではこの問題は全く議論されていません。

で、AIで元の絵を7割ぐらい作成して、3割位自分で修正した場合はどうなのか、とかそういう細かい議論はまだ全く結論が出ていません。ただ10割AIが作成した絵に関してはほぼ100%の確率で著作権は無い。と考えられています。

つまりAIの絵は現状、パクリ放題な訳です。

著作権で守られている絵を使用してAIが学習しても合法である>

機械学習とか深層学習では膨大なDataをAIに学習させる必要があります。

この元のData、つまり絵ですが、AIはネットにUpされている著作権で保護されている絵を勝手に使用して学習している訳です。しかも無許可で。

これが許されるかどうかですが、許されると考えています。

著作権で守られる芸術的な絵を描く画家も、著作権で守られている先人の画家の絵を見て学習してきた訳です。

それに対してお前は俺の絵を真似て自分の絵を描くから、俺の絵を見て学習するの禁止な。とは言えない訳です。

これがAIの学習に対しての同じである。と考えています。

<AIであるイラストレーターの画風そっくりのイラストを生成しても著作権で訴える事は出来ない>

先程の話に繋がるのでこっちを先に解説しますが、例えばAIの学習にJojoの奇妙な冒険の絵ばっかり使用したとします。そしてAIがJojoそっくりの画風の絵を描けるようになったとします。

このAIの絵を誰かがネットに公開したとします。

これで荒木先生が怒って、著作権違反だとその絵を訴えたとしても、荒木先生は裁判で負ける。という事です。

その理由ですが、画風は著作権の適応範囲外だからそうです。

この辺、日本の著作権はどうなんでしょうね。画風も著作権で保護されるんでしょうか?

<AIが勝手に作成した絵でもその絵が著作権で守られている物を侵害している場合は、その絵をUploadした人が賠償する責任を負う>

一体何を言っているんだと思うかもしれませんので、これも例え話で話します。

先程のJOJO風のイラストですが、どんなに荒木先生の画風にそっくりでも裁判で負ける事は無いです。しかしAIがDIOそっくりのキャラを生成したとします。もう誰が見てもDIOです。

それを私がNetにUpしたとします。

はい。これは著作権違反になります。

DIOは荒木先生の著作物で他人が勝手に使用すると著作権を侵害した事になるんだそうです。これはAIが生成したとしても全く関係ないそうです。

しかも賠償金を払うのはAIではなく私になります。

私がこの絵はAIが作成したの。だから私は関係ない。と主張しても駄目だそうです。

著作権違反は別に絵を描いた人だけが負うのではなく絵をネットにUpした人も負うそうです。

はい。

こんな話をYouTubeでまとめていこうと思います。

7. Gaeaの勉強

7.1 UEのLayerの関係を再確認する

Gaeaの勉強ですがUEのLayerの関係を再確認する事から始めます。

先週もまとめましたがUEではLayerに使用したMaskの取り扱いは以下の様になっています。

後で思ったんですが、これLandscapeでLayer Infoを作成する時、

以下のような選択が表示されます。

これ何気なくWeight-Blended Layer (normal)を選択していたんですが、Non Weight- Blended Layerを選択しても同じ結果になるのか気になったんです。

何となくですが、Non Weight- Blended Layerを選択した場合はGaeaとおなじような混合の結果になりそうな気がします。

それを試します。

今回のTestはUE5.1を使用します。

新しいLandscapeを作成して以下の様にLayerを追加しました。

試験方法は2023-03-06のBlogのやり方と全く同じです。

結果です。

100%混合しています。

今度は灰色のあるMaskを使用します。

結果です。

色の変化が見え易いようにUnlitで撮影しました。

灰色の濃さに応じて混合割合が変わっています。

Layer Infoを作成する際にNon Weight- Blended Layerを選択した場合、Layerの混合はGaeaのColorの混合と全く同じになります。

うーん。

これは驚きの結果です。

となるとGaeaのColorの勉強も無駄では無くなります。

7.2 Environment Creation: Fixing Heightmap Stretching in Blender [6]を勉強する

先週、Render Bucket氏の Environment Creation: Making Realistic Desert Rocks In Gaea [7]を勉強しました。今週はその続きのEnvironment Creation: Fixing Heightmap Stretching in Blender [6]を勉強します。

このTutorialでは以下に示した様な垂直方向への歪んだ伸びを含んだHeight Mapを修正する方法を学習するそうです。

GaeaからExportしたHeight Mapをそのまま使用してUEでLandscapeを作成した場合

GaeaからExportしたHeight MapをBlenderのGeometry Node?で修正してUEでLandscapeを作成した場合

確かに崖の変な縦伸びが無くなって自然な地層が追加されています。

うーん。

でもこれってGaeaにあるNodeでも出来そうですが?

一寸調べます。

うーん。分からん。

以下に示したErosion GroupかLookDev GroupのどちらかにあるNodeで

地層を追加する機能をもったNodeが有ったはずです。

あ、地層の英語名を調べれば良いのか。

stratum

でした。

となると怪しいのはErosion GroupにあるStratifyノードです。

説明を見るともろにStrataと書かれています。StrataはStratumの複数形です。

StratifyでBlogを検索します。

3回だけ勉強していますね。

2022-05-02のBlogのはまだGaeaの勉強初めたばかりのヤツですね。

パッと読んだんですが、全く理解してない状態で、泣きながらGaeaの勉強をしています。

凄い。

継続は力なりですね。

この時の頑張りが有って今のGaeaへの理解がある訳です。

2023-02-13のBlogではStratifyノードの機能について以下の様にまとめてありました。

これは分かり易い。

しかしこのScreenshotだと崖にStrataが追加されているのかが分かりません。

まあ、これは後で実装する時確認します。

今週はこのTutorialを勉強します。

以下のNodeをHeight MapとしてExportするそうです。

2048でExportするそうです。

2048でExport出来るという事はRender Bucket氏は有料版を使用しているって事ですね。

StructureをTrisに変更しました。

なんと次の場面では既にHeight MapをObjでExportしてBlenderに取り込んだ後になっています。

うん。

Exportの仕方とかは無しなの?

後、Objで取り込むって言っていましたけどHeight MapとしてExportしたんじゃないの?

よく分かりません。

まあ良いです。

こっからはBlenderの使用方法です。

Geometry Nodeに移動します。

以下のような画面になっています。

画面の下半分に表示されているPaneの名称が不明ですが、Geometry Graphとでも呼んでおきます。

このGeometry Graphの上部にある以下のNewを押します。

すると以下のNodeが追加されます。

おお、興味深いですね。

以下の実装を組みました。

NormalのZの値によってGeometryを分けているのはBlenderのWorld CoordinateはXZが地面でYが上だからでしょう。UEならXYが地面でZが上になるはずです。

結果です。

やっぱり側面だけ抜き取られています。

この結果にDistribute Points on Facesノードを追加します。

このNodeはその名前からしてGeometryの上にPointを分配するんでしょうか。

次の実装です。

分配したPointsをVolumeに変更して、更にMeshに変更しています。

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

更にMeshを細かくしたいならSubdivide Meshノードを追加します。

こんな結果になりました。

前よりも細かくなっているんでしょうか?

これと元のLandscapeの平な部分を足します。

以下の実装でLandscapeの平な部分を抜き出します。

前に崖の部分を抜き出したのと逆をやっているだけです。

Join Geometryノードで2つのGeometryを混合します。

結果です。

うん?

これは良くなっているのか?

この後でDetailを追加するそうです。

うーん。

それなら良かった。

表面のDetailを追加するために以下の実装を追加します。

これを先程のGeometryの結果とSet Positionノードで繋げます。

表面のDetailを追加するための実装はSet PositionノードのOffsetに繋げます。

結果です。

Wave TextureノードなどのParameterを調整しています。

Render Bucket氏はこの方法による調整をProceduralな調整と言っています。

うーん、

Houdini的な意味で言っているのかもしれませんね。

うーん。

これって単にGeometryを追加しただけで、それがGeologyとしての一貫性があるのかって話になるとかなり違う気がします。

GaeaのNodeはどれもGeologyに準拠して作成されています。のでそれぞれがGeology的に意味のある形状を作成しています。

このBlenderで追加した部分は歪んだMeshを細かくはしましたが、Geology的に意味のある形状に変更した訳では無いです。

以下の新しく生成された崖の表面を見れば

地球上でErosionされた表面がこんな形状を維持出来ないのはすぐに理解出来ます。

これじゃ火星の表面です。

まあ、良いです。先に行きます。

Shading画面に移ります。

以下のようなPreview画面になりました。

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

Principled BSDFノードは知っています。

去年、Blenderで法線転写について勉強した時に使用しました。

このPrincipled BSDFノードのBase Colorに2D Texture Combinedノードを繋げます。

この2D Texture CombinedノードにはGaeaで作成したTextureが入っているそうです。

このTextureの作成方法、私は知っていますが普通の学習者は知らない訳でそれを説明しないでいきなりここで使用するのは不親切な気がします。

Shading画面からGeometry Node画面に戻ると

以下の様になっていました。

やっぱり新しく作成した部分にはTextureが乗っていません。

これを修正します。

もっとも簡単に修正する方法はTextureをProjectする方法だそうです。

まずLayout画面に移動します。

AddからMeshを選択してGridを追加します。

追加されました。

GridのサイズをLandscapeと同じにします。

ここからが面倒です。

Landscapeを選択しModifiersを選択し

UV Project Modifierを追加します。

そしてUV Project ModifierのObjectに先程のGridをセットします。

これって、GridのUVをLandscapeにProjectするって事でしょうか?

うーん。

これだけだと分かりませんね。

取りあえず続きを見てみましょう。

なんとLandscapeの結果が以下のように変化しています。

新しくGeometryを追加した箇所以外の部分はGaeaで作成したTextureが綺麗にProjectされています。

むー。

さっきのUVの投影はこんな結果をもたらすんですね。

今度は先程、新しく作成したGeometryの部分にもTextureのProjectionが出来るようにします。

Geometry Node画面に戻り、Set Materialノードを追加します。

ここで使用しているMaterial.002は先程Shader画面で作成したMaterialの事です。

結果です。

崖の部分です。

ううん。

感想は保留です。

このやり方は良い点と悪い点がある気がします。

後でその辺を検証します。

この後、Renderingの設定を変えたりしていますが、UEと関係ない部分はSkipします。

一寸最後まで見て確認します。

はい。

すぐにBlenderからUEにExportする方法を説明します。ってなりました。

Modeling画面に移動します。

こういう画面です。

ここからそのやり方を説明するのかと思ったら、このTutorialはここで終わりでした。

次のTutorialでそのやり方を説明すると言っています。

ただしその次のTutorialはまだ出ていません。

以上でした。

7.3 Environment Creation: Fixing Heightmap Stretching in Blender [6]を勉強した感想

感想を以下に示します。

  • Blenderを使用してGaeaのHeight Mapにある問題を修正すると言う発想は俊逸
  • Blenderで作成したGeometryの品質には不満
  • UVをProjectする方法に対しての評価はよく分からない
  • Blenderで生成した新しいLandscapeをUEにExportした状態を見るまでは評価出来ない
  • なんとなくHoudiniの隠し味がする。Houdiniではこのようなやり方でTerrainを作成しているのでは?

Blenderを使用してGaeaのHeight Mapにある問題を修正すると言う発想は俊逸>

GaeaのHeight MapをそのままUEで使用すると以下のような不自然な凹凸が形成されます。

これを一々手動で直していたら、3D酔いしてしまいました。

なんとかして一括で直す手はないのかと色々試行錯誤しています。

最初に考えたのはFoliageの岩で覆い隠してします事です。(2023-03-20のBlogより)

これで解決した。

と思ったらFoliageの岩の数には限界があり、あまり数が多くなるとLandscapeの境界を跨いだ時にFPSが凄く落ちるようになります。

ので他の方法で解決出来るのならそれを試したいです。

そんな時にBlenderでHeight Mapの問題がある所を改良する。と言う発想は目から鱗でした。

Blenderで作成したGeometryの品質には不満>

ただし今回のBlenderで修正した方法には不満があります。

今回、このTutorialでは崖のMeshの歪みを直しましたが、その結果がこれです。

これではせっかくGaeaで作成したErosionの表面が全く無くなってしまっています。

やっぱりGaeaはTerrain形成に特化しているだけあって地形の表面の形成に関しては科学的に正しく生成する事が出来ます。

BlenderでそのQualityを出すのは難しいんじゃないのか。と思いました。

<UVをProjectする方法に対しての評価はよく分からない>

この後、Gaeaで作成したTextureを張り付けるためにUVをProjectしましたが、この方法自体だけでなくその理屈もよく分かっていません。

のでこのやり方がどんだけ凄いのか、全く分かりません。

のでこのやり方に対しての評価をする事も出来ません。

Blenderで生成した新しいLandscapeをUEにExportした状態を見るまでは評価出来ない>

結論は、このやり方で作成したHeight Mapを使用して作成したLandscapeをUEで見るまでは、良いとも悪いとも言えないです。

つまり評価はPendingです。

<なんとなくHoudiniの隠し味がする。Houdiniではこのようなやり方でTerrainを作成しているのでは?>

最後に、私の単なる感想ですが、Houdini感がします。

Nodeを並べてGeometryを作成する事をProceduralな方法で作成と言ったりしているからです。

HoudiniにおけるTerrainの作成方法を勉強したら何か分かるかもしれません。

8. Houdiniの勉強

今週は「11. Transform Objects and Geometry」を実装します。

これでやっとFOUNDATIONS | OVERVIEW [1]のTutorialが終わります。

<Rubber Toy>

まずこれからやってみます。

Licenseが無いので開けません。とか出て来ました。

新しくLicenseを習得したら開けました。

まあFreeのしか使用していませんので、どうでもいいですが。

Rubber Toyを配置します。

左端のToolから以下のIconを選択します。

Tutorialの説明通りに軸が表示されました。

矢印を使用してRubber Toyを移動させました。

以下のIconを使用してScene Viewを四分割します。

以下の様になっています。

Link Ortho ViewにCheckを入れて

下の3つのViewをLinkさせます。

先週は、この次のTutorialの説明を理解出来なかったんだ。

先週の説明を読むと以下のIconをEnableすると

Construction Planが現れてConstruction Planeに沿った移動が出来るようになるそうです。

うーん。

まずIconにCheckを入れてみましょう。

確かにPlaneらしき物が現れてRubber Toyの足の半分位がそのPlaneの下にあるように見えます。

これでRubber Toyを移動させてみます。

色々試行しましたが、このPlaneを表示させた時とさせない時になんの違いも無かったです。

もう一回Tutorialを見て確認します。

やっぱり先週まとめた内容であっています。

Construction PlanにCheckを入れない場合はCamera Planeに沿って移動しますが、Checkを入れた場合はGround Planeに沿って移動する。と言っています。

もう一回試して見ますが、全く違うが分かりません。

検索しましたが不明です。

Bingで質問したら以下の回答が返ってきました。

うーん。

この情報が正しいなら、以下の私のProjectはCamera ViewとGround PlaneのViewが同じ状態になっているんでしょうね。

そういう事だと納得して次に行きます。

ああ、分かった。

Construction PlaneがOffの状態です。

Rubber Toyに表示されている以下の紫のCubicを選択し

Mouseで移動させます。

Mouseの動きに応じて上下左右自由に移動します。

今度はConstruction PlaneにCheckを入れます。

そして同じようにPurpleのCubicを選択してRubber Toyをグリグリ動かします。

同じようにグリグリ動かしますが、以下に示した様に

左右にしか移動しません。

上下には移動しません。

これがConstruction Planeの機能なんです。

となるとConstruction Planeを検索すれば良いんです。

しました。

公式のDocumentであるSnapping, construction plane, and alignment [8]にConstruction Planeについての詳しい解説が載っていました。

え?

そうなの?

これ読むとConstruction Planeってどこにでもおけそうです。

以下の説明もありました。

うーん。

これ読むとConstruction PlaneってUEで言う所のLocal Spaceと同じな気がします。

今分かっている事はConstruction Planeと言う座標を使用している時にObjectを移動させると、左右にしか移動しない事だけです。

Shiftを押すと今度は上下だけの動きになるそうです。

試します。

なりました。

RotationやScalingも試しました。

この2つの操作はConstruction Planeの場合も通常の場合も全く同じみたいです。

次に行きます。

今度はDefault値に戻す方法です。

Tutorialの説明通りにRotateやTranslateを右Clickして以下のBoxを表示させ

Revert to Defaultsを選択します。

するとDefault値に戻ります。

先週のBlogでは値を選択してやっている。と書いていますが値は選択出来ませんでした。

後、Construction Planeを切っても同じように出来ました。

次はPose Toolの使用方法についてです。

先週のBlogでは

とだけ書かれています。

次のToolです。

先週のBlogには「Translation、Rotation、そしてScalingの操作の全部が行えるそうです。」と書かれていました。

確かに行えそうです。

Pose Toolに戻ります。

先週のBlogには以下の様に書かれていました。

試して見ます。

Yを押します。

これはScalingの調整用みたいです。

もう一回Yを押します。

これは移動用ですね。

もう一回Yを押します。

あれ、元に戻ってしまった。

  • 回転、移動が同時に出来る
  • Scalingが出来る
  • 移動が出来る

の3つのPatternがあるみたいです。

Handle Toolの場合も同じでした。

今度はAnimationの追加です。

Rubber Toyを以下の位置に移動させて

Kを押します。

Time Lineは以下の様になっています。

Kを押す事でFrame 1にこのRubber Toyの位置が記憶されたはずです。

でもTime Lineは何も変化していません。

Rubber Toyの位置を以下の場所に移動させて

Key Lineの240を選択した状態でKを押しました。

さらに途中に回転させた状態を追加しました。

これはKey Frameの指定が無かったので168の所でKを押しました。

再生してみます。

何とFrame1が記憶されていません。

いきなりこの場所に現れます。

もう一回設定しなおしました。

今度は大丈夫でした。

正し1秒間で240 Frame動くみたいで、ものすごく早く動きます。

Motion PathにCheckを入れました。

Rulerが表示されました。

Tutorialの説明通りです。

先週のBlogのまとめを見るとこのRulerは掴んで移動出来るとありますが、出来ません。

出来るのは端に表示されている赤いCubicだけです。

赤いCubeを追加するにはKey Frameを移動してその位置でKを押します。

すると赤いCubeを追加する事が出来ます。

赤いCubeを追加して以下の様にRulerを変形してみました。

Show Tangentを追加して

傾きを調整しました。

Ribbon ModeをOnにしました。

Ribbon Modeで傾きを調整しました。

これは非常にやりやすいです。

滑らかなAnimationになりました。

<Squab>

今度はSquabです。

Pivot Pointが表示されています。

Tutorialの説明通りにやったら以下の様にPivot Pointを移動させる事が出来ました。

今度はGeometry Modeで以下の3つの点を選択しました。

この状態で右Clickしたら以下のBoxが表示されました。

先週のBlogによると

以下のBoxが表示されるはずです。

うーん。

Tutorialを見て確認します。

分かりました。

Tutorialでは3つのPointsを選択した後でRotation を選択しています。

この状態で右ClickしたらTutorialと同じBoxが表示されました。

Attach to GeometryのCheckを外します。

を選択します。

一番したのPointを選択しました。

Attach to GeometryのCheckを入れます。

これで回転させます。

選択したPointが中心になって回転しています。

このやり方だと別に選択したPointじゃなくてもPivotに指定出来ますね。

これはPointの間をPivotに指定しました。

Tutorialで確認してみます。

TutorialではSoft Editが0になっていますね。

まあ、これがPivotの位置に影響を及ぼす事は無いでしょう。

後は、全く同じでした。

<Pig Head>

Pig Headです。

私のは色がついていて更にRealです。

Tutorialの指示に従ってWireを表示しました。

この状態でGeometry Modeに入ったら以下のような表示になりました。

Tutorialで確認したらTutorialでは以下のIconが選択されていました。

表示が同じになりました。

この後の操作ですが、先週のBlogを読んだだけだとよく分かりません。

Tutorialを見直します。

なんか色々弄っていたらTutorialと同じ状態になりました。

選択したPointを移動させます。

Soft Edit Radiusを移動させます。

結果です。

今度は両耳の先端にあるPointを選択しました。

耳の形を変形しました。

今度はStrideを選択して

以下のEdgeを選択しました。

Edgeの移動が出来ました。

次はPeakを試します。

以下に示した2つのPointsを選択しました。

引っ張ってみます。

それぞれのNormalに沿って移動しています。

Soft Edit Radiusの値を変更しました。

結果です。

もうなんか可哀想です。

止めて上げてって感じです。

次はScriptを選択しました。

次にEdit1の

Groupの値を0から2885に変更しました。

全てのPointが選択されました。

これでScriptが出来るとありますが出来ません。

Tutorialで確認します。

Tutorialを見て戻ってきたら突然出来るようになりました。

うーん。よく分かりません

一応、出来たのでOKとします。

今度は以下の様にFaceを移動して

Soft Edit Radiusが使用出来ない事を確認します。

Soft transformノードを追加しようとしたら出来ません。

Tutorialを見ます。

Pointが選択された状態でSoft transformノードを追加していました。

同じようにPointsを選択しました。

この状態でTabを押してSoft Transformノードを選択しました。

今度は追加出来ました。

このNodeとEditノードの違いが分かりませんね。

一寸使用しただけでは同じに感じます。

先週のBlogはこれ以上の解説は無いです。

Tutorialの説明を聞きます。

聞いたけどよく分かりません。

最後のTransformノードを試します。

これの違いはすぐに分かりました。

これはSoft edit Radiusがありません。

選択したPointだけ厳密に移動させます。

これで終わりでした。

TutorialはこれでObjectとGeometryの両方のTransformのやり方を理解したはずです。と言って終わりました。

うん。

まあ、大体は理解しました。

<Houdiniの勉強のまとめ>

これでFOUNDATIONS | OVERVIEW [1]のTutorialが終わりました。

まあ、まだ知りたい事は何も分かってないです。

来週は、今まで勉強した内容を復習します。

後、Houdiniを使用してUE5内で大量の建物をProceduralに生成する方法についても調査する事にします。

9. Unreal Engine For Fortniteの勉強

9.1 YouTubeのSub Channel用のVideoを作成する

先程、まとめたAIが描いたイラストの著作権についてのまとめを動画にします。

そしてこの動画のBackground動画には私が作成しているGameを使用します。

これでGameの宣伝も出来て2重で得になります。

家族に聞かせたらGameの効果音が大きすぎると言われました。

Gameの画像の撮影とTalkの録音を別にしました。

音声の録音です。

音声はWindows 10に付属のVoice Recorderで録音しました。

Davinci Resolveで編集します。

うーん。

Talkの部分で活舌が悪くて聞き取れない箇所が一か所だけあります。

この部分だけ編集出来ないんですかね。

後、あんまり音声良くないですね。

せっかくマイクでしゃべっているのにこんなに声が割れるのはどういう事なんでしょうか?

調べたらマイクに近すぎの場合に声割れが起きるそうです。

後、自分の声を録音したのを聞いたのはほとんど初めてだったんですが、なんか江戸時代の町人みたいな声しています。

恥ずかしい。

うーん。

これって逆に江戸時代の町人のガワを使用したらいいかもしれません。

一寸探します。

調べたらうきよえすとっく[9]と言うサイトで以下のイラストを見つけました。

これなんかすごいあっています。

これ使用する事にします。

色付けました。

以下の様になりました。

後ろの画像が主張しすぎている気がします。

Colorに移動してBackの録画を選択しContrastの値を0.5に下げました。

結果です。

うーん。

良い感じです。

BGMも探してみます。

音楽は沢山あり過ぎてよくわかりません。

LoopしてもOKで、和風なBGMで検索して一番、良い感じが以下の曲でした。

これでBGMを追加します。

Titleも追加しました。

YouTube用の動画としてExportしました。

もう2,3個こういう動画を練習用として作成します。

その後で本当にYouTubeに公開する事にします。

結構疲れました。

9.2  Unreal Editor for Fortnite Beginner Tutorial - UEFN Starter Course! [10]の続きを勉強する

この勉強をやる時間はもうないです。

これは来週やる事にします。

10. DirectXの勉強

10.1 C++ DirectX 12 Game Engineの先週勉強した内容を復習する

先週はOlympus Engine ProjectにあるIAppilcation.hとBlank ProjectにあるApplication.hを継承させたはずです。

それは覚えています。

まず先週のBlogを読み直します。

Olympus Engine ProjectにあるIAppilcation.hとBlank ProjectにあるApplication.hを継承させました。と言う、上のまとめの通りでした。

しかし最後に

と書かれていました。

うーん。

今週は実装するだけじゃなくて、それぞれの手順の意味も解明するの?

まあ、やるしかないですね。

10.2 先週の手順の意味を検証する

先週、やった内容を見ていきましょう。

<__declspec()>

まずはこれです。

以下の箇所で使用しています。

公式のサイトを見つけました。

__declspec [11]です。

以下の様な説明がありました。

うーん。

Microsoftの特別なStorage-classのAttributeに保持されるのは分かったんですが、それがなんなのか分かりません。

もう少し調べます。

なんと次のお勧めに出て来たのは日本語のサイトで

LIGHT11氏の以下のサイト[12]でした。

このサイトでは__declspec()の機能は

と書かれていました。

この外部からの意味が別のProjectから参照すると言う意味なら、この解答で完璧でしょう。

一応、他のサイトの解答も調べておきます。

Stack Overflowにもありました。

What is __declspec and when do I need to use it? [13]です。

まず最初の解答ですが、

WindowsでDLLを使用するには必要。

とあります。

これはこれでありな解答ですね。

その後、ずっとクソみたい解答が続いています。

Stack Overflowも凄い質が落ちました。

驕れるものは久しからず。とはよく言ったものです。

DLLにExportしたDLLからImportしたりする(関数?)につけるSymbolと解説しています。

他のサイトも調べます。

あ、Visual C++でDLLを使用する方法を調べた方が早いかもしれません。

はい。

Exporting Class Methods and Functions in Microsoft Visual Studio [14]で以下の解説がありました。

つまり、DLLにある関数をExportしたい場合はその関数名の前に__declspec(dllexport)を追加して、そのClass全部をExportしたい場合はそのクラス名の前に__declspec(dllexport)をつけるように。と言っています。

DLLでExportしたくないクラスや関数は基本的には無い訳で、WindowsでDLLを作成する時は必ずこれは付けなければならないと考えておけば問題なさそうです。

それは兎も角、この解説を乗せているサイトなんですが、絶対に英語のサイトに飛べないようになっています。

そのくせ、解答文は完全な英語で返って読みにくくなっています。

名前がNiとかなっていてかなり怪しい感じがしますが、この解答は今まで見た解答の中でもかなり上位の解答です。

実は凄い会社なんでしょうか?

製品を見たらLabViewがありました。

え、LabViewを作成している会社なの?

National Instrumentsのホームページだった。

凄い所じゃなかったです。

<dll_Export>

これは先程の__declspec()の調査でこの意味も分かってしまったのでもう調査はしません。

<BUILD_DLL>

BUILD_DLLは単なるMacroなはずです。

ここで重要なのはこのMacroを以下のPropertiesのC++のPreprocessor DefinitionsにBUILD_DLLを追加する事で

機能するようになっている事です。

このPreprocessor Definitionsの機能が本当は何なのかについて調べます。

公式のSiteである/D (Preprocessor Definitions) [15]を見るとここでセットされたMacroは1がセットされているみたいです。

ネットに書かれている説明を読んだんですが、それ以上はよく分かりませんでした。

OLYMPUS_API

次は以下の部分です。

これこそ、単なるMacroを定義しているだけです。

そして先程のIApplication.hの設定を

から

に書き換えています。

ここまでがOlympus Engine Projectの設定で今度はBlank Projectの設定です。

<Additional Include Directories>

これは調べなくても知っています。Includingを使用した時に、どのFolderを調べるのかを指定します。

<References>

このReferencesの機能については全く覚えていません。

復習します。

と思ったら下のCommentにしっかり解答がありました。

DllやCppをIncludeするために使用するそうです。

以上です。

うーん。

PropertiesのC++のPreprocessor Definitionsの機能はあんまり良く分からなかったですね。でもそれ以外は結構理解しました。

本当はこの後、実装もしたかったんですが、残り時間の配分を考えるとここで今週のC++ DirectX 12 Game Engineの勉強は終わりです。

10.3 「DirectX 12の魔導書」の勉強

今度は「DirectX 12の魔導書」の勉強です。

これからはDirectX 12の勉強は以下の様にSubの節をつけるようにします。

10.3.1「DirectX 12の魔導書」の先々週の勉強を復習する

先週はDouble Bufferingの仕組みがやっと理解出来てそれについてまとめていました。

まあ。

分かっちゃったら小学生でも理解出来る内容ではあったんですが、やっぱり理解するのに結構時間が掛かったのでそれなりに感慨深かったです。

簡単にまとめ直すと以下に示した様に完成する前のImageを画面に表示してしまうと、

画面を見ている人には、映像がチラついてるように見えてしますそうです。

それを直すために以下に示した様に画像が完成するまで裏で画像のDataを受け取って

画像が完成した瞬間に表の画像と切り替える訳です。

これがDouble Bufferingだった訳です。

10.3.2 「3.3.4 Swap Chain」の「Swap Chainの生成」を勉強する

読みました。

先週は凄い沢山のCodeが並んでいたので、一寸威圧されてしまっていましたが、きちんと読んだらそんなに難しい事はしていませんでした。

Sample Codeを見ながら教科書の内容を確認します。

まずSwape Chainを作成するために以下の関数を使用します。

Create Swap Chain For Hwnd()関数です。

「Swap Chainの生成」の内容は簡単に言ってしまえば、この関数のParameterについて解説しているだけです。

最初のParameterですが、Command Queueです。

教科書では何故、ここがID3D12DeviceではなくCommand Queueなのかを長々と説明していますが、よく分かりません。正直興味も無いです。

後、教科書、ここで第3,第4引数がNullptrで、第2引数であるswapchainDescについて説明します。と書いていますが、これ第2引数はHWNDです。ので全部一個ずれます。

まあ、そんな細かいミスはどうでも良いです。

一応、公式のサイトも見ておきます。

IDXGIFactory2::CreateSwapChainForHwnd method (dxgi1_2.h)[17]です。

こんな説明がされていました。

最初のParameterですが以下の解説がありました。

これ読んだたら、教科書の言っている事が理解出来ました。

点と線が繋がった感じです。

まあ、Direct3D 11を知らない私は、あんまり興味の無い話である事には変わりません。

次に行きます。

ここでswapchainDescの宣言をします。

この宣言の仕方を見るとSwapchainDecsはStructの様です。

更に生成したSwapChainDecsに値をセットします。

はい。

ここの要素の機能についてはほとんど説明していません。

公式のサイトであるDXGI_SWAP_CHAIN_DESC structure (dxgi.h)[16]を見ると

それぞれのMemberの機能についての詳しい解説が載っていました。

必要になったらこれを読む事にします。

これで終わりです。

10.3.3 「3.3.4 Swap Chain」の「Swap Chainの生成」を実装する

それではSwap Chainを生成するための実装を私のProjectに追加します。

Swap Chainそのものは前から宣言していました。

Swap Chain Descを宣言します。

それぞれのMemberに値をセットします。

ここはSample Codeの丸コピーです。

後で興味が出てきたらこのMemberの設定について勉強します。

Create Swap Chain For Hwnd()関数を追加します。

これもSample Codeからの丸コピーです。

あれ?

_swapchainがErrorになっています。

私のはCが大文字になっていました。

うーん。どっちに統一しよう。

読み易いのは断然、私の書き方です。のでCを大文字にします。

Errorが消えました。

TestでPlayしてみました。

普通に動きます。

Errorとかも出なかったです。

Chat GPTが教えてくれた以下の実装を使用して本当にSpawn Chainが生成されているのか確認します。

Resultの値がS_OKである事を確認しました。

出来てます。

10.4 HLSLシェーダーの魔導書を勉強する

これも先週何を勉強したのか覚えていません。復習からやって行きます。

10.4.1 先週の復習

先週は色々やったんですが、簡単にまとめると教科書の「3.1.6 メモリー転送」の「Descriptor Heap」を読んで理解しただけです。

特にまとめ直す内容も無いので次の章を読む事にします。

10.4.2 「3. 1. 7 ワールド行列を作成して三角形を動かしてみよう」を勉強する

まず教科書を読みます。

結構、Volumeがありました。

これ実装するだけなら簡単ですが、それだけで終わらせてしますとこの教科書がここで主張したい所を見逃してします可能性があります。

今週は敢えて、この部分の内容をまとめる事に集中する事にします。

<定数Bufferの作成>

定数Bufferを作成します。

ここは提供されているClassを使用します。

先々週と先週はこの提供されている定数Bufferを作成するClassの仕組みを理解しようとして、訳分からん深みに嵌ってしまいました。

今回はこの提供されているClassについてはそういうもんだ。と仮定して先に進みます。

そうする事で全体の流れを理解します。

<Descriptor Heapの作成>

ここで使用しているDescriptor Heapもこの教材で作成されたClassでした。

この辺は深く入り込まず、

  1. 定数Bufferを作成した。
  2. Descriptor Heapを作成した。
  3. 作成したDescriptor Heapに定数Bufferをパスした。

位の流れを理解しておくにとどめておきます。

<World座標を作成>

ここで移動先の座標軸を指定しています。

この辺はOpenGLと同じです。

<World座標をGraphic MemoryにCopy>

ここで定数BufferにWorld座標をCopyしています。

<Descriptor Heapを設定>

ここは実際に何をやっているのか不明です。

Descriptor HeapをGPU側に送っているんでしょうか?

<Register b0のDataにAccessするための変数を定義する>

ここからHLSLの実装になります。

以下の部分がRegister b0のDataにAccessするための変数の作成方法だそうです。

うーん。

あんまし考えないで流れを理解する方向で勉強します。

ので次に行きます。

<World Coordinateと(三角形の)座標を掛けて座標変換を行う>

サンプルコードの以下の部分がそれをやっているみたいです。

うん。これがやっています。

これで完成です。

<流れを整理する>

大体の流れは理解しました。

変に自分で考えるより教科書に書かれている通りに理解するのが一番、分かり易いです。

以下に流れをまとめ直します。

CPU側

  1. 定数Bufferの作成
  2. Descriptor Heapの作成
  3. 三角形の移動先をWorld座標で指定
  4. その座標を定数BufferにCopyする
  5. Descriptor Heapの設定を指定?

GPU

  1. Register b0のDataにAccessするための変数を定義(三角形の移動先のDataが入っている箇所)
  2. 三角形の移動を行う。(World Coordinateと(三角形の)座標を掛けて座標変換を行う)

大体、こんな流れになっています。

これは理解するとかなり分かり易いです。

DataがCPU側からGPU側に渡されていく様が、何と書くですが可視化されます。

おばあさんが大きな桃の中に手紙を入れてその桃を川に流します。川下でおじいさんがその桃を回収して、中にある手紙を読みます。そしてその手紙に書かれている通りに何かをする。

みたいな感じで頭の中でDirectX12のCPUとGPUのDataのやり取りがなんか可視化されそうです。

10.5 「Direct3D 12 ゲームグラフィック実践ガイド」の勉強

10.5.1 先週の復習

先週は、Double Bufferingの説明を勉強し直しただけです。その前の週はSWAP_CHAIN_DESC構造体についての勉強をしていました。

調べたらSwap Chain構造体の勉強をしたのは2023-03-20のBlogでした。

ここでもSwap Chain構造体をCreate Swap Chain()関数の2番目のParameterと言っています。

なんとCreate Swap Chain()関数は以下の様に3つのParameterしか受け取らない構造になっていました。

ふーん。

DirectX 12の魔導書」ではほとんど説明が無かったSWAP_CHAIN_DESC構造体の中身についてですが、ここではかなり詳しく説明しています。

ここでFormatの意味が分からないと言っています。

ここで勉強が止まっていますね。

Double Bufferingの真の意味を理解した今ならFormatの意味を判明するのも容易いでしょう。

もう一回勉強してみる事にします。

10.5.2 SWAP_CHAIN_DESC構造体をもう一回勉強する

<Format>

公式のサイトであるDXGI_FORMAT enumeration (dxgiformat.h) [18]を見ます。

はい。

以下に示した2つのMemberを見ただけでFormatが何を指定してるのか理解しました。

FormatはRGBAのそれぞれのサイズとかTypeを指定しています。

サンプルコードで使用されているのは以下のMemberでした。

これですね。

一番性能が低いとは言いませんが、一番性能が低い中の程々のヤツですね。

教科書にもきちんと説明がありました。

Pocol. Direct3D12 ゲームグラフィックス実践ガイド (p.156). 株式会社技術評論社. Kindle 版.

と後で気が付きましたが、この説明では何を言っているのか分かりませんね。

これは説明はしているけど、きちんとした説明では無いです。

大体、表示形式のPixel Formatという言葉の意味自体がよく分かりません。

<Scanline Ordering>

今度はScanline Orderingを調べます。

公式サイトのDXGI_MODE_SCANLINE_ORDER enumeration[19]を読みます。

これ読むとRasterizationのやり方を指定しているみたいです。

以下の3つのやり方と指定しない1つのやり方があるそうです。

今一、ピンと来ません。

Upper fieldやLower FieldからImageを作成したとしても最終的には全部のImageを作成する訳でしょう。

あんまり違いがあるようには感じません。

Sample Codeではどれを使用しているんでしょうか?

Sample Codeではやり方を指定してしないのを指定していました。

教科書には走査線描画Modeと書かれていました。

走査線で検索したら結構情報が出て来ました。

読みます。

大体理解しました。

このサイトの説明が分かり易かったです。

第6回 とがった技術で映像をもっと滑らかに――液晶ディスプレイの「I/P変換」とは?[20]

このサイトによると

走査線を描画する方式には「インターレース方式(飛び越し走査方式)」と「プログレッシブ方式(順次走査方式)」の2つがあるそうです。

ここで言う「プログレッシブ方式(順次走査方式)」がDXGI_MODE_SCANLINE_ORDER_PROGRESSIVEに当たりそうです。

この2つは走査線の表示方法が全く同じに聞こえました。

あ、名前にProgressiveとありますね。

となるとこの2つが同じになりますね。

インターレース方式(飛び越し走査方式)」は奇数フィールドと偶数フィールドを交互に表示するそうです。

第6回 とがった技術で映像をもっと滑らかに――液晶ディスプレイの「I/P変換」とは?[20]より

おそらくですがこれのどっちを先に表示するのかを指定するのが以下の2つのMemberなんでしょう。

第6回 とがった技術で映像をもっと滑らかに――液晶ディスプレイの「I/P変換」とは?[20]にある「インターレース方式(飛び越し走査方式)」はLower fieldを先に表示しているのでDXGI_MODE_SCANLINE_ORDER_LOWER_FIELD_FIRSTに当たると考えられます。

うーん。

これはあくまで仮説ですが、かなり当たっている気がします。

ここで時間が無くなってしまいました。いつもDirectX 12の勉強が割り食っている気がしますが、仕方ないです。ゆっくりですが確実に理解は進んでいるので良しとしましょう。

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

11. まとめと感想

まとめている時間がないのでまとめはなしです。

12. 参照(Reference)

[1] NumenBrothers. (2022b, December 25). Improve GPU Performance in Unreal Engine 5 by Allocating Maximum VRAM for Texture Streaming [Video]. YouTube. https://www.youtube.com/watch?v=yMHXwh_q8TA

[2] CGHOW. (2023c, March 31). Ribbon Fire in Unreal Engine 5.2 Niagara Tutorial | Download Files [Video]. YouTube. https://www.youtube.com/watch?v=rVrZltluAuQ

[3] Subsurface Profile Shading Model. (n.d.). https://docs.unrealengine.com/5.1/en-US/subsurface-profile-shading-model-in-unreal-engine/

[4] Ben Cloward. (2022c, November 17). Subsurface Scattering - Advanced Materials - Episode 8 [Video]. YouTube. https://www.youtube.com/watch?v=an8zDRTjUYc

[5] Ben Cloward. (2022d, November 24). Car Paint Shader - Advanced Materials - Episode 9 [Video]. YouTube. https://www.youtube.com/watch?v=dtc3WmL5OTU

[6] renderBucket. (2022b, December 29). Environment Creation: Fixing Heightmap Stretching in Blender [Video]. YouTube. https://www.youtube.com/watch?v=4_zeRW6IXxs

[7] renderBucket. (2022, October 3). Environment Creation: Making Realistic Desert Rocks In Gaea [Video]. YouTube. https://www.youtube.com/watch?v=sgsf-sPr9fc

[8] Snapping, construction plane, and alignment. (n.d.). https://www.sidefx.com/docs/houdini/model/aids.html

[9] Ukiyoestockjp. (2022). トップページ. Ukiyoe Stock. https://ukiyoestock.com/jp/

[10] Fortnite Sensei. (2023, March 31). Unreal Editor for Fortnite Beginner Tutorial - UEFN Starter Course! [Video]. YouTube. https://www.youtube.com/watch?v=0CcoOq963O8

[11] TylerMSFT. (2022, March 2). __declspec. Microsoft Learn. https://learn.microsoft.com/en-us/cpp/cpp/declspec?view=msvc-170

[12] Halya. (2019). 【C++C++でDLLを作るときに書くdeclspecとかstdcallについて~defファイルまで. LIGHT11. https://light11.hatenadiary.com/entry/2019/05/26/210615

[13] What is __declspec and when do I need to use it? (n.d.). Stack Overflow. https://stackoverflow.com/questions/2284610/what-is-declspec-and-when-do-i-need-to-use-it

[14] 製品ドキュメント - NI. (n.d.). https://www.ni.com/docs/ja-JP/bundle/teststand/page/tsref/infotopics/exporting_in_net.htm

[15] TylerMSFT. (2021, August 3). /D (Preprocessor Definitions). Microsoft Learn. https://learn.microsoft.com/en-us/cpp/build/reference/d-preprocessor-definitions?view=msvc-170

[16] Stevewhims. (2022, July 27). DXGI_SWAP_CHAIN_DESC (dxgi.h) - Win32 apps. Microsoft Learn. https://learn.microsoft.com/en-us/windows/win32/api/dxgi/ns-dxgi-dxgi_swap_chain_desc

[17] Stevewhims. (2021, October 13). IDXGIFactory2::CreateSwapChainForHwnd (dxgi1_2.h) - Win32 apps. Microsoft Learn. https://learn.microsoft.com/en-us/windows/win32/api/dxgi1_2/nf-dxgi1_2-idxgifactory2-createswapchainforhwnd

[18] Stevewhims. (2022, August 19). DXGI_FORMAT (dxgiformat.h) - Win32 apps. Microsoft Learn. https://learn.microsoft.com/en-us/windows/win32/api/dxgiformat/ne-dxgiformat-dxgi_format?redirectedfrom=MSDN

[19] DXGI_MODE_SCANLINE_ORDER enumeration (Windows). (2018b, May 18). Microsoft Learn. https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/bb173067(v=vs.85)

[20] 第6回 とがった技術で映像をもっと滑らかに――液晶ディスプレイの「I/P変換」とは? | EIZO株式会社. (n.d.). EIZO Corporation. All Rights Reserved. https://www.eizo.co.jp/eizolibrary/other/itmedia02_06/