Create RenderTarget Utilitiy Library for Capturing Images to Texture2D Object #47

Merged
evanvyktori merged 3 commits from Ancient23/LuckyWorldV2:main into main 2025-04-29 23:49:18 +00:00
2 changed files with 162 additions and 37 deletions
Showing only changes of commit 5cc5b232cb - Show all commits

View File

@ -1,87 +1,180 @@
// Fill out your copyright notice in the Description page of Project Settings. // Fill out your copyright notice in the Description page of Project Settings.
#include "LRRenderUtilLibrary.h" #include "LRRenderUtilLibrary.h"
#include "Components/SceneCaptureComponent2D.h" #include "Components/SceneCaptureComponent2D.h"
#include "Engine/TextureRenderTarget2D.h" #include "Engine/TextureRenderTarget2D.h"
#include "Kismet/KismetRenderingLibrary.h" #include "Kismet/KismetRenderingLibrary.h"
#include "GameFramework/Actor.h"
#include "Engine/World.h"
void ULRRenderUtilLibrary::SetupSceneCaptureForMesh(USceneCaptureComponent2D* SceneCapture, UStaticMeshComponent* MeshComp) void ULRRenderUtilLibrary::SetupSceneCaptureForMesh(
USceneCaptureComponent2D* SceneCapture,
UStaticMeshComponent* MeshComp,
TEnumAsByte<enum ESceneCaptureSource> CaptureSource)
{ {
if (!SceneCapture || !MeshComp) if (!SceneCapture || !MeshComp)
{ {
UE_LOG(LogTemp, Warning, TEXT("SetupSceneCaptureForMesh: Invalid SceneCapture or MeshComp"));
return;
}
if (!MeshComp->IsValidLowLevel())
{
UE_LOG(LogTemp, Warning, TEXT("SetupSceneCaptureForMesh: MeshComp is not valid"));
return; return;
} }
// Set the scene capture to focus on the mesh // Set the scene capture to focus on the mesh
SceneCapture->ShowOnlyComponent(MeshComp); SceneCapture->ShowOnlyComponent(MeshComp);
SceneCapture->CaptureSource = ESceneCaptureSource::SCS_BaseColor; SceneCapture->CaptureSource = CaptureSource;
SceneCapture->bCaptureEveryFrame = false; SceneCapture->bCaptureEveryFrame = false;
SceneCapture->bCaptureOnMovement = false; SceneCapture->bCaptureOnMovement = false;
SceneCapture->FOVAngle = 90.f; SceneCapture->FOVAngle = 90.f;
// Set a solid background color (black by default) // Set a solid background color
SceneCapture->CompositeMode = ESceneCaptureCompositeMode::SCCM_Overwrite; SceneCapture->CompositeMode = ESceneCaptureCompositeMode::SCCM_Overwrite;
SceneCapture->TextureTarget->ClearColor = FLinearColor::Transparent;
// Ensure we have a valid texture target
if (SceneCapture->TextureTarget)
{
SceneCapture->TextureTarget->ClearColor = FLinearColor::Transparent;
}
else
{
UE_LOG(LogTemp, Warning, TEXT("SetupSceneCaptureForMesh: TextureTarget is null"));
return;
}
// Adjust the transform to frame the mesh // Adjust the transform to frame the mesh
FVector MeshBounds = MeshComp->Bounds.BoxExtent; FVector MeshBounds = MeshComp->Bounds.BoxExtent;
FVector MeshOrigin = MeshComp->Bounds.Origin; FVector MeshOrigin = MeshComp->Bounds.Origin;
// Calculate the camera distance // Calculate the camera distance based on mesh size
float CameraDistance = MeshBounds.Size() * 1.1f; // Adjust multiplier as needed float MaxExtent = FMath::Max3(MeshBounds.X, MeshBounds.Y, MeshBounds.Z);
float CameraDistance = MaxExtent * 2.5f; // Adjusted to ensure mesh fits in view
// Calculate the camera location // Calculate the camera location - position from front of mesh (+X axis)
FVector CameraLocation = MeshOrigin + FVector(CameraDistance, 0.f, 0.f); // Default to capturing from the +X axis FVector CameraLocation = MeshOrigin + FVector(CameraDistance, 0.f, 0.f);
// Calculate the camera rotation // Calculate the camera rotation to look at mesh center
FRotator CameraRotation = (MeshOrigin - CameraLocation).Rotation(); FRotator CameraRotation = (MeshOrigin - CameraLocation).Rotation();
SceneCapture->SetWorldLocationAndRotation(CameraLocation, CameraRotation); // Adjust rotation as needed SceneCapture->SetWorldLocationAndRotation(CameraLocation, CameraRotation);
// Register component to make sure it will render
if (!SceneCapture->IsRegistered())
{
SceneCapture->RegisterComponent();
}
} }
UTextureRenderTarget2D* ULRRenderUtilLibrary::CaptureMeshToRenderTarget(UStaticMeshComponent* MeshComp, const FVector2D& ImageSize, UObject* WorldContextObject) UTextureRenderTarget2D* ULRRenderUtilLibrary::CaptureMeshToRenderTarget(
UStaticMeshComponent* MeshComp,
const FVector2D& ImageSize,
UObject* WorldContextObject,
TEnumAsByte<enum ESceneCaptureSource> CaptureSource)
{ {
if (!MeshComp || !WorldContextObject) if (!MeshComp || !WorldContextObject || !WorldContextObject->GetWorld())
{ {
UE_LOG(LogTemp, Warning, TEXT("CaptureMeshToRenderTarget: Invalid parameters"));
return nullptr; return nullptr;
} }
// Create a render target // Create a render target with proper size
UTextureRenderTarget2D* RenderTarget = UKismetRenderingLibrary::CreateRenderTarget2D( UTextureRenderTarget2D* RenderTarget = UKismetRenderingLibrary::CreateRenderTarget2D(
WorldContextObject, ImageSize.X, ImageSize.Y, ETextureRenderTargetFormat::RTF_RGBA8); WorldContextObject,
FMath::Max(32, static_cast<int32>(ImageSize.X)),
FMath::Max(32, static_cast<int32>(ImageSize.Y)),
ETextureRenderTargetFormat::RTF_RGBA8);
if (!RenderTarget) if (!RenderTarget)
{ {
UE_LOG(LogTemp, Warning, TEXT("CaptureMeshToRenderTarget: Failed to create render target"));
return nullptr; return nullptr;
} }
// Create a temporary actor to hold the scene capture component // Create a temporary actor to hold the scene capture component
AActor* TempActor = WorldContextObject->GetWorld()->SpawnActor<AActor>(); AActor* TempActor = WorldContextObject->GetWorld()->SpawnActor<AActor>();
if (!TempActor)
{
UE_LOG(LogTemp, Warning, TEXT("CaptureMeshToRenderTarget: Failed to spawn temporary actor"));
return RenderTarget;
}
// Create a root component if it doesn't exist
if (!TempActor->GetRootComponent())
{
USceneComponent* RootComponent = NewObject<USceneComponent>(TempActor, TEXT("RootComponent"));
TempActor->SetRootComponent(RootComponent);
RootComponent->RegisterComponent();
}
// Create and set up scene capture component
USceneCaptureComponent2D* SceneCapture = NewObject<USceneCaptureComponent2D>(TempActor); USceneCaptureComponent2D* SceneCapture = NewObject<USceneCaptureComponent2D>(TempActor);
SceneCapture->AttachToComponent(TempActor->GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform); if (SceneCapture)
SceneCapture->TextureTarget = RenderTarget; {
SceneCapture->RegisterComponent();
SceneCapture->AttachToComponent(TempActor->GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform);
SceneCapture->TextureTarget = RenderTarget;
// Setup the scene capture // Setup the scene capture
SetupSceneCaptureForMesh(SceneCapture, MeshComp); SetupSceneCaptureForMesh(SceneCapture, MeshComp, CaptureSource);
UKismetRenderingLibrary::ClearRenderTarget2D(WorldContextObject, SceneCapture->TextureTarget, FLinearColor::Transparent); // Clear the render target
UKismetRenderingLibrary::ClearRenderTarget2D(WorldContextObject, RenderTarget, FLinearColor::Transparent);
// Disable post-processing effects // Disable post-processing effects
SceneCapture->PostProcessSettings.bOverride_AutoExposureMethod = true; SceneCapture->PostProcessSettings.bOverride_AutoExposureMethod = true;
SceneCapture->PostProcessSettings.AutoExposureMethod = EAutoExposureMethod::AEM_Manual; SceneCapture->PostProcessSettings.AutoExposureMethod = EAutoExposureMethod::AEM_Manual;
SceneCapture->PostProcessSettings.bOverride_AutoExposureBias = true; SceneCapture->PostProcessSettings.bOverride_AutoExposureBias = true;
SceneCapture->PostProcessSettings.AutoExposureBias = 1.0f; SceneCapture->PostProcessSettings.AutoExposureBias = 1.0f;
SceneCapture->PostProcessSettings.bOverride_BloomIntensity = true; SceneCapture->PostProcessSettings.bOverride_BloomIntensity = true;
SceneCapture->PostProcessSettings.BloomIntensity = 0.0f; SceneCapture->PostProcessSettings.BloomIntensity = 0.0f;
// Trigger a one-time capture // Trigger a one-time capture
SceneCapture->CaptureScene(); SceneCapture->CaptureScene();
// Force the GPU to complete rendering
FlushRenderingCommands();
}
else
{
UE_LOG(LogTemp, Warning, TEXT("CaptureMeshToRenderTarget: Failed to create scene capture component"));
}
// Clean up the temporary actor // Clean up the temporary actor
TempActor->Destroy(); TempActor->Destroy();
return RenderTarget; return RenderTarget;
} }
bool ULRRenderUtilLibrary::CaptureSceneNow(USceneCaptureComponent2D* SceneCapture)
{
if (!SceneCapture || !SceneCapture->IsValidLowLevel())
{
UE_LOG(LogTemp, Warning, TEXT("CaptureSceneNow: Invalid scene capture component"));
return false;
}
if (!SceneCapture->TextureTarget)
{
UE_LOG(LogTemp, Warning, TEXT("CaptureSceneNow: Scene capture has no texture target"));
return false;
}
// Ensure component is registered
if (!SceneCapture->IsRegistered())
{
SceneCapture->RegisterComponent();
}
// Trigger the capture
SceneCapture->CaptureScene();
// Force the GPU to complete rendering
FlushRenderingCommands();
return true;
}

