UE4の勉強記録

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

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

1.今週の予定

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

木のFoliageを追加します。

更にその木が風に揺らぐ設定にします。

Niagaraの勉強>

CGHOW氏のTutorialであるSprite Rotation Sprite Alignment Sprite Facing | UE5 Niagara Tutorial | Download Project File [1]を勉強します。

<Materialの勉強>

Ben Cloward先生のIce Shader Part 1 - Advanced Materials - Episode 5 [2 ]を勉強します。

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

音楽を追加します。

<Gaeaの勉強>

Andrea Cantelli氏のGaea Tutorial for Beginners #6 | Texturing our first terrain [3]を勉強します。

<Houdiniの勉強>

公式のTutorialであるFOUNDATIONS | OVERVIEW [4]の続きを勉強します。

<Volumetric Cloudの勉強>

雷鳴の表示方法を検証します。

DirectXの勉強>

Olympus Mons Tutorials氏の C++ DirectX 12 Game Engine - [S01E03] - Creating A Game Engine [5]を勉強します。

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

2.1 先週までの経過のまとめと何故、最初に木を植える事になったのかについて

先週、Naniteで岩をLandscapeに追加しました。

この岩の追加の目的の一つは以下のような不自然なLandscapeの尖っている部分を隠す事です。

以下の様に岩のFoliageを配置する所まではできましたが、

この岩なんか不自然です。

もっと地面に埋まっているべきか、よくわかりませんが何か不自然です。

Unreal Sensei氏のTutorialを見直したらなんと、大きいFoliageから配置しろと説明していました。

それはそうです。

のでこの岩の問題は一端止めて、木のFoliageを試す事にします。

2.2 木のFoliageを配置する

<一本の木で試してみる>

SM_BlackAlder_Forest_01_PPで試してみます。

Naniteにして配置しました。

こんな感じです。

昨日、たまたまYouTubeのお勧めに出てきた動画で木をNaniteにするのがあって飯を食べる時にそれを見ていたんですが、なんと木の種類によってはNaniteにすると遠くに移動した時に変な挙動を示すのがあるそうです。

この木が遠くに移動した時にどんな挙動を示すのか確認します。

これぐらい離れると木の形状が変化しますが、全くおかしくはないです。

この木に関しては問題ないですね。

あ、そうだ。大切な事を忘れていました。

Bookmarkを追加します。

PlayerStartがある辺りにBookmark0をセットしました。

ここからの見た目は、西洋の絵画のような美しい見た目にしていきます。

後、見た目で人の大きさが分からないとFoliageを滅茶苦茶なSizeで配置してしまう。とUnreal Sensei氏のTutorialで言っていたので

Quinnを配置します。

<同じ種類の木を沢山配置してみる>

この状態で先程の木を配置してみます。

Layer Grassに配置してみます。

設定は以下の様にとりあえずします。

木は真っすぐ生えてもらう必要があります。Align to NormalをOffにしました。

これで木が真っすぐ生えてくれるのかどうかは知らないんですが、少なくともOnになっていたら真っすぐにはならないだろうと言う事でOffにしました。

当然、Grassをセットします。

木に衝突してすり抜けてしまったら、絶対オカシイのでCollisionするようにします。

とりあえずこの条件でPaintします。

木が密集しすぎです。

Density/1Kuuを1にしました。

UU(Unreal Unit)は1cmですので、1000倍したら10mです。

流石に10mに一本の木は少ないですね。

まあ適当にPaintしてから考えます。

結果です。

木のサイズが同じなのと同じ種類の木しか生えていないので少し変ですが、後はまあ良い感じじゃないでしょうか?

近づいてもう少し詳しく観察してみます。

木が浮いていました。

これはOffsetの値を調整して直します。

気にぶつかってみました。

きちんと衝突します。すり抜けたりしません。

ここはOKですね。

あと木は真っすぐ生えていますね。

ここもOKです。

もう一回やり直します。

今度は木の大きさをばらけさせてみました。

木も少しだけLandscapeより下から生えるようにしました。

この位の木と木の間が空いていると本物の雑木林感が出て来ます。

あ、Naniteの確認をするのを忘れていました。

します。

はい。

出来ていました。

<風で揺れる実装を追加する>

これのやり方が分かりません。

まずやり方を調べる事からします。

以下のSimpleWindの方にあるSampleは最初から風で揺れています。

Screenshotでは揺れているのを撮る事は出来ませんが、

兎に角、揺れています。

こっちでFoliageを作成してみます。

滅茶苦茶木が揺れています。

正直揺れすぎです。

あと揺れる方向が海に向かって揺れています。

Naniteも確認しておきます。

普通に効いています。

BP_GlobalFoliageActor_UE5で風の管理を行うそうです。

Level上に配置しました。

風を弱くしてみました。

木の揺れが弱くなりました。

一発で全部の木の揺れを管理出来ました。

BP_GlobalFoliageActor_UE5は便利なんですがこれPlay画面でも消えてくれません。

何かで隠す必要があります。

これは後で考えます。

Season Strengthの値を変えると

以下に示した様に

葉の色を変える事が出来ます。

<ほかの種類の木も追加する>

SM_BlackAlder_Field_03と

SM_BlackAlder_Forest_07を両方追加します。

こんな感じです。

Naniteを見ます。

普通に効いています。

木にも衝突します。

もう少し工夫してみます。

木の数を10分の1にしてみました。

これぐらいの方が奥の山が見えて良い気がします。

ただし以下に示した様に

Landscapeの凸凹は全く直っていません。

取りあえず木のFoliageは出来る事が判明したので岩の配置をまた検討する事にします。

2.3 岩をもう一回配置する

やっぱりCliff Layerに岩を配置する必要があります。

<岩を黒くする>

岩を黒くしてみます。

新しいMaterialを作成してSpecularを0、Base Colorに0.1を掛けてみました。

この岩が

こんな色になりました。

うーん。

付け刃ですがこれで行きましょう。

これで試してみます。

これはこれで有りかもしれません。

<平べったい岩を配置する>

もう少し平べったい岩にしてみます。

うーん。良い感じです。

でもこれはCollisionは要らないですね。

Procedural Foliageで追加する事にします。

2.4 LandscapeをNaniteにしてみる

これ、先週見つけたLandscapeをNaniteにする方法です。

これを試してみます。

Landscapeを選択して以下のEnable Naniteを選択しRebuild Dataを押しました。

あれ、真っ黒になってしまいました。

もう一回Materialをセットし直してLayerのMaskを指定し直しました。

一瞬、色が出たんですがその後、Auto Saveが始まって真っ暗に戻ってしまいました。

NaniteだとLandscape layerは使用出来ないのかもしれません。

元に戻します。

Enable NaniteのCheckを外しました。

一瞬で、Landscapeの色が元に戻りました。

うん。

LandscapeにNaniteを適用するのは止めておきます。

2.5 Procedural Foliageの復習

Procedural Foliageの作成方法を忘れてしまいました。ので復習からやります。

まずはBlogの見直しをして過去にどんな勉強をしたのかを思い出します。

2022-02-14のblog

公式のDocumentであるOpen World Tools [6]にProcedural Foliageが載っているのでこれを勉強する事にすると語っています。

このBlogのOpen World Tools [6]は4.27のOpen World ToolsですがLinkを5.1に変えておきました。

こっちが4.27の画面です。

こっちは5.1の画面です。

4.27ではExperimental StateだったProcedural Foliage Toolが5.1ではExperimental Stateが外されています。

製品版で使用しても問題ないとなったみたいです。

2022-02-21のBlog

Procedural Foliage Toolを勉強するためにGrass Quick Startを勉強しています。

うーん。Grassの作成の方がProcedural Foliage Toolより難しかったような気がしますが、まあそれは良いです。

これBlogで読むとそのTutorialでどんな事を勉強したのかが、大体理解出来て非常に役に立ちます。

大体、こんな感じで草を追加しています。

Landscape Grass Typeを作成します。

これを開いて以下の設定を変更します。

今度は、Landscapeに使用しているMaterialを開き、

  • Landscape Layer Sampleノード
  • Landscape Grass Outputノード

を追加します。

Landscape Grass Outputノードに先程のLandscape Grass Typeをセットします。

Landscape Layer Sampleノードの設定から使用するLayerを指定します。

ここではGrass Layerを指定していました。

そしてLandscape Grass OutputノードをLandscape Layer SampleノードのGrass Pinに接続します。

以上です。

これで草や小石のProcedural Foliageのやり方は分かりました。

Naniteでも使用出来るのかを試す必要がありますね。

2022-03-07のBlog

Procedural Foliage Toolの使用方法について勉強しています。

これもProcedural Foliage Toolの使用方法が簡単にまとめられていて読んだらやり方が分かりました。

本当にこの辺のBlogのまとめは役に立ちます。

以下にProcedural Foliage Toolの手順を簡単にまとめ直します。

Procedural Foliage Spawnerを作成します。

作成したProcedural Foliage SpawnerをLevel上に配置します。

今度はStatic Mesh Foliageを作成します。

この後、いきなり

とProcedural Foliageが出て来ます。

これってProcedural Foliage Spawnerの事でしょうか?

うーん。

こっちのまとめは駄目ですね。

これ読んだだけじゃ何をやっているのか不明です。公式のDocumentであるProcedural Foliage Tool Quick Start [7]を見る事にします。

Procedural Foliage Spawnerの事でした。

Tutorialを読んでみたんですが、TutorialはTutorialで分かりにくいです。

ここからはもう簡単です。

Foliage Type Objectに先程作成したStatic Mesh Foliageをセットします。

Static Mesh Foliageを開いて使用する木のStatic Meshをセットします。

Level上に戻り、配置したProcedural Foliage Spawnerを選択し

Re-Simulateボタンを押します。

以上です。

うーん。簡単ですね。

後、このやり方だとやっぱり木を通過してしまう事が述べられていました。

2.6 Procedural Foliageで草や小さな岩を配置する

それでは公式のGrass Quick Start [8]のやり方で草を配置してみます。

5.1のTutorialを読みましたがやり方は一緒でした。ので2022-02-21のBlogのやり方でやります。

Landscape Grass Typeから新しいBPを作成します。名前はGT_SmallRockにします。

不覚。

先程使用した石の名前が分かりません。記録しておくのを忘れていました。

多分、これです。

S_Mossy_Forest_Rock_wdbnbbb_lod3_Var1でした。

GT_SmallRockのGrass Meshにセットします。

これParameterにOffsetがありません。

これは駄目かもしれません。

Materialを開いてLandscape Layer SampleノードとLandscape Grass Outputノードを追加しました。

Landscape Grass OutputノードにCliffを追加し、先程Landscape Grass Typeから作成したGT_SmallRockを追加しました。

Landscape Layer SampleノードのParameter NameにLayerの名前をセットしました。

うーん。

これで良いのかな?

結果です。

あれ、全体に配置されています。

それ以前にLayerがCliffとGrassしかありません。

一寸そっちをまず直します。

直しました。

もう一回Grass Quick Startを試します。

これは全然駄目ですね。

以下に拡大したScreenshotを示しますが、

Z軸のOffsetが無いため、岩がLandscapeから浮いてしまっています。

一応、Naniteは効いているみたいですね。

まあ、ダメだという事が確認出来たので良しとします。

2.7 今週のまとめと来週の予定

今週、最初に予定していた以下の2つの実装のやり方を判明させる事

  • 木のFoliageをNaniteで追加する事
  • その木に揺らぎを追加する事

