ずっとKawaiiPhysicsばっかり触ってたけどC++プロジェクトにしたくないときに便利な
Anim Dynamics 関連ノード の中にSpring Controllerがあります。
IsFalling にNOTをつないでBoolをAlphaにつなぎます。

設定値は以下の通りです。ボーン以外の参考にしてください。


ずっとKawaiiPhysicsばっかり触ってたけどC++プロジェクトにしたくないときに便利な
Anim Dynamics 関連ノード の中にSpring Controllerがあります。
IsFalling にNOTをつないでBoolをAlphaにつなぎます。
設定値は以下の通りです。ボーン以外の参考にしてください。
エラー表示は無く、以下がループしていました。
2 packages in the savequeue:
UATHelper: Packaging (Windows): LogCook: Display: /Game/jennie9/SwimSuit_Top_FRONT_5010
UATHelper: Packaging (Windows): LogCook: Display: /Game/jennie9/Skirt_Short_Cage2_Middle_M
UATHelper: Packaging (Windows): LogCook: Display: 2 objects that have not yet returned true from IsCachedCookedPlatformDataLoaded:
UATHelper: Packaging (Windows): LogCook: Display: Material /Game/jennie9/SwimSuit_Top_FRONT_5010.SwimSuit_Top_FRONT_5010
UATHelper: Packaging (Windows): LogCook: Display: Material /Game/jennie9/Skirt_Short_Cage2_Middle_M.Skirt_Short_Cage2_Middle_M
UATHelper: Packaging (Windows): LogCook: Display: Cook Diagnostics: OpenFileHandles=311, VirtualMemory=4265MiB, VirtualMemoryAvailable=106810MiB
連鎖的な影響があるかどうかはわかりませんが、「XGE コントローラー」プラグインに関連しているようです。
私が収集した限りでは、これは Incredibuild を利用したコンパイル配布プラグインですが、実際には CPU 上の複数のコアが完全に利用されるのを妨げるだけのようです。
シェーダーのコンパイルが非常に遅く、かつシェーダーのコンパイル時に ShaderCompileWorker.exe プロセスが1つしか起動されていない場合は、これも原因の可能性があります。実際には、タスクマネージャーの「プロセス」タブには3つの ShaderCompileWorker プロセスが表示されることがありますが、詳細タブに切り替えると、「shadercompileworker.exe」プロセスが1つと「XGEControlWorker.exe」プロセスが2つしか表示されないことがあります。ほとんどの環境では、「XGEControlWorker.exe」プロセスは表示されず、「shadercompileworker.exe」プロセスが多数表示されます。なぜ一部の環境でこの動作が異なるのかは、私にはわかりません。
とにかく、コンパイル時間を大幅に短縮できる解決策として私が見つけたのは、
「XGE Controller」プラグインを完全に無効にすることです。(エディターで「編集」>「プラグイン」を選択し、「XGE Controller」を検索して「有効」のチェックを外します。)
追記:このマシンにIncredibuild Coordinatorというツールがインストールされているのを見つけました。シェーダーコンパイルタスクが配布待ちになっていることを検出しましたが、有効なライセンスがインストールされていなかったため、実際には複数のコアに配布されていませんでした。おそらくこれが、ほとんどの人がこの問題に遭遇しない理由でしょう。Incredibuild Coordinator(または類似のツール?)がインストールされていない場合、エンジンはデフォルトでXGE Incredibuildを利用したコンパイルを使用しません。
参考URL
https://forums.unrealengine.com/t/only-a-single-shadercompileworker-process/455973/2
1, [Section Selection (セクション選択)]
2,左クリックを使って、クロスとして使用したいメッシュの一部を選択します。次に右クリックして、コンテキスト メニューを開いて Cloth アセットを作成します。
3,コンテキスト メニューから、[Create Cloth Asset from Selection (選択したものから Cloth アセットを作成)] を選びます。
A,Asset Name – 後で簡単に見つけられるようにアセットに名前を付けてください。
B,Remove from Mesh – クロスとして関連付けたい別個のジオメトリのメッシュの構成要素があれば、このオプションを有効にします。そうでなければ、チェックを入れずにこのままにします。
C,Physics Asset – Cloth アセットがキャラクター用ならば、その Physics アセットを使ってクロス シミュレーションで適切なコリジョンが生じるようにします。
4,[Create] ボタンをクリックします。
5,セクションを再度右クリックして、コンテキスト メニューを表示させて、
[Apply Clothing Asset] にマウスをかざし、利用可能なクロス アセットから適用するものを選択します。これで作成した任意のクロス アセットが選択したセクションに関連付けられます。
ウィンドウ上部 [Activate Cloth Paint] ボタンをクリックして、選択した Cloth アセットをペイントするために使用可能なプロパティを有効にします。
「Cloth Window」の下のほうの
・ブラシの半径を5にして
・強度を0.2 か1でいいかも
・フォールオフ0.5
でポリゴン頂点をクリックすると塗れる。ピンクが塗ってない場所
・ペイント – マウスの左ボタン
・消去 – Shift キー + マウスの左ボタン
・クロスのプレビュー H キー
塗れた状態。
コツとしてマテリアルをisolateの状態にしてそれだけのメッシュを表示して塗ったほうが確実だ。
参考に走っても問題ない塗り
最後に Applyすることで動くようになる。
UE53PuciCo22G3 パッケージダウンロードはこちら
https://drive.google.com/file/d/1CSP6l-e4Dvui1CH9GYw_ifelUDYluELD/view?usp=sharing
使っているシェーダーは3Dnchuさんの
LV_StylizedPP_Example
の
ScreenSpaceHatching_Example
をカスタムしたものです。
管理用プロジェクト
https://drive.google.com/file/d/1qhC8rWejar8ctAWtRB9DCl6uqW9W-rDy/view?usp=sharing
こちらの記事を丸っと参考にさせていただいて
【UE5】シェーダーファイルのインクルード方法について(Customノード編)
確認をとった
プロジェクト名はProjects_CustomNode
プロジェクトフォルダの直下にShadersフォルダを作成します。
Glitter.usf
float3 Glitter = float3(0.0,1.0,0.0);
return Glitter;
先ほど作成したシェーダーファイルを適用させるために、Projects_CustomNode.Build.cs に RenderCore を追加します。
// Copyright Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
public class Projects_CustomNode : ModuleRules
{
public Projects_CustomNode(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore","RenderCore" });
PrivateDependencyModuleNames.AddRange(new string[] { });
// Uncomment if you are using Slate UI
// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
// Uncomment if you are using online features
// PrivateDependencyModuleNames.Add("OnlineSubsystem");
// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
}
}
Projects_CustomNode.h を開き、新しく “Modules/ModuleManager.h” を インクルードします。
さらに、継承クラスとして FDefaultGameModuleImpl を宣言し、StartupModule関数 と ShutdownModule関数 を一緒にオーバライドします。
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
class FProjects_CustomNodeModule : public FDefaultGameModuleImpl
{
public:
virtual void StartupModule() override;
virtual void ShutdownModule() override;
};
Projects_CustomNode.cpp を開き、IMPLEMENT_PRIMARY_GAME_MODULE の最初の引数を Projects_CustomNode.h 側のクラス名に書き換えます。
// Copyright Epic Games, Inc. All Rights Reserved.
#include "Projects_CustomNode.h"
#include "Modules/ModuleManager.h"
void FProjects_CustomNodeModule::StartupModule()
{
FString ShaderDir = FPaths::Combine(FPaths::ProjectDir(), "Shaders");
AddShaderSourceDirectoryMapping("/Project", ShaderDir);
}
void FProjects_CustomNodeModule::ShutdownModule()
{
}
IMPLEMENT_PRIMARY_GAME_MODULE(FProjects_CustomNodeModule, Projects_CustomNode, "Projects_CustomNode" );
以上の流れが完了しましたら、一度ビルドを行います。
マテリアル作成しCustomノードのCodeに
#include "/Project/Glitter.usf"
return 0;
と入力したらOKでした。
プロジェクトデータ
https://drive.google.com/file/d/1Ro4pcatwqWKCQ64ZUObSndKtIyagYKE7/view?usp=sharing
基本的にこれをやった。
コンテンツ配布、DLC | Unreal Engine 5.5 ドキュメンテーション
https://dev.epicgames.com/documentation/ja-jp/unreal-engine/patching-content-delivery-and-dlc-in-unreal-engine
注意
・プロジェクトを作ったら一度ビルドしないと
[ProjectName]/Source/[ProjectName]Build.cs がない状態になります。
Primary Asset Label の設定はこれが正しいようだ。
フォルダに置けばディレクトリやファイルのパスの設定は不要の様子
パッケージ化したディレクトリに.pak ファイルができあがった。
Audit
[Tools] > [Asset Audit] の順にクリックして、[Asset Audit] ウィンドウでチャンクを確認することもできます。
ディスク上のサイズ ではなく ファイル サイズ を使用する
マニフェスト ファイルは、次のとおりです。
BuildManifest-Windows.txt
$NUM_ENTRIES = 9
$BUILD_ID = PatchingDemoKey
pakchunk1001-Windows.ucas 400 ver01 1001 /Windows/pakchunk1001-Windows.ucas
pakchunk1002-Windows.ucas 400 ver01 1002 /Windows/pakchunk1002-Windows.ucas
pakchunk1003-Windows.ucas 416 ver01 1003 /Windows/pakchunk1003-Windows.ucas
pakchunk1001-Windows.utoc 383 ver01 1001 /Windows/pakchunk1001-Windows.utoc
pakchunk1002-Windows.utoc 383 ver01 1002 /Windows/pakchunk1002-Windows.utoc
pakchunk1003-Windows.utoc 381 ver01 1003 /Windows/pakchunk1003-Windows.utoc
pakchunk1001-Windows.pak 339 ver01 1001 /Windows/pakchunk1001-Windows.pak
pakchunk1002-Windows.pak 339 ver01 1002 /Windows/pakchunk1002-Windows.pak
pakchunk1003-Windows.pak 339 ver01 1003 /Windows/pakchunk1003-Windows.pak
このファイル作成が面倒なので、pythonで自動化しました。
参考のエラー
log chunkdownloader: error: manifest parse error at ../../../../../../sandbox/ue554assemanager/010chunkdowloader/patchingdemo 4_6 all2/saved/persistentdownloaddir/pakcache/cachedbuildmanifest.txt:1
参考URL
https://forums.unrealengine.com/t/primaryassetlabel-explicitassets/455608
Project/PatchingDemoKeyAuto_python.py
# 1 BuildManifest-Windows.txt to Auto Coding
# 1-1 Open Dir \Windows\PatchingDemo\Content\Paks
import os
dir_path = "./Windows/PatchingDemo/Content/Paks/"
files = os.listdir(dir_path)
#print(files)
txtData=""
#minus global Line -2
filelength=len(files)-2
#txtData=txtData+" $NUM_ENTRIES = 9"+"\r\n"
txtData=txtData+"$NUM_ENTRIES = "+str(filelength)+"\r"
txtData=txtData+"$BUILD_ID = PatchingDemoKey"+"\r"
for filename in files:
globalFindNum=filename.find('global')
print("globalFindNum= "+str(globalFindNum))
if(globalFindNum==0):
pass
else:
endNum=filename.find('-')
filenum=filename[8:endNum]
fileSize=os.path.getsize(dir_path+filename)
windowsPath="/Windows/"+filename
#print("filename= "+filename+" fileSize= "+str(fileSize))
tab="\t"
print(tab+filename+tab+str(fileSize)+tab+"ver01"+tab+filenum+tab+windowsPath)
txtData=txtData+filename+tab+str(fileSize)+tab+"ver001"+tab+filenum+tab+windowsPath+"\r"
filePath="./BuildManifest-Windows.txt"
f = open(filePath, 'w', encoding='UTF-8')
f.write(txtData)
f.close()
# 2 copy
起動用バッチファイル
@echo off
set cwdirpath=%~dp0
set pythonpath=D:\Sandbox\python\python-3.12.7\
set codepath=%cwdirpath%\
set pyfile=PatchingDemoKeyAuto_python.py
%pythonpath%python.exe %codepath%%pyfile%
::pause
cmd /k
パッケージ ファイルを「/Windows/PatchingDemo/Content/Paks/
」から「PatchingDemoKey」フォルダのマニフェストと一緒に並んでいる「Windows」という名前のサブフォルダ内にコピーします。
・ファイルをローカル テスト サーバーでホスティングする
IISサーバーをオンにするためにWindows エクスプローラーで [Start Menu] を開き、[Turn Windows Features on or off (Windows の機能の有効化または無効化)] を検索して開きます
[Windows Features] メニューで、[Internet Information Services (インターネット情報サービス)] を有効にして [OK] をクリックします。
(IIS Managerを開いて [Directory Browsing (ディレクトリをブラウズ)] を有効にします。
[Add MIME Type] ウィンドウで [File Name extension] を .pak
に設定し、[MIME type] を「application/octet-stream」に設定します。.ucas
と .utoc
にも同様の操作をします。
これにより、IIS はリクエストされると、ただファイルをダウンロードします。
[Default Web Site] フォルダに移動します。デフォルトでは「C:\inetpub\wwwroot」です。フォルダを作成し、「PatchingDemoCDN」という名前を付けます。
「PatchingDemoKey」フォルダを「PatchingDemoCDN」にコピーします。
プロジェクトのConfig/ DefaultGame.ini
ファイルを開き、次の情報を追加して CDN Base URL を定義します。
[/Script/Plugins.ChunkDownloader PatchingDemoLive]
+CdnBaseUrls=127.0.0.1/PatchingDemoCDN
この URL は、ファイルが配置されているウェブサイトを ChunkDownloader に示しています。PatchingDemoLive 修飾子により、ターゲットのプラットフォームに応じて様々な CDN デプロイ コンフィギュレーションを使用できます。
アセットをパッケージ ファイルに分割し、ローカル ウェブサイトにステージングできたので、Unreal Engine でパッチ適用ソリューションを使用してアクセスすることができるようになりました。
PatchingDemoGameInstance を
ブランクなC++プロジェクトにC++フォルダがない状態で、C++ クラスを作る方法
「Tools」プルダウンメニューから「New C++ Class…」を選択します。
ここで新しいクラスを作成できます。
GameInstance
PatchingDemoGameInstance.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "PatchingDemoGameInstance.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FPatchCompleteDelegate, bool, Succeeded);
/**
*
*/
UCLASS()
//class UPatchingDemoGameInstance : public UGameInstance
class PATCHINGDEMO_API UPatchingDemoGameInstance :public UGameInstance
{
GENERATED_BODY()
public:
// Overrides
virtual void Init() override;
virtual void Shutdown() override;
UFUNCTION(BlueprintPure, Category = "Patching|Stats")
void GetLoadingProgress(int32& BytesDownloaded, int32& TotalBytesToDownload, float& DownloadPercent, int32& ChunksMounted, int32& TotalChunksToMount, float& MountPercent) const; // Delegates
// Fired when the patching process succeeds or fails
UPROPERTY(BlueprintAssignable, Category = "Patching");
FPatchCompleteDelegate OnPatchComplete;
// Starts the game patching process.Returns false if the patching manifest is not up to date.*/
UFUNCTION(BlueprintCallable, Category = "Patching")
bool PatchGame();
protected:
//Tracks if our local manifest file is up to date with the one hosted on our website
bool bIsDownloadManifestUpToDate;
//Called when the chunk download process finishes
void OnManifestUpdateComplete(bool bSuccess);
// List of Chunk IDs to try and download
UPROPERTY(EditDefaultsOnly, Category = "Patching")
TArray<int32> ChunkDownloadList;
// Called when the chunk download process finishes
void OnDownloadComplete(bool bSuccess);
// Called whenever ChunkDownloader's loading mode is finished
void OnLoadingModeComplete(bool bSuccess);
// Called when ChunkDownloader finishes mounting chunks
void OnMountComplete(bool bSuccess);
};
PatchingDemoGameInstance.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "PatchingDemoGameInstance.h"
#include "ChunkDownloader.h"
#include "Misc/CoreDelegates.h"
#include "AssetRegistry/AssetRegistryModule.h"
void UPatchingDemoGameInstance::Init()
{
Super::Init();
const FString DeploymentName = "PatchingDemoLive";
const FString ContentBuildId = "PatchingDemoKey";
// initialize the chunk downloader with chosen platform
TSharedRef<FChunkDownloader> Downloader = FChunkDownloader::GetOrCreate();
Downloader->Initialize("Windows", 8);
// load the cached build ID
Downloader->LoadCachedBuild(DeploymentName);
// update the build manifest file
TFunction<void(bool bSuccess)> UpdateCompleteCallback = [&](bool bSuccess) {bIsDownloadManifestUpToDate = true; };
Downloader->UpdateBuild(DeploymentName, ContentBuildId, UpdateCompleteCallback);
}
void UPatchingDemoGameInstance::Shutdown()
{
Super::Shutdown();
// Shut down ChunkDownloader
FChunkDownloader::Shutdown();
}
void UPatchingDemoGameInstance::OnManifestUpdateComplete(bool bSuccess)
{
bIsDownloadManifestUpToDate = bSuccess;
}
void UPatchingDemoGameInstance::GetLoadingProgress(int32& BytesDownloaded, int32& TotalBytesToDownload, float& DownloadPercent, int32& ChunksMounted, int32& TotalChunksToMount, float& MountPercent) const
{
//Get a reference to ChunkDownloader
TSharedRef<FChunkDownloader> Downloader = FChunkDownloader::GetChecked();
//Get the loading stats struct
FChunkDownloader::FStats LoadingStats = Downloader->GetLoadingStats();
//Get the bytes downloaded and bytes to download
BytesDownloaded = LoadingStats.BytesDownloaded;
TotalBytesToDownload = LoadingStats.TotalBytesToDownload;
//Get the number of chunks mounted and chunks to download
ChunksMounted = LoadingStats.ChunksMounted;
TotalChunksToMount = LoadingStats.TotalChunksToMount;
//Calculate the download and mount percent using the above stats
DownloadPercent = ((float)BytesDownloaded / (float)TotalBytesToDownload) * 100.0f;
MountPercent = ((float)ChunksMounted / (float)TotalChunksToMount) * 100.0f;
}
bool UPatchingDemoGameInstance::PatchGame()
{
// make sure the download manifest is up to date
if (bIsDownloadManifestUpToDate)
{
// get the chunk downloader
TSharedRef<FChunkDownloader> Downloader = FChunkDownloader::GetChecked();
// report current chunk status
for (int32 ChunkID : ChunkDownloadList)
{
int32 ChunkStatus = static_cast<int32>(Downloader->GetChunkStatus(ChunkID));
UE_LOG(LogTemp, Display, TEXT("Chunk %i status:%i"), ChunkID, ChunkStatus);
}
TFunction<void(bool bSuccess)> DownloadCompleteCallback = [&](bool bSuccess) {OnDownloadComplete(bSuccess); };
Downloader->DownloadChunks(ChunkDownloadList, DownloadCompleteCallback, 1);
// start loading mode
TFunction<void(bool bSuccess)> LoadingModeCompleteCallback = [&](bool bSuccess) {OnLoadingModeComplete(bSuccess); };
Downloader->BeginLoadingMode(LoadingModeCompleteCallback);
return true;
}
// you couldn't contact the server to validate your Manifest, so you can't patch
UE_LOG(LogTemp, Display, TEXT("Manifest Update Failed.Can't patch the game"));
return false;
}
void UPatchingDemoGameInstance::OnLoadingModeComplete(bool bSuccess)
{
OnDownloadComplete(bSuccess);
}
void UPatchingDemoGameInstance::OnMountComplete(bool bSuccess)
{
OnPatchComplete.Broadcast(bSuccess);
}
void UPatchingDemoGameInstance::OnDownloadComplete(bool bSuccess)
{
if (bSuccess)
{
UE_LOG(LogTemp, Display, TEXT("Download complete"));
// get the chunk downloader
TSharedRef<FChunkDownloader> Downloader = FChunkDownloader::GetChecked();
FJsonSerializableArrayInt DownloadedChunks;
for (int32 ChunkID : ChunkDownloadList)
{
DownloadedChunks.Add(ChunkID);
}
//Mount the chunks
TFunction<void(bool bSuccess)> MountCompleteCallback = [&](bool bSuccess) {OnMountComplete(bSuccess); };
Downloader->MountChunks(DownloadedChunks, MountCompleteCallback);
OnPatchComplete.Broadcast(true);
}
else
{
UE_LOG(LogTemp, Display, TEXT("Load process failed"));
// call the delegate
OnPatchComplete.Broadcast(false);
}
}
Unreal Editor で、新規「Blueprints」フォルダを コンテンツ ブラウザ に作成します。次に、ベース クラスとして PatchingDemoGameInstance を使用して 新しいブループリント を作成します。
新しいブループリント クラスの名前を「CDGameInstance」にします。
新しく GameMode ブループリントを PatchingGameMode という名前で作成します。
「Maps」フォルダを作成し、次に 2 つの新規レベルで作成します。
PatchingDemoEntry レベルは空のマップをベースに、
PatchingDemoTest レベルはデフォルトのマップを
ベースにする必要があります。
[Project Settings (プロジェクト設定)] を開いて [Project] > [Maps & Modes (マップ & モード)] に移動します。次のパラメータを設定します。
1 | Game Instance Class (ゲーム インスタンス クラス) | CDGameInstance |
2 | Editor Startup Map (エディタのスタートアップ マップ) | PatchingDemoTest |
3 | Game Default Map (ゲームのデフォルト マップ) | PatchingDemoEntry |
CDGameInstance を ブループリント エディタ で開きます。[Details (詳細)] パネルで 3 つのエントリを [Chunk Download List (チャンク ダウンロード リスト)] に追加し、それぞれの値を 1001、1002、1003 と入力します。これらがチャンク ID です。
PatchingGameMode を ブループリント エディタ で開き、[EventGraph] に
Bigin Playに
Tickで
キャラクター メッシュを表示するには、それらへの参照を取得する必要があります。このセクションでは、アクタのスポーン方法のシンプルな例を説明します。
[Meshes (メッシュ)] の [Variable Type (変数の型)] の隣にあるアイコンをクリックし、[Array (配列)] に変更します。ブループリントをコンパイルして変更を適用します。
[Meshes] の [Default Value (デフォルト値)] に 3 つのエントリを追加し、Boris、Crunch、およびKhaimera のスケルタルメッシュを選択します。
レベルの イベントグラフ で BeginPlayに
レベル内の Player Start を
位置 (256.0, 400.0, 100.0) に移動します。
回転を(0.0,0.0,-90.0)に回転します。
PatchingDemoEntryレベルのゲームモードオーバーライドをPatchingGameModeにします。
Editorでできた!
1,windowsパッケージ化
2,Project/PatchingDemoKeyAuto_cmd.cmd実行
3,Project/BuildManifest-Windows.txt を
4,C:\inetpub\wwwroot\PatchingDemoCDN\PatchingDemoKey へコピー
5,Project\Windows\PatchingDemo\Content\Paks の内容を全部
6,C:\inetpub\wwwroot\PatchingDemoCDN\PatchingDemoKey\Windowsへ コピー
7,Project/WindowsのPatchingDemo.exeを起動
出た!
管理用 全作業データダウンロード
https://drive.google.com/file/d/1YajdJSvuFCg2lAjnPIcIGXcuFC_oHsVm/view?usp=sharing
是非迫力のエギゾーストノートを聞いて遊んでみてください。
WindowsPackageExe 公開用 感想などコメント頂けると泣いて喜びます。
https://drive.google.com/file/d/1mNnAWK8KZajVryUgoKA3BCy5YUSVvKDI/view?usp=sharing
止まってるだけでも絵になるなあ
オフロードコース
ハマったら出られません。笑
最初はシャーシからNurbsCurveで作り始めたが、顔から作ればやる気がでて効率がいいことに気づいた
フロントウィングを作った
リアが完成した。
タイヤが完成した。
Cyber formula Orga Maya Model 管理用ですが 欲しかったらfurcraea.tokyo@gmail.comまでメールください。日本語でのみ受け付けます。
.ma
https://drive.google.com/file/d/1YpUd8rDY4Rh7Fg3B-Iv9IkyLorPdX21t/view?usp=sharing
.fbx
https://drive.google.com/file/d/1y11N32CEY0Ufmu9x0Y4ZNFtGWOs6Q_Ma/view?usp=sharing
以下が六輪の真ん中のタイヤの制御の追加方法
凰呀 AOI OGRE AN-21 V12気筒エンジンサウンドをMetaSoundで作ったよ。パラメータ調整大変だった。。 ちゃんとアクセルの具合でエギゾーストノートがピッチ調整される具合が大変だったよ
MetaSoundノード自体はシンプルだがピッチを25にしてる
Speed変数に0.01をかけてからMultifyPich調整に使ってる。これを見つけるまで8時間以上かかった。
プロジェクトデータ管理用
https://drive.google.com/file/d/1YZlIi7QW0XiNGtU4tvSg_OKFdlpLE8z_/view?usp=sharing
D:\Program Files\Epic Games\UE_5.3\Engine\Source\Runtime\Engine\Classes\Animation\AnimInstance.h
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
//中略
#include "Animation/AnimSubsystemInstance.h"
#include "Animation/AnimSync.h"
#include "Animation/AnimNotifies/AnimNotify.h"
#include "AnimInstance.generated.h"
// Post Compile Validation requires WITH_EDITOR
#define ANIMINST_PostCompileValidation WITH_EDITOR
struct FDisplayDebugManager;
class FDebugDisplayInfo;
class IAnimClassInterface;
class UAnimInstance;
//中略
struct FSmartNameMapping;
struct FAnimNode_LinkedAnimLayer;
struct FNodeDebugData;
enum class ETransitionRequestQueueMode : uint8;
enum class ETransitionRequestOverwriteMode : uint8;
class UAnimMontage;
typedef TArray<FTransform> FTransformArrayA2;
namespace UE::Anim
{
struct FHeapAttributeContainer;
using FSlotInertializationRequest = TPair<float, const UBlendProfile*>;
struct FCurveFilterSettings;
} // namespace UE::Anim
//中略
//デリゲートのパラメータもらうやつ
DECLARE_DELEGATE_OneParam(FOnMontageStarted, UAnimMontage*)
DECLARE_DELEGATE_TwoParams(FOnMontageEnded, UAnimMontage*, bool /*bInterrupted*/)
DECLARE_DELEGATE_TwoParams(FOnMontageBlendingOutStarted, UAnimMontage*, bool /*bInterrupted*/)
/**
* Delegate for when Montage がスタートした時
*/
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnMontageStartedMCDelegate, UAnimMontage*, Montage);
/**
* Delegate for when Montage が再生 completedの時, 中断されたかinterrupted or 終了したかfinished
* このモンタージュの重みは 0.f なので、出力ポーズへの寄与は停止します
*
* プロパティが完了していない場合は bInterrupted = true
*/
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnMontageEndedMCDelegate, UAnimMontage*, Montage, bool, bInterrupted);
/**すべてのモンタージュインスタンスが終了したときに委任します。 */
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnAllMontageInstancesEndedMCDelegate);
/**
モンタージュがブレンドアウトを開始したタイミング(中断または終了)のデリゲート
* このモンタージュの DesiredWeight は 0.f になりますが、これは出力ポーズに引き続き影響します
*
* プロパティが終了していない場合は bInterrupted = true
*/
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnMontageBlendingOutStartedMCDelegate, UAnimMontage*, Montage, bool, bInterrupted);
/** ネイティブコードがフックして追加の遷移ロジックを提供できるデリゲート */
DECLARE_DELEGATE_RetVal(bool, FCanTakeTransition);
/** ネイティブコードがフックして状態の開始/終了を処理できるデリゲート */
DECLARE_DELEGATE_ThreeParams(FOnGraphStateChanged, const struct FAnimNode_StateMachine& /*Machine*/, int32 /*PrevStateIndex*/, int32 /*NextStateIndex*/);
/** ユーザーがカスタムアニメーションカーブ値を挿入できるようにするデリゲート - 今のところは単一のみです。これを複数のデリゲートにして値を順番に取得する方法はわかりません。 */
DECLARE_DELEGATE_OneParam(FOnAddCustomAnimationCurves, UAnimInstance*)
/** 「PlayMontageNotify」および「PlayMontageNotifyWindow」によって呼び出されるデリゲート **/
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FPlayMontageAnimNotifyDelegate, FName, NotifyName, const FBranchingPointNotifyPayload&, BranchingPointPayload);
//中略
/** Helper struct to store a Queued Montage BlendingOut event. */
struct FQueuedMontageBlendingOutEvent
{
TObjectPtr<class UAnimMontage> Montage;
bool bInterrupted;
FOnMontageBlendingOutStarted Delegate;
FQueuedMontageBlendingOutEvent()
: bInterrupted(false)
{}
FQueuedMontageBlendingOutEvent(class UAnimMontage* InMontage, bool InbInterrupted, FOnMontageBlendingOutStarted InDelegate)
: Montage(InMontage)
, bInterrupted(InbInterrupted)
, Delegate(InDelegate)
{}
};
/** 以下長すぎるので省略 */
UPROPERTY(BlueprintAssignable)
FOnMontageStartedMCDelegate OnMontageStarted;
/** Called when a montage has ended, whether interrupted or finished*/
UPROPERTY(BlueprintAssignable)
FOnMontageEndedMCDelegate OnMontageEnded;
DECLARE_DELEGATE_OneParam(FOnMontageStarted, UAnimMontage) DECLARE_DELEGATE_TwoParams(FOnMontageEnded, UAnimMontage, bool /bInterrupted/)
DECLARE_DELEGATE_TwoParams(FOnMontageBlendingOutStarted, UAnimMontage, bool /bInterrupted*/)
D:\Program Files\Epic Games\UE_5.3\Engine\Source\Runtime\Engine\Private\Animation\AnimInstance.cpp
//SET
void UAnimInstance::Montage_SetEndDelegate(FOnMontageEnded& InOnMontageEnded, UAnimMontage* Montage)
{
if (Montage)
{
FAnimMontageInstance* MontageInstance = GetActiveInstanceForMontage(Montage);
if (MontageInstance)
{
MontageInstance->OnMontageEnded = InOnMontageEnded;
}
}
else
{
// If no Montage reference, do it on all active ones.
for (int32 InstanceIndex = 0; InstanceIndex < MontageInstances.Num(); InstanceIndex++)
{
FAnimMontageInstance* MontageInstance = MontageInstances[InstanceIndex];
if (MontageInstance && MontageInstance->IsActive())
{
MontageInstance->OnMontageEnded = InOnMontageEnded;
}
}
}
}
//GET
FOnMontageEnded* UAnimInstance::Montage_GetEndedDelegate(UAnimMontage* Montage)
{
if (Montage)
{
FAnimMontageInstance* MontageInstance = GetActiveInstanceForMontage(Montage);
if (MontageInstance)
{
return &MontageInstance->OnMontageEnded;
}
}
else
{
// If no Montage reference, use first active one found.
for (int32 InstanceIndex = 0; InstanceIndex < MontageInstances.Num(); InstanceIndex++)
{
FAnimMontageInstance* MontageInstance = MontageInstances[InstanceIndex];
if (MontageInstance && MontageInstance->IsActive())
{
return &MontageInstance->OnMontageEnded;
}
}
}
return nullptr;
}
Montage_SetEndDelegate関数によってSETできるデリゲート
void UAnimInstance::Montage_SetEndDelegate(FOnMontageEnded& InOnMontageEnded, UAnimMontage* Montage)
Montage_GetEndedDelegate関数によってGETできるデリゲート
FOnMontageEnded* UAnimInstance::Montage_GetEndedDelegate(UAnimMontage* Montage)
動いた
// ヘッダー内の関数宣言
void OnAnimationEnded(UAnimMontage* Montage, bool bInterrupted);
// 実装内
// デリゲート FOnMontageEnded型のEndDelegate を宣言
FOnMontageEnded EndDelegate;
// バインド
EndDelegate.BindUObject(this, &UMyClass::OnAnimationEnded);
// 設定
MyAnimInstance->Montage_SetEndDelegate(EndDelegate);
参考URL
AnimInstance->OnMontageEnd に関数をバインドするにはどうすればよい
https://forums.unrealengine.com/t/how-can-i-bind-a-function-to-animinstance-onmontageend/290717/2
D:\Program Files\Epic Games\UE_5.3\Engine\Plugins\Online\OnlineSubsystemOculus\Source\Classes\OculusFindSessionsCallbackProxy.h
FOnFindSessionsCompleteDelegate Delegate; これがデリゲート変数の型指定
//登録された OnFindSessionsComplete デリゲートへのハンドル
FDelegateHandle DelegateHandle;
というのは・・・・
D:\Program Files\Epic Games\UE_5.3\Engine\Plugins\Online\OnlineSubsystem\Source\Public\Interfaces\OnlineSessionDelegates.h
でこのように定義されている
.h 全文
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "UObject/Object.h"
#include "Net/OnlineBlueprintCallProxyBase.h"
#include "Interfaces/OnlineSessionInterface.h"
#include "FindSessionsCallbackProxy.h"
#include "OculusFindSessionsCallbackProxy.generated.h"
/**
* Exposes FindSession of the Platform SDK for blueprint use.
*/
UCLASS(MinimalAPI)
class UOculusFindSessionsCallbackProxy : public UOnlineBlueprintCallProxyBase
{
GENERATED_UCLASS_BODY()
// Called when there is a successful query
UPROPERTY(BlueprintAssignable)
FBlueprintFindSessionsResultDelegate OnSuccess;
// Called when there is an unsuccessful query
UPROPERTY(BlueprintAssignable)
FBlueprintFindSessionsResultDelegate OnFailure;
// Searches for matchmaking room sessions with the oculus online subsystem
UFUNCTION(BlueprintCallable, Category = "Oculus|Session", meta = (BlueprintInternalUseOnly = "true"))
static UOculusFindSessionsCallbackProxy* FindMatchmakingSessions(int32 MaxResults, FString OculusMatchmakingPool);
// Searches for moderated room sessions with the oculus online subsystem
UFUNCTION(BlueprintCallable, Category = "Oculus|Session", meta = (BlueprintInternalUseOnly = "true"))
static UOculusFindSessionsCallbackProxy* FindModeratedSessions(int32 MaxResults);
// UOnlineBlueprintCallProxyBase interface
virtual void Activate() override;
// End of UOnlineBlueprintCallProxyBase interface
private:
// Internal callback when the session search completes, calls out to the public success/failure callbacks
void OnCompleted(bool bSuccess);
private:
// The delegate executed by the online subsystem
FOnFindSessionsCompleteDelegate Delegate;//デリゲート宣言
// Handle to the registered OnFindSessionsComplete delegate
FDelegateHandle DelegateHandle;//デリゲートハンドル宣言
// Object to track search results
TSharedPtr<FOnlineSessionSearch> SearchObject;
// Maximum number of results to return
int MaxResults;
// Optional: if searching within a matchmaking pool
FString OculusPool;
bool bSearchModeratedRoomsOnly;
};
D:\Program Files\Epic Games\UE_5.3\Engine\Plugins\Online\OnlineSubsystemOculus\Source\Private\OculusFindSessionsCallbackProxy.cpp では
Super(ObjectInitializer) のあと
Delegate(FOnFindSessionsCompleteDelegate::CreateUObject(this, &ThisClass::OnCompleted))
if (OculusSessionInterface.IsValid()) のタイミングで
DelegateHandle = OculusSessionInterface->AddOnFindSessionsCompleteDelegate_Handle(Delegate);
// Copyright Epic Games, Inc. All Rights Reserved.
#include "OculusFindSessionsCallbackProxy.h"
#include "OnlineSubsystemOculusPrivate.h"
#include "Online.h"
#include "OnlineSessionInterfaceOculus.h"
#include "OnlineSubsystemOculusPrivate.h"
UOculusFindSessionsCallbackProxy::UOculusFindSessionsCallbackProxy(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
, Delegate(FOnFindSessionsCompleteDelegate::CreateUObject(this, &ThisClass::OnCompleted))
, MaxResults(0)
, bSearchModeratedRoomsOnly(false)
{
//デリゲートにOnComplitedをバインド
}
UOculusFindSessionsCallbackProxy* UOculusFindSessionsCallbackProxy::FindMatchmakingSessions(int32 MaxResults, FString OculusMatchmakingPool)
{
UOculusFindSessionsCallbackProxy* Proxy = NewObject<UOculusFindSessionsCallbackProxy>();
Proxy->SetFlags(RF_StrongRefOnFrame);
Proxy->MaxResults = MaxResults;
Proxy->OculusPool = MoveTemp(OculusMatchmakingPool);
Proxy->bSearchModeratedRoomsOnly = false;
return Proxy;
}
UOculusFindSessionsCallbackProxy* UOculusFindSessionsCallbackProxy::FindModeratedSessions(int32 MaxResults)
{
UOculusFindSessionsCallbackProxy* Proxy = NewObject<UOculusFindSessionsCallbackProxy>();
Proxy->SetFlags(RF_StrongRefOnFrame);
Proxy->MaxResults = MaxResults;
Proxy->bSearchModeratedRoomsOnly = true;
return Proxy;
}
void UOculusFindSessionsCallbackProxy::Activate()
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
auto OculusSessionInterface = Online::GetSessionInterface(OCULUS_SUBSYSTEM);
PRAGMA_ENABLE_DEPRECATION_WARNINGS
if (OculusSessionInterface.IsValid())
{
//デリゲートハンドルにDelegateを渡してる。(コールしてる)
DelegateHandle = OculusSessionInterface->AddOnFindSessionsCompleteDelegate_Handle(Delegate);
SearchObject = MakeShareable(new FOnlineSessionSearch);
SearchObject->MaxSearchResults = MaxResults;
SearchObject->QuerySettings.Set(SEARCH_OCULUS_MODERATED_ROOMS_ONLY, bSearchModeratedRoomsOnly, EOnlineComparisonOp::Equals);
if (!OculusPool.IsEmpty())
{
SearchObject->QuerySettings.Set(SETTING_OCULUS_POOL, OculusPool, EOnlineComparisonOp::Equals);
}
OculusSessionInterface->FindSessions(0, SearchObject.ToSharedRef());
}
else
{
UE_LOG_ONLINE_SESSION(Error, TEXT("Oculus platform service not available. Skipping FindSessions."));
TArray<FBlueprintSessionResult> Results;
OnFailure.Broadcast(Results);
}
}
void UOculusFindSessionsCallbackProxy::OnCompleted(bool bSuccess)
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
auto OculusSessionInterface = Online::GetSessionInterface(OCULUS_SUBSYSTEM);
PRAGMA_ENABLE_DEPRECATION_WARNINGS
if (OculusSessionInterface.IsValid())
{
OculusSessionInterface->ClearOnFindSessionsCompleteDelegate_Handle(DelegateHandle);
}
TArray<FBlueprintSessionResult> Results;
if (bSuccess && SearchObject.IsValid())
{
for (auto& Result : SearchObject->SearchResults)
{
FBlueprintSessionResult BPResult;
BPResult.OnlineResult = Result;
Results.Add(BPResult);
}
OnSuccess.Broadcast(Results);
}
else
{
OnFailure.Broadcast(Results);
}
}
ちょっと複雑すぎてちょと何言ってるかわからない感じもする。が
FOnFindSessionsCompleteDelegate Delegate;
FDelegateHandle DelegateHandle;
Delegate(FOnFindSessionsCompleteDelegate::CreateUObject(this, &ThisClass::OnCompleted))
DelegateHandle = OculusSessionInterface->AddOnFindSessionsCompleteDelegate_Handle(Delegate);
自信がないので間違っていたら連絡してほしいです。