Unreal Engine 4 Postprocess
はじめに
UE4のRendererModuleはユーザが独自のパスを追加できるいくつかのコールバックがあります. Unityのように独自のポストプロセスパスを追加したいため調査しました.
IRendererModule のコールバック
GetModule("Renderer")
で取得できる IRendererModule
にある描画関連のコールバックは次の3つになります.
- PostOpaqueRender
- OverlayRender
- ResolvedSceneColor
テンプレートとしてのコードは次のようになります. 各パスでは何もしていないですが, RenderDocでパスの流れを確認するにはこれで十分です.
RenderHookComponent.cpp
#include "RenderHookComponent.h"
#include <Modules/ModuleManager.h>
#include <Modules/ModuleInterface.h>
#include <RendererInterface.h>
#include <RenderUtils.h>
#include <ClearQuad.h>
URenderHookComponent::URenderHookComponent()
{
PrimaryComponentTick.bCanEverTick = false;
}
void URenderHookComponent::BeginPlay()
{
Super::BeginPlay();
// Get Rendere Module
IRendererModule* RendererModule = (IRendererModule*)(FModuleManager::Get().GetModule("Renderer"));
// Add delegates
FPostOpaqueRenderDelegate OverlayRenderDelegate;
OverlayRenderDelegate.BindUObject(this, &URenderHookComponent::OnOverlayRender);
OnOverlayRenderHandle_ = RendererModule->RegisterOverlayRenderDelegate(OverlayRenderDelegate);
FPostOpaqueRenderDelegate PostOpaqueRenderDelegate;
PostOpaqueRenderDelegate.BindUObject(this, &URenderHookComponent::OnPostOpaqueRender);
OnPostOpaqueRenderHandle_ = RendererModule->RegisterPostOpaqueRenderDelegate(PostOpaqueRenderDelegate);
OnResolvedSceneColorHandle_ = RendererModule->GetResolvedSceneColorCallbacks().AddUObject(this, &URenderHookComponent::OnResoledSceneColor);
}
void URenderHookComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
IRendererModule* RendererModule = (IRendererModule*)(FModuleManager::Get().GetModule("Renderer"));
if(OnOverlayRenderHandle_.IsValid()){
RendererModule->RemoveOverlayRenderDelegate(OnOverlayRenderHandle_);
OnOverlayRenderHandle_.Reset();
}
if(OnPostOpaqueRenderHandle_.IsValid()){
RendererModule->RemovePostOpaqueRenderDelegate(OnPostOpaqueRenderHandle_);
OnPostOpaqueRenderHandle_.Reset();
}
if(OnResolvedSceneColorHandle_.IsValid()){
RendererModule->GetResolvedSceneColorCallbacks().Remove(OnResolvedSceneColorHandle_);
OnResolvedSceneColorHandle_.Reset();
}
}
void URenderHookComponent::OnOverlayRender(FPostOpaqueRenderParameters& PostOpaqueRenderParameters)
{
FRHICommandList& RHICmdList = *PostOpaqueRenderParameters.RHICmdList;
FRHIRenderPassInfo RenderPassInfo;
RHICmdList.BeginRenderPass(RenderPassInfo, TEXT("OverlayRender"));
RHICmdList.EndRenderPass();
}
void URenderHookComponent::OnPostOpaqueRender(FPostOpaqueRenderParameters& PostOpaqueRenderParameters)
{
FRHICommandList& RHICmdList = *PostOpaqueRenderParameters.RHICmdList;
FRHIRenderPassInfo RenderPassInfo;
RHICmdList.BeginRenderPass(RenderPassInfo, TEXT("PostOpaqueRender"));
RHICmdList.EndRenderPass();
}
void URenderHookComponent::OnResoledSceneColor(FRHICommandListImmediate& RHICmdList, class FSceneRenderTargets& SceneContext)
{
FRHIRenderPassInfo RenderPassInfo;
RHICmdList.BeginRenderPass(RenderPassInfo, TEXT("ResoledSceneColor"));
DrawClearQuad(RHICmdList, FLinearColor::White);
RHICmdList.EndRenderPass();
}
ローカルマルチプレイを考慮した次のような場合,
レンダリングパスは次のようになります. Post Opaque
とOverlay
は各プレーヤのビュー毎に, Post Resolved Scene Color
はシーン全体で一度だけ呼び出されます.
これはデフォルトの単純なシーンのパスですので, 例えばCustom Depth
などの機能を使用した場合にパスが追加されると思います.

独自ポストプロセスパス
パスを追加する箇所は, Overlay
かPost Resolved Scene Color
が候補になると思います.
全てのポストプロセスを自前で用意するならばこれで話は終わりなのですが, やはりPostProcessingVolumeも使いたいと思うでしょう. 再利用できないかと調べましたが, 相変わらず各機能がエンジンに深く関連しているため難しいように思います.
ポストプロセスを行う場合, 一般的にシーンのカラーをレンダーターゲット以外にコピーする必要があります. PostProcessingVolumeは最小でも次の処理をしています, この処理が重複するオーバーヘッドも考慮しないといけません.
- PostProcessInput0へSceneColorをコピー
- CustomStencilへステンシルをコピー
まとめ
独自のパスを追加できるのですが, PostProcessingVolumeの再利用が難しいためオーバーヘッドが気になります.