は、簡単に出来ました。

更に先週の続きとしてLandscapeの不自然な形状を隠すために、Cliff Layerに岩を配置したりProcedural Foliageを試したりする事も出来ました。

この結果から

  • 岩は黒くしたり平らな小さな岩を使用したりすれば、Landscapeの不自然な形状を隠す事が可能であること。
  • Procedural FoliageはLandscapeの不自然な形状を隠すためには不向きで有る事

が判明しました。

後、LandscapeのNanite化も試しました。これをするとLandscape Layerが使用出来なくなる事が分かりました。

来週の予定としては、

  • Runtime Virtual Textureを使用して岩のMaterialをLandscapeのMaterialと合成する
  • World Aligned Blendノードを使用してCliff Layerに別なMaterialを追加する

の二つを試す事とします。

2023-01-01のBlogを見ると

と書かれています。

建物をHoudiniで作成するのはまだ無理です。最速でも来年でしょう。

建物については後で考える事にします。

3.Niagaraの勉強

3.1 先週、分からなかったところの確認

以下の実装の意味が分からないと書いていました。

これはVelocityとVector BのCross Productを計算しているだけです。

うーん。

この時点で矢印はVelocityと同じ方向に向いているはずです。矢印とVelocityが同じと仮定するとVelocityは赤い矢印になります。

X方向は矢印の向きに対してどの方向になる可能性もあります。ここではたまた矢印の横方向がX軸だったと仮定して真横に青い矢印を引きました。

この赤い矢印と青い矢印とのCross Productは黄色の矢印になるはずです。

あ、向きが逆か。

赤い矢印から青い矢印にCounterclockwiseで回るから下向きの矢印になるのか。

でもこれだと

こういう回転はしませんね。

分かりません。

3.2 Sprite Rotation Sprite Alignment Sprite Facing | UE5 Niagara Tutorial | Download Project File [1]を勉強する

今週はもっと簡単な例でSpriteのFacingのAlignmentを勉強する事にします。

そこで基本をしっかり身に着ける事にします。

まず軽く一回見ました。

これ古いNiagaraです。今のNiagaraとはかなりUIが違います。

まあ理論は同じはずなので、これでも勉強は出来るでしょう。

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

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

Mainノードの設定です。

実装部です。

この辺は、先週の実装と同じでも良いはずです。

Niagara SystemにFountain Templateを追加して新しいNiagara Systemを作成します。

いつものやつです。

Render SectionのSprite Renderer Moduleの

Materialに先程作成したArrowを追加します。

ここからArrowが見えやすいように微調整します。

この辺はまとめなくても良いかもしれませんが、微調整の一例という事で一応記録に残しておきます。

Emitter Update SectionのSpawn Rate Moduleの

Spawn Rateを10にします。

Particle Spawn SectionにあるInitialize Particle Moduleの

Sprite Size ModeをUniform、

そしてUniform Sprite Sizeを20にします。(後で30に変更)

結果です。

矢印の方向がバラバラなのが確認出来ます。

こういうのはDefaultのParticleを見ただけでは確認出来ません。

Spriteに使用されているMaterialを矢印に変更したから確認出来るようになったんです。

やっぱりこういう基礎の勉強は大切です。

この原因は、Sprite Rotation ModeがDefaultではRandomにセットされているからです。

これをUnsetに変更すると

以下に示した様に矢印が真上を向くようになります。

これってよく分からないんですよ。

いや、機能としてはわかっていますが、Unsetという名称がよく分からないんです。

普通、UnsetっていったらRandomの時の様に値がバラバラって感じがします。このように一定の方向をみんなが向く時は、Uniformが正しいんじゃないでしょうか?

矢印の向きを指定出来るのはDirect Angle(Degrees)です。

このParameter、UnrealのParameterではめずらしく0~1で指定するのではなくDegreeで指定出来ます。

180度の時は、矢印の向きが逆になっています。

当然、Attributeなので、値の代わりにDynamic Inputをセットする事も出来ます。

ここではRandom Range Floatを値の代わりにセットしました。

Random Range FloatのMinimumには-90をMaximumには90をセットしています。

結果です。

矢印の向きが-90~90の間を取るようになりました。

いや、矢印の向きが-90~90の間を取るんじゃなくて、矢印の向きが-90か90のどちらかの向きを取るのかをRandomに指定したいんですけど。

という時もあります。

その時は以下に示したUniform AOr BFloatを使用します。

アメリカの大学に入学すると、私のような英語が第一言語じゃない人は必ず取らされる英語の授業があります。

そこでは「Capitalizationには厳密なRuleがあります。それを必ず守りましょう。っ」て教わるんですが、このAOr BFloatのCapitalizationはそのRuleを全部無視していて滅茶苦茶です。

でもこっちの方が読み易いです。

だからRuleを一義的に何でも正しいとして全てに厳密に適用すべきじゃないんです。

例えば英文を書く時は、主語は必ず一文に一個入れる必要があります。

でも日本語はそうじゃないです。

「○○は、」と一回主語を定義したら、新たに別な主語を定義するまで、文を跨いでその主語が使用される事もあります。

これを「だから日本語は遅れた言語なんだ。」と無理やり英語の文法通りに一文に一個主語を入れるようにすると、凄く読みにくい文になってしまいます。

主語が文を跨いでも通じるのは、日本語の極めて優れた点であり、それ故に欧米が出来ないUniqueな発想が出来る原因でもある訳です。

話がそれました。

今度はSprite Rotation ModeにDirect Normalized Angle(0-1)をセットしています。

これは先程の0~360をNormalizeしただけです。

<Sprite UV Mode>

Sprite UV Modeです。

これの説明の意味が不明です。

まずRandom Xです。

変化しません。

PreviewのCameraがX軸に対して並行である事と関係しているんでしょうか?

Random Yです。

これは上下の矢印が出来ています。

あー。

分かった。

これはUV値を弄っているんです。

矢印は左右対称です。のでXの値がRandomになっても変化しません。

上下は非対称です。のでYの値がRandomになると向きが逆になります。

<Alignment>

Render SectionにあるSprite Renderer Moduleの

AlignmentとFacing Modeについてです。

AlignmentをVelocity Alignedに変更します。

Velocityと同じ方向に矢印が向いています。

これ、今は理解出来ましたが理解出来るまでかなり大変でした。

AlignmentにCustom Alignmentをセットした場合です。

これの使い方は既に先週勉強してしまいましたが、一応ここにまとめておきます。

まずCustom Alignmentなので自由にAlignmentを調整出来ると思ったら、そのためのParameterはどこにも表示されません。

これは以下の方法で調整します。

まずSprite Alignment BindingにセットされているParameterを調べます。

ここでは[PARTICLE]Sprite Alignmentがセットされていました。

なのでParticle Update SectionにSet Parameter Moduleを追加し

そのSet Parameter Moduleに先程の[PARTICLE]Sprite Alignmentをセットします。

そして以下に示した様に、ここで[PARTICLE]Sprite Alignmentの値をTweakする事で

望みのAlignmentをセットします。

AttributeなのでDynamic Inputを使用する事も出来ます。

<Facing Mode>

今度はFacing Modeです。

Facing ModeにFace Cameraがセットされています。

当然、Cameraを向いています。

AlignmentとFace Modeの違いが分かりません。

これ私には凄い疑問で先週からずっと悩んでいるんですが、ここしっかり勉強している人っているんですかね。

ここは来週実装する時にじっくり調査する事にします。

TutorialではFace Cameraの場合はProspectiveでFace Camera Planeの時はOrthogonalになると説明しています。

Custom Facing Vectorです。

これもAlignmentのCustom Alignmentに繋がっています。

Face Camera Positionです。

これは説明聞いても何を言っているのか分かりません。

Googleで検索しても何の情報も出て来ません。UE5を外して検索したらUnityのFace Camera Position [8]が出て来ました。

要はCameraに向かって並ぶって事です。

TutorialではFace Cameraとの違いを示すために以下の例を挙げていました。

矢印のFountainを上から見た時です。

Face Camera Positionの場合です。

矢印が外側を向いています。

Face Cameraの時は以下に示した様に

全部が上を向いています。

Face Camera Distance Blendです。

これは単にFace CameraとFace Camera PositionをBlendしただけだそうです。

<Sprite Rotation Rate Module>

Particle Update SectionにSprite Rotation Rate Moduleを追加します。

Sprite Rotation Rate ModuleのAttributeであるRotation Rateに360をセットします。

Tutorialによるとここは回転するためのDegreeを指定する箇所だそうです。

セットした角度/secondで回転するそうです。

この条件だと1秒間で1回の回転をします。

こんな感じで回転しています。

もし回転の速度を遅くしたい場合は、

Rotation Rateの値を下げます。

これは当たり前すぎて何言っているの?と一寸思ってしましました。

Lifeの長さとSpriteのRotationを繋げたい場合は以下のやり方でやるそうです。

ParameterのSprite RotationをParticle Update Sectionに追加します。

そしてSprite RotationにDynamic InputであるFloat from Curveを追加します。

そしてCurveを上に示した様にセットします。

ここでTutorialは何故、このやり方だとLifeの長さとSpriteのRotationが一致するのかをCurveIndexが[PARICLES]NormalzedAgeにセットされているからと説明しています。

確かにSprite Rotation ModuleのDelta Timeは[ENGINE]Delta TimeにセットされているのでParticleのLifeの長さからは独立していました。

この辺はSpriteのFacingとはあんまり関係ないです。

<球体の表面に矢印を張り付ける方法>

以下のEffectを作成するそうです。

Particle Spawn SectionにSphere Location Moduleを追加します。

Sphere Location ModuleがあるのがこのTutorialの古さを感じさせます。

たった一年前に作成されたTutorialですが、この辺の進化は本当に日進月歩です。

結果です。

Sphere Location Module のSurface Only Band ThicknessをEnableします。

これでSphereを表面とそのBandのみだけに限定します。

結果です。

今は矢印の向きはCamera Facingです。

これを球の表面に対して矢印が並ぶようにします。

お、一寸だけAlignmentに関係してきました。

Render SectionのSprite Renderer ModuleのAlignmentとFacing Modeの設定を

Customに変更します。

Particle Spawn SectionにAlign Sprite to Mesh Orientation Moduleをセットします。

Align Sprite to Mesh Orientation ModuleのMesh Orientation Relative Sprite Facingに

[OUTPUT][SPHERER LOCATION] SphereNormalをセットします。

そんだけだそうです。

うーん。そんな事が勉強したくてこのTutorialを見てる訳じゃないんですよ。

これ。

何か、こっちが知りたい所に掠りそうで掠らない内容です。

もうTutorialの4分の3が終わりましたが、AlignmentとFace Modeについて、何も新しい知見が得られていません。

一寸腹立ってきました。

やっぱりここはTutorialを盲目的に頼ってしまったのが悪かったのかもしれません。

自分で矢印を並べて一個ずつ確認すべきでした。

そのためのTest方法をここで考えるべきだったです。

このTutorialの勉強は一端ここで中止します。

3.3 AlignmentとFace Modeに関しての問題点のまとめ

AlignmentとFace Modeの関係性については自分でもう一回、蝶のTutorialを見直して考える事にします。

後、完全に勉強だけに振り切ってしまうと、今回のTutorialの勉強のように知っている事しか出てこなかった時に、非常に時間を浪費した気分になります。

やっぱり見た事ないEffectを制作しつつNiagaraの機能を勉強した方が、例え機能を全部理解出来なくてもEffectは完成するので時間を浪費した気にならなくて済みます。

