// Copyright Epic Games, Inc. All Rights Reserved. #include "PocketCapture.h" #include "Components/SceneCaptureComponent2D.h" #include "Engine/TextureRenderTarget2D.h" #include "PocketCaptureSubsystem.h" #include "Camera/CameraComponent.h" #include "Components/PrimitiveComponent.h" // UPocketCapture //--------------------------------------------------------------------------------- UPocketCapture::UPocketCapture() { } void UPocketCapture::Initialize(UWorld* InWorld, int32 InRendererIndex) { PrivateWorld = InWorld; RendererIndex = InRendererIndex; CaptureComponent = NewObject(this, "Thumbnail_Capture_Component"); CaptureComponent->RegisterComponentWithWorld(InWorld); CaptureComponent->bConsiderUnrenderedOpaquePixelAsFullyTranslucent = true; CaptureComponent->PrimitiveRenderMode = ESceneCapturePrimitiveRenderMode::PRM_UseShowOnlyList; CaptureComponent->bCaptureEveryFrame = false; CaptureComponent->bCaptureOnMovement = false; CaptureComponent->bAlwaysPersistRenderingState = true; //UE_LOG(LogPocketLevels, Log, TEXT("ThumbnailRenderer: Initialize:%s"), *GetName()); } void UPocketCapture::Deinitialize() { CaptureComponent->UnregisterComponent(); //UE_LOG(LogPocketLevels, Log, TEXT("ThumbnailRenderer: Deinitialize:%s"), *GetName()); } void UPocketCapture::BeginDestroy() { Super::BeginDestroy(); if (CaptureComponent) { CaptureComponent->UnregisterComponent(); CaptureComponent = nullptr; } } void UPocketCapture::SetRenderTargetSize(int32 Width, int32 Height) { if (SurfaceWidth != Width || SurfaceHeight != Height) { SurfaceWidth = Width; SurfaceHeight = Height; if (DiffuseRT) { DiffuseRT->ResizeTarget(SurfaceWidth, SurfaceHeight); } if (AlphaMaskRT) { AlphaMaskRT->ResizeTarget(SurfaceWidth, SurfaceHeight); } if (EffectsRT) { EffectsRT->ResizeTarget(SurfaceWidth, SurfaceHeight); } } //UE_LOG(LogPocketLevels, Log, TEXT("ThumbnailRenderer: SetRenderTargetSize:%dx%d"), Width, Height); } UTextureRenderTarget2D* UPocketCapture::GetOrCreateDiffuseRenderTarget() { if (DiffuseRT == nullptr) { DiffuseRT = NewObject(this, TEXT("ThumbnailRenderer_Diffuse")); DiffuseRT->RenderTargetFormat = RTF_RGBA8; DiffuseRT->InitAutoFormat(SurfaceWidth, SurfaceHeight); DiffuseRT->UpdateResourceImmediate(true); } return DiffuseRT; } UTextureRenderTarget2D* UPocketCapture::GetOrCreateAlphaMaskRenderTarget() { if (AlphaMaskRT == nullptr) { AlphaMaskRT = NewObject(this, TEXT("ThumbnailRenderer_AlphaMask")); AlphaMaskRT->RenderTargetFormat = RTF_R8; AlphaMaskRT->InitAutoFormat(SurfaceWidth, SurfaceHeight); AlphaMaskRT->UpdateResourceImmediate(true); } return AlphaMaskRT; } UTextureRenderTarget2D* UPocketCapture::GetOrCreateEffectsRenderTarget() { if (EffectsRT == nullptr) { EffectsRT = NewObject(this, TEXT("ThumbnailRenderer_Fx")); EffectsRT->RenderTargetFormat = RTF_R8; EffectsRT->InitAutoFormat(SurfaceWidth, SurfaceHeight); EffectsRT->UpdateResourceImmediate(true); } return EffectsRT; } void UPocketCapture::SetCaptureTarget(AActor* InCaptureTarget) { CaptureTargetPtr = InCaptureTarget; OnCaptureTargetChanged(InCaptureTarget); } void UPocketCapture::SetAlphaMaskedActors(const TArray& InCaptureTargets) { AlphaMaskActorPtrs.Reset(); for (AActor* CaptureTarget : InCaptureTargets) { AlphaMaskActorPtrs.Add(CaptureTarget); } } UPocketCaptureSubsystem* UPocketCapture::GetThumbnailSystem() const { return CastChecked(GetOuter()); } TArray UPocketCapture::GatherPrimitivesForCapture(const TArray& InCaptureActors) const { const bool bIncludeFromChildActors = true; TArray PrimitiveComponents; for (AActor* CaptureActor : InCaptureActors) { TArray ChildPrimitiveComponents; CaptureActor->GetComponents(ChildPrimitiveComponents, bIncludeFromChildActors); for (UPrimitiveComponent* ChildPrimitiveComponent : ChildPrimitiveComponents) { if (!ChildPrimitiveComponent->bHiddenInGame) { PrimitiveComponents.Add(ChildPrimitiveComponent); } } } return PrimitiveComponents; } bool UPocketCapture::CaptureScene(UTextureRenderTarget2D* InRenderTarget, const TArray& InCaptureActors, ESceneCaptureSource InCaptureSource, UMaterialInterface* OverrideMaterial) { if (InRenderTarget == nullptr) { //UE_LOG(LogPocketLevels, Error, TEXT("")); return false; } if (AActor* CaptureTarget = CaptureTargetPtr.Get()) { if (InCaptureActors.Num() > 0) { TArray PrimitiveComponents = GatherPrimitivesForCapture(InCaptureActors); GetThumbnailSystem()->StreamThisFrame(PrimitiveComponents); TArray OriginalMaterials; if (OverrideMaterial) { for (UPrimitiveComponent* PrimitiveComponent : PrimitiveComponents) { const int32 MaterialCount = PrimitiveComponent->GetNumMaterials(); for (int32 MaterialIndex = 0; MaterialIndex < MaterialCount; MaterialIndex++) { OriginalMaterials.Add(PrimitiveComponent->GetMaterial(MaterialIndex)); PrimitiveComponent->SetMaterial(MaterialIndex, OverrideMaterial); } } } UCameraComponent* Camera = CaptureTarget->FindComponentByClass(); if (ensure(Camera)) { CaptureComponent->ShowOnlyActors = InCaptureActors; FMinimalViewInfo CaptureView; Camera->GetCameraView(0, CaptureView); // We need to make sure the texture streamer takes into account this new location, // this request only lasts for one tick, so we call it every time we need to draw, // so that they stay resident. //IStreamingManager::Get().AddViewSlaveLocation(CaptureView.Location); CaptureComponent->TextureTarget = InRenderTarget; CaptureComponent->PostProcessSettings = Camera->PostProcessSettings; CaptureComponent->SetCameraView(CaptureView); CaptureComponent->ShowFlags.SetDepthOfField(false); CaptureComponent->ShowFlags.SetMotionBlur(false); CaptureComponent->ShowFlags.SetScreenPercentage(false); CaptureComponent->ShowFlags.SetScreenSpaceReflections(false); CaptureComponent->ShowFlags.SetDistanceFieldAO(false); CaptureComponent->ShowFlags.SetLensFlares(false); CaptureComponent->ShowFlags.SetOnScreenDebug(false); //CaptureComponent->ShowFlags.SetEyeAdaptation(false); CaptureComponent->ShowFlags.SetColorGrading(false); CaptureComponent->ShowFlags.SetCameraImperfections(false); CaptureComponent->ShowFlags.SetVignette(false); CaptureComponent->ShowFlags.SetGrain(false); CaptureComponent->ShowFlags.SetSeparateTranslucency(false); CaptureComponent->ShowFlags.SetScreenPercentage(false); CaptureComponent->ShowFlags.SetScreenSpaceReflections(false); CaptureComponent->ShowFlags.SetTemporalAA(false); // might cause reallocation if we render rarely to it - for now off CaptureComponent->ShowFlags.SetAmbientOcclusion(false); // Requires resources in the FScene, which get reallocated for every temporary scene if enabled CaptureComponent->ShowFlags.SetIndirectLightingCache(false); CaptureComponent->ShowFlags.SetLightShafts(false); CaptureComponent->ShowFlags.SetPostProcessMaterial(false); CaptureComponent->ShowFlags.SetHighResScreenshotMask(false); CaptureComponent->ShowFlags.SetHMDDistortion(false); CaptureComponent->ShowFlags.SetStereoRendering(false); CaptureComponent->ShowFlags.SetVolumetricFog(false); CaptureComponent->ShowFlags.SetVolumetricLightmap(false); CaptureComponent->ShowFlags.SetSkyLighting(false); CaptureComponent->CaptureSource = InCaptureSource; CaptureComponent->ProfilingEventName = TEXT("Pocket Capture"); CaptureComponent->CaptureScene(); if (OriginalMaterials.Num() > 0) { int32 TotalMaterialIndex = 0; for (UPrimitiveComponent* PrimitiveComponent : PrimitiveComponents) { const int32 MaterialCount = PrimitiveComponent->GetNumMaterials(); for (int32 MaterialIndex = 0; MaterialIndex < MaterialCount; MaterialIndex++) { PrimitiveComponent->SetMaterial(MaterialIndex, OriginalMaterials[TotalMaterialIndex]); TotalMaterialIndex++; } } } return true; } } else { //UE_LOG(LogPocketLevels, Warning, TEXT("UPocketCapture: %s CaptureScene Failed: No Capture Actors"), *GetName()); } } else { //UE_LOG(LogPocketLevels, Warning, TEXT("UPocketCapture: %s CaptureScene Failed: No Capture Target"), *GetName()); } return false; } void UPocketCapture::CaptureDiffuse() { if (UTextureRenderTarget2D* RenderTarget = GetOrCreateDiffuseRenderTarget()) { TArray CaptureActors; if (AActor* CaptureTarget = CaptureTargetPtr.Get()) { CaptureTarget->GetAttachedActors(CaptureActors); CaptureActors.Add(CaptureTarget); } CaptureScene(RenderTarget, CaptureActors, ESceneCaptureSource::SCS_FinalColorLDR, nullptr); } } void UPocketCapture::CaptureAlphaMask() { if (UTextureRenderTarget2D* RenderTarget = GetOrCreateAlphaMaskRenderTarget()) { TArray CaptureActors; for (const TWeakObjectPtr& AlphaMaskTargetPtr : AlphaMaskActorPtrs) { if (AActor* AlphaMaskTarget = AlphaMaskTargetPtr.Get()) { CaptureActors.Add(AlphaMaskTarget); } } CaptureScene(RenderTarget, CaptureActors, ESceneCaptureSource::SCS_SceneColorHDR, AlphaMaskMaterial); } } void UPocketCapture::CaptureEffects() { if (UTextureRenderTarget2D* RenderTarget = GetOrCreateEffectsRenderTarget()) { ensure(false);//TODO TArray CaptureActors; CaptureScene(RenderTarget, CaptureActors, ESceneCaptureSource::SCS_SceneColorHDR, EffectMaskMaterial); } } void UPocketCapture::ReleaseResources() { if (DiffuseRT) { DiffuseRT->ReleaseResource(); } if (AlphaMaskRT) { AlphaMaskRT->ReleaseResource(); } if (EffectsRT) { EffectsRT->ReleaseResource(); } //OnReleaseResources(); } void UPocketCapture::ReclaimResources() { if (DiffuseRT) { DiffuseRT->UpdateResource(); } if (AlphaMaskRT) { AlphaMaskRT->UpdateResource(); } if (EffectsRT) { EffectsRT->UpdateResource(); } //OnReclaimResources(); } int32 UPocketCapture::GetRendererIndex() const { return RendererIndex; }