diff --git a/Source/LuckyWorldV2/Private/LRRenderUtilLibrary.cpp b/Source/LuckyWorldV2/Private/LRRenderUtilLibrary.cpp index 6db149f5..e5397ce5 100644 --- a/Source/LuckyWorldV2/Private/LRRenderUtilLibrary.cpp +++ b/Source/LuckyWorldV2/Private/LRRenderUtilLibrary.cpp @@ -1,87 +1,180 @@ // Fill out your copyright notice in the Description page of Project Settings. - #include "LRRenderUtilLibrary.h" #include "Components/SceneCaptureComponent2D.h" #include "Engine/TextureRenderTarget2D.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 CaptureSource) { 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; } // Set the scene capture to focus on the mesh SceneCapture->ShowOnlyComponent(MeshComp); - SceneCapture->CaptureSource = ESceneCaptureSource::SCS_BaseColor; + SceneCapture->CaptureSource = CaptureSource; SceneCapture->bCaptureEveryFrame = false; SceneCapture->bCaptureOnMovement = false; SceneCapture->FOVAngle = 90.f; - // Set a solid background color (black by default) + // Set a solid background color 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 FVector MeshBounds = MeshComp->Bounds.BoxExtent; FVector MeshOrigin = MeshComp->Bounds.Origin; - // Calculate the camera distance - float CameraDistance = MeshBounds.Size() * 1.1f; // Adjust multiplier as needed + // Calculate the camera distance based on mesh size + 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 - FVector CameraLocation = MeshOrigin + FVector(CameraDistance, 0.f, 0.f); // Default to capturing from the +X axis + // Calculate the camera location - position from front of mesh (+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(); - 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 CaptureSource) { - if (!MeshComp || !WorldContextObject) + if (!MeshComp || !WorldContextObject || !WorldContextObject->GetWorld()) { + UE_LOG(LogTemp, Warning, TEXT("CaptureMeshToRenderTarget: Invalid parameters")); return nullptr; } - // Create a render target + // Create a render target with proper size UTextureRenderTarget2D* RenderTarget = UKismetRenderingLibrary::CreateRenderTarget2D( - WorldContextObject, ImageSize.X, ImageSize.Y, ETextureRenderTargetFormat::RTF_RGBA8); + WorldContextObject, + FMath::Max(32, static_cast(ImageSize.X)), + FMath::Max(32, static_cast(ImageSize.Y)), + ETextureRenderTargetFormat::RTF_RGBA8); if (!RenderTarget) { + UE_LOG(LogTemp, Warning, TEXT("CaptureMeshToRenderTarget: Failed to create render target")); return nullptr; } // Create a temporary actor to hold the scene capture component AActor* TempActor = WorldContextObject->GetWorld()->SpawnActor(); + 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(TempActor, TEXT("RootComponent")); + TempActor->SetRootComponent(RootComponent); + RootComponent->RegisterComponent(); + } + + // Create and set up scene capture component USceneCaptureComponent2D* SceneCapture = NewObject(TempActor); - SceneCapture->AttachToComponent(TempActor->GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform); - SceneCapture->TextureTarget = RenderTarget; + if (SceneCapture) + { + SceneCapture->RegisterComponent(); + SceneCapture->AttachToComponent(TempActor->GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform); + SceneCapture->TextureTarget = RenderTarget; - // Setup the scene capture - SetupSceneCaptureForMesh(SceneCapture, MeshComp); + // Setup the scene capture + 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 - SceneCapture->PostProcessSettings.bOverride_AutoExposureMethod = true; - SceneCapture->PostProcessSettings.AutoExposureMethod = EAutoExposureMethod::AEM_Manual; - SceneCapture->PostProcessSettings.bOverride_AutoExposureBias = true; - SceneCapture->PostProcessSettings.AutoExposureBias = 1.0f; - SceneCapture->PostProcessSettings.bOverride_BloomIntensity = true; - SceneCapture->PostProcessSettings.BloomIntensity = 0.0f; - - // Trigger a one-time capture - SceneCapture->CaptureScene(); + // Disable post-processing effects + SceneCapture->PostProcessSettings.bOverride_AutoExposureMethod = true; + SceneCapture->PostProcessSettings.AutoExposureMethod = EAutoExposureMethod::AEM_Manual; + SceneCapture->PostProcessSettings.bOverride_AutoExposureBias = true; + SceneCapture->PostProcessSettings.AutoExposureBias = 1.0f; + SceneCapture->PostProcessSettings.bOverride_BloomIntensity = true; + SceneCapture->PostProcessSettings.BloomIntensity = 0.0f; + + // Trigger a one-time capture + 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 TempActor->Destroy(); 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; +} diff --git a/Source/LuckyWorldV2/Public/LRRenderUtilLibrary.h b/Source/LuckyWorldV2/Public/LRRenderUtilLibrary.h index 459c7ac9..5587da7a 100644 --- a/Source/LuckyWorldV2/Public/LRRenderUtilLibrary.h +++ b/Source/LuckyWorldV2/Public/LRRenderUtilLibrary.h @@ -6,20 +6,52 @@ #include "Kismet/BlueprintFunctionLibrary.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 { GENERATED_BODY() 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") - UTextureRenderTarget2D* CaptureMeshToRenderTarget(UStaticMeshComponent* MeshComp, const FVector2D& ImageSize, UObject* WorldContextObject); + UObject* WorldContextObject, + TEnumAsByte 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 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); };