そういう事も考慮してこれからどのTutorialを勉強するのかを決定します。

3.4 発想の転換をすべき

いやこれは、発想を変えるべきなんです。

分からん所とトコトン詰めても仕方ないです。

分からん所はそのままにして、今出来る所からどうやってその技術を生かすのかを考えるべきだったんです。

CGHOW氏のTutorialを勉強してほぼ正確にCGHOW氏が作成したNiagaraを再現出来る人ってあまりいません。

まずこの事実を認識すべきでした。

みんなTutorialをパッと見て一寸だけ試すけど途中でGive upしています。

だから完成したEffectを使用出来る人ってあんまりいません。

完成したEffectをどう利用するかを考えるべきでした。

例えば先週作成した蝶のEffectは

とても綺麗ですが、このままではAnimation Sequenceには使用出来ません。

何故なら、蝶が地面に衝突せずに地面の下まで飛んで行ってしまっているからです。

先々週、作成した黒い雨が降るEffectも

地面に衝突したら地面にDripが表示されるのではなく、World座標でZが0の所でDripが表示されるような設計になっています。つまりWorld座標が0より高い位置にあるとDripは表示されません。

こういう細かいBugは実際にAnimation Sequenceに組んだら結構出て来るんです。

これらは自分で直すしかありません。

こっち方面を頑張るべきでした。

今週はNiagaraの勉強がグダグダになってしまいました。

4.Materialの勉強

今週はBen Cloward先生のIce Shader Part 1 - Advanced Materials - Episode 5 [2]を勉強します。

4.1 Ice Shader Part 1 - Advanced Materials - Episode 5 [2]を勉強する

こんなのを作成するそうです。

正直、本物のIceとは何かが違う気がしますね。

うーん。

黒さが足りない?

Clear Iceで検索してみました。

まずIceが黒いと思ったのは間違いでした。

背景が黒い場合のみIceも黒い部分が出て来ます。

実際のIceにあってこのCGには無い点を以下に上げます。

  • 輪郭線。実際のIceは内側からIceの輪郭線が見える。これはその輪郭線に沿ってRefractionの率が変化しているからかもしれない。
  • 泡、氷に閉じ込められた泡が確認出来る。
  • Reflection。反射して周りの風景をわずかに映している。
  • 影。氷内部に影が出来ている。氷自体の影も独特な形状になっている。

今見て、気が付いただけでこんだけ違います。

まず軽く全部見てどう勉強するのかを考えます。

全部、見ました。

Reflectionは追加していました。

Refractionの屈曲率はわざとごくわずかにしていました。

これはもっと値が高い方が、氷に見える気がします。

以下に実際の実装方法をまとめます。

Ice用のMaterialを作成します。

まずBlend ModeをTranslucentにセットします。

次にLighting ModeにSurface Translucency Volumeをセットします。

結果です。

まだ、何も変わっていませんね。

Scene ColorノードをBase Colorに繋げます。

結果です。

お、透明になりました。

次にRoughnessを0にします。

Reflectionが追加されました。

これ、実際にLevel上に配置された時はあんまり分からないんですが、Reflectionをはっきりさせるための設定とかあるんでしょうか?

UE4ではLight Massの設定云々。ってやった気がしますがもう忘れてしまいました。

今度は、氷を透けて見える風景に対してRefractionを追加します。

以下の様にScreenPositionノードに0.1を追加した値をScene ColorのUVsに使用します。

Tutorialの説明によるとScene ColorノードのDefaultのUV値はScreenPositionの値を使用しているそうです。

そこにOffsetを追加する事でRefractionを自然に再現出来るそうです。

結果です。

これぐらいRefractionがあった方が氷っぽいです。

この後0.1の値の代わりに以下の実装を追加しています。

Tutorialではこれによって正しいRefractionの値が得られると説明していますが、どうなんでしょう。

まあNormalに基づいて計算しているのでそれなりに正しそうではあります。

結果ですが、とんでもないRefractionが生じています。

これはVertex Normalの値が-1~1の間だからそのままOffsetに使用すると大きすぎるからだそうです。

確かに言われてみればその通りです。

0.05を掛けて弱くしました。

結果です。

0.05は弱すぎでしょう。

0.1の例も示していますが、

こっちの方が本物っぽいです。

Level上に配置したRockにこのIce Materialを適用しています。

うーん。

Tutorialはこれでは荒すぎと言っています。

確かにそれはそうですが、こっちの方が何か氷らしさの根本を再現している気がします。

氷に細部の細かさを足します。

まずNormal MapをNormalに追加します。

更にOffsetの計算にもNormalの値を追加します。

結果です。

おお。

これはかなり氷っぽいです。

Level上のIceです。

うーん。

これが最初の氷ですね。

何か氷っぽくないんだよな。

今週はここまでで終わりでした。

4.2 Ice Shader Part 1 - Advanced Materials - Episode 5 [2]を実装する

IceのTutorialは非常に短かったので実装もやっていまいます。

まずMaterialを作成します。

名前はM_Iceにします。

Blend Modeを

にして

Lighting ModeにSurface Translucency Volumeをセットします。

Scene ColorノードをBase Colorに繋げます。

結果です。

ここまではTutorial通りの結果です。

まだ氷っぽくはないです。

次にRoughnessを0にしてReflectionを追加します。

綺麗なReflectionが追加されました。

SreenPositionノードにOffset分を追加してSceneColorノードのUVsに繋げます。

結果です。

おお、まだ氷には見えませんがガラスには見えますね。

Offsetの値をVertexNormalから計算します。

結果です。

確かにこれでは強すぎます。

0.05を掛けて値を小さくしました。

結果です。

これ見ると結構Refractionがありますね。

このまま続行します。

Level上に配置したRockに適応してみました。

うーん。

氷って感じはしませんね。

後、Reflectionが消えてしまっています。

Reflectionを表示するためにはUE5のLight側の設定もいじる必要があるみたいです。

氷に細部の細かさを足します。

まずNormal MapをNormalに追加します。

Normal Mapを追加します。

更にOffsetの値にNormal Mapの値も追加します。

うーん。これがよく分かりません。

VetexNormalWSはView Speceに変換されています。それに対してNormal MapはTangent Spaceのままです。

この2つ座標軸が違うのに足して良いんでしょうか?

後で、Normal MapをView Spaceに変換してOffsetに足した場合も試してみます。

取りあえずはこのまま先に進みます。

結果です。

かなり氷っぽくなりました。

Level上に配置したIceです。

まず、確かに氷らしくはなっていますね。

何かが足りないです。

先程書いたこの氷のCGに足りない部分です。

  • 輪郭線。実際のIceは内側からIceの輪郭線が見える。これはその輪郭線に沿ってRefractionの率が変化しているからかもしれない。
  • 泡、氷に閉じ込められた泡が確認出来る。
  • Reflection。反射して周りの風景をわずかに映している。
  • 影。氷内部に影が出来ている。氷自体の影も独特な形状になっている。

これそのまま当てはまりますね。

まず輪郭線というかCGの氷はRefractionの値が全部一緒です。ので本物の氷のように歪みがバラバラのRefractionがありません。これでは氷じゃなくてガラスです。

氷に閉じ込められた気泡がないです。

Reflectionも無くなってしまっています。これは後で調べます。

影は全くないですね。

<Normal MapをView Spaceに変換した場合>

一応、これも試してみます。

結果です。

Normal MapをView Spaceに変換しない場合です。

うーん。

一寸は違っているのか?

よく分かりません。

以下の様にしてBooleanのParameterを作成し

Material Instanceを使用してLevel上でOn Offして比較してみました。

View Spaceに変換した場合です。

しない場合です。

氷の下の部分のRefractionが全く違いますね。

でも、これからだけではView Spaceに変換した方が綺麗とは言えませんね。

素人目にはどっちでもあんまり変らないです。

<Reflectionについて>

Level上のReflectionについても調べます。

以下に示したようなRoughnessの値を0に指定したMaterialを作成し

Level上に配置したSphereに使用してみました。

普通にReflectionしています。

Reflectionを実装するためにLevel上で何かをする必要は無いみたいです。

<次のTutorialも少しだけ見ておきます>

次のTutorialでこの氷を更に氷らしくするはずですのでどんな実装を追加するのかを軽く確認しておきます。

最初の1分間だけ見ました。

Volumetric RenderingのようにObjectの中もMaterialで実装するそうです。

これは予想外でした。

ふーん。

氷ってそうやって実装していたのか。

内部に実装するためにTextureを用意していましたが、

そのTextureには泡らしいImageも入っていました。

更にBen Cloward先生がこのTutorialで言っていましたが、2年前にも氷のMaterialのTutorialを作成していて理論的な内容はそっちで深堀しているそうです。

Volumetric Ice Shader - UE4 Materials 101 - Episode 11という名前だそうです。

これですね。

このTutorialを見る必要もありそうです。

今週のMaterialの勉強はこれで終わりです。

一応氷の作成方法が理解出来たので、満足しました。Niagaraの勉強の不満が凄くて、まだ満足感が足りませんが。

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

今週から音を追加します。

5.1 先週の復習

先週、Effectを全部付け終わった事は覚えていたんですが、このMini-Gameをどうやって売るのかについても考察していました。

これ書いたときはもうやる気が無くなって余った時間を潰すために仕方なく書いたんですが、今読み直すとかなり示唆に富む内容になっています。

このシリーズは継続してやる事にします。

Gameをやる理由ってRole Playingの一環なんだ。とRole Playの一部をGameが担当しているんです。

だからRole Playが面白くないとダメなんです。

と言う先週の結論は今読んでもかなり凄みがありました。

<音の追加>

一応、以下の予定になっています。

今週は魔術師と妖精タイプのMonsterの効果音を追加します。

5.2 魔術師のどこに効果音を追加するかを調査する

まずWidgetです。

Monsterを壺にセットする時に音を出します。

決定ボタンを押した時に音が出ようにします。

Monsterの召喚魔法を唱えた時の効果音が必要です。

更にMonsterが召喚された時の効果音も必要かもしれません。

使用する魔法を選択する時です。

魔法を買えるMonsterを選択する時です。

取りあえずここまでです。

5.3 効果音の追加方法を調査します

音の追加方法を忘れてしまったので調べます。

まずAnimationに音を追加する方法を調べました。

というのもこれはAnimation Sequenceに追加すれば終わりじゃないの?と思ったからです。

公式のDocumentであるAnimation Notifies [9]に音の追加方法も解説されていました。

Effectの追加方法と全く同じですね。

あれ、Meta Soundって何?

もしかしてQuixel Bridgeに音もあるの?

公式のDocumentであるMeta Sound[10]を見てみます。

違いました。

そう言えばUE5がReleaseされた時にMeta Soundが追加されたって聞きましたわ。

一応、後で読んでおきますか。

Widgetのボタンを押した時の効果音の追加方法も調べます。

公式のFourmのTrigger metasoundsound with a button widget[11]に以下の解答がありました。

そうだSound2Dノードです。

思い出しました。

これで実装方法は分かりました。

5.4 効果音を探す

取りあえずAssetにあったMega Game Music CollectionとSound Phenomenon FantasyをProjectに追加します。

ここから相応しい音を選ぶ事にします。

ありえん。

Kb/sしか出ていません。

規制がかかっているみたいです。

これは終わらんわ。

先に公式のDocumentであるMeta Sound[10]を読む事にします。

5.5 公式のDocumentであるMeta Sound[10]を読む

