見出し画像

⓵UE5でのMetaQuest3でVRを作るためにVirtualRealityテンプレートのソースを追う


注意

UE5のソースではシェアードポインタが当たり前に使われるのでシェアードポインタと断りは容れないです。書き殴りなので整理してないです。

VRPawnを追う

VRの初期設定における重要なものの一つはCameraです。
VirtualRealityのテンプレートを使うとVRPawnというブループリントがあります。
これがプレイヤーキャラクター。
Default Pawn Classで設定されているのがVRPawnです。
VRGameModeはパッと見た感じDefault Pawn Classしか変わってないので追う必要はなさそうです。

Default Pawn Class

Event Graph を見てみます。
BeginPlayノードから見ていきます
Is Head Mounted Display EnabledノードというのがVR関連の機器を頭に被っているかチェックしているものと思われます。


Event Graph

\Engine\Plugins\Runtime\XRBase\Source\XRBase\Public\HeadMountedDisplayFunctionLibrary.h
\Engine\Plugins\Runtime\XRBase\Source\XRBase\Private\HeadMountedDisplayFunctionLibrary.cpp

bool UHeadMountedDisplayFunctionLibrary::IsHeadMountedDisplayEnabled()
{
	return GEngine->XRSystem.IsValid() && GEngine->XRSystem->IsHeadTrackingAllowed();
}

GEngine->XRSystem.IsValid()
シェアードポインタチェック
GEngine->XRSystem->IsHeadTrackingAllowed();
現在の状況でヘッドトラッキングが許可されているかどうかをチェックする

GEngine->XRSystemとは何か?

XRSystemはIXRTrackingSystemを実装したFOpenXRHMDです
IsHeadTrackingAllowed()はFHeadMountedDisplayBaseクラスで定義されています。FOpenXRHMDはFHeadMountedDisplayBaseを継承しているため

GEngine->XRSystem->IsHeadTrackingAllowed();

のように呼び出すことが可能です。

XRSystemはどこで代入されているか?

UEngine::InitializeHMDDevice()

ですね。デバイスの初期化時に呼ばれているので起動して最初のほうだと推測することができます。

\Engine\Source\Runtime\Engine\Private\UnrealEngine.cpp
UEngine::InitializeHMDDevice()
{
...
    XRSystem = HMDModule->CreateTrackingSystem()
...
}

CreateTrackingSystemを追うと
\Plugins\Runtime\OpenXR\Source\OpenXRHMD\Private\OpenXRHMDModule.cpp
TSharedPtr< class IXRTrackingSystem, ESPMode::ThreadSafe >
FOpenXRHMDModule::CreateTrackingSystem()
にたどり着きます。

Engine.h
TSharedPtr< class IXRTrackingSystem, ESPMode::ThreadSafe > XRSystem;

XRSystemは通常、IXRSystemインターフェースを実装したクラスのインスタンスが格納されます。具体的には、以下のようになります:

  1. IXRTrackingSystem:
    これはXRシステムの基本的なインターフェースを定義する抽象クラスです。Engine/Source/Runtime/HeadMountedDisplay/Public/IXRTrackingSystem.hに定義されています。

  2. OpenXRの実装:
    IXRTrackingSystemインターフェースを実装した独自のクラスを持っています。FOpenXRHMD (OpenXR用)

Meta Questの場合ではXRSystemが指しているのはFOpenXRHMDクラスのインスタンス。

UCameraComponentを追う

void UCameraComponent::GetCameraView(float DeltaTime, FMinimalViewInfo& DesiredView)
{
    if (IsXRHeadTrackedCamera())
    {
       HandleXRCamera();
    }
...
bool UCameraComponent::IsXRHeadTrackedCamera() const
{
	if (GEngine && GEngine->XRSystem.IsValid() && GetWorld() && GetWorld()->WorldType != EWorldType::Editor)
	{
		IXRTrackingSystem* XRSystem = GEngine->XRSystem.Get();
		auto XRCamera = XRSystem->GetXRCamera();

		if (XRCamera.IsValid())
		{
			if (XRSystem->IsHeadTrackingAllowedForWorld(*GetWorld()))
			{
				return true;
			}
		}
	}

	return false;
}




Meta Quest 3 の OpenXR サポート

Meta Quest 3 は、OpenXR 標準をサポートしています。したがって、FOpenXRHMDModule を使用して、OpenXR デバイスのトラッキング情報を取得し、OpenXR アプリケーションを実装することができます。

FOpenXRHMDModule の利点

FOpenXRHMDModule を使用することで、以下の利点があります。

  • OpenXR デバイスのトラッキング情報を取得できる

  • OpenXR アプリケーションを実装するためのインターフェースを提供する

  • OpenXR 標準に準拠した HMD デバイスに対応する

FOpenXRHMDModule の説明


FOpenXRHMDModule は、OpenXR 標準に準拠した HMD デバイスに対応するためのモジュールです。このモジュールは、OpenXR デバイスのトラッキング情報を取得し、OpenXR アプリケーションを実装するためのインターフェースを提供します。

IsHeadTrackingAllowed()
FOpenXRHMD
IXRTrackingSystem


起動時からのソース解析

\Engine\Source\Runtime\Launch\Private\Windows\LaunchWindows.cpp

int32 WINAPI WinMain(_In_ HINSTANCE hInInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ char* pCmdLine, _In_ int32 nCmdShow)
{
    int32 Result = LaunchWindowsStartup(hInInstance, hPrevInstance, pCmdLine, nCmdShow, nullptr);
    LaunchWindowsShutdown();
    return Result;
}
LAUNCH_API int32 LaunchWindowsStartup( HINSTANCE hInInstance, HINSTANCE hPrevInstance, char*, int32 nCmdShow, const TCHAR* CmdLine )
{
...
 		{
			GIsGuarded = 1;
			// Run the guarded code.
			ErrorLevel = GuardedMainWrapper( CmdLine );
			GIsGuarded = 0;
		}
...
}
LAUNCH_API int32 GuardedMainWrapper( const TCHAR* CmdLine )
{
...
	ErrorLevel = GuardedMain( CmdLine );
...
}

GuardedMainはLaunchWindowsの他に他のOSのLaunch*****で呼び出されるので実質GuardedMainがUE5.4のMainだと思う。


\Engine\Source\Runtime\Launch\Private\Launch.cpp

int32 GuardedMain( const TCHAR* CmdLine )
{
...

	FTrackedActivity::GetEngineActivity().Update(TEXT("Initializing"));
	int32 ErrorLevel = EnginePreInit( CmdLine );
...

int32 EnginePreInit( const TCHAR* CmdLine )
{
	int32 ErrorLevel = GEngineLoop.PreInit( CmdLine );

	return( ErrorLevel );
}

int32 EngineInit()
{
	int32 ErrorLevel = GEngineLoop.Init();

	return( ErrorLevel );
}
...
}


\Engine\Source\Runtime\Launch\Private\LaunchEngineLoop.cpp

int32 FEngineLoop::PreInit(int32 ArgC, TCHAR* ArgV[], const TCHAR* AdditionalCommandline)
{
	FString CmdLine = FCommandLine::BuildFromArgV(nullptr, ArgC, ArgV, AdditionalCommandline);

	// send the command line without the exe name
	return GEngineLoop.PreInit(*CmdLine);
}


int32 FEngineLoop::PreInit(const TCHAR* CmdLine)
{
#if UE_ENABLE_ARRAY_SLACK_TRACKING
	ArraySlackTrackInit();
#endif

	const int32 rv1 = PreInitPreStartupScreen(CmdLine);
	if (rv1 != 0)
	{
		PreInitContext.Cleanup();
		return rv1;
	}

	const int32 rv2 = PreInitPostStartupScreen(CmdLine);
	if (rv2 != 0)
	{
		PreInitContext.Cleanup();
		return rv2;
	}

	return 0;
}
int32 FEngineLoop::PreInitPostStartupScreen(const TCHAR* CmdLine)
{
...
	GEngine = NewObject<UEngine>(GetTransientPackage(), EngineClass);
	check(GEngine);
	GEngine->ParseCommandline()
	UE_LOG(LogInit, Log, TEXT("Initializing Game Engine..."));
	GEngine->Init(this);
	UE_LOG(LogInit, Log, TEXT("Initializing Game Engine Completed"));
...
}


Cameraコンポーネントについて

VRカメラと非VRカメラのDetailsパネルでの主な設定の違いは以下の通りです:

  1. Use Pawn Control Rotation

    • VR: オフ(通常)

    • 非VR: オン(通常)

  2. Location

    • VR:トラッキングシステムで動的に決まるためデフォルトの0,0,0で良い

  3. Field of View (FOV)

    • VRカメラのFOV設定:

      • 実際の設定値: 90.0度

この設定について、以下の点を説明します:

  1. 基本設定値
    90度のFOVは、多くのVRアプリケーションで一般的に使用される値です。これは、多くのVRヘッドセットの視野角に近い値であり、自然な視覚体験を提供します。

  2. HMDとの関係
    設定されたFOV値は、HMDの実際の視野角とは異なる場合があります。多くのVRシステムでは、この値をベースにしつつ、実際のHMDの特性に合わせて調整が行われます。

  3. パフォーマンスとの関係
    90度のFOVは、視覚的な没入感とパフォーマンスのバランスを取るために選択されることが多いです。より広いFOVは没入感を高めますが、レンダリング負荷も増加します。

  4. カスタマイズの可能性
    開発者は必要に応じてこの値を調整できます。特定のVRヘッドセットに最適化したい場合や、特殊な視覚効果を実現したい場合などに変更することがあります。

  5. プロジェクト固有の要件
    VirtualRealityテンプレートでは90度が初期値として設定されていますが、プロジェクトの要件に応じて調整することは可能です。

エンジン側で設定された値がベースとなり、それをHMDやVRシステムが解釈して最終的な視覚体験を生成します。

  1. Lens->Exposure

    • VR: すべてのチェックボックスがオフ

この状態では、以下のような状況が発生します:

  1. Auto Exposureの設定が実質的に無効化されています。

  2. Metering ModeがAuto Exposure Histogramに設定されていても、チェックボックスが外れているため機能しません。

  3. Exposure Compensationや他の露出関連の設定も、チェックボックスが外れているため適用されません。

つまり、Auto Exposureに関連する設定が存在し、値が入力されていても、チェックボックスが外れているため、これらの設定は実際のレンダリングや画面表示に影響を与えません。この設定状態では、カメラの露出は固定され、環境光の変化に自動的に適応することはありません。VR環境では、急激な明るさの変化を避けてVR酔いを防ぐために、Auto Exposureを無効にすることがあります。ただし、必要に応じてこれらの設定を有効にし、VR体験を調整することは可能です。プロジェクトの要件や目指す視覚効果に応じて、これらの設定を適切に調整することが重要です。

  1. Projection Mode

    • VR: Perspective(固定)

    • 非VR: PerspectiveまたはOrthographicを選択可能

VRカメラの設定では、ユーザーの快適性とパフォーマンスが最優先されます。一方、非VRカメラでは、ゲームプレイやビジュアル効果の要求に応じてより柔軟な設定が可能です。VR開発では、これらの違いを理解し、適切に設定することが重要です


よくわからんものメモ

class OPENXRHMD_API IOpenXRHMDModule : public IHeadMountedDisplayModule
{
	static inline IOpenXRHMDModule& Get()
	{
		return FModuleManager::LoadModuleChecked< IOpenXRHMDModule >( "OpenXRHMD" );
	}
...


いいなと思ったら応援しよう!