I’ve copied over the post process settings from my global post process volume in the blueprint. I’ve also since this post gone through each setting one by one and verifying they match up and I still couldn’t ever get it to look the same.
Path tracer is another option I’ve looked at however it only works on certain graphics cards which isn’t ideal.
I suspect there is a bug in UE 5.5 when it comes to screenshots in shipping builds, as these functions work in UE 5.4 regardless of build:
void UMyBlueprintFunctionLibrary::ConsoleCommandScreenshot(const FString FilePath, APlayerController* PlayerController)
{
PlayerController->ConsoleCommand(FString::Printf(TEXT("HighResShot 1 filename=\"%s\""), *FilePath));
}
void UMyBlueprintFunctionLibrary::FScreenshotRequestScreenshot(const FString FilePath)
{
if (!GEngine || !GEngine->GameViewport) return;
FViewport* Viewport = GEngine->GameViewport->Viewport;
if (!Viewport) return;
FIntPoint Size = Viewport->GetSizeXY();
GetHighResScreenshotConfig().SetResolution(Size.X, Size.Y);
GetHighResScreenshotConfig().FilenameOverride = FilePath;
FScreenshotRequest::RequestScreenshot(false);
}
I’ve also tried reading pixel data from the viewport directly, but this also doesn’t work in shipping builds for both UE 5.5 and UE 5.4:
void UMyBlueprintFunctionLibrary::ViewportReadPixelsScreenshot(const FString FilePath)
{
if (!GEngine || !GEngine->GameViewport) return;
// Access the game viewport
FViewport* Viewport = GEngine->GameViewport->Viewport;
if (!Viewport) return;
// Capture the screenshot
TArray<FColor> Bitmap;
bool bReadPixels = Viewport->ReadPixels(Bitmap);
if (!bReadPixels)
{
UE_LOG(LogTemp, Error, TEXT("Failed to read pixels from the viewport."));
return;
}
for (FColor& Pixel : Bitmap)
{
// Set each pixel to be fully opaque
Pixel.A = 255;
}
FIntPoint Size = Viewport->GetSizeXY();
// Compress the Bitmap to a PNG format
FImageView Image(Bitmap.GetData(), Size.X, Size.Y);
bool bSaved = FImageUtils::SaveImageByExtension(*FilePath, Image);
if (bSaved)
{
UE_LOG(LogTemp, Log, TEXT("Screenshot saved to: %s"), *FilePath);
}
else
{
UE_LOG(LogTemp, Error, TEXT("Failed to save screenshot to: %s"), *FilePath);
}
}
void UMyBlueprintFunctionLibrary::ViewportReadSurfaceDataScreenshot(const FString FilePath)
{
if (!GEngine || !GEngine->GameViewport) return;
// Access the game viewport
FViewport* Viewport = GEngine->GameViewport->Viewport;
if (!Viewport) return;
FIntPoint Size = Viewport->GetSizeXY();
FTextureRHIRef RenderTarget = Viewport->GetRenderTargetTexture();
if (!RenderTarget) return;
// Enqueue the rendering command
ENQUEUE_RENDER_COMMAND(CaptureScreenshotCommand)(
[RenderTarget, FilePath, Size](FRHICommandListImmediate& RHICmdList)
{
// Read pixel data from the render target
TArray<FColor> Bitmap;
FReadSurfaceDataFlags ReadPixelFlags(RCM_UNorm);
RHICmdList.ReadSurfaceData(RenderTarget, FIntRect(0, 0, Size.X, Size.Y), Bitmap, ReadPixelFlags);
for (FColor& Pixel : Bitmap)
{
// Set each pixel to be fully opaque
Pixel.A = 255;
}
// Compress the Bitmap to a PNG format
FImageView Image(Bitmap.GetData(), Size.X, Size.Y);
bool bSaved = FImageUtils::SaveImageByExtension(*FilePath, Image);
if (bSaved)
{
UE_LOG(LogTemp, Log, TEXT("Screenshot saved to: %s"), *FilePath);
}
else
{
UE_LOG(LogTemp, Error, TEXT("Failed to save screenshot to: %s"), *FilePath);
}
}
);
}
ViewportReadPixelsScreenshot
fails in shipping builds as Viewport->ReadPixels(Bitmap)
returns an array of black pixels.
ViewportReadSurfaceDataScreenshot
fails in shipping builds as Viewport->GetRenderTargetTexture();
returns a nullptr. Both functions work in any other build.
At this stage I’ve tried everything I can think of and I’m either going to downgrade to UE5.4 or just go with the render target solution above and accept that it won’t look identical. Unless anyone else has any suggestions?