Using USceneCaptureComponent2D to create a snapshot at runtime

I’d like to be able to take a snapshot at runtime in certain moments. So, when some event occurs, I create a USceneCaptureComponent2D, place it where the player camera is located, take the snapshot and set it in a UMG widget. This is what I would like to accomplish.

This is how I’m creating the USceneCaptureComponent2D:

// Creating the render target
UTextureRenderTarget2D *renderTarget2D = NewObject<UTextureRenderTarget2D>();

renderTarget2D->bHDR = false;
renderTarget2D->ClearColor = FLinearColor::Blue;
renderTarget2D->InitAutoFormat(512, 512);

// Getting the camera's transform and creating the scene capturere actor
FTransform cameraTransform = UGameplayStatics::GetPlayerCameraManager(GetWorld(), 0)->GetRootComponent()->GetComponentTransform();
ASceneCapture2D *sceneCaptureActor = (ASceneCapture2D*) GetWorld()->SpawnActor<ASceneCapture2D>(ASceneCapture2D::StaticClass());

if(sceneCaptureActor != nullptr)
{
    // Getting the actual component, registering and putting it where the camera was
	USceneCaptureComponent2D *sceneCaptureComponent = sceneCaptureActor->GetCaptureComponent2D();
	sceneCaptureComponent->RegisterComponent();
	sceneCaptureComponent->SetWorldTransform(cameraTransform);

	// Setting the target
	sceneCaptureComponent->TextureTarget = renderTarget2D;

	// Defining some properties; the most important one is that it won't capture every frame
	sceneCaptureComponent->ProjectionType = ECameraProjectionMode::Type::Perspective;
	sceneCaptureComponent->FOVAngle = 90.0f;
	sceneCaptureComponent->CaptureSource = ESceneCaptureSource::SCS_SceneColorHDR;
	sceneCaptureComponent->CompositeMode = ESceneCaptureCompositeMode::SCCM_Overwrite;
	sceneCaptureComponent->bCaptureOnMovement = false;
	sceneCaptureComponent->bCaptureEveryFrame = false;
	sceneCaptureComponent->MaxViewDistanceOverride = -1.0f;
	sceneCaptureComponent->bAutoActivate = true;
	sceneCaptureComponent->DetailMode = EDetailMode::DM_High;

	// Taking the snapshot
	sceneCaptureComponent->CaptureScene();

    // Telling the target to "refresh"
	renderTarget2D->UpdateResourceImmediate();

	// Creating the actual texture
	UTexture2D *newTexture = renderTarget2D->ConstructTexture2D(this, FString("Snapshot"), EObjectFlags::RF_NoFlags);

	// Calling a function that will trigger a Blueprint event, passing the texture to a UMG widget
	AddTexture(newTexture);
}

And this is the Blueprint function that receives the texture and set it to an UMG widget:

Where “TextureWidget” is an Image widget.

The result of the code is just a 512x512 blue image (I set the texture render to use blue as clear color), so it’s kind of like an empty image.

I don’t understand what I’m doing wrong…

  • Only set the location and rotation, not the full transform. No idea why this is an issue.
  • Remove UpdateResourceImmediate, it clears by default
  • Use SCS_FinalColorLDR. Not sure why, but the other mode doesn’t capture dynamic lighting.

The capture doesn’t look quite like the original, does anyone know what it could be? The contrast is higher and there’s a weird noise pattern.