読もうとしたらMetaSounds: The Next Generation Sound Sources [12]とMetaSounds Reference Guide [13]の2つに分かれていました。

MetaSounds: The Next Generation Sound Sources [12]を読む>

<Introducing MetaSounds>

Digital Signal Processing (DSP) graphと言うのがあるみたいです。

<A Fully Procedural Audio Engine>

ここでもDigital Signal Processing (DSP) rendering graphがスゲーって事しか言っていません。

<More Control for Audio Designers>

MetaSound Editorが有るからProgrammingの出来ないDesignerの方でも凄い簡単に編集や操作が出来ます的な事がかかれています。

はい。

ここまで読んで一個も有用な情報がないです。

流石にこれ以上読む気は起きません。

私は字を見ると勝手に呼んでします読書病なんで、一応最後まで読んでおきますが、記録するべき重要な情報は一個もないと思います。

最後まで読みましたが全く重要な情報はなかったです。

MetaSounds Reference Guide [13]を読む>

ここはMeta Sound関連のNodeについて解説していました。

これは大事ですがMeta Soundの使用方法を先に学ぶ必要があります。

Downloadの進捗をみたらまだ30%位です。

5.6 販売戦略を考える(Gameをやる理由を追加する)

こっちを先に考える事にします。

Gameをやる必要って無いんです。

Gameについての情報は必須なんですが、GameのPlay情報は贅沢品みたいなもので有ったら良い位なんです。

と先週のまとめに書きました。

私は最初からこの事に気が付いていました。

しかしあるGameなどの紹介をしているYouTuberが、先週それを保証するような発言をしていたので、まあ私としては裏取れた感じです。

その人は最近のYouTuberの減収について語っていたんですが、特にGame実況の再生回数の落ち込みが酷いと言っていました。

ところが、同じGameでも新作が販売された直後の批評はものすごい再生回数を稼げるそうです。

しかもボロクソに言えば言うほど再生回数が爆上げするそうです。

その人は本当にGameをPlayするのが好きなので再生回数がどんどん落ちて、減収で大変だ。と言っていました。

でもこれってGameなんかPlayしないで新しいGameが販売されたらボロクソに言っていれば、逆に増収につながるって事です。

新しいGameが販売されたらそのGameについての批判をネットから適当に拾ってきます。それをまとめてYouTubeに上げる事を繰り返していれば逆に増収になる訳です。

適者生存に原理に従ってそういうYouTuberがこれから伸びていくだろうし、それが出来ないYouTuberは逆に沈んでいくだけでしょう。

しかしそんなのに巻き込まれたら、Indieで細々とGameを作っている人はたまったもんじゃありません。

やっと泳ぎ方を覚えて呑気に川を泳いでいたらピラニアの群れに襲われるようなもんです。

じゃあ、どうしたら良いのかを今週は考える事にします。

まず事実の確認から行います。

Game紹介をするYouTuberがGameを紹介したからと言ってそのGameを買う人はいません。

そのYouTuberの動画を見ている人達はPlayするGameを探しているんじゃなくて、そのGameがいかにクソであるかについての情報を探しているんです。それが手に入ったらそれで満足なんです。

だからそんな所で紹介されても全く売上にはつながりません。

これData Scientistに頼まなくても、英語圏のYouTuberがよくやっているこの番組を見た人だけに特別なcodeをPresentします。このCodeから購入した人は30%引きです。みたいなのをやればすぐに判明します。

同じ商品を30%引きで買えるんですよ。買う気のあるヤツならすぐに買いますよ。

すぐにGameの紹介をしてもらっても無駄だというDataが取れるはずです。

しかし、あなたがGameが完成したけど誰も買ってくれない。という事態になったとします。

どうしますか?

宣伝が足りないからだと、広告にお金を掛けますか?

無駄です。

Gameをplayする必要なんて現代人にとって全くないんです。

宣伝費を幾らかけても無駄です。

だから「Gameをplayする必要なんてない。」を変える必要があるんです。

このGameをPlayする必要があるGameに改変する必要があるんです。

ここに凄い分かり易い例があるんです。

全く売れないクソゲーだったのが、一夜にして発売初日よりも多いPlayer数を獲得したGameがあるんです。

そう、

Cyberpunk 2077です。

最初は鳴り物入りで今年の覇権ゲーと言われていたのに、質の悪いGPUだとPlay出来ない事が判明して(この件に関してはPC Gamerの方が悪いと思っていますがそれは別な話なのでここでは深入りしません。)、ブーイングの嵐となり、遂には返品騒動にまで発展してしまいました。

アメリカ人は新しいものに対してかなりOpen Mindで好意的に解釈しますが、一端駄目出しすると完全に見捨てます。

VRが良い例ですが、駄目だと結論出すのも早いですし、駄目となったものは物凄い勢いで捨ててしまい二度と相手にしません。

これ、開拓民時代の名残何だと思います。

駄目なものに頼っていたら村ごと滅んでしまいます。

厳しい自然の中で生き残るためには、駄目だと判明したらすぐにそれを捨てて代替策で対応する必要があるんです。

そのアメリカ人が既に見捨てたCyberpunk 2077をPlayし始めました。それも発売初日よりも多いPlayer数でです。

一体、何をしたのか知っていますか?

日本のアニメ会社がCyberpunkのアニメを作成したんです。

それが、もう完全にPromotion型のアニメなんです。

そのアニメ自体はものすごい胸糞悪い終わり方をするんです。敵側のボスキャラにぼっこぼこにされて終わる訳です。

その敵側のボスはまあGame内にいて、そのGameをPlayする事で倒す事が可能なんです。

もうこんなのそのアニメを見た人はそのGameをPlayしに戻るに決まっているじゃないですか。

そしたらそのアニメに出てきた風景がそのGame内のいたるところにある訳ですよ。

そしたら聖地巡礼ですよ。

アメリカ人が聖地巡礼、始めちゃった訳です。

しかもその途中には、アニメに出ていたキャラが使用していた銃が落ちていたりする訳です。

もう大満足でそのGameをPlayしている訳です。

はい。

これです。

そのGameを売るためのアニメを作成するのは勿論、無理ですが16ページ位の漫画だったら何とかなるでしょう。

そこにそのGameをやるための理由をつけるんです。

勿論、そのためのストーリーやネーム位までは自分で考える必要がありますが。実際の絵はお金を払って描いて貰ってもいいと思います。

それこそがIndie Gameを売るための必勝法です。

5.7 効果音を探す

やっとMega Game Music CollectionのInstallが終わったので、そこから魔術師の効果音を探します。

これって効果音のセットじゃなかった。

BGM集でした。

Retro 8Bit Soundsを追加します。

後、こっちも追加しておきます。

こっちのAssetはすぐにInstall出来ました。

Retro 8bit Soundsは色々使えそうな音が有りました。

5.8 音を追加する

壺にMonsterをセットした時の効果音を追加しました。

W_DropTo Widget

On Drop Eventに

Play Sound 2Dを追加しました。

効果音は以下のCueにしました。

この音が合っているのか分かりません。

今度は決定ボタンに効果音を追加します。

W_PlayerSummonDecide Widget

On Clicked(Button) EventにPlay Sound 2Dノードを追加します。

こっちはretro_collect_pickup_coin_01_Cueをセットしました。

実際に音が出るのか試してみます。

出ました。

結構大きな音が出ます。

まあ良いです。

細かい調整はまた後でやる事にします。

今度はMonsterの召喚魔法を唱えた時の効果音を追加します。

Attack02_MagicWandAnim_meを開いて

以下に示した様にNotifiesに

Play Soundを追加します。

Play SoundのSoundにArcane_Spell_10_1_Cueをセットしました。

テストします。

普通に音はしていますが、思ったより音が小さいです。

これだとMonsterを壺に入れた時の方がImpactが大きくなってしまいます。

この辺は後で微調整します。

使用する魔法を選択する時に押すButtonに音を追加します。

Buttonを押す音はretro_collect_pickup_coin_01_Cueに統一します。

W_PlayerMakeDecision Widgetにある

すべてのOn Click(Button)にPlay Sound2Dノードを追加しました。

勿論、全てのPlay Sound2Dノードにはretro_collect_pickup_coin_01_Cueがセットされています。

テストします。

音が鳴っているのを確認しました。

今週はここまでやったら十分な気がします。のでこれで終わりにします。

5.9 来週の予定

来週は以下の部分に効果音を追加します。

開始ボタンです。

先攻後攻を決めるCardの選択です。

これはCursorを乗せた時も音がするようにします。

勿論、Clickした時も音を出します。

対戦相手の魔術師がMonsterを召喚します。

このAnimation時にも音を追加します。

これが出来てから、Monsterが召喚された時の効果音とか、妖精族が攻撃した時の効果音を追加していく事にします。

以上です。

6.Gaeaの勉強

Andrea Cantelli氏のGaea Tutorial for Beginners #6 | Texturing our first terrain [3]を勉強します。

今週からTextureの勉強に入ります。

6.1 Gaea Tutorial for Beginners #6 | Texturing our first terrain [3]を勉強する

まず軽く全部見ます。

見ました。

Textureの作成、Colorの追加方法、そしてMixノードの使用方法について教えて、最後に一寸だけVegetationについても解説しています。

Textureの作成部分もTerrainの作成と同じように、手順を一般化し、それぞれの手順で使用出来るNodeを整理し、誰が使用しても一定以上の質を保ったTextureの作成が出来るようにします。

Textureの作成で重要なのは、ここで作成したTextureはそのままMaskとしてExportされる事です。

つまりどのようにTextureの領域を選択するのかでUE5におけるLandscapeの質が決まります。

本来ならTextureの作成方法の手順をまとめ、そこで使用するすべてのNodeの機能について調査します。

しかし私はまだこの辺の手順についてよく分かっていません。

ので今週はこのTutorialのTextureの部分の手順をまとめる所から始める事にします。

以下にTutorialのTextureの部分をまとめます。

<Intro>

まずTextureとMaskを分けて解説しています。

Maskの定義は特定の色を塗る箇所をTerrainから分離する事です。

Textureの定義はTerrainの指定した箇所に指定した色を追加するとなっています。

私は上記でTextureをMaskの作成、Colorで色の追加と分けました。

これは

となっていて名称は違いますが、意味は同じです。

この辺の細かい名称の定義になると人それぞれで独自の名称を使用しています。

どこかの団体がConventionで宣言してそれを強制するようにしないとずっとバラバラの名称が通るようになるでしょうね。

そしてそんな力を持った団体は存在しませんので、この辺の名称はずっとバラバラでしょう。

ここで大切なのは名称ではなくて手順です。

名称はバラバラですが手順は一緒です。手順が違っていたらその人が間違っています。

ここでは2つの手順が行われています。

  1. 色を追加するためにTerrainの表面をある条件に従って分割する
  2. 分割したTerrainに色を追加

これ厳密に言うと色を追加している訳じゃないです。Textureを追加しています。

でもここでTextureを使用すると「TextureはTerrainにTextureを張り付けるためにTerrainの表面を分離する事です。」とx=x+1みたいな文になって一部の読者は混乱してしまいます。

GaeaはProgrammingを知らない人で使用出来るように設計されているので、x=x+1みたいな文はなるべく書くべきではないので、あえて色と言う表現をしました。

ここはTextureを名称に使用するから混乱するんです。

  1. Textureを張り付けるためにTerrainをある条件に沿って分割
  2. 張り付けたTextureに色、またはImageを追加

