Recursive Rendering In UE5

Edit:
Revised version of the update. Works with deferred rendering!


void APortal::UpdatePortalView()
{
	// Increase current frame count.
	currentFrameCount++;

	// Get cameras post-processing settings.
	portalCapture->PostProcessSettings = portalPawn->camera->PostProcessSettings;

	if (isInited == false) {
		// Setup clip plane to cut out objects between the camera and the back of the portal.
	portalCapture->bEnableClipPlane = true;
	portalCapture->bOverride_CustomNearClippingPlane = true;
	portalCapture->ClipPlaneNormal = pTargetPortal->portalMesh->GetForwardVector();
	portalCapture->ClipPlaneBase = pTargetPortal->portalMesh->GetComponentLocation() - (portalCapture->ClipPlaneNormal * 1.0f);

	// Get the Projection Matrix from the players camera view settings.
	UPortalPlayer* portalPlayer = Cast<UPortalPlayer>(portalController->GetLocalPlayer());
	CHECK_DESTROY(LogPortal, !portalPlayer, "UpdatePortalView: Portal player class couldn't be found in the portal %s.", *GetName());
	portalCapture->bUseCustomProjectionMatrix = true;
	portalCapture->CustomProjectionMatrix = portalPlayer->GetCameraProjectionMatrix();
	portalCapture->bCaptureEveryFrame = false;
	portalCapture->bCaptureOnMovement = false;
	//portalCapture->bAlwaysPersistRenderingState = true;
	isInited = true;
	}
	// Get reference to player camera.		
	UCameraComponent* playerCamera = portalPawn->camera;
	// Get the position of the main camera transform to the target portal.
	

	if (DotProductCull == true) {
		FRotator lookRot = UKismetMathLibrary::FindLookAtRotation(GetActorLocation(), playerCamera->GetComponentLocation());
		float dp = FVector::DotProduct(UKismetMathLibrary::Conv_RotatorToVector(lookRot), playerCamera->GetForwardVector());
		if (dp > 0) {
			//GEngine->AddOnScreenDebugMessage(-1, 1, FColor::Orange, "Skipping " + GetName());
			return;
		}
	}

	FVector newCameraLocation = ConvertLocationToPortal(playerCamera->GetComponentLocation(), this, pTargetPortal);
	FRotator newCameraRotation = ConvertRotationToPortal(playerCamera->GetComponentRotation(), this, pTargetPortal);

	FVector recursiveCamLoc;
	FRotator recursiveCamRot;

	recursiveCamLoc = newCameraLocation;
	recursiveCamRot = newCameraRotation;

	// Recurse backwards for the max number of recursions and render to the texture each time overlaying each portal view.
	for (int i = recursionAmount; i >= 0; i--)
	{
		// Update location of the scene capture.
		recursiveCamLoc = newCameraLocation;
		recursiveCamRot = newCameraRotation;

		for (int p = 0; p < i; p++)
		{
			recursiveCamLoc = ConvertLocationToPortal(recursiveCamLoc, this, pTargetPortal);
			recursiveCamRot = ConvertRotationToPortal(recursiveCamRot, this, pTargetPortal);
		}

		portalCapture->SetWorldLocationAndRotation(recursiveCamLoc, recursiveCamRot);

		// Use-full for debugging convert transform to target function on the camera.
		if (debugCameraTransform) DrawDebugBox(GetWorld(), recursiveCamLoc, FVector(10.0f), recursiveCamRot.Quaternion(), FColor::Red, false, 0.05f, 0.0f, 2.0f);

		// Set portal to not be rendered if its the first recursion event.
		// NOTE: Caps off the end so theres no visual glitches.
		if (i == recursionAmount) portalMesh->SetVisibility(false);

		// Update the portal scene capture to render it to the RT.
		//portalCapture->CaptureScene();			


		FSceneInterface* Scene = GetWorld()->Scene;
		portalCapture->UpdateDeferredCaptures(Scene);
		portalCapture->CaptureSceneDeferred();

		// Set portal to be rendered for next recursion.
		if (i == recursionAmount) {			
			GetWorld()->SendAllEndOfFrameUpdates();			
			portalMesh->SetVisibility(true);
		}
	}
}

in header added

UPROPERTY()
	bool isInited = false;

The key was sending the update on the first pass so it gets registered !. No more black mirrors in the final (well first really) pass.