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!"));
}
}
}