という言い方にして1をMasking、2をColoringと言えば学習者は混乱を避ける事が出来ます。

ただしここはTutorialの内容をまとめる箇所です。

言葉の定義はTutorialの定義に従ってまとめるます。混乱を避けるためにそのつど注釈を追加する事にします。

Tutorialを見たらAndrea Cantelli氏もそんなにしっかりした定義をしている訳じゃなくて、そのつどTexturingと言ったりMaskingと言ったりしています。

これは学習者は凄い混乱します。

なのでやっぱり私の先程の定義をそのまま使用します。

まずMaskingです。

MaskingにはData Groupに属しているNodeを使用するそうです。

マジで!

これは確認する必要があります。

Tutorialの説明によれば、この中で最も使用されるのはHeight、Mask、Slope、そしてSoilの4つのノードだそうです。

先週作成したTerrainで試してみます。

まずSoilノードです。

結果です。

あれ、Tutorialの結果だと平らな2Dが表示されていたはずです。

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

やっぱりなっています。

TutorialのはPortalで繋げているからなのかと思い、同じようにPortalにしてみました。

結果は変わりません。

おそらくですが、VersionがUpしてMicroErosionノードにPin as Underlayを

使用しなくても3D表示するようになったんでしょう。

他の3つのNodeも試してみます。

Heightです。

おお、これは良いですね。

砂漠の砂の部分と岩山の部分を分割するのに適切です。

少しだけParameterを調節したら綺麗に分割出来そうです。

Slopeです。

あれ?

Slopeの激しい箇所が黒、なだらかな箇所が白くなっています。

想像していたのと逆です。

後、UE5でこのMaskの結果をWorld Aligned Blendノードの代わりに使用しようとしたんですが、駄目でした。

これ見ると、駄目だった理由はSlopeの結果が白と黒が逆だったのを知らなかったからかもしれません。

この辺は後で検証します。

あれ?

私のData GroupにはMaskノードは含まれていませんね。

Maskというノードはありますが、

InputがないPrimitive型のNodeのようです。

調べるとやっぱりPrimitiveにありました。

これは完全に違う機能ですね。

この後、TutorialはPortの作成方法や、Soilノードを繋げると3D Imageが平面になってしまう事などを述べています。

これらは既にまとめた事があるのでここで詳しくまとめる事はしません。

<Texture>

ここでMaskのために新しいNodeが使用されています。

Textureノードです。

このNodeは全てのNodeの中でも最も複雑なNodeだそうです。

確かに複雑なNodeだけあってApply Changesがあります。

今回のまとめではそれぞれのNodeのParameterの調整についてまではやらない予定なので、Parameterについてはこれ以上深入りしません。

ここからColoringについての話になっています。

のでTutorialの勉強は、一端中止にします。

6.2 MaskingのためのData GroupのNodeを検証・整理する

<Angle>

これ太陽光に当たる部分だけ黒くなるMaskですね。

特定の植物が生える箇所をしていしたりするのに使えそうです。

<Curvature>

Curvatureは文字通りCurveしているのかを見定めるためのMaskみたいです。

Curveの幅をParameterのMaxとMinで指定してその部分を白くしているようです。

Parameterを色々弄ってみましたが、このNodeの機能はよく分からなかったです。

<Details>

真っ黒です。

使い道はなさそうです。

<Distribution>

これもどんなMaskかよく分かりません。

要は角度が急な所には沢山の白い点を追加して点によってMapを描いているって事です。

何か使えなさそうなMaskばかりです。

使えそうなのだけ記録するようにします。

<Flow>

当然使えます。

ただし砂漠の部分にもFlowが有るのは問題です。これMaskでFlowを追加する場所を限定したいです。

Growth

これは、

やっぱり。

これは特定の植物の生える位置を指定するのに使用出来るでしょう。

<ProTrusion>

これは何処をMaskしているんでしょうか?

だそうです。

話は変わりますが、UE5で二つのMaskで指定された場所のLayerってどうなっているんでしょうか?

両方のLayerになっているのか?

後から上書きされた方のLayerになっているのか?

それともWeightによってそれぞれのPercentで混合されているのか?
望のMaskを作成するためには、この辺を先にはっきりさせる必要があります。

こっちを先に調べます。

6.3 UE5のLandscapeのMaskとLayerの関係について調査する

以下の方法でテストする事にします。

まず以下の2枚のTextureを作成しました。

この2つをMaskとして以下のLandscapeに使用してみます。

まずLandscape用のMaterialに以下のMaterialを用意しました。

Layer1は赤、Layer2は緑、Layer3は青です。

Layer1はBlank、Layer2に先程のTextureのMask1をセットします。

Importします。

Layer3にMask2をセットしImportします。

結果です。

後からImportした方が100%上書きしています。

次は以下の様に灰色を追加したMaskで試してみます。

結果です。

何これ?

うーん。

ここから推測するに灰色の箇所はどうなるのかはその場しだいみたいです。

Maskは白黒で灰色が入らないようにしないといけませんね。

新しいLayerInfoを作成して、もう一度試したら以下の様になりました。

今度はきちんと出来ました。

まず赤と青の灰色が混ざっている箇所ですが、マゼンタ色になっています。

次に赤と緑が曲がっている所ですが黄色になっています。

緑と青が混ざっている所は水色になっていますね。

水色でした。

最後に、赤と緑と青が混ざっている所ですが、白くなっています。

はい。

灰色の部分は、前のLayerと混合して存在している事が確認出来ました。

もう一つ確認出来たんですが、前のLayerがへんな挙動を示しているときは、

LandscapeのPaintからPaintを選択して

下地になるLayerのThumbnailを右Clickして、以下のBoxを表示させ

Clear Layerを選択した後、Fill Layerを選択したら直ります。

後、MaskのGray ScaleのImageを灰色にするための方法も調べました。

GIMPでMaskを読み込んで、ColorからThreshold..を選択します。

以下のBoxが表示されるので

何処から白黒決定するのかを決定してOKを押すだけです。

うーん。

これも活用する時が来そうですね。

6.4 おまけ

Maskを色々Tweakしてアメコミ調のTerrainを作成してみました。

Gaeaを使用しているから絶対にPhoto-RealisticなLandscapeを作成しないといけないという事は無い訳でGaeaにおけるLandscape作成方法の手順が完成したら、Gaeaを使用したStylizedされたLandscapeの作成も試してみます。

7.Houdiniの勉強

公式のTutorialであるFOUNDATIONS | OVERVIEW [4]の続きを勉強します。

7.1 Accessing Tools

ここでは違う方法でToolにアクセスする方法を学習するそうです。

まず以下のTool BarはShelfと言うそうですが、

ここのTubeを選択して配置します。

以下のParameterを操作する事で

TubeのGeometryを変化する事が出来ます。

値を変更して以下のような形状に変更しました。

それは良いんですが、突然、以下のRadial Menuを開いて

あーだこーだ始めています。

これはVを押すと開けました。このVですが画面で僅か0.2秒位しか表示されていません。

こういう基本的な操作って何回も繰り返して初めて覚える事が出来る操作だと思うんです。

これを0.2秒しか表示しないTutorialってどうなんすかね。

それともこれらのTutorialって片目瞑って時間潰しのために見るために作成されたんでしょうか?

何か、そんな気もします。

まあ、公開されたTutorialをどう勉強しようがこっちの勝手です。

先程のRadial MenuからShadingを選択します。

すると以下のRadial Menuが表示されます。

Smooth Wire Shadedを選択します。

Space Bar + Bで以下のViewを表示します。

ここから右下のViewをCursorで選択した状態で、もう一回Space Bar + Bを押すと

右下のViewだけが表示されます。

この画面内で、Altを押しながらMouseのMiddle Buttonを回すと

Objectの距離を調節出来ます。

更にAltを押した状態+MouseのMiddleボタンを押した状態でMouseを上下すると

Objectを上下に移動する事が出来ます。

この状態で、またSpace Bar+Bを押すと

先程の4つViewが見える画面に戻りますが

先程の右下のViewは変更したImageのままになります。

元の画面に戻ります。

ここからTutorialではEdgeを選択してLoopしています。

以下のIconを選択して

EdgeをDouble ClickしてLoopを選択します。

Tab MenuからPolyFillを選択します。

底が塞がりましたが、Polygonの形状がいびつです。

PolyFillの

ParameterであるFill Modeを

Quadrilateral Gridに変更します。

底のMeshが上記のような形状に変化しました。

今度はPointを選択してScaleを大きくしました。

何かTutorialと形が違う。

最初から作り直しました。

色々間違えている箇所があったんですが、Space Bar + Bの所でやっていたのはこのTubeの位置を移動させて底を原点に設置させるためでした。

Soft Editを使用して

形状を滑らかにします。

綺麗なCupが出来ました。

今度は厚みを追加しました。

やり方は、

Primitiveに変更して面全体を選択します。

Cを押して以下のRadial Menuを表示し

Modelを選択し

Polygonを選択し

PolyExtrudeを選択します。

すると以下のような赤い線が表示されます。

赤い線の内側の端をObjectの内側に移動させて以下の様にします。

この状態で、Polyextrudeノードの

ParameterであるOutput BackにCheckを入れると

以下の様にCupに厚みが出来ます。

ただしこの状態ではNormal Vectorが逆なので、

全部のMeshを選択した状態でTab BarからReverseを選択しMeshを裏返します。

これで出来ました。

今度は以下のHandleを追加します。

出来ました。

やり方を以下にまとめます。

PolygonからPolyBridgeを選択します。

SourceとDestinationの2つのPrimitiveを選択しEnterを押します。

選択した2つのPrimitiveの間にBridgeが形成されます。

がこの時点ではなんだか分かりません。

ここからPolyBridgeのParameterを調整していきます。

Divisionsを10

Spine ShapeをCurvedにします。

更にSourceのMagnitudeを3、

DestinationのMagnitudeを2にします。

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

ここでSourceのDepartをExplicit Directionに変更します。

そして表示されている矢印の赤い方向に移動させると

Handleが外側に移動します。

Handleは付きましたが形がなんか変です。

以下のParameterでHandleの厚さを変形出来るそうです。

確かに変形出来ましたが、形がオカシイのは直っていません。

今度はSubDivideを適用しました。

本来なら、Objectを選択した状態でTab Barを開きSubDivideを選択します。

しかし何も選択していない状態で、SubDivideを選択し、その後でNを押してObject全体を選択し、Enderを押す事でSubDivideを適用する事も出来るそうです。

次です。

何か凄い事になっています。

これのやり方をまとめます。

まずModelのShatterを選択します。

すると以下に示した様にCupに亀裂が入り

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

ここからChunkCentersノードを選択し

そのParameterであるForce Total Countの値を

50に増やします。

するとCupの破片の数が増えました。

おそらく破片の数が50個になったのでしょう。

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

すると以下の様に画面が変化します。

ここでExplodeViewノードのDisplay/RenderをEnableすると

以下の様になりました。

更に、Uniform Scaleの値を変化させる事で

以下に示した様に破片の位置を移動できます。

なんか突然花粉症になってしまったらしく鼻水とくしゃみが止まりません。

不本意ですが今週のHoudiniの勉強はここまでにします。

8.Volumetric Cloudの勉強

8.1 Gonzalez vs. Googleの件について

先週、Gonzalez vs. GoogleでSCOUTでGoogleが負けてYouTubeのCEOが辞職したと書きましたが、裁判の判決はまだ出てなかったです。

まあ、このNewsだけ追いかけている訳じゃないので、そういう詳細は間違えてしまう事もあります。

