Files
UnrealEngineUWP/Engine/Source/Runtime/Renderer/Private/SceneCaptureRendering.cpp
Rolando Caloca ce168f2846 UE4 - Renamed depth compare enums, changed some checks to static_asserts
[CL 2498658 by Rolando Caloca in Main branch]
2015-04-01 10:53:07 -04:00

363 lines
13 KiB
C++

// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
/*=============================================================================
=============================================================================*/
#include "RendererPrivate.h"
#include "ScenePrivate.h"
#include "SceneFilterRendering.h"
#include "UniformBuffer.h"
#include "ShaderParameters.h"
#include "ScreenRendering.h"
#include "PostProcessAmbient.h"
#include "PostProcessing.h"
#include "SceneUtils.h"
// Copies into render target, optionally flipping it in the Y-axis
static void CopyCaptureToTarget(FRHICommandListImmediate& RHICmdList, const FRenderTarget* Target, const FIntPoint& TargetSize, FViewInfo& View, const FIntRect& ViewRect, FTextureRHIParamRef SourceTextureRHI, bool bNeedsFlippedRenderTarget)
{
SetRenderTarget(RHICmdList, Target->GetRenderTargetTexture(), NULL);
RHICmdList.SetRasterizerState(TStaticRasterizerState<FM_Solid, CM_None>::GetRHI());
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI());
TShaderMapRef<FScreenVS> VertexShader(View.ShaderMap);
TShaderMapRef<FScreenPS> PixelShader(View.ShaderMap);
static FGlobalBoundShaderState BoundShaderState;
SetGlobalBoundShaderState(RHICmdList, View.GetFeatureLevel(), BoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader);
FRenderingCompositePassContext Context(RHICmdList, View);
VertexShader->SetParameters(RHICmdList, View);
PixelShader->SetParameters(RHICmdList, TStaticSamplerState<SF_Point>::GetRHI(), SourceTextureRHI);
if (bNeedsFlippedRenderTarget)
{
DrawRectangle(
RHICmdList,
ViewRect.Min.X, ViewRect.Min.Y,
ViewRect.Width(), ViewRect.Height(),
ViewRect.Min.X, ViewRect.Height() - ViewRect.Min.Y,
ViewRect.Width(), -ViewRect.Height(),
TargetSize,
TargetSize,
*VertexShader,
EDRF_UseTriangleOptimization);
}
else
{
DrawRectangle(
RHICmdList,
ViewRect.Min.X, ViewRect.Min.Y,
ViewRect.Width(), ViewRect.Height(),
ViewRect.Min.X, ViewRect.Min.Y,
ViewRect.Width(), ViewRect.Height(),
TargetSize,
GSceneRenderTargets.GetBufferSizeXY(),
*VertexShader,
EDRF_UseTriangleOptimization);
}
}
static void UpdateSceneCaptureContent_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneRenderer* SceneRenderer, FTextureRenderTargetResource* TextureRenderTarget, const FName OwnerName, const FResolveParams& ResolveParams, bool bUseSceneColorTexture)
{
FMemMark MemStackMark(FMemStack::Get());
// update any resources that needed a deferred update
FDeferredUpdateResource::UpdateResources(RHICmdList);
{
#if WANTS_DRAW_MESH_EVENTS
FString EventName;
OwnerName.ToString(EventName);
SCOPED_DRAW_EVENTF(RHICmdList, SceneCapture, TEXT("SceneCapture %s"), *EventName);
#else
SCOPED_DRAW_EVENT(RHICmdList, UpdateSceneCaptureContent_RenderThread);
#endif
const bool bIsMobileHDR = IsMobileHDR();
const bool bRHINeedsFlip = RHINeedsToSwitchVerticalAxis(GMaxRHIShaderPlatform);
const bool bNeedsFlippedRenderTarget = !bIsMobileHDR && bRHINeedsFlip;
// Intermediate render target that will need to be flipped (needed on !IsMobileHDR())
TRefCountPtr<IPooledRenderTarget> FlippedPooledRenderTarget;
const FRenderTarget* Target = SceneRenderer->ViewFamily.RenderTarget;
if (bNeedsFlippedRenderTarget)
{
// We need to use an intermediate render target since the result will be flipped
auto& RenderTarget = Target->GetRenderTargetTexture();
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(Target->GetSizeXY(),
RenderTarget.GetReference()->GetFormat(),
TexCreate_None,
TexCreate_RenderTargetable,
false));
GRenderTargetPool.FindFreeElement(Desc, FlippedPooledRenderTarget, TEXT("SceneCaptureFlipped"));
}
// Helper class to allow setting render target
struct FRenderTargetOverride : public FRenderTarget
{
FRenderTargetOverride(FRHITexture2D* In)
{
RenderTargetTextureRHI = In;
}
virtual FIntPoint GetSizeXY() const { return FIntPoint(RenderTargetTextureRHI->GetSizeX(), RenderTargetTextureRHI->GetSizeY()); }
FTexture2DRHIRef GetTextureParamRef() { return RenderTargetTextureRHI; }
} FlippedRenderTarget(
FlippedPooledRenderTarget.GetReference()
? FlippedPooledRenderTarget.GetReference()->GetRenderTargetItem().TargetableTexture->GetTexture2D()
: nullptr);
FViewInfo& View = SceneRenderer->Views[0];
FIntRect ViewRect = View.ViewRect;
FIntRect UnconstrainedViewRect = View.UnconstrainedViewRect;
SetRenderTarget(RHICmdList, Target->GetRenderTargetTexture(), NULL);
RHICmdList.Clear(true, FLinearColor::Black, false, (float)ERHIZBuffer::FarPlane, false, 0, ViewRect);
// Render the scene normally
{
SCOPED_DRAW_EVENT(RHICmdList, RenderScene);
if (bNeedsFlippedRenderTarget)
{
// Hijack the render target
SceneRenderer->ViewFamily.RenderTarget = &FlippedRenderTarget; //-V506
}
SceneRenderer->Render(RHICmdList);
if (bNeedsFlippedRenderTarget)
{
// And restore it
SceneRenderer->ViewFamily.RenderTarget = Target;
}
}
if (bNeedsFlippedRenderTarget)
{
// We need to flip this texture upside down (since we depended on tonemapping to fix this on the hdr path)
SCOPED_DRAW_EVENT(RHICmdList, FlipCapture);
FIntPoint TargetSize(UnconstrainedViewRect.Width(), UnconstrainedViewRect.Height());
CopyCaptureToTarget(RHICmdList, Target, TargetSize, View, ViewRect, FlippedRenderTarget.GetTextureParamRef(), true);
}
else if (bUseSceneColorTexture && (bIsMobileHDR || SceneRenderer->FeatureLevel >= ERHIFeatureLevel::SM4))
{
// Copy the captured scene into the destination texture (only required on HDR or deferred as that implies post-processing)
SCOPED_DRAW_EVENT(RHICmdList, CaptureSceneColor);
FIntPoint TargetSize(UnconstrainedViewRect.Width(), UnconstrainedViewRect.Height());
CopyCaptureToTarget(RHICmdList, Target, TargetSize, View, ViewRect, GSceneRenderTargets.GetSceneColorTexture(), false);
}
RHICmdList.CopyToResolveTarget(TextureRenderTarget->GetRenderTargetTexture(), TextureRenderTarget->TextureRHI, false, ResolveParams);
}
delete SceneRenderer;
}
FSceneRenderer* FScene::CreateSceneRenderer( USceneCaptureComponent* SceneCaptureComponent, UTextureRenderTarget* TextureTarget, const FMatrix& ViewRotationMatrix, const FVector& ViewLocation, float FOV, float MaxViewDistance, bool bCaptureSceneColour, FPostProcessSettings* PostProcessSettings, float PostProcessBlendWeight )
{
FIntPoint CaptureSize(TextureTarget->GetSurfaceWidth(), TextureTarget->GetSurfaceHeight());
FTextureRenderTargetResource* Resource = TextureTarget->GameThread_GetRenderTargetResource();
FSceneViewFamilyContext ViewFamily(FSceneViewFamily::ConstructionValues(
Resource,
this,
SceneCaptureComponent->ShowFlags)
.SetResolveScene(!bCaptureSceneColour));
FSceneViewInitOptions ViewInitOptions;
ViewInitOptions.SetViewRectangle(FIntRect(0, 0, CaptureSize.X, CaptureSize.Y));
ViewInitOptions.ViewFamily = &ViewFamily;
ViewInitOptions.ViewOrigin = ViewLocation;
ViewInitOptions.ViewRotationMatrix = ViewRotationMatrix;
ViewInitOptions.BackgroundColor = FLinearColor::Black;
ViewInitOptions.OverrideFarClippingPlaneDistance = MaxViewDistance;
ViewInitOptions.SceneViewStateInterface = SceneCaptureComponent->GetViewState();
if (bCaptureSceneColour)
{
ViewFamily.EngineShowFlags.PostProcessing = 0;
ViewInitOptions.OverlayColor = FLinearColor::Black;
}
// Build projection matrix
{
float XAxisMultiplier;
float YAxisMultiplier;
if (CaptureSize.X > CaptureSize.Y)
{
// if the viewport is wider than it is tall
XAxisMultiplier = 1.0f;
YAxisMultiplier = CaptureSize.X / (float)CaptureSize.Y;
}
else
{
// if the viewport is taller than it is wide
XAxisMultiplier = CaptureSize.Y / (float)CaptureSize.X;
YAxisMultiplier = 1.0f;
}
if ((int32)ERHIZBuffer::IsInverted != 0)
{
ViewInitOptions.ProjectionMatrix = FReversedZPerspectiveMatrix(
FOV,
FOV,
XAxisMultiplier,
YAxisMultiplier,
GNearClippingPlane,
GNearClippingPlane
);
}
else
{
ViewInitOptions.ProjectionMatrix = FPerspectiveMatrix(
FOV,
FOV,
XAxisMultiplier,
YAxisMultiplier,
GNearClippingPlane,
GNearClippingPlane
);
}
}
FSceneView* View = new FSceneView(ViewInitOptions);
View->bIsSceneCapture = true;
check(SceneCaptureComponent);
for (auto It = SceneCaptureComponent->HiddenComponents.CreateConstIterator(); It; ++It)
{
// If the primitive component was destroyed, the weak pointer will return NULL.
UPrimitiveComponent* PrimitiveComponent = It->Get();
if (PrimitiveComponent)
{
View->HiddenPrimitives.Add(PrimitiveComponent->ComponentId);
}
}
ViewFamily.Views.Add(View);
View->StartFinalPostprocessSettings(ViewLocation);
View->OverridePostProcessSettings(*PostProcessSettings, PostProcessBlendWeight);
View->EndFinalPostprocessSettings(ViewInitOptions);
return FSceneRenderer::CreateSceneRenderer(&ViewFamily, NULL);
}
void FScene::UpdateSceneCaptureContents(USceneCaptureComponent2D* CaptureComponent)
{
check(CaptureComponent);
if (CaptureComponent->TextureTarget)
{
FTransform Transform = CaptureComponent->GetComponentToWorld();
FVector ViewLocation = Transform.GetTranslation();
// Remove the translation from Transform because we only need rotation.
Transform.SetTranslation(FVector::ZeroVector);
FMatrix ViewRotationMatrix = Transform.ToInverseMatrixWithScale();
// swap axis st. x=z,y=x,z=y (unreal coord space) so that z is up
ViewRotationMatrix = ViewRotationMatrix * FMatrix(
FPlane(0, 0, 1, 0),
FPlane(1, 0, 0, 0),
FPlane(0, 1, 0, 0),
FPlane(0, 0, 0, 1));
const float FOV = CaptureComponent->FOVAngle * (float)PI / 360.0f;
const bool bUseSceneColorTexture = CaptureComponent->CaptureSource == SCS_SceneColorHDR;
FSceneRenderer* SceneRenderer = CreateSceneRenderer(CaptureComponent, CaptureComponent->TextureTarget, ViewRotationMatrix , ViewLocation, FOV, CaptureComponent->MaxViewDistanceOverride, bUseSceneColorTexture, &CaptureComponent->PostProcessSettings, CaptureComponent->PostProcessBlendWeight);
FTextureRenderTargetResource* TextureRenderTarget = CaptureComponent->TextureTarget->GameThread_GetRenderTargetResource();
const FName OwnerName = CaptureComponent->GetOwner() ? CaptureComponent->GetOwner()->GetFName() : NAME_None;
ENQUEUE_UNIQUE_RENDER_COMMAND_FOURPARAMETER(
CaptureCommand,
FSceneRenderer*, SceneRenderer, SceneRenderer,
FTextureRenderTargetResource*, TextureRenderTarget, TextureRenderTarget,
FName, OwnerName, OwnerName,
bool, bUseSceneColorTexture, bUseSceneColorTexture,
{
UpdateSceneCaptureContent_RenderThread(RHICmdList, SceneRenderer, TextureRenderTarget, OwnerName, FResolveParams(), bUseSceneColorTexture);
});
}
}
void FScene::UpdateSceneCaptureContents(USceneCaptureComponentCube* CaptureComponent)
{
struct FLocal
{
/** Creates a transformation for a cubemap face, following the D3D cubemap layout. */
static FMatrix CalcCubeFaceTransform(ECubeFace Face)
{
static const FVector XAxis(1.f, 0.f, 0.f);
static const FVector YAxis(0.f, 1.f, 0.f);
static const FVector ZAxis(0.f, 0.f, 1.f);
// vectors we will need for our basis
FVector vUp(YAxis);
FVector vDir;
switch (Face)
{
case CubeFace_PosX:
vDir = XAxis;
break;
case CubeFace_NegX:
vDir = -XAxis;
break;
case CubeFace_PosY:
vUp = -ZAxis;
vDir = YAxis;
break;
case CubeFace_NegY:
vUp = ZAxis;
vDir = -YAxis;
break;
case CubeFace_PosZ:
vDir = ZAxis;
break;
case CubeFace_NegZ:
vDir = -ZAxis;
break;
}
// derive right vector
FVector vRight(vUp ^ vDir);
// create matrix from the 3 axes
return FBasisVectorMatrix(vRight, vUp, vDir, FVector::ZeroVector);
}
} ;
check(CaptureComponent);
if (GetFeatureLevel() >= ERHIFeatureLevel::SM4 && CaptureComponent->TextureTarget)
{
const float FOV = 90 * (float)PI / 360.0f;
for (int32 faceidx = 0; faceidx < (int32)ECubeFace::CubeFace_MAX; faceidx++)
{
const ECubeFace TargetFace = (ECubeFace)faceidx;
const FVector Location = CaptureComponent->GetComponentToWorld().GetTranslation();
const FMatrix ViewRotationMatrix = FLocal::CalcCubeFaceTransform(TargetFace);
FSceneRenderer* SceneRenderer = CreateSceneRenderer(CaptureComponent, CaptureComponent->TextureTarget, ViewRotationMatrix, Location, FOV, CaptureComponent->MaxViewDistanceOverride);
FTextureRenderTargetCubeResource* TextureRenderTarget = static_cast<FTextureRenderTargetCubeResource*>(CaptureComponent->TextureTarget->GameThread_GetRenderTargetResource());
const FName OwnerName = CaptureComponent->GetOwner() ? CaptureComponent->GetOwner()->GetFName() : NAME_None;
ENQUEUE_UNIQUE_RENDER_COMMAND_FOURPARAMETER(
CaptureCommand,
FSceneRenderer*, SceneRenderer, SceneRenderer,
FTextureRenderTargetCubeResource*, TextureRenderTarget, TextureRenderTarget,
FName, OwnerName, OwnerName,
ECubeFace, TargetFace, TargetFace,
{
UpdateSceneCaptureContent_RenderThread(RHICmdList, SceneRenderer, TextureRenderTarget, OwnerName, FResolveParams(FResolveRect(), TargetFace), true);
});
}
}
}