Add setup_scene command for automated scene setup

The setup_scene command creates all required actors for rendering control:
- PostProcessVolume (unbound, with auto-exposure override)
- DirectionalLight (sun)
- SkyLight
- ExponentialHeightFog
- CineCameraActor

This allows full AI control without manual UE5 setup.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
jamestagg 2026-01-14 17:22:39 -06:00
parent bc15fac02e
commit 0a9ce7b371
3 changed files with 143 additions and 0 deletions

View File

@ -361,6 +361,11 @@ FString URalphaMCPServer::ProcessCommand(const FString& JsonCommand)
ResponseObject->SetStringField(TEXT("error"), TEXT("Missing settings"));
}
}
else if (CommandType == TEXT("setup_scene"))
{
TSharedPtr<FJsonObject> SetupResult = ParameterBridge->SetupScene();
ResponseObject = SetupResult;
}
else
{
ResponseObject->SetBoolField(TEXT("success"), false);

View File

@ -879,3 +879,138 @@ TSharedPtr<FJsonObject> URalphaParameterBridge::GetActorDetails(const FString& A
return Result;
}
// ============================================================================
// Scene Setup
// ============================================================================
TSharedPtr<FJsonObject> URalphaParameterBridge::SetupScene()
{
TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
TArray<FString> CreatedActors;
TArray<FString> ExistingActors;
UWorld* World = GetCurrentWorld();
if (!World)
{
Result->SetBoolField(TEXT("success"), false);
Result->SetStringField(TEXT("error"), TEXT("No world available"));
return Result;
}
// Check/Create PostProcessVolume
if (!FindPostProcessVolume())
{
FActorSpawnParameters SpawnParams;
SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
APostProcessVolume* PPV = World->SpawnActor<APostProcessVolume>(FVector::ZeroVector, FRotator::ZeroRotator, SpawnParams);
if (PPV)
{
PPV->bUnbound = true;
PPV->Settings.bOverride_AutoExposureBias = true;
PPV->Settings.AutoExposureBias = 0.0f;
#if WITH_EDITOR
PPV->SetActorLabel(TEXT("Ralpha_PostProcess"));
#endif
CreatedActors.Add(TEXT("PostProcessVolume"));
}
}
else
{
ExistingActors.Add(TEXT("PostProcessVolume"));
}
// Check/Create DirectionalLight
if (!FindDirectionalLight())
{
FActorSpawnParameters SpawnParams;
SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
ADirectionalLight* Light = World->SpawnActor<ADirectionalLight>(FVector::ZeroVector, FRotator(-45.0f, 0.0f, 0.0f), SpawnParams);
if (Light)
{
#if WITH_EDITOR
Light->SetActorLabel(TEXT("Ralpha_Sun"));
#endif
CreatedActors.Add(TEXT("DirectionalLight"));
}
}
else
{
ExistingActors.Add(TEXT("DirectionalLight"));
}
// Check/Create SkyLight
if (!FindSkyLight())
{
FActorSpawnParameters SpawnParams;
SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
ASkyLight* Light = World->SpawnActor<ASkyLight>(FVector(0.0f, 0.0f, 1000.0f), FRotator::ZeroRotator, SpawnParams);
if (Light)
{
#if WITH_EDITOR
Light->SetActorLabel(TEXT("Ralpha_SkyLight"));
#endif
CreatedActors.Add(TEXT("SkyLight"));
}
}
else
{
ExistingActors.Add(TEXT("SkyLight"));
}
// Check/Create ExponentialHeightFog
if (!FindExponentialHeightFog())
{
FActorSpawnParameters SpawnParams;
SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
AExponentialHeightFog* Fog = World->SpawnActor<AExponentialHeightFog>(FVector::ZeroVector, FRotator::ZeroRotator, SpawnParams);
if (Fog)
{
#if WITH_EDITOR
Fog->SetActorLabel(TEXT("Ralpha_Fog"));
#endif
CreatedActors.Add(TEXT("ExponentialHeightFog"));
}
}
else
{
ExistingActors.Add(TEXT("ExponentialHeightFog"));
}
// Check/Create CineCameraActor
if (!FindCineCamera())
{
FActorSpawnParameters SpawnParams;
SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
ACineCameraActor* Camera = World->SpawnActor<ACineCameraActor>(FVector(0.0f, -500.0f, 200.0f), FRotator(0.0f, 90.0f, 0.0f), SpawnParams);
if (Camera)
{
#if WITH_EDITOR
Camera->SetActorLabel(TEXT("Ralpha_Camera"));
#endif
CreatedActors.Add(TEXT("CineCameraActor"));
}
}
else
{
ExistingActors.Add(TEXT("CineCameraActor"));
}
Result->SetBoolField(TEXT("success"), true);
TArray<TSharedPtr<FJsonValue>> CreatedArray;
for (const FString& Actor : CreatedActors)
{
CreatedArray.Add(MakeShared<FJsonValueString>(Actor));
}
Result->SetArrayField(TEXT("created"), CreatedArray);
TArray<TSharedPtr<FJsonValue>> ExistingArray;
for (const FString& Actor : ExistingActors)
{
ExistingArray.Add(MakeShared<FJsonValueString>(Actor));
}
Result->SetArrayField(TEXT("existing"), ExistingArray);
return Result;
}

View File

@ -63,6 +63,9 @@ public:
bool SetActorTransform(const FString& ActorId, const FVector* Location, const FRotator* Rotation, const float* Scale, bool bRelative);
TSharedPtr<FJsonObject> GetActorDetails(const FString& ActorId, bool bIncludeComponents, bool bIncludeMaterials);
// Scene Setup - creates required actors for rendering control
TSharedPtr<FJsonObject> SetupScene();
private:
// Find actors of specific types in the world
APostProcessVolume* FindPostProcessVolume();