From 928726bf359dd465067fc36d01e3846dd4c3281e Mon Sep 17 00:00:00 2001 From: nsubiron Date: Tue, 7 Mar 2017 13:47:27 +0000 Subject: [PATCH] Port code for scene capture to file --- Source/Carla/SceneCaptureCamera.cpp | 169 ++++++++++++++++++++++++++++ Source/Carla/SceneCaptureCamera.h | 89 +++++++++++++++ 2 files changed, 258 insertions(+) create mode 100644 Source/Carla/SceneCaptureCamera.cpp create mode 100644 Source/Carla/SceneCaptureCamera.h diff --git a/Source/Carla/SceneCaptureCamera.cpp b/Source/Carla/SceneCaptureCamera.cpp new file mode 100644 index 000000000..c6182acf0 --- /dev/null +++ b/Source/Carla/SceneCaptureCamera.cpp @@ -0,0 +1,169 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#include "Carla.h" +#include "SceneCaptureCamera.h" + +#include "Components/DrawFrustumComponent.h" +#include "Components/SceneCaptureComponent2D.h" +#include "Components/StaticMeshComponent.h" +#include "Engine/CollisionProfile.h" +#include "Engine/TextureRenderTarget2D.h" +#include "HighResScreenshot.h" +#include "Paths.h" +#include "StaticMeshResources.h" +#include "TextureResource.h" + +// -- Static methods ----------------------------------------------------------- + +static void SaveRenderTargetToDisk(UTextureRenderTarget2D* InRenderTarget, FString Filename) +{ + FTextureRenderTargetResource* RTResource = InRenderTarget->GameThread_GetRenderTargetResource(); + + FReadSurfaceDataFlags ReadPixelFlags(RCM_UNorm); + ReadPixelFlags.SetLinearToGamma(true); + + TArray OutBMP; + RTResource->ReadPixels(OutBMP, ReadPixelFlags); + for (FColor& color : OutBMP) + { + color.A = 255; + } + FIntPoint DestSize(InRenderTarget->GetSurfaceWidth(), InRenderTarget->GetSurfaceHeight()); + FString ResultPath; + FHighResScreenshotConfig& HighResScreenshotConfig = GetHighResScreenshotConfig(); + HighResScreenshotConfig.SaveImage(Filename, OutBMP, DestSize, &ResultPath); +} + +// -- ASceneCaptureCamera ------------------------------------------------------ + +ASceneCaptureCamera::ASceneCaptureCamera(const FObjectInitializer& ObjectInitializer) : + Super(ObjectInitializer), + SaveToFolder(FPlatformProcess::UserDir()), + FileName("capture_%05d.png"), + CapturesPerSecond(15.0f), + SizeX(200u), + SizeY(200u) +{ + PrimaryActorTick.bCanEverTick = true; + + MeshComp = CreateDefaultSubobject(TEXT("CamMesh0")); + + MeshComp->SetCollisionProfileName(UCollisionProfile::NoCollision_ProfileName); + + MeshComp->bHiddenInGame = true; + MeshComp->CastShadow = false; + MeshComp->PostPhysicsComponentTick.bCanEverTick = false; + RootComponent = MeshComp; + + DrawFrustum = CreateDefaultSubobject(TEXT("DrawFrust0")); + DrawFrustum->bIsEditorOnly = true; + DrawFrustum->SetupAttachment(GetMeshComp()); + + CaptureRenderTarget = CreateDefaultSubobject(TEXT("CaptureRenderTarget0")); + + CaptureComponent2D = CreateDefaultSubobject(TEXT("SceneCaptureComponent2D")); + CaptureComponent2D->SetupAttachment(GetMeshComp()); +} + +ASceneCaptureCamera::~ASceneCaptureCamera() {} + +void ASceneCaptureCamera::OnInterpToggle(bool bEnable) +{ + CaptureComponent2D->SetVisibility(bEnable); +} + +void ASceneCaptureCamera::UpdateDrawFrustum() +{ + if(DrawFrustum && CaptureComponent2D) + { + DrawFrustum->FrustumStartDist = GNearClippingPlane; + + // 1000 is the default frustum distance, ideally this would be infinite but that might cause rendering issues + DrawFrustum->FrustumEndDist = (CaptureComponent2D->MaxViewDistanceOverride > DrawFrustum->FrustumStartDist) + ? CaptureComponent2D->MaxViewDistanceOverride : 1000.0f; + + DrawFrustum->FrustumAngle = CaptureComponent2D->FOVAngle; + //DrawFrustum->FrustumAspectRatio = CaptureComponent2D->AspectRatio; + } +} + +void ASceneCaptureCamera::PostActorCreated() +{ + Super::PostActorCreated(); + + // no need load the editor mesh when there is no editor +#if WITH_EDITOR + if(GetMeshComp()) + { + if (!IsRunningCommandlet()) + { + if( !GetMeshComp()->GetStaticMesh()) + { + UStaticMesh* CamMesh = LoadObject(NULL, TEXT("/Engine/EditorMeshes/MatineeCam_SM.MatineeCam_SM"), NULL, LOAD_None, NULL); + GetMeshComp()->SetStaticMesh(CamMesh); + } + } + } +#endif + + // Sync component with CameraActor frustum settings. + UpdateDrawFrustum(); +} + +void ASceneCaptureCamera::BeginPlay() +{ + Super::BeginPlay(); + + CaptureRenderTarget->InitCustomFormat(SizeX, SizeY, PF_B8G8R8A8, false); + CaptureRenderTarget->UpdateResource(); + + CaptureComponent2D->Deactivate(); + CaptureComponent2D->TextureTarget = CaptureRenderTarget; + CaptureComponent2D->UpdateContent(); + CaptureComponent2D->Activate(); +} + +void ASceneCaptureCamera::Tick(float Delta) +{ + Super::Tick(Delta); + + const float CaptureUpdateTime = 1.0f / CapturesPerSecond; + ElapsedTimeSinceLastCapture += Delta; + + if (bCaptureScene && (ElapsedTimeSinceLastCapture >= CaptureUpdateTime)) + { + if (CaptureComponent2D == nullptr) + { + UE_LOG(LogCarla, Error, TEXT("Missing capture component")); + } + + if (CaptureRenderTarget) + { + // Capture scene. + FString FilePath = FPaths::Combine(SaveToFolder, FString::Printf(*FileName, CaptureFileNameCount)); + //UE_LOG(LogCarla, Log, TEXT("Delta %fs: Capture %s"), ElapsedTimeSinceLastCapture, *FilePath); + SaveRenderTargetToDisk(CaptureRenderTarget, FilePath); + ++CaptureFileNameCount; + } + else + { + UE_LOG(LogCarla, Error, TEXT("Missing render target")); + } + ElapsedTimeSinceLastCapture = 0.0f; + } +} + +UStaticMeshComponent* ASceneCaptureCamera::GetMeshComp() const +{ + return MeshComp; +} + +USceneCaptureComponent2D* ASceneCaptureCamera::GetCaptureComponent2D() const +{ + return CaptureComponent2D; +} + +UDrawFrustumComponent* ASceneCaptureCamera::GetDrawFrustum() const +{ + return DrawFrustum; +} diff --git a/Source/Carla/SceneCaptureCamera.h b/Source/Carla/SceneCaptureCamera.h new file mode 100644 index 000000000..af676bb26 --- /dev/null +++ b/Source/Carla/SceneCaptureCamera.h @@ -0,0 +1,89 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +/** + * Own SceneCapture, re-implementing some of the methods since ASceneCapture + * cannot be subclassed. + */ + +#pragma once + +#include "GameFramework/Actor.h" +#include "StaticMeshResources.h" +#include "SceneCaptureCamera.generated.h" + +class UDrawFrustumComponent; +class USceneCaptureComponent2D; +class UStaticMeshComponent; + +UCLASS(hidecategories=(Collision, Material, Attachment, Actor)) +class CARLA_API ASceneCaptureCamera : public AActor +{ + GENERATED_BODY() + + float ElapsedTimeSinceLastCapture = 0.0f; + + size_t CaptureFileNameCount = 0u; + +public: + UPROPERTY(Category = SceneCapture, EditAnywhere) + bool bCaptureScene = true; + + UPROPERTY(Category = SceneCapture, EditAnywhere, meta = (EditCondition = bCaptureScene)) + FString SaveToFolder; + + UPROPERTY(Category = SceneCapture, EditAnywhere, meta = (EditCondition = bCaptureScene)) + FString FileName; + + UPROPERTY(Category = SceneCapture, EditAnywhere, meta = (EditCondition = bCaptureScene)) + float CapturesPerSecond; + + UPROPERTY(Category = SceneCapture, EditAnywhere, meta = (EditCondition = bCaptureScene)) + uint32 SizeX; + + UPROPERTY(Category = SceneCapture, EditAnywhere, meta = (EditCondition = bCaptureScene)) + uint32 SizeY; + +private: + /** To display the 3d camera in the editor. */ + UPROPERTY() + class UStaticMeshComponent* MeshComp; + + /** To allow drawing the camera frustum in the editor. */ + UPROPERTY() + class UDrawFrustumComponent* DrawFrustum; + + /** Render target necessary for scene capture */ + UPROPERTY(Transient) + class UTextureRenderTarget2D* CaptureRenderTarget; + + /** Scene capture component. */ + UPROPERTY(Transient) + class USceneCaptureComponent2D* CaptureComponent2D; + +public: + + ASceneCaptureCamera(const FObjectInitializer& ObjectInitializer); + + ~ASceneCaptureCamera(); + + virtual void PostActorCreated() override; + + virtual void BeginPlay() override; + + virtual void Tick(float Delta) override; + + /** Used to synchronize the DrawFrustumComponent with the SceneCaptureComponent2D settings. */ + void UpdateDrawFrustum(); + + UFUNCTION(BlueprintCallable, Category="Rendering") + void OnInterpToggle(bool bEnable); + + /** Returns CaptureComponent2D subobject **/ + USceneCaptureComponent2D* GetCaptureComponent2D() const; + + /** Returns DrawFrustum subobject **/ + UDrawFrustumComponent* GetDrawFrustum() const; + + /** Returns MeshComp subobject **/ + UStaticMeshComponent* GetMeshComp() const; +};