YouTubeのCEOが辞職したのは、YouTube側にとって不利になる判決が出る事がほぼ確定したからだ。と言う噂レベルの話でした。

ただしそれ以外はあっていましたし、その結果、私の意見が変わる事もないです。

まあ、事実を正しく認識するのは大切ですので、今度Blogに書く時は事実の確認をしっかりするか、私が理解した限りではと、注釈を追加する事にします。

しかし事実を100%正しく認しくするまで何も書かないでいると、永遠に何も書けない事態になる可能性もあるので、注釈を追加する方で行こうと思います。

そう日本人は間違えるのを恥じ過ぎなんですよ。

未知の領域を進むときは失敗しない訳には行きません。失敗しながら前に進むしかない訳です。

だからそういうのを恥ずかしいと感じて、新しい事に全く挑戦しない事の方が本当の恥なんです。

その点は、完全にアメリカ文化の方が優れていて、後で間違っているって分かっても全く恥ずかしがりません。周りも間違っているのが分かったらそれでお終いです。

この前のイラク戦争でもイラク大量破壊兵器を作っている。と主張してイラクを征服したらやっぱり無かったわ。でお終いです。

この話をアメリカ人にするとほとんどのアメリカ人がそれでもイラクが民主主義になったんだから、総合的に見たらイラク人も得しているからOKと言います。

それでお終いです。

これって浅いようでかなり深い話で、やっぱり人間、結果良ければ全て良し。なんです。

だから間違っていたら恥ずかしいとかで実行するのを躊躇っていたら、そこでお終いなんです。そこは間違って後で恥ずかしい思いしても仕方ないと覚悟を決めて進むしかないんです。

今回の件だって、私が不確かな情報でありながらSection 230とGoogleの裁判の件の話をしたから、その続報的にもっと情報が集まって結果的に正しい情報で上書きされた訳です。

8.2 録画の方法を勉強する

今週は雷鳴の追加方法を勉強しようと思ったんですが、それよりも動画の作成方法を勉強する方が重要だと気が付きました。

実は私、まだYouTubeが今ほど有名じゃない時に動画を上げていたんですが、今のようなほぼプロが作成するような高品質の動画の作成方法は全く知りません。

のでここで勉強し直す事にします。

<Window+Alt+R>

一個目の録画方法です。Windowに付属の録画機能です。

当然、無料ですが以下の欠点もあります。

  • 使用している一個のアプリしか録画出来ない。
  • Desktop画面は録画出来ない。
  • FPSが30で固定

Desktop画面が録画出来ないのは、完全にデメリットとは言えない気がします。FPSについては全く考えていませんでした。HDで取らないとUE Editorの文字って読めないんです。のでHDは必須ですがその辺はどうしたら良いのか不明です。

GeForce Experience>

正直、これが本命です。

GeForce Experienceを開いて以下のIconを選択すると

録画するが表示されます。

この「録画する」を押せば良いみたいです。

Alt+F9でも録画出来るそうです。

録画の質の調整ですが、設定から

Video Captureを選択し

以下の画面を開きます。

ここで設定できるみたいです。

更に録画した動画の保存先も以下の録画から指定出来るみたいです。

後は録画するPCの画面の指定方法です。

これは自動的にMain Monitorだけ録画するみたいです。

あ、録画の開始方法は分かりましたが停止方法が分かりません。

一寸、YouTubeのVideoでも見てみます。

Alt+F9で録画の開始と終了の両方が可能みたいです。

試してみます。

UE5を起動して

Alt+F9を押しました。

4つのVolumetric Cloudを表示しました。

Alt+F9を押してRecordingを停止しました。

ギャラリーから録画出来ているか確認します。

普通に出来ていました。

一応、動画を再生して確認しましたが普通に出来ていました。

再生した動画の画面の文字も普通に読めます。

うーん。

これで録画の問題は解決しました。

8.3 動画の編集ソフトについて

3 BEST FREE Video Editing Software for PC – 2023 [14]によると

無料の動画編集ソフトでは

  • Microsoft社のClickChamp
  • TikTok社のCapcut
  • Blackmagic Design社のDaVinci Resolve

が良いらしいです。

この動画制作者はDavinci Resolveの無料版を使用しているそうです。

<DaVinci Resolve>

DaVinci Resolveの使い方を調べます。

DaVinci Resolve 18 - Full Tutorial for Beginners [15]が最初に出て来ました。この動画もKevin Stratvert氏の動画でした。彼はこの界隈では第一人者みたいですね。

軽く全部見ようとしたらこの動画、40分もあります。

まあ、全部出来なくても出来る所までやってみましょう。

まずDaVinci ResolveをDownloadします。

Davinci Resolve 18の方がFreeだそうです。

Windowを選択しました。

個人情報を入力してくれと出て来たの入力しました。

日本の電話番号ってそのまま入力しても良かったんでしょうか?

調べたら

81+0を取った電話番号

と出て来ました。携帯の場合も同じだそうです。

これってそのまま使えるんでしょうか?

昔、アメリカ人の友達がアメリカから持ってきた携帯から私の携帯(勿論日本で購入したもの)に電話を掛けたら、電話は通じるんですが、声が聞こえない時があったんです。

2重認証があったらパスしないかもしれませんね。

取りあえず試してみます。

2重認証とか特になかったです。

適当な電話番号入れても問題なかったかもしれません。

Downloadが終わりました。

展開しました。

Exe.fileを実行します。

今度はDavinci Resolveを開始するためにC++の以下のRedistributableを追加させろ。と言っています。

普段なら本当にInstallする必要があるのか厳しくCheckするんですが、今は気力が湧きません。

全部YesにしてInstallを開始しました。

以下の3つのAppがInstallされました。

DaVinci Resolveを使用するためにはPCを再起動しろ。と出て来ました。

しました。

おお、Desktop画面にDaVinci ResolveのIconが表示されています。

あれ、Tutorialとは画面が違います。

Tutorialでは以下のような画面が表示されています。

Continueを押して全部の設定を終了したら、以下の画面が表示されました。

これはTutorialの画面と大体同じです。

Tutorialの続きを見ます。

以下に示した小さなBoxから新しいProjectを作成しています。

この小さなBox、私のDavinci Resolveにはありません。

どうせ新しいProjectを作成するだけなので、

を選択しました。

以下のBoxが表示されたのでProjectの名前を入れて

Createを押しました。

左上にProject名が表示されています。

Tutorialの続きを見ます。

Editorの一番下にある以下のButtonについて解説しています。

DaVinci Resolveは動画編集に必要な事が全て出来るようになっているそうです。

動画編集にどんな事が必要なのか自体知らないので、ふーん。って感じですが、まあ凄いんでしょう。

その中でそれぞれの機能を表示するために上記のButtonがあるそうです。

最初に初心者する事はEditを選択して

以下に示したMedia Poolを見る事だそうです。

ここに編集する元の動画をPoolしておくそうです。

いや、説明聞いたら、動画だけじゃなくて音楽とかImageとか、兎に角編集に使う素材を全部ここに入れておくそうです。そしてそういう素材を全部ひっくるめてMediaと呼ぶそうです。

で、肝心のMediaの追加方法ですが、このMedia Pool内にCursorを置いた状態で右Clickすると以下のBoxが表示されます。

ここからImport Mediaを選択します。

試しに先程作成したUE5のVolumetric Cloudの動画をImportしてみます。

うん。この動画のFrame Rateは60 Frame Per Secondだったはず。

Davinci ResolveのDefaultのFrame Per Secondは違うんでしょうか?

まあ良いです。

動画が追加されました。

これだけだと編集もクソもないので、なんかBGMでもDownloadしてきます。

bensound.com [16]から

をDownloadしました。

YouTubeでこの音楽を使用した場合はMusic by Bensound.comを記載する必要があるそうです。

このBGMもImportしました。

この後、TutorialではWorkspacekからReset UI Layoutを選択して

UIのLayoutをDefaultの状態に戻していました。

今日初めてDavinci Resolveを開いたんだから、私のUIはDefaultのままのはずですが、何故かTutorialのDefaultと少しだけ形状が違います。

私もWorkspaceからReset UI Layoutを選択しました。

今度はTutorialと全く同じUIのLayoutになりました。

まず上部に表示されている2枚のScreenですが、左側のScreenがSource Viewerで

Media Poolに保持されている動画をDouble ClickするとこのSource Viewerにその動画が表示されるそうです。

試してみます。

普通に表示されました。

Tutorialによると、Media Poolにある動画がどんな内容なのかをここで確認するそうです。

じゃ音楽も確認出来るんでしょうか?

出来ました。

普通に音楽を聴く事も出来ます。

Source ViewerからTime Lineにdrag and dropをすると以下の様に動画をTimelineにセットできます。

ついでにBGMも追加してみました。

この状態で右のScreenの再生ボタンを押したら

BGMがついた動画が再生されました。

TutorialによるとこっちのViewerの名前はTimeline Viewerだそうです。

次はSource Viewerにある以下のButtonについてです。

これはSource Viewerの動画をTrimmingする時に使用するそうです。

試しにTrimmingした動画をTimelineに追加してみました。

Trimmingした部分だけが追加されました。

同じ事はTimeline上でも出来るそうです。

Cursorを以下の動画の端にあわせると

Cursorが独特の形状に変化します。

これがScreenshotに取れません。

CursorをScreenshotで取る方法を調べたんですが簡単なやり方が出て来ません。

ので諦めました。

その状態で動画を引っ張ると、その部分の動画が消えます。

Tutorialでは2つの動画を重ねてTrimmingする方法も示していました。

今は動画が一個しかないのでこれは来週試す事にします。

今週のDaVinci Resolveの勉強はこの辺で終わりにします。

DaVinci Resolve 18 - Full Tutorial for Beginners [15]のEdit on Timelineまで勉強しました。

来週はSplit Clips with Blade Toolから勉強します。

8.4 DaVinci Resolveを勉強した感想

もう動画編集はこれ一本で充分だと思いました。

こんな凄いSoftが無料とは。

来週からDaVinci Resolveの使い方の勉強をする事にします。

まずはDaVinci Resolve 18 - Full Tutorial for Beginners [15]を最後まで勉強する所からやります。

今週はVolumetric Cloudの勉強は無しでこれで終わりにします。

9.DirectXの勉強

9.1 C++ DirectX 12 Game Engine - [S01E03] - Creating A Game Engine [18]Creating Olympusを勉強する

先週軽く見ましたが、今週はしっかり見て手順をしっかりまとめます。

Episode2のFolderをDuplicateしてEpisode3を作成します。

これはやらんでも良い気もしています。

どうしようかな?

この後、Game Engineを新しいProjectとして作成する予定で有る事を説明しています。

Solutionを右Clickして

Addを選択しNew Projectを追加します。

するとどのTemplateを選択するのか聞いてきますので

Empty Projectを選択します。

今度はConfigure your new projectが開きます。

Project Nameの値をOlympasに変更します。

Createを押します。

以下に示した様にOlympus Projectが追加されました。

前にBlank ProjectでやったようにHeader Fileの名前を

Publicに

Source Fileの名前を

Privateにします。

この辺の設定方法は既に完全に忘れてしまいました。

最後にResource Fileの名前をResourceに変更しました。

見やすくするためにSource Fileを作成してその中にPrivateとPublicを移しました。

次はSwitch Viewを押してFolder Viewを選択します。

以下のような画面に移行しますので

OlympusをClickしてSource Fileを追加します。

