Hello, so my issue is that I can’t save a screenshot through code. Now, my basic idea was to make it so that every second TakeScreenshot() function gets called, and then I take a screenshot that’s corresponding to my selected camera (I have multiple cameras and I want to take a screenshot from each one of them every second) and then I want to save them in screenshot folder.
My TakeScreenshot() function currently looks like this:
void ARealCar::TakeScreenshot()
{
APlayerController* PlayerController = GetWorld()->GetFirstPlayerController();
if (!PlayerController)
{
UE_LOG(LogTemp, Warning, TEXT("PlayerController is null"));
return;
}
// Store the original view target
OriginalViewTarget = PlayerController->GetViewTarget();
// Switch to each camera and capture a screenshot
if (Camera1 && PlayerController)
{
PlayerController->SetViewTarget(Camera1->GetOwner());
// Remove the callback to avoid multiple additions
UGameViewportClient* GameViewportClient = GEngine->GameViewport;
GameViewportClient->OnScreenshotCaptured().RemoveAll(this);
// Capture the screenshot with a callback
GameViewportClient->OnScreenshotCaptured().AddUObject(this, &ARealCar::OnScreenshotCaptured);
// Trigger the screenshot capture
UE_LOG(LogTemp, Warning, TEXT("Calling RequestScreenshot for %s"), *Camera1->GetName());
FScreenshotRequest::RequestScreenshot(
GetScreenshotPath(),
false,
false
);
}
ScreenshotIndex++;
}
so, it does end up adding OnScreenshotCaptured() delegate and then, once I call RequestScreenshot() it does actually execute. And OnScreenshotCaptured() looks like this:
void ARealCar::OnScreenshotCaptured(int32 SizeX, int32 SizeY, const TArray<FColor>& Bitmap)
{
UE_LOG(LogTemp, Warning, TEXT("Started OnScreenshotCaptured"));
// Generate a filename based on the current date
const FDateTime Now = FDateTime::Now();
// store screenshot in Project directory next to main UProject/EXE based on the build type
#if WITH_EDITOR
const FString ImageDirectory = FString::Printf(TEXT("%s%s"), *FPaths::ProjectDir(), TEXT("Screenshots"));
#else
const FString ImageDirectory = FString::Printf(TEXT("%s/../%s"), *FPaths::ProjectDir(), TEXT("Screenshots"));
#endif
const FString ImageFilename = FString::Printf(TEXT("%s/Screenshot_%d%02d%02d_%02d%02d%02d_%03d.png"), *ImageDirectory, Now.GetYear(), Now.GetMonth(), Now.GetDay(), Now.GetHour(), Now.GetMinute(), Now.GetSecond(), Now.GetMillisecond());
FScreenshotRequest::RequestScreenshot(ImageFilename, false, false);
UE_LOG(LogTemp, Warning, TEXT("Saved screenshot at; %s"), *ImageFilename);
}
So here i’m getting the filename, and calling FScreenshotRequest::RequestScreenshot()
to supposedly save the image. And when I run the game, each second the OnScreenCaptured() gets called, and my log looks something like this:
LogTemp: Warning: Calling RequestScreenshot for Camera1
LogTemp: Warning: Started OnScreenshotCaptured
LogTemp: Warning: Saved screenshot at; …/…/…/…/…/projects/Games/ZPD/Screenshots/Screenshot_20231126_120731_855.png
As for the screenshot saving logic, I took it from here, though I had to modify const FString ImageDirectory = FString::Printf(TEXT("%s%s"), *FPaths::ProjectDir()
and remove the slash between %s/%s
to prevent it from adding a double slash between/ZPD//Screenshots
. I don’t know how outdated and deprecated that code is, but i couldn’t really find any other guide that does something like that. Also it’s important that I don’t slow down the game while taking the screenshots (like it happens with high-res screenshots), as well as that I don’t actually switch my view to the camera that I want to take a screenshot from (that’s why i’m using PlayerController->SetViewTarget(Camera1->GetOwner());
which seems to not change my view of the camera.
So yeah, any help would be appreciated. Thanks!