UE5 - Alpha inverted- USceneCaptureComponent2D capture transparent background scene

UE v5.3.2

I have the following Actor to capture scene into a PNG image. I want it renders a person with transparent background but I got something inverted.

Here is my project setting

Why Alpha is inverted? Am I doing something wrong? I can only invert it back pixel by pixel? that is low-efficient because I am trying to stream the scene.

UCLASS()
class MYPROJECT2_API ASceneStreamProducer : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ASceneStreamProducer();


	UPROPERTY(EditAnywhere, Category = "Output Information", meta = (ClampMin = "32", ClampMax = "4096", UIMin = "32", UIMax = "4096"))
	uint32 ResolutionX;

	UPROPERTY(EditAnywhere, Category = "Output Information", meta = (ClampMin = "32", ClampMax = "4096", UIMin = "32", UIMax = "4096"))
	uint32 ResolutionY;

	UPROPERTY(EditAnywhere, Category = "Output Information", meta = (ClampMin = "20.0", ClampMax = "170.0", UIMin = "20.0", UIMax = "179.9"))
	float FieldOfView;

	UPROPERTY(EditAnywhere, Category = "Stereo Setup")
	FVector OurCameraTranslation;

	UPROPERTY(EditAnywhere, Category = "Stereo Setup")
	FQuat OurCameraRotation;


protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	UTextureRenderTarget2D* RenderTarget;
	USceneCaptureComponent2D* SceneCapture;
	UCameraComponent* OurCamera;
};



// Sets default values
ASceneStreamProducer::ASceneStreamProducer()
	: RenderTarget(0)
	, SceneCapture(0)
	, ResolutionX(1920)
	, ResolutionY(1080)
	, FieldOfView(90.0f)
	, OurCameraTranslation(0.0f, 0.0f, 0.0f)
	, OurCameraRotation(0., 0., 0., 1.)
{
	PrimaryActorTick.bCanEverTick = true;

	// Only tick once all updates regarding movement and physics have happened
	PrimaryActorTick.TickGroup = TG_PostUpdateWork;

	RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));

	// Initialize Render Target
	RenderTarget = CreateDefaultSubobject<UTextureRenderTarget2D>(TEXT("RenderTarget"));
	RenderTarget->RenderTargetFormat = ETextureRenderTargetFormat::RTF_RGBA8; // Adjust format as needed
	RenderTarget->InitAutoFormat(ResolutionX, ResolutionY); // Set desired width and height

	OurCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("ViewportCamera"));
	OurCamera->SetupAttachment(RootComponent);

	SceneCapture = CreateDefaultSubobject<USceneCaptureComponent2D>(TEXT("SceneCapture"));
	SceneCapture->SetupAttachment(OurCamera);


	UE_LOG(LogTemp, Warning, TEXT("ASceneStreamProducer has been created!"));

}

// Called when the game starts or when spawned
void ASceneStreamProducer::BeginPlay()
{
	Super::BeginPlay();
	
	UE_LOG(LogTemp, Warning, TEXT("ASceneStreamProducer BeginPlay!"));


	OurCamera->FieldOfView = FieldOfView;
	SceneCapture->FOVAngle = FieldOfView;

	OurCamera->SetRelativeLocation(OurCameraTranslation);
	OurCamera->SetRelativeRotation(OurCameraRotation);


	RenderTarget = NewObject<UTextureRenderTarget2D>();
	RenderTarget->InitCustomFormat(ResolutionX, ResolutionY, EPixelFormat::PF_B8G8R8A8, true);
	RenderTarget->ClearColor = FLinearColor::Transparent;
	RenderTarget->UpdateResourceImmediate();

	
	SceneCapture->CaptureSource = SCS_FinalColorHDR;
	SceneCapture->TextureTarget = RenderTarget;
	SceneCapture->bCaptureEveryFrame = true;
}

// Called every frame
void ASceneStreamProducer::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	auto RenderTargetResource = RenderTarget->GameThread_GetRenderTargetResource();

	if (RenderTargetResource)
	{
		TArray<FColor> PixelBuffer;
		RenderTargetResource->ReadPixels(PixelBuffer);

		const int32 Width = RenderTargetResource->GetSizeX();
		const int32 Height = RenderTargetResource->GetSizeY();

		// Create an FHdrImageWrapper object
		IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
		TSharedPtr<IImageWrapper> ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::PNG);

		if (ImageWrapper.IsValid())
		{
			// Set the raw pixel data from buffer8
			ImageWrapper->SetRaw(PixelBuffer.GetData(), Width * Height * 4, Width, Height, ERGBFormat::BGRA, 8);

			// Compress the image data
			TArray64<uint8> ImageData = ImageWrapper->GetCompressed();
			// Specify a desired file path
			FString FilePath = "F:\\projects\\ar_muxer\\output\\FrameCapture.png";
			FFileHelper::SaveArrayToFile(ImageData, *FilePath);
			UE_LOG(LogTemp, Warning, TEXT("Frame saved to: %s"), *FilePath);
		}
		else
		{
			UE_LOG(LogTemp, Error, TEXT("Failed to create image wrapper!"));
		}
	}
}
1 Like

Take the alpha and inside of the RT Texture sample of the Render to texture node add a one minus node before connecting to the alpha channel (inside of the material containing the final render target)

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.