このEngineを最適化するためにはPre-Complied Headerが必要になります。

だたしPchはすでにBlank Projectで使用してしまったので

同じ名前を使用するとどのPre-Compileなのか混乱してしまいます。

ここからTutorialの説明がよく分からなくなります。

のでその辺の説明はSkipして結果だけを示すと、

Olympus ProjectのSource FolderにOlympus.cppとOlympus.hを追加します。

ここまで出来たらまたSolution Viewに戻ります。

まずSource Fileにpch Fileを追加します。

ここに先程作成したOlympus.hとOlympus.cppを追加します。

ProjectからPropertiesを開きます。

ここの設定もBlank Projectでやったやり方と全く同じだそうです。

まず右上のConfiguration Manager..を押して

X86をRemoveします。

今度はOlympusのPlatformの設定を調整します。

Win32を外します。

今度はBlank ProjectにあるOutput Directoryの値をCopyして

Olympus ProjectのOutput Directoryの値にPasteします。

Intermediate Directoryの値も同様にします。

次にConfiguration Typeに

Dynamic Library (.dll)をセットします。

これが、DLLを作成するための設定だと思ったんですが、一応確認します。

Making and Working with Libraries in C++ (Multiple Projects in Visual Studio) [18]でこの箇所をStatic Libraryにしていました。

この動画、もう何年も前に一回勉強した事があるんですが、今見ると結構勉強になります。

というかこの動画で述べられている話、もう忘れてしまっています。

残りの設定です。

Tutorialでは、これらは最新のVersionにセットしろと言っていますが、Blank Projectと同じ設定にします。

今度はC/C++のPrecompiled Headerを選択し

Precompiled HeaderとPrecompiled Fileに以下の設定を

セットします。

やっぱりOlympus.hがPrecompiled Fileになっています。

Olympusの実装をこれから行っていきます。

まずOlympus.cppに以下の実装を追加します。

もうこれは当然過ぎて何も言う事もないです。

Olympus.hの方ですが以下の実装を追加しました。

まあWindows.hを追加しただけです。

この機能を有効にするためにもう一回Olympus ProjectのPropertiesを開き

LinkerのSystemのSubSystemの設定をNot Setにします。

次はConfigurationの設定を

Debugに変更して

C/C++のPreprocessorの設定を

以下の様に変更します。

Releaseの方は以下の様に設定します。

ここでCreating Olympusは終わりです。

本当は実装までやろうと思っていたんですが、花粉症が酷いのであんまり頭が働きません。

ここで止める事にします。

実装は来週やります。

9.2 「DirectX 12の魔導書」の「3.2.2 DirectX D12の初期化」の実装の続きをやる

先週はLevelの配列を追加した所で終わりました。

今週はその続きからやっていきます。

D3D12CreateDevice()関数の最初のParameterがnullptrになっています。

ここは後で実装するんでしょうね。

教科書を読むと_devがnullptrの場合、つまり全部駄目だった場合についての記述がありますが、その時の実装は書かれていません。

Sample Codeの方も見ましたがその場合の対応は載っていませんでした。

ので_devがnullptrだった時の実装は無視します。

早速、GPUが複数ある場合について説明が始まりました。

PCに存在するAdapterを全部列挙するためにDXGIFactory Objectを生成します。

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

このCode、色々謎があります。

一個ずつ解明していきます。

まず_dxgiFactory変数です。

ここにAdapterがAssignされると思われますが、この変数作成していません。

どうしてErrorにならないんでしょうか?

作成していました。

次にSample Codeでは、以下に示した様に

CreateDXGIFactory2()関数が使用されています。

しかもParameterが最低でも2個あります。

違いを調べます。

CreateDXGIFactory1 function (dxgi.h)[19]です。

と書かれています。

CreateDXGIFactory2 function (dxgi1_3.h) [20]です。

うーん。

DXGIDebug.dllについて述べています。

更に以下に示した最初のParameterが

DXGI_CREATE_FACTORY_DEBUGか0のどちらかの値を取る事を考慮すると

CreateDXGIFactory2()関数を使用したSample Codeが以下の実装をした事は

何となく理解出来ます。

何となくですが。

CreateDXGIFactory1()関数とCreateDXGIFactory2()関数の違いに関しては、

CreateDXGIFactory1()関数はDXGI 1.1 factoryを作成するのに対して、CreateDXGIFactory2()関数はDXGI 1.3 factoryを作成しています。

うーん。

これはどっちを使用しても良い気がします。

ただSample CodeにはCreateDXGIFactory2()関数の使用方法しか紹介されていないので、最終的にはCreateDXGIFactory2()関数を使用する事にします。

以下の実装に変更しました。

これで_dxigiFactoryにDXGI 1.3 factoryがセットされるはずです。

元々のCodeにAuto resultがあるので、Sample CodeにあったHRESULT resultも追加しておきました。

今度はこのObjectを使用して使用可能なAdapterに関する情報を全部習得します。

それではこの部分を実装します。

勿論、Vectorが使用出来るように

は追加しています。

この部分の実装はSample Codeも教科書も全く同じです。

まあ大体何をやっているのかは見ただけで分かりますが、一応DXGIFactoryのMember Function(Method)であるEnumAdapters()関数は調べておきましょう。

IDXGIFactory::EnumAdapters method (dxgi.h)[21]です。

Adapterの何をEnum化するんでしょうか?

後、ここだとAdapterそのものをVideo Cardと呼んでいますね。

2023-02-19のBlogでは

と書いていたんですが、AdapterがVideo Cardそのものである可能性も出て来ました。

こういう箇所ってどんなに頑張っても一回目の勉強では不完全です。

腹をくくってと言うか、諦めて何回か勉強しないと完全な理解は無理です。

今は軽い気持ちでやる事にします。

ちなみにIDXGIAdapter interface (dxgi.h)[22]の解説では

と書かれていました。

GPUを含むDisplay SubsystemがAdapterと呼ばれているみたいです。

教科書を読み直したらDXGI_ADAPTER_DESC構造体って書かれていました。

DXGI_ADAPTER_DESC structure (dxgi.h) [23]を見ると以下の構成になっていました。

うーん。

どれがVideo Cardの名前を示しているの?

最初の要素であるDescription

だけがVideo Cardの名前を指している可能性がありますね。

というかここでは、Enumのそれぞれの要素をMemberと呼んでいます。

そんな呼び方したっけ?

あれ。

Structになっている?

げ。

教科書を読み直したらDXGI_ADAPTER_DESC構造体はIDXGIAdapterじゃなかったです。

IDXGIAdapterからGetDesc()関数を使用して得られるStructでした。

Structが構造体、Enumは列挙体でした。

間違えていました。

では次の部分の実装もやってしまいます。

しました。

この部分の実装は教科書もSample Codeも同じでした。

やっぱりDescriptionの値を習得していますね。

後、Structの宣言ってこうやるんでしたっけ?

これ純粋なC++の疑問ですが一応調べておきます。

cppreference.comのStruct and union initialization [23]によると

と書かれていました。

Structの初期化はnullptrじゃダメみたいですね。

Sample Codeのように{}を使用する必要があるみたいです。

この辺は、またC++でCodeを書く時になったら勉強し直します。

兎に角、これでNVidiaのVideo CardのAdapterどれなのかが判明しました。

NVidiaのVideo CardのAdapterの情報はIDXGIAdapter のObjectであるtmpAdapterが保持しているはずです。

D3D12CreateDevice()関数の最初のParameterに

nullPtrの代わりにtmpAdapterをセットしました。

これでVideo Cardが複数ある場合でもNVIDIAGPUがセットされるようになりました。

これNVIDIAじゃなくて別の会社のGPUを使用していた場合はどうすんでしょうか?

と思ったら教科書にもその辺の注意書きが書かれていました。

まあ私のPCはRTX3070tiなのでその辺は気にしないで先に進みます。

キリが良いので今週はここまでにします。

9.3 HLSLシェーダーの魔導書を勉強する

先週は「2.3.4 頂点シェーダー」を勉強してSemanticについて理解したところで終わりました。

今、教科書を読み直したら2.3は全部、読み終わっていました。

「2.4 ピクセルシェーダー入門」を読みます。

Pixel Shaderについてです。

Pixel Shaderの実装を改造して三角形を青くしろ。と書いています。

この辺はOpenGLのGLSLと同じなのでまあ簡単ではあります。

一応、油断大敵なのでしっかりやっておく事にします。

次は緑色にします。

次は黄色です。

次の課題が

となっています。

これは教科書を見ないで答えを考えてみます。

これでどうでしょうか?

この書き方が可能なのか分かりませんが試してみます。

結果です。

うーん。

これあっているの?

これPositionの値が色として処理されてそうです。

教科書を読んで確認します。

教科書は以下の様な実装をしていました。

うーん。

Color.xでxの値が取れるんですね。

これはこれで勉強になります。

結果は同じですね。

一応、あっていた事にします。

ここでChapter2が終わっています。

キリが良いのでここまでとします。

9.4 HLSLシェーダーの魔導書のD3D12CreateDevice()関数のParameterを確認する

HLSLシェーダーの魔導書のSample CodeのD3D12CreateDevice()関数の最初と二番目のParameterを確認しておきます。

これですね。

最初のParameterはuseAdapter、二番目のParameterはFeatureLevelになっています。

二番目のParameterから見ていくことにします。

まずFeatureLevelsがどうやってDirectXのLevelを指定しているかです。

FeatureLevelsは、ここで指定されていました。

これは「DirectX 12の魔導書」の指定方法と全く同じです。

よく見たらFor Loopは以下の部分まで含んでいました。

今度は最初のParameterであるuseAdaptorを見ます。

useAdaptorは以下の箇所で宣言されています。

あれ、Adapterだけでこんなに有ります。

その前のdxgiFactoryを作成するための関数が以下の様になっていました。

む。

これを読むと先程、CreateDXGIFactory2 function (dxgi1_3.h) [20]を読んで意味の分からなかったdxgiFactoryFlagsの意味が何となく分かって来ました。

ここはDebug以外の時は0なんです。そしてDebugの時は以下に示した様に

DXGI_CREATE_FACTORY_DEBUGになります。

以下の符号の意味が分かりません。

調べます。

Stack OverflowのWhat does "|=" mean? (pipe equal operator)[24]に以下の解説が有りました。

うーん。

じゃ|の意味が知りたい。

と思ったらそれも書いてありました。

あ、思い出しました。

ORのOperationをやるやつです。

となるとDXGI_CREATE_FACTORY_DEBUGがどんなBitなのか知る必要があります。

あ、それが0x01なのか。

0000 0000 0000 0001

って事?

探したけど見つかりません。

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

来週は以下のDebugControllerのLayerについてから勉強します。

9.5「Direct3D 12 ゲームグラフィック実践ガイド」の「2.3 Direct X 12の初期化処理」の勉強の続き

以下に示した様に、先週はD3D12CreateDevice()関数まで勉強しました。

<Command Queueの生成>

次のCommand Queueを実装します。

そのままSample Codeの実装をCopyしました。

一個ずつ見ていきます。

{}で宣言しているので、これはStructですね。

公式のDocumentであるD3D12_COMMAND_QUEUE_DESC structure (d3d12.h)[24]を見ます。

以下の構成になっています。

個々のMemberの値は以下の実装で指定していますね。

<<Type>>

まずTypeですがD3D12_COMMAND_LIST_TYPE_DIRECTを使用しています。

そもそもD3D12_COMMAND_QUEUE_DESC structure (d3d12.h)[24]でTypeは以下の様に説明されています。