View File

@ -6,20 +6,52 @@
#include "Kismet/BlueprintFunctionLibrary.h" #include "Kismet/BlueprintFunctionLibrary.h"
#include "LRRenderUtilLibrary.generated.h" #include "LRRenderUtilLibrary.generated.h"
class USceneCaptureComponent2D;
class UTextureRenderTarget2D;
class UStaticMeshComponent;
/** /**
* * Utility library for capturing and rendering objects in the Lucky Robots system
*/ */
UCLASS() UCLASS(BlueprintType, Blueprintable)
class LUCKYWORLDV2_API ULRRenderUtilLibrary : public UBlueprintFunctionLibrary class LUCKYWORLDV2_API ULRRenderUtilLibrary : public UBlueprintFunctionLibrary
{ {
GENERATED_BODY() GENERATED_BODY()
public: public:
/**
* Captures a static mesh component to a render target texture
* @param MeshComp The static mesh component to capture
* @param ImageSize The size of the output image
* @param WorldContextObject The world context
* @param CaptureSource The type of data to capture (default is BaseColor)
* @return The rendered texture
*/
UFUNCTION(BlueprintCallable, Category = "Lucky Robots|Render Utilities")
static UTextureRenderTarget2D* CaptureMeshToRenderTarget(
UStaticMeshComponent* MeshComp,
const FVector2D& ImageSize,
UFUNCTION(BlueprintCallable, Category = "Render Utilities") UObject* WorldContextObject,
UTextureRenderTarget2D* CaptureMeshToRenderTarget(UStaticMeshComponent* MeshComp, const FVector2D& ImageSize, UObject* WorldContextObject); TEnumAsByte<enum ESceneCaptureSource> CaptureSource = ESceneCaptureSource::SCS_BaseColor);
private: /**
void SetupSceneCaptureForMesh(USceneCaptureComponent2D* SceneCapture, UStaticMeshComponent* MeshComp); * Sets up a scene capture component to focus on a specific mesh
* @param SceneCapture The scene capture component to set up
* @param MeshComp The static mesh component to focus on
* @param CaptureSource The type of data to capture (default is BaseColor)
*/
UFUNCTION(BlueprintCallable, Category = "Lucky Robots|Render Utilities")
static void SetupSceneCaptureForMesh(
USceneCaptureComponent2D* SceneCapture,
UStaticMeshComponent* MeshComp,
TEnumAsByte<enum ESceneCaptureSource> CaptureSource = ESceneCaptureSource::SCS_BaseColor);
/**
* Captures the current view of a scene capture component to its render target
* @param SceneCapture The scene capture component to trigger
* @return Success status
*/
UFUNCTION(BlueprintCallable, Category = "Lucky Robots|Render Utilities")
static bool CaptureSceneNow(USceneCaptureComponent2D* SceneCapture);
}; };