UE源码剖析 - Scene View Extension

Scene View Extension是引擎提供的一个接口,可以方便地在后处理的某个pass后插入一个pass,相关的接口实现在Engine\Source\Runtime\Engine\Public\SceneViewExtension.h

本文将介绍这套工具的使用方法和实现逻辑。

简介

宏观层面,对于这个工具我们应该了解:

  1. 仅支持deferred shading path,mobile并没有这个特性。
  2. 支持在四个后处理pass后插入,分别是
  • MotionBlur
  • Tonemap
  • FXAA
  • VisualizeDepthOfField
  1. 这个工具的底层逻辑,是注册一个回调函数,在指定位置调用,该回调函数的签名是:
FUNC_DECLARE_DELEGATE(FAfterPassCallbackDelegate, FScreenPassTexture /*ReturnSceneColor*/, FRDGBuilder& /*GraphBuilder*/, const FSceneView& /*View*/, const FPostProcessMaterialInputs& /*Inputs*/)

即返回值FScreenPassTexture,输入参数有三个:FRDGBuilderFSceneViewFPostProcessMaterialInputs

  1. 除了回调函数提供的三个参数,还可以间接获得的参数包括
  • FViewInfo:可以从FSceneView转换过来:const FViewInfo* ViewInfo = static_cast<const FViewInfo*>(&View);
  • FPostProcessingInputs:从虚函数PrePostProcessPass_RenderThread传入。

使用方法

在源码的Engine\Source\Runtime\Engine\Public\SceneViewExtension.h文件里,Epic在注释里给出了SceneViewExtension的推荐用法。

第一步,创建一个类,继承自FSceneViewExtensionBase

class FMyExtension : public FSceneViewExtensionBase
{
public:
    FMyExtension( const FAutoRegister& AutoRegister, FYourParam1 Param1, FYourParam2 Param2 )
        : FSceneViewExten
可以参考以下步骤来创建一个具有截图保存功能的Actor: 1. 首先创建一个继承自Actor的子类,并在头文件中添加以下include语句: ```cpp #include "Engine/TextureRenderTarget2D.h" #include "EngineUtils.h" ``` 2. 在子类中添加以下成员变量: ```cpp UPROPERTY(EditAnywhere) int32 Width = 1024; UPROPERTY(EditAnywhere) int32 Height = 1024; UPROPERTY(EditAnywhere) FString SavePath = FPaths::ProjectSavedDir() + "Screenshots/"; UPROPERTY(EditAnywhere) FString FileNamePrefix = "Screenshot_"; ``` 这些变量将控制截图的大小、保存路径和文件名前缀。 3. 在子类中添加以下函数: ```cpp void SaveScreenshot(UTextureRenderTarget2D* RenderTarget, const FString& FilePath); FString GetUniqueFilename(const FString& Prefix, const FString& Extension); ``` SaveScreenshot函数将保存截图到指定路径,GetUniqueFilename函数将生成一个唯一的文件名。 4. 在子类的cpp文件中实现以上两个函数: ```cpp void AMyActor::SaveScreenshot(UTextureRenderTarget2D* RenderTarget, const FString& FilePath) { TArray<FColor> Bitmap; FIntRect Rect(0, 0, RenderTarget->SizeX, RenderTarget->SizeY); RenderTarget->ReadPixels(Bitmap, FReadSurfaceDataFlags(), Rect); FString Filename = GetUniqueFilename(FileNamePrefix, ".png"); FString FullPath = FilePath + Filename; FFileHelper::CreateDirectory(*FilePath); FSaveImageDialog::SaveImage(FullPath, Rect.Width(), Rect.Height(), Bitmap.GetData(), nullptr); } FString AMyActor::GetUniqueFilename(const FString& Prefix, const FString& Extension) { FString Filename; int32 Number = 0; do { Filename = Prefix + FString::FromInt(Number++) + Extension; } while (FPlatformFileManager::Get().GetPlatformFile().FileExists(*Filename)); return Filename; } ``` 5. 在子类中添加以下函数: ```cpp void CaptureScreenshot(); ``` 这个函数将截图并保存到指定路径。 6. 在子类的cpp文件中实现CaptureScreenshot函数: ```cpp void AMyActor::CaptureScreenshot() { UWorld* World = GetWorld(); if (!World) { return; } TArray<AActor*> Actors; UGameplayStatics::GetAllActorsOfClass(World, APlayerController::StaticClass(), Actors); if (Actors.Num() == 0) { return; } APlayerController* PlayerController = Cast<APlayerController>(Actors[0]); if (!PlayerController) { return; } ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(PlayerController->Player); if (!LocalPlayer) { return; } UTextureRenderTarget2D* RenderTarget = NewObject<UTextureRenderTarget2D>(); RenderTarget->ClearColor = FLinearColor::Black; RenderTarget->InitAutoFormat(Width, Height); RenderTarget->UpdateResourceImmediate(); FViewport Viewport(0, 0, Width, Height); FSceneViewFamilyContext ViewFamily(FSceneViewFamily::ConstructionValues( Viewport, World->Scene, LocalPlayer->ViewportClient->EngineShowFlags) .SetRealtimeUpdate(true)); FSceneView* View = LocalPlayer->CalcSceneView(&ViewFamily); View->ViewRect = FIntRect(0, 0, Width, Height); View->UpdateViewMatrix(); View->SetScreenPercentage(100.0f); FTextureRenderTargetResource* RenderTargetResource = RenderTarget->GameThread_GetRenderTargetResource(); View->Family->RenderInterface->Render(View, FTextureRHIRef(), FTextureRHIRef(), RenderTargetResource->GetRenderTargetTexture(), View->ViewRect, false); SaveScreenshot(RenderTarget, SavePath); } ``` 这个函数使用场景中的第一个PlayerController来获取场景视图,并将其渲染到一个RenderTarget上,然后调用SaveScreenshot函数保存截图。 7. 最后,可以在Actor的BeginPlay函数中调用CaptureScreenshot函数来测试截图功能: ```cpp void AMyActor::BeginPlay() { Super::BeginPlay(); CaptureScreenshot(); } ``` 这样就完成了一个具有截图保存功能的Actor。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值