D3D12_COMMAND_LIST_TYPE enumeration (d3d12.h)[25]を見ると

以下のTypeがあり

D3D12_COMMAND_LIST_TYPE_DIRECTは、

以下の様に説明されていました。

何を言っているのか不明ですが、

分からないなりに訳すと以下の様になります。

  • GPUで実行するCommand Bufferを指定する
  • GPUの状態は継承しない

何の事か全く分からないですね。

毎週、使用させてもらっている以下の図ですが、

Command ListとCommand Queueはありますが、Command Bufferはありません。

教科書の「2. 3. 2 コマンド キューの生成」を読むと「GPUが実行可能なCommand Bufferを指定する」と書かれていました。

あれ。

あ。本当だ。

いかん。読み間違えていました。

先程のD3D12_COMMAND_LIST_TYPE enumeration (d3d12.h)[25]のTypeの説明は

GPUが実行できるCommand Bufferを指定する」が正しい解釈ですね。

で、肝心のCommand Bufferが何を指しているのかですが、Command Listの事みたいです。

<<Priority>>

次のPropertiesはPriorityです。

Sample Code及び教科書の実装では以下に示したように

D3D12_COMMAND_QUEUE_PRIORITY_NORMALを使用しています。

D3D12_COMMAND_QUEUE_DESC structure (d3d12.h)[24]ではPriorityは以下の様に説明されています。

これもこの説明を読んだだけでは意味不明です。

意味不明なりにこの説明を解釈すると

  • D3D12_COMMAND_QUEUE_PRIORITY enumerationを使用してNormalかHighを選択する

となります。

Normalを選択したりHighを選択したりするとどうなるのかとかそもそもこの解釈であっているのかとかは全然分かりません。

D3D12_COMMAND_QUEUE_PRIORITY enumeration (d3d12.h)[26]を見ます。

まず以下の説明がありました。

「Command QueueのPriority Levelを定義する」とあります。

お。

段々、理解してきました。Command QueueにはPriority Levelがあってそれを指定するのがこのPropertyという事です。

そして以下に示した様にPriorityには3つのLevelがありました。

大体理解しましたが、一応教科書の説明も読んでおきます。

Command Queueの優先度を指定している。と解説していました。

GPUが色々な実行をする中でCommand Queueの実行をどの程度優先するのかを指定するって事でしょうか。

まあ、何となくのImageは掴めました。

<<Flags>>

次はFlagsです。

D3D12_COMMAND_QUEUE_FLAG_NONEを使用しています。

D3D12_COMMAND_QUEUE_PRIORITY enumeration (d3d12.h)[26]の説明です。

この説明を超訳すると

  • D3D12_COMMAND_QUEUE_FLAGS enumerationのFlagを指定する

となります。

これは分かっています。

これを指定するとどうなるのかが知りたいんです。

D3D12_COMMAND_QUEUE_FLAGS enumeration (d3d12.h)[27]に説明がありました。

Flagの指定がD3D12_COMMAND_QUEUE_FLAG_NONEの時はCommand QueueはDefaultのまま実行されるようです。

D3D12_COMMAND_QUEUE_FLAG_DISABLE_GPU_TIMEOUTの時はGPU timeoutが機能しないようになるそうです。

うん。

これも大体理解しました。

教科書の解説もこれ以上深入りしていませんでした。

<<NodeMask>>

NodeMaskについてです。

Sample Codeでは0を指定しています。

D3D12_COMMAND_QUEUE_PRIORITY enumeration (d3d12.h)[26]の説明です。

む、これ読むとGPUを何台も同時に使用するPCの時には0以外を指定するみたいですね。

私のPCには同時に使用出来るGPUは一個しかないので0で良いはずです。

教科書の説明では、GPUが一個の時は0にセットしろ。とありました。

これGPUの実際の数じゃなくて、同時に使用するGPUの数が何個なのか、が問題だと解釈したんですが、その辺は教科書の解釈と違いますね。

まあ、問題になる事はないでしょう。

<<Command Queueの生成>>

これで

の初期化が終わりました。

今度はこれを使用してCommand Queueを生成します。

はい。

まずID3D12DeviceのObjectであるm_pDeviceを使用しています。

ID3D12Deviceを作成する目的の一つがCommand Queueなどの生成をするためである。

と言うのはこれまでのDirectX12の勉強のほとんど根幹をなす仮説でした。

それが、やっとここで証明されました。

この仮説、自分の中では間違いないはずとは思っていましたが、こうやって実際に確認出来ると感動します。

ID3D12Device からCreateCommandQueue()関数を呼び出していますね。

最初のParameterには先程作成したStructであるD3D12_COMMAND_QUEUE_DESCのObject(Structの場合はObjectと呼んで良いのか知りませんが)であるdescがセットされています。

次のParameterにセットされているm_pQueueってObject、これ何時作成したんでしょう。

見たことない変数です。

ここで作成していました。

ID3D12CommandQueueのObjectでした。

IID_PPV_ARGSとかif (FAILED(hr))とかは、あまりにも一般的な内容なのでここで検証する事はしません。

これで一応、Command Queueの生成まで理解出来ました。

今週は、時間の関係もあってここでお終いですね。

来週はSwap Chainの生成からやる事にします。

9.6 Swap Chainの生成にあるIDXGIFactory4の謎

正直、これは今週やりたかったんですが、時間的に無理でした。

ので何が気になっているのかだけここに記録しておきます。

Direct3D 12 ゲームグラフィック実践ガイド」ではSwap Chainを作成するに当たって以下に示した様に

DXGIFactoryを生成しています。

DirectX 12の魔導書」や「HLSLシェーダーの魔導書」でもDXGIFactoryを生成していましたが、

これはDeviceを生成する時に使用するD3D12CreateDevice()関数の最初のParameterに指定するAdapter(GPU)を指定するために使用しています。

ところが、「Direct3D 12 ゲームグラフィック実践ガイド」ではこのParameterは以下に示した様に

nullPtrを指定しています。

つまりこのParameterはDefault値をそのまま使用しているのでAdapter(GPU)を指定するためにDXGIFactoryを生成する必要はないんです。

にもかかわらず、Swap Chainを作成するに当たってわざわざDXGIFactoryを生成しているんです。

これは滅茶苦茶興味深いです。

この謎は来週、検証します。

10.まとめと感想

今週は別にやる事が出来ちゃったので、勉強はこれでお終いです。

11.参照(Reference)

[1] CGHOW. (2021, July 23). Sprite Rotation Sprite Alignment Sprite Facing | UE5 Niagara Tutorial | Download Project File. YouTube. https://www.youtube.com/watch?v=EIP6mg8V5YU

[2] Ben Cloward. (2022c, October 27). Ice Shader Part 1 - Advanced Materials - Episode 5 [Video]. YouTube. https://www.youtube.com/watch?v=ppBoKzKTWZ8

[3] Andrea Cantelli. (2020b, June 6). Gaea Tutorial for Beginners #6 | Texturing our first terrain [Video]. YouTube. https://www.youtube.com/watch?v=d879QNdQG7U

[4] Magee, R. (n.d.). Foundations | Overview | SideFX. https://www.sidefx.com/tutorials/foundations-overview/

[5] OlympusMonsTutorials. (2021, March 17). C++ DirectX 12 Game Engine - [S01E03] - Creating A Game Engine [Video]. YouTube. https://www.youtube.com/watch?v=YgZSSE3qZqA

[6] Open World Tools. (n.d.). https://docs.unrealengine.com/5.1/en-US/open-world-tools-in-unreal-engine/

[7] Epic Games. (n.d.). Procedural Foliage Tool Quick Start. Unreal Engine Documentation. Retrieved March 6, 2022, from https://docs.unrealengine.com/4.27/en-US/BuildingWorlds/OpenWorldTools/ProceduralFoliage/QuickStart/

[8] Orient: Face [Mode] | Visual Effect Graph | 10.3.2. (n.d.). https://docs.unity3d.com/Packages/com.unity.visualeffectgraph@10.3/manual/Block-Orient.html

[9] Animation Notifies. (n.d.). https://docs.unrealengine.com/5.0/en-US/animation-notifies-in-unreal-engine/

[10] MetaSounds. (n.d.). https://docs.unrealengine.com/5.0/en-US/metasounds-in-unreal-engine/

[11] C. (2022a, August 27). Trigger metasoundsound with a button widget. Epic Developer Community Forums. https://forums.unrealengine.com/t/trigger-metasoundsound-with-a-button-widget/635087

[12] MetaSounds: The Next Generation Sound Sources. (n.d.). https://docs.unrealengine.com/5.0/en-US/metasounds-the-next-generation-sound-sources-in-unreal-engine/

[13] MetaSounds Reference Guide. (n.d.). https://docs.unrealengine.com/5.0/en-US/metasounds-reference-guide-in-unreal-engine/

[14] Kevin Stratvert. (2023, January 27). 🎬 3 BEST FREE Video Editing Software for PC - 2023 [Video]. YouTube. https://www.youtube.com/watch?v=JpYESoy63cE

[15] Kevin Stratvert. (2022, May 16). DaVinci Resolve 18 - Full Tutorial for Beginners [Video]. YouTube. https://www.youtube.com/watch?v=EEksPdEc7aI

[16] Free Music for Youtube & Videos - No copyright claim. (n.d.). https://www.bensound.com/free-music-for-videos

[17] OlympusMonsTutorials. (2021, March 17). C++ DirectX 12 Game Engine - [S01E03] - Creating A Game Engine [Video]. YouTube. https://www.youtube.com/watch?v=YgZSSE3qZqA

[18] The Cherno. (2017, October 18). Making and Working with Libraries in C++ (Multiple Projects in Visual Studio) [Video]. YouTube. https://www.youtube.com/watch?v=Wt4dxDNmDA8

[19] S. (2022, August 23). CreateDXGIFactory1 function (dxgi.h) - Win32 apps. Microsoft Learn. https://learn.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-createdxgifactory1

[20] S. (2021, October 13). CreateDXGIFactory2 function (dxgi1_3.h) - Win32 apps. Microsoft Learn. https://learn.microsoft.com/en-us/windows/win32/api/dxgi1_3/nf-dxgi1_3-createdxgifactory2

[21] S. (2021b, October 13). IDXGIFactory::EnumAdapters (dxgi.h) - Win32 apps. Microsoft Learn. https://learn.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgifactory-enumadapters

[22] S. (2021a, July 22). IDXGIAdapter (dxgi.h) - Win32 apps. Microsoft Learn. https://learn.microsoft.com/en-us/windows/win32/api/dxgi/nn-dxgi-idxgiadapter

[23] Struct and union initialization - cppreference.com. (n.d.). https://en.cppreference.com/w/c/language/struct_initialization

[24] S. (2021a, July 12). D3D12_COMMAND_QUEUE_DESC (d3d12.h) - Win32 apps. Microsoft Learn. https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ns-d3d12-d3d12_command_queue_desc

[25] S. (2023, February 14). D3D12_COMMAND_LIST_TYPE (d3d12.h) - Win32 apps. Microsoft Learn. https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_command_list_type

[26] S. (2022a, January 31). D3D12_COMMAND_QUEUE_PRIORITY (d3d12.h) - Win32 apps. Microsoft Learn. https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_command_queue_priority

[27] S. (2022a, January 31). D3D12_COMMAND_QUEUE_FLAGS (d3d12.h) - Win32 apps. Microsoft Learn. https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_command_queue_flags