diff --git a/Source/LuckyWorldV2/LuckyWorldV2.Build.cs b/Source/LuckyWorldV2/LuckyWorldV2.Build.cs index 7829bc2c..0c55e960 100644 --- a/Source/LuckyWorldV2/LuckyWorldV2.Build.cs +++ b/Source/LuckyWorldV2/LuckyWorldV2.Build.cs @@ -19,7 +19,8 @@ public class LuckyWorldV2 : ModuleRules "SocketIOClient", "VaRest", "SIOJson", - "NavigationSystem" + "NavigationSystem", + "RenderCore" }); PrivateDependencyModuleNames.AddRange(new string[] { }); diff --git a/Source/LuckyWorldV2/Private/LRRenderUtilLibrary.cpp b/Source/LuckyWorldV2/Private/LRRenderUtilLibrary.cpp new file mode 100644 index 00000000..e5397ce5 --- /dev/null +++ b/Source/LuckyWorldV2/Private/LRRenderUtilLibrary.cpp @@ -0,0 +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, + 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 = CaptureSource; + SceneCapture->bCaptureEveryFrame = false; + SceneCapture->bCaptureOnMovement = false; + SceneCapture->FOVAngle = 90.f; + + // Set a solid background color + SceneCapture->CompositeMode = ESceneCaptureCompositeMode::SCCM_Overwrite; + + // 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 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 - position from front of mesh (+X axis) + FVector CameraLocation = MeshOrigin + FVector(CameraDistance, 0.f, 0.f); + + // Calculate the camera rotation to look at mesh center + FRotator CameraRotation = (MeshOrigin - CameraLocation).Rotation(); + + 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, + TEnumAsByte CaptureSource) +{ + if (!MeshComp || !WorldContextObject || !WorldContextObject->GetWorld()) + { + UE_LOG(LogTemp, Warning, TEXT("CaptureMeshToRenderTarget: Invalid parameters")); + return nullptr; + } + + // Create a render target with proper size + UTextureRenderTarget2D* RenderTarget = UKismetRenderingLibrary::CreateRenderTarget2D( + 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); + if (SceneCapture) + { + SceneCapture->RegisterComponent(); + SceneCapture->AttachToComponent(TempActor->GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform); + SceneCapture->TextureTarget = RenderTarget; + + // Setup the scene capture + SetupSceneCaptureForMesh(SceneCapture, MeshComp, CaptureSource); + + // 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(); + + // 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 new file mode 100644 index 00000000..5587da7a --- /dev/null +++ b/Source/LuckyWorldV2/Public/LRRenderUtilLibrary.h @@ -0,0 +1,57 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#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(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, + + UObject* WorldContextObject, + TEnumAsByte CaptureSource = ESceneCaptureSource::SCS_BaseColor); + + /** + * 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); +};