Backend: - Add /api/v1/ue/* endpoints (compute-points, cables, landing-points, satellites, status) returning flat JSON optimised for UE5 C++ parsing UE5 client (ue_client/): - PlanetDataManager: HTTP fetch + local mock JSON loader, spawns ComputePointActors - ComputePointActor / InteractiveObjectBase: hover/select state, material switching - GlobeInteractionComponent: drag-to-rotate via CesiumGeoreference origin shift, inertia, zoom - StereoRenderingManager: runtime SbS/TbB stereo toggle, IPD control (format TBD) - MotionCaptureInterface: protocol-agnostic gesture/rotate/zoom delegate interface (impl TBD) - PlanetPlayerController: unified mouse + motion-capture input routing - PlanetGameMode, Build.cs, Config, mock data Docs: - ue5_mvp_fused_plan.md updated to v3.0 for LED display context - ue_client_setup_guide.md: step-by-step editor setup guide - ue_todo.md: pending items blocked on vendor answers (stereo format + mocap protocol) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
132 lines
4.2 KiB
C++
132 lines
4.2 KiB
C++
#include "StereoRenderingManager.h"
|
||
#include "Engine/Engine.h"
|
||
#include "Engine/World.h"
|
||
|
||
AStereoRenderingManager::AStereoRenderingManager()
|
||
{
|
||
PrimaryActorTick.bCanEverTick = false;
|
||
}
|
||
|
||
void AStereoRenderingManager::BeginPlay()
|
||
{
|
||
Super::BeginPlay();
|
||
|
||
if (bAutoEnableOnPlay)
|
||
{
|
||
EnableStereo(DefaultStereoMode);
|
||
}
|
||
else
|
||
{
|
||
UE_LOG(LogTemp, Log,
|
||
TEXT("StereoRenderingManager: 立体渲染未自动启动。"
|
||
"确认视频处理器格式后,在 Details 面板勾选 bAutoEnableOnPlay。"));
|
||
}
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// 公开 API
|
||
// ---------------------------------------------------------------------------
|
||
|
||
void AStereoRenderingManager::EnableStereo(EStereoOutputMode Mode)
|
||
{
|
||
if (Mode == EStereoOutputMode::Off)
|
||
{
|
||
DisableStereo();
|
||
return;
|
||
}
|
||
|
||
// TODO(供应商回复后检查这里的命令是否与视频处理器匹配):
|
||
//
|
||
// UE5 内置立体模式通过以下方式启用。
|
||
// 如果视频处理器需要特殊格式,可能需要修改 stereo mode 参数。
|
||
//
|
||
// 参考命令:
|
||
// stereo on —— 开启立体渲染(需要 VR 设备或自定义立体设备)
|
||
// r.StereoRendering 1 —— 软件层立体渲染标志
|
||
// vr.StereoMode <n> —— 0=SbS full, 1=SbS half, 2=TbB full, 3=TbB half
|
||
//
|
||
// 目前使用 r.StereoRendering 的"双视口"方式,兼容性最好。
|
||
|
||
switch (Mode)
|
||
{
|
||
case EStereoOutputMode::SideBySide:
|
||
// Side-by-Side:左半=左眼,右半=右眼,总分辨率 2x 宽
|
||
ExecConsoleCommand(TEXT("r.StereoRendering 1"));
|
||
ExecConsoleCommand(TEXT("stereo on"));
|
||
ExecConsoleCommand(TEXT("vr.StereoMode 0")); // TODO: 根据实际效果调整
|
||
break;
|
||
|
||
case EStereoOutputMode::TopBottom:
|
||
// Top-Bottom:上半=左眼,下半=右眼,总分辨率 2x 高
|
||
ExecConsoleCommand(TEXT("r.StereoRendering 1"));
|
||
ExecConsoleCommand(TEXT("stereo on"));
|
||
ExecConsoleCommand(TEXT("vr.StereoMode 2")); // TODO: 根据实际效果调整
|
||
break;
|
||
|
||
case EStereoOutputMode::FrameSequential:
|
||
// 本项目屏幕 60Hz,帧序列需要 120Hz,暂不支持
|
||
UE_LOG(LogTemp, Warning,
|
||
TEXT("StereoRenderingManager: Frame Sequential 需要 120Hz 输出,"
|
||
"当前屏幕规格不支持,已忽略。"));
|
||
return;
|
||
|
||
default: break;
|
||
}
|
||
|
||
// 设置 IPD
|
||
SetIPD(IPDCm);
|
||
|
||
bStereoActive = true;
|
||
CurrentMode = Mode;
|
||
UE_LOG(LogTemp, Log, TEXT("StereoRenderingManager: 立体渲染已开启,模式=%s,IPD=%.1fcm"),
|
||
*ModeToString(Mode), IPDCm);
|
||
}
|
||
|
||
void AStereoRenderingManager::DisableStereo()
|
||
{
|
||
ExecConsoleCommand(TEXT("stereo off"));
|
||
ExecConsoleCommand(TEXT("r.StereoRendering 0"));
|
||
bStereoActive = false;
|
||
CurrentMode = EStereoOutputMode::Off;
|
||
UE_LOG(LogTemp, Log, TEXT("StereoRenderingManager: 立体渲染已关闭,切回 2D"));
|
||
}
|
||
|
||
void AStereoRenderingManager::ToggleStereo()
|
||
{
|
||
if (bStereoActive)
|
||
DisableStereo();
|
||
else
|
||
EnableStereo(DefaultStereoMode);
|
||
}
|
||
|
||
void AStereoRenderingManager::SetIPD(float NewIPDCm)
|
||
{
|
||
IPDCm = FMath::Clamp(NewIPDCm, 1.f, 10.f);
|
||
// UE5 以米为单位设置 IPD
|
||
FString Cmd = FString::Printf(TEXT("vr.HMDIPDInMeters %.4f"), IPDCm / 100.f);
|
||
ExecConsoleCommand(Cmd);
|
||
}
|
||
|
||
// ---------------------------------------------------------------------------
|
||
// 内部工具
|
||
// ---------------------------------------------------------------------------
|
||
|
||
void AStereoRenderingManager::ExecConsoleCommand(const FString& Cmd)
|
||
{
|
||
if (GEngine)
|
||
{
|
||
GEngine->Exec(GetWorld(), *Cmd);
|
||
}
|
||
}
|
||
|
||
FString AStereoRenderingManager::ModeToString(EStereoOutputMode Mode)
|
||
{
|
||
switch (Mode)
|
||
{
|
||
case EStereoOutputMode::SideBySide: return TEXT("SideBySide");
|
||
case EStereoOutputMode::TopBottom: return TEXT("TopBottom");
|
||
case EStereoOutputMode::FrameSequential: return TEXT("FrameSequential");
|
||
default: return TEXT("Off");
|
||
}
|
||
}
|