You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
1089 lines
38 KiB
C++
1089 lines
38 KiB
C++
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
TranslucentRendering.cpp: Translucent rendering implementation.
|
|
=============================================================================*/
|
|
|
|
#include "RendererPrivate.h"
|
|
#include "ScenePrivate.h"
|
|
#include "ScreenRendering.h"
|
|
#include "SceneFilterRendering.h"
|
|
#include "LightPropagationVolume.h"
|
|
#include "SceneUtils.h"
|
|
|
|
static void SetTranslucentRenderTargetAndState(FRHICommandList& RHICmdList, const FViewInfo& View, bool bSeparateTranslucencyPass, bool bFirstTimeThisFrame = false)
|
|
{
|
|
bool bSetupTranslucentState = true;
|
|
|
|
if (bSeparateTranslucencyPass && GSceneRenderTargets.IsSeparateTranslucencyActive(View))
|
|
{
|
|
bSetupTranslucentState = GSceneRenderTargets.BeginRenderingSeparateTranslucency(RHICmdList, View, bFirstTimeThisFrame);
|
|
}
|
|
else
|
|
{
|
|
GSceneRenderTargets.BeginRenderingTranslucency(RHICmdList, View);
|
|
}
|
|
|
|
if (bSetupTranslucentState)
|
|
{
|
|
// Enable depth test, disable depth writes.
|
|
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_DepthNearOrEqual>::GetRHI());
|
|
}
|
|
}
|
|
|
|
static void FinishTranslucentRenderTarget(FRHICommandListImmediate& RHICmdList, const FViewInfo& View, bool bSeparateTranslucencyPass)
|
|
{
|
|
if (bSeparateTranslucencyPass && GSceneRenderTargets.IsSeparateTranslucencyActive(View))
|
|
{
|
|
GSceneRenderTargets.FinishRenderingSeparateTranslucency(RHICmdList, View);
|
|
}
|
|
else
|
|
{
|
|
GSceneRenderTargets.FinishRenderingTranslucency(RHICmdList, View);
|
|
}
|
|
}
|
|
|
|
const FProjectedShadowInfo* FDeferredShadingSceneRenderer::PrepareTranslucentShadowMap(FRHICommandList& RHICmdList, const FViewInfo& View, FPrimitiveSceneInfo* PrimitiveSceneInfo, bool bSeparateTranslucencyPass)
|
|
{
|
|
const FVisibleLightInfo* VisibleLightInfo = NULL;
|
|
FProjectedShadowInfo* TranslucentSelfShadow = NULL;
|
|
|
|
// Find this primitive's self shadow if there is one
|
|
if (PrimitiveSceneInfo->Proxy && PrimitiveSceneInfo->Proxy->CastsVolumetricTranslucentShadow())
|
|
{
|
|
for (FLightPrimitiveInteraction* Interaction = PrimitiveSceneInfo->LightList;
|
|
Interaction && !TranslucentSelfShadow;
|
|
Interaction = Interaction->GetNextLight()
|
|
)
|
|
{
|
|
const FLightSceneInfo* LightSceneInfo = Interaction->GetLight();
|
|
|
|
if (LightSceneInfo->Proxy->GetLightType() == LightType_Directional
|
|
// Only reuse cached shadows from the light which last used TranslucentSelfShadowLayout
|
|
// This has the side effect of only allowing per-pixel self shadowing from one light
|
|
&& LightSceneInfo->Id == CachedTranslucentSelfShadowLightId)
|
|
{
|
|
VisibleLightInfo = &VisibleLightInfos[LightSceneInfo->Id];
|
|
FProjectedShadowInfo* ObjectShadow = NULL;
|
|
|
|
for (int32 ShadowIndex = 0; ShadowIndex < VisibleLightInfo->AllProjectedShadows.Num(); ShadowIndex++)
|
|
{
|
|
FProjectedShadowInfo* CurrentShadowInfo = VisibleLightInfo->AllProjectedShadows[ShadowIndex];
|
|
|
|
if (CurrentShadowInfo && CurrentShadowInfo->bTranslucentShadow && CurrentShadowInfo->GetParentSceneInfo() == PrimitiveSceneInfo)
|
|
{
|
|
TranslucentSelfShadow = CurrentShadowInfo;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Allocate and render the shadow's depth map if needed
|
|
if (TranslucentSelfShadow && !TranslucentSelfShadow->bAllocatedInTranslucentLayout)
|
|
{
|
|
check(IsInRenderingThread());
|
|
bool bPossibleToAllocate = true;
|
|
|
|
// Attempt to find space in the layout
|
|
TranslucentSelfShadow->bAllocatedInTranslucentLayout = TranslucentSelfShadowLayout.AddElement(
|
|
TranslucentSelfShadow->X,
|
|
TranslucentSelfShadow->Y,
|
|
TranslucentSelfShadow->ResolutionX + SHADOW_BORDER * 2,
|
|
TranslucentSelfShadow->ResolutionY + SHADOW_BORDER * 2);
|
|
|
|
// Free shadowmaps from this light until allocation succeeds
|
|
while (!TranslucentSelfShadow->bAllocatedInTranslucentLayout && bPossibleToAllocate)
|
|
{
|
|
bPossibleToAllocate = false;
|
|
|
|
for (int32 ShadowIndex = 0; ShadowIndex < VisibleLightInfo->AllProjectedShadows.Num(); ShadowIndex++)
|
|
{
|
|
FProjectedShadowInfo* CurrentShadowInfo = VisibleLightInfo->AllProjectedShadows[ShadowIndex];
|
|
|
|
if (CurrentShadowInfo->bTranslucentShadow && CurrentShadowInfo->bAllocatedInTranslucentLayout)
|
|
{
|
|
verify(TranslucentSelfShadowLayout.RemoveElement(
|
|
CurrentShadowInfo->X,
|
|
CurrentShadowInfo->Y,
|
|
CurrentShadowInfo->ResolutionX + SHADOW_BORDER * 2,
|
|
CurrentShadowInfo->ResolutionY + SHADOW_BORDER * 2));
|
|
|
|
CurrentShadowInfo->bAllocatedInTranslucentLayout = false;
|
|
|
|
bPossibleToAllocate = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
TranslucentSelfShadow->bAllocatedInTranslucentLayout = TranslucentSelfShadowLayout.AddElement(
|
|
TranslucentSelfShadow->X,
|
|
TranslucentSelfShadow->Y,
|
|
TranslucentSelfShadow->ResolutionX + SHADOW_BORDER * 2,
|
|
TranslucentSelfShadow->ResolutionY + SHADOW_BORDER * 2);
|
|
}
|
|
|
|
if (!bPossibleToAllocate)
|
|
{
|
|
// Failed to allocate space for the shadow depth map, so don't use the self shadow
|
|
TranslucentSelfShadow = NULL;
|
|
}
|
|
else
|
|
{
|
|
check(TranslucentSelfShadow->bAllocatedInTranslucentLayout);
|
|
|
|
// Render the translucency shadow map
|
|
TranslucentSelfShadow->RenderTranslucencyDepths(RHICmdList, this);
|
|
|
|
// Restore state
|
|
SetTranslucentRenderTargetAndState(RHICmdList, View, bSeparateTranslucencyPass);
|
|
}
|
|
}
|
|
}
|
|
|
|
return TranslucentSelfShadow;
|
|
}
|
|
|
|
/** Pixel shader used to copy scene color into another texture so that materials can read from scene color with a node. */
|
|
class FCopySceneColorPS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FCopySceneColorPS,Global);
|
|
public:
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform) { return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4); }
|
|
|
|
FCopySceneColorPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer):
|
|
FGlobalShader(Initializer)
|
|
{
|
|
SceneTextureParameters.Bind(Initializer.ParameterMap);
|
|
}
|
|
FCopySceneColorPS() {}
|
|
|
|
void SetParameters(FRHICommandList& RHICmdList, const FViewInfo& View)
|
|
{
|
|
SceneTextureParameters.Set(RHICmdList, GetPixelShader(), View);
|
|
}
|
|
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
Ar << SceneTextureParameters;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
FSceneTextureShaderParameters SceneTextureParameters;
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(,FCopySceneColorPS,TEXT("TranslucentLightingShaders"),TEXT("CopySceneColorMain"),SF_Pixel);
|
|
|
|
FGlobalBoundShaderState CopySceneColorBoundShaderState;
|
|
|
|
void FTranslucencyDrawingPolicyFactory::CopySceneColor(FRHICommandList& RHICmdList, const FViewInfo& View, const FPrimitiveSceneProxy* PrimitiveSceneProxy)
|
|
{
|
|
|
|
SCOPED_DRAW_EVENTF(RHICmdList, EventCopy, TEXT("CopySceneColor for %s %s"), *PrimitiveSceneProxy->GetOwnerName().ToString(), *PrimitiveSceneProxy->GetResourceName().ToString());
|
|
RHICmdList.SetRasterizerState(TStaticRasterizerState<FM_Solid, CM_None>::GetRHI());
|
|
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
|
|
RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI());
|
|
|
|
GSceneRenderTargets.ResolveSceneColor(RHICmdList);
|
|
|
|
GSceneRenderTargets.BeginRenderingLightAttenuation(RHICmdList);
|
|
RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f);
|
|
|
|
TShaderMapRef<FScreenVS> ScreenVertexShader(View.ShaderMap);
|
|
TShaderMapRef<FCopySceneColorPS> PixelShader(View.ShaderMap);
|
|
SetGlobalBoundShaderState(RHICmdList, View.GetFeatureLevel(), CopySceneColorBoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *ScreenVertexShader, *PixelShader);
|
|
|
|
/// ?
|
|
PixelShader->SetParameters(RHICmdList, View);
|
|
|
|
DrawRectangle(
|
|
RHICmdList,
|
|
0, 0,
|
|
View.ViewRect.Width(), View.ViewRect.Height(),
|
|
View.ViewRect.Min.X, View.ViewRect.Min.Y,
|
|
View.ViewRect.Width(), View.ViewRect.Height(),
|
|
FIntPoint(View.ViewRect.Width(), View.ViewRect.Height()),
|
|
GSceneRenderTargets.GetBufferSizeXY(),
|
|
*ScreenVertexShader,
|
|
EDRF_UseTriangleOptimization);
|
|
|
|
GSceneRenderTargets.FinishRenderingLightAttenuation(RHICmdList);
|
|
}
|
|
|
|
/** The parameters used to draw a translucent mesh. */
|
|
class FDrawTranslucentMeshAction
|
|
{
|
|
public:
|
|
|
|
const FViewInfo& View;
|
|
const FProjectedShadowInfo* TranslucentSelfShadow;
|
|
FHitProxyId HitProxyId;
|
|
bool bBackFace;
|
|
float DitheredLODTransitionValue;
|
|
bool bUseTranslucentSelfShadowing;
|
|
|
|
/** Initialization constructor. */
|
|
FDrawTranslucentMeshAction(
|
|
const FViewInfo& InView,
|
|
bool bInBackFace,
|
|
float InDitheredLODTransitionValue,
|
|
FHitProxyId InHitProxyId,
|
|
const FProjectedShadowInfo* InTranslucentSelfShadow,
|
|
bool bInUseTranslucentSelfShadowing
|
|
):
|
|
View(InView),
|
|
TranslucentSelfShadow(InTranslucentSelfShadow),
|
|
HitProxyId(InHitProxyId),
|
|
bBackFace(bInBackFace),
|
|
DitheredLODTransitionValue(InDitheredLODTransitionValue),
|
|
bUseTranslucentSelfShadowing(bInUseTranslucentSelfShadowing)
|
|
{}
|
|
|
|
bool UseTranslucentSelfShadowing() const
|
|
{
|
|
return bUseTranslucentSelfShadowing;
|
|
}
|
|
|
|
const FProjectedShadowInfo* GetTranslucentSelfShadow() const
|
|
{
|
|
return TranslucentSelfShadow;
|
|
}
|
|
|
|
bool AllowIndirectLightingCache() const
|
|
{
|
|
return View.Family->EngineShowFlags.IndirectLightingCache;
|
|
}
|
|
|
|
bool AllowIndirectLightingCacheVolumeTexture() const
|
|
{
|
|
// This will force the cheaper single sample interpolated GI path
|
|
return false;
|
|
}
|
|
|
|
/** Draws the translucent mesh with a specific light-map type, and fog volume type */
|
|
template<typename LightMapPolicyType>
|
|
void Process(
|
|
FRHICommandList& RHICmdList,
|
|
const FProcessBasePassMeshParameters& Parameters,
|
|
const LightMapPolicyType& LightMapPolicy,
|
|
const typename LightMapPolicyType::ElementDataType& LightMapElementData
|
|
) const
|
|
{
|
|
const bool bIsLitMaterial = Parameters.ShadingModel != MSM_Unlit;
|
|
|
|
const FScene* Scene = Parameters.PrimitiveSceneProxy ? Parameters.PrimitiveSceneProxy->GetPrimitiveSceneInfo()->Scene : NULL;
|
|
|
|
TBasePassDrawingPolicy<LightMapPolicyType> DrawingPolicy(
|
|
Parameters.Mesh.VertexFactory,
|
|
Parameters.Mesh.MaterialRenderProxy,
|
|
*Parameters.Material,
|
|
Parameters.FeatureLevel,
|
|
LightMapPolicy,
|
|
Parameters.BlendMode,
|
|
// Translucent meshes need scene render targets set as textures
|
|
ESceneRenderTargetsMode::SetTextures,
|
|
bIsLitMaterial && Scene && Scene->SkyLight && !Scene->SkyLight->bHasStaticLighting,
|
|
Scene && Scene->HasAtmosphericFog() && View.Family->EngineShowFlags.AtmosphericFog && View.Family->EngineShowFlags.Fog,
|
|
View.Family->EngineShowFlags.ShaderComplexity,
|
|
Parameters.bAllowFog
|
|
);
|
|
RHICmdList.BuildAndSetLocalBoundShaderState(DrawingPolicy.GetBoundShaderStateInput(View.GetFeatureLevel()));
|
|
DrawingPolicy.SetSharedState(RHICmdList, &View, typename TBasePassDrawingPolicy<LightMapPolicyType>::ContextDataType());
|
|
|
|
int32 BatchElementIndex = 0;
|
|
uint64 BatchElementMask = Parameters.BatchElementMask;
|
|
do
|
|
{
|
|
if(BatchElementMask & 1)
|
|
{
|
|
DrawingPolicy.SetMeshRenderState(
|
|
RHICmdList,
|
|
View,
|
|
Parameters.PrimitiveSceneProxy,
|
|
Parameters.Mesh,
|
|
BatchElementIndex,
|
|
bBackFace,
|
|
DitheredLODTransitionValue,
|
|
typename TBasePassDrawingPolicy<LightMapPolicyType>::ElementDataType(LightMapElementData),
|
|
typename TBasePassDrawingPolicy<LightMapPolicyType>::ContextDataType()
|
|
);
|
|
DrawingPolicy.DrawMesh(RHICmdList, Parameters.Mesh,BatchElementIndex);
|
|
}
|
|
|
|
BatchElementMask >>= 1;
|
|
BatchElementIndex++;
|
|
} while(BatchElementMask);
|
|
}
|
|
};
|
|
|
|
static void CopySceneColorAndRestore(FRHICommandList& RHICmdList, const FViewInfo& View, const FPrimitiveSceneProxy* PrimitiveSceneProxy)
|
|
{
|
|
check(IsInRenderingThread());
|
|
FTranslucencyDrawingPolicyFactory::CopySceneColor(RHICmdList, View, PrimitiveSceneProxy);
|
|
// Restore state
|
|
SetTranslucentRenderTargetAndState(RHICmdList, View, false);
|
|
}
|
|
|
|
class FCopySceneColorAndRestoreRenderThreadTask
|
|
{
|
|
FRHICommandList& RHICmdList;
|
|
const FViewInfo& View;
|
|
const FPrimitiveSceneProxy* PrimitiveSceneProxy;
|
|
public:
|
|
|
|
FCopySceneColorAndRestoreRenderThreadTask(FRHICommandList& InRHICmdList, const FViewInfo& InView, const FPrimitiveSceneProxy* InPrimitiveSceneProxy)
|
|
: RHICmdList(InRHICmdList)
|
|
, View(InView)
|
|
, PrimitiveSceneProxy(InPrimitiveSceneProxy)
|
|
{
|
|
}
|
|
|
|
FORCEINLINE TStatId GetStatId() const
|
|
{
|
|
RETURN_QUICK_DECLARE_CYCLE_STAT(FCopySceneColorAndRestoreRenderThreadTask, STATGROUP_TaskGraphTasks);
|
|
}
|
|
|
|
ENamedThreads::Type GetDesiredThread()
|
|
{
|
|
return ENamedThreads::RenderThread_Local;
|
|
}
|
|
|
|
static ESubsequentsMode::Type GetSubsequentsMode() { return ESubsequentsMode::TrackSubsequents; }
|
|
|
|
void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent)
|
|
{
|
|
CopySceneColorAndRestore(RHICmdList, View, PrimitiveSceneProxy);
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Render a dynamic or static mesh using a translucent draw policy
|
|
* @return true if the mesh rendered
|
|
*/
|
|
bool FTranslucencyDrawingPolicyFactory::DrawMesh(
|
|
FRHICommandList& RHICmdList,
|
|
const FViewInfo& View,
|
|
ContextType DrawingContext,
|
|
const FMeshBatch& Mesh,
|
|
const uint64& BatchElementMask,
|
|
bool bBackFace,
|
|
float DitheredLODTransitionValue,
|
|
bool bPreFog,
|
|
const FPrimitiveSceneProxy* PrimitiveSceneProxy,
|
|
FHitProxyId HitProxyId
|
|
)
|
|
{
|
|
bool bDirty = false;
|
|
const auto FeatureLevel = View.GetFeatureLevel();
|
|
|
|
// Determine the mesh's material and blend mode.
|
|
const FMaterial* Material = Mesh.MaterialRenderProxy->GetMaterial(FeatureLevel);
|
|
const EBlendMode BlendMode = Material->GetBlendMode();
|
|
const EMaterialShadingModel ShadingModel = Material->GetShadingModel();
|
|
|
|
// Only render translucent materials.
|
|
if(IsTranslucentBlendMode(BlendMode))
|
|
{
|
|
if (Material->RequiresSceneColorCopy_RenderThread())
|
|
{
|
|
if (DrawingContext.bSceneColorCopyIsUpToDate == false)
|
|
{
|
|
if (!RHICmdList.Bypass() && !IsInRenderingThread())
|
|
{
|
|
FRHICommandList* CmdList = new FRHICommandList;
|
|
FGraphEventRef RenderThreadCompletionEvent = TGraphTask<FCopySceneColorAndRestoreRenderThreadTask>::CreateTask().ConstructAndDispatchWhenReady(*CmdList, View, PrimitiveSceneProxy);
|
|
RHICmdList.QueueRenderThreadCommandListSubmit(RenderThreadCompletionEvent, CmdList);
|
|
}
|
|
else
|
|
{
|
|
// otherwise, just do it now. We don't want to defer in this case because that can interfere with render target visualization (a debugging tool).
|
|
CopySceneColorAndRestore(RHICmdList, View, PrimitiveSceneProxy);
|
|
}
|
|
// separate translucency is not updating scene color so we don't need to copy it multiple times.
|
|
// optimization:
|
|
// we should consider the same for non separate translucency (could cause artifacts but will be much faster)
|
|
DrawingContext.bSceneColorCopyIsUpToDate = DrawingContext.bSeparateTranslucencyPass;
|
|
}
|
|
}
|
|
|
|
const bool bDisableDepthTest = Material->ShouldDisableDepthTest();
|
|
const bool bEnableResponsiveAA = Material->ShouldEnableResponsiveAA();
|
|
// editor compositing not supported on translucent materials currently
|
|
const bool bEditorCompositeDepthTest = false;
|
|
|
|
if( bEnableResponsiveAA )
|
|
{
|
|
if( bDisableDepthTest )
|
|
{
|
|
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false,CF_Always,true,CF_Always,SO_Keep,SO_Keep,SO_Replace>::GetRHI(), 1);
|
|
}
|
|
else
|
|
{
|
|
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false,CF_DepthNearOrEqual,true,CF_Always,SO_Keep,SO_Keep,SO_Replace>::GetRHI(), 1);
|
|
}
|
|
}
|
|
else if( bDisableDepthTest )
|
|
{
|
|
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false,CF_Always>::GetRHI());
|
|
}
|
|
|
|
ProcessBasePassMesh(
|
|
RHICmdList,
|
|
FProcessBasePassMeshParameters(
|
|
Mesh,
|
|
BatchElementMask,
|
|
Material,
|
|
PrimitiveSceneProxy,
|
|
!bPreFog,
|
|
bEditorCompositeDepthTest,
|
|
ESceneRenderTargetsMode::SetTextures,
|
|
FeatureLevel
|
|
),
|
|
FDrawTranslucentMeshAction(
|
|
View,
|
|
bBackFace,
|
|
DitheredLODTransitionValue,
|
|
HitProxyId,
|
|
DrawingContext.TranslucentSelfShadow,
|
|
PrimitiveSceneProxy && PrimitiveSceneProxy->CastsVolumetricTranslucentShadow()
|
|
)
|
|
);
|
|
|
|
if (bDisableDepthTest || bEnableResponsiveAA)
|
|
{
|
|
// Restore default depth state
|
|
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false,CF_DepthNearOrEqual>::GetRHI());
|
|
}
|
|
|
|
bDirty = true;
|
|
}
|
|
return bDirty;
|
|
}
|
|
|
|
|
|
/**
|
|
* Render a dynamic mesh using a translucent draw policy
|
|
* @return true if the mesh rendered
|
|
*/
|
|
bool FTranslucencyDrawingPolicyFactory::DrawDynamicMesh(
|
|
FRHICommandList& RHICmdList,
|
|
const FViewInfo& View,
|
|
ContextType DrawingContext,
|
|
const FMeshBatch& Mesh,
|
|
bool bBackFace,
|
|
bool bPreFog,
|
|
const FPrimitiveSceneProxy* PrimitiveSceneProxy,
|
|
FHitProxyId HitProxyId
|
|
)
|
|
{
|
|
return DrawMesh(
|
|
RHICmdList,
|
|
View,
|
|
DrawingContext,
|
|
Mesh,
|
|
Mesh.Elements.Num()==1 ? 1 : (1<<Mesh.Elements.Num())-1, // 1 bit set for each mesh element
|
|
bBackFace,
|
|
Mesh.DitheredLODTransitionAlpha,
|
|
bPreFog,
|
|
PrimitiveSceneProxy,
|
|
HitProxyId);
|
|
}
|
|
|
|
/**
|
|
* Render a static mesh using a translucent draw policy
|
|
* @return true if the mesh rendered
|
|
*/
|
|
bool FTranslucencyDrawingPolicyFactory::DrawStaticMesh(
|
|
FRHICommandList& RHICmdList,
|
|
const FViewInfo& View,
|
|
ContextType DrawingContext,
|
|
const FStaticMesh& StaticMesh,
|
|
const uint64& BatchElementMask,
|
|
bool bPreFog,
|
|
const FPrimitiveSceneProxy* PrimitiveSceneProxy,
|
|
FHitProxyId HitProxyId
|
|
)
|
|
{
|
|
float DitherValue = View.GetDitheredLODTransitionValue(StaticMesh);
|
|
return DrawMesh(
|
|
RHICmdList,
|
|
View,
|
|
DrawingContext,
|
|
StaticMesh,
|
|
BatchElementMask,
|
|
false,
|
|
DitherValue,
|
|
bPreFog,
|
|
PrimitiveSceneProxy,
|
|
HitProxyId
|
|
);
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
FTranslucentPrimSet
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
void FTranslucentPrimSet::DrawAPrimitive(
|
|
FRHICommandList& RHICmdList,
|
|
const FViewInfo& View,
|
|
FDeferredShadingSceneRenderer& Renderer,
|
|
bool bSeparateTranslucencyPass,
|
|
int32 PrimIdx
|
|
) const
|
|
{
|
|
const TArray<FSortedPrim, SceneRenderingAllocator>* PhaseSortedPrimitivesPtr = NULL;
|
|
|
|
// copy to reference for easier access
|
|
const TArray<FSortedPrim, SceneRenderingAllocator>& PhaseSortedPrimitives =
|
|
bSeparateTranslucencyPass ? SortedSeparateTranslucencyPrims : SortedPrims;
|
|
check(PrimIdx < PhaseSortedPrimitives.Num());
|
|
|
|
FPrimitiveSceneInfo* PrimitiveSceneInfo = PhaseSortedPrimitives[PrimIdx].PrimitiveSceneInfo;
|
|
int32 PrimitiveId = PrimitiveSceneInfo->GetIndex();
|
|
const FPrimitiveViewRelevance& ViewRelevance = View.PrimitiveViewRelevanceMap[PrimitiveId];
|
|
|
|
checkSlow(ViewRelevance.HasTranslucency());
|
|
|
|
const FProjectedShadowInfo* TranslucentSelfShadow = Renderer.PrepareTranslucentShadowMap(RHICmdList, View, PrimitiveSceneInfo, bSeparateTranslucencyPass);
|
|
|
|
RenderPrimitive(RHICmdList, View, PrimitiveSceneInfo, ViewRelevance, TranslucentSelfShadow, bSeparateTranslucencyPass);
|
|
}
|
|
|
|
class FVolumetricTranslucentShadowRenderThreadTask
|
|
{
|
|
FRHICommandList& RHICmdList;
|
|
const FTranslucentPrimSet &PrimSet;
|
|
const FViewInfo& View;
|
|
FDeferredShadingSceneRenderer& Renderer;
|
|
bool bSeparateTranslucencyPass;
|
|
int32 Index;
|
|
|
|
public:
|
|
|
|
FORCEINLINE_DEBUGGABLE FVolumetricTranslucentShadowRenderThreadTask(FRHICommandList& InRHICmdList, const FTranslucentPrimSet& InPrimSet, const FViewInfo& InView, FDeferredShadingSceneRenderer& InRenderer, bool InbSeparateTranslucencyPass, int32 InIndex)
|
|
: RHICmdList(InRHICmdList)
|
|
, PrimSet(InPrimSet)
|
|
, View(InView)
|
|
, Renderer(InRenderer)
|
|
, bSeparateTranslucencyPass(InbSeparateTranslucencyPass)
|
|
, Index(InIndex)
|
|
{
|
|
}
|
|
|
|
FORCEINLINE TStatId GetStatId() const
|
|
{
|
|
RETURN_QUICK_DECLARE_CYCLE_STAT(FVolumetricTranslucentShadowRenderThreadTask, STATGROUP_TaskGraphTasks);
|
|
}
|
|
|
|
ENamedThreads::Type GetDesiredThread()
|
|
{
|
|
return ENamedThreads::RenderThread_Local;
|
|
}
|
|
|
|
static ESubsequentsMode::Type GetSubsequentsMode() { return ESubsequentsMode::TrackSubsequents; }
|
|
|
|
void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent)
|
|
{
|
|
PrimSet.DrawAPrimitive(RHICmdList, View, Renderer, bSeparateTranslucencyPass, Index);
|
|
}
|
|
};
|
|
|
|
void FTranslucentPrimSet::DrawPrimitivesParallel(
|
|
FRHICommandList& RHICmdList,
|
|
const FViewInfo& View,
|
|
FDeferredShadingSceneRenderer& Renderer,
|
|
bool bSeparateTranslucencyPass,
|
|
int32 FirstIndex, int32 LastIndex
|
|
) const
|
|
{
|
|
const TArray<FSortedPrim, SceneRenderingAllocator>* PhaseSortedPrimitivesPtr = NULL;
|
|
|
|
// copy to reference for easier access
|
|
const TArray<FSortedPrim, SceneRenderingAllocator>& PhaseSortedPrimitives =
|
|
bSeparateTranslucencyPass ? SortedSeparateTranslucencyPrims : SortedPrims;
|
|
check(LastIndex < PhaseSortedPrimitives.Num());
|
|
// Draw sorted scene prims
|
|
for (int32 PrimIdx = FirstIndex; PrimIdx <= LastIndex; PrimIdx++)
|
|
{
|
|
FPrimitiveSceneInfo* PrimitiveSceneInfo = PhaseSortedPrimitives[PrimIdx].PrimitiveSceneInfo;
|
|
int32 PrimitiveId = PrimitiveSceneInfo->GetIndex();
|
|
const FPrimitiveViewRelevance& ViewRelevance = View.PrimitiveViewRelevanceMap[PrimitiveId];
|
|
|
|
checkSlow(ViewRelevance.HasTranslucency());
|
|
|
|
if (PrimitiveSceneInfo->Proxy && PrimitiveSceneInfo->Proxy->CastsVolumetricTranslucentShadow())
|
|
{
|
|
check(!IsInRenderingThread());
|
|
// can't do this in parallel, defer
|
|
FRHICommandList* CmdList = new FRHICommandList;
|
|
FGraphEventRef RenderThreadCompletionEvent = TGraphTask<FVolumetricTranslucentShadowRenderThreadTask>::CreateTask().ConstructAndDispatchWhenReady(*CmdList, *this, View, Renderer, bSeparateTranslucencyPass, PrimIdx);
|
|
RHICmdList.QueueRenderThreadCommandListSubmit(RenderThreadCompletionEvent, CmdList);
|
|
}
|
|
else
|
|
{
|
|
RenderPrimitive(RHICmdList, View, PrimitiveSceneInfo, ViewRelevance, nullptr, bSeparateTranslucencyPass);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FTranslucentPrimSet::DrawPrimitives(
|
|
FRHICommandListImmediate& RHICmdList,
|
|
const FViewInfo& View,
|
|
FDeferredShadingSceneRenderer& Renderer,
|
|
bool bSeparateTranslucencyPass
|
|
) const
|
|
{
|
|
const TArray<FSortedPrim,SceneRenderingAllocator>* PhaseSortedPrimitivesPtr = NULL;
|
|
|
|
// copy to reference for easier access
|
|
const TArray<FSortedPrim,SceneRenderingAllocator>& PhaseSortedPrimitives =
|
|
bSeparateTranslucencyPass ? SortedSeparateTranslucencyPrims : SortedPrims;
|
|
|
|
if( PhaseSortedPrimitives.Num() )
|
|
{
|
|
// Draw sorted scene prims
|
|
for( int32 PrimIdx=0; PrimIdx < PhaseSortedPrimitives.Num(); PrimIdx++ )
|
|
{
|
|
FPrimitiveSceneInfo* PrimitiveSceneInfo = PhaseSortedPrimitives[PrimIdx].PrimitiveSceneInfo;
|
|
int32 PrimitiveId = PrimitiveSceneInfo->GetIndex();
|
|
const FPrimitiveViewRelevance& ViewRelevance = View.PrimitiveViewRelevanceMap[PrimitiveId];
|
|
|
|
checkSlow(ViewRelevance.HasTranslucency());
|
|
|
|
const FProjectedShadowInfo* TranslucentSelfShadow = Renderer.PrepareTranslucentShadowMap(RHICmdList, View, PrimitiveSceneInfo, bSeparateTranslucencyPass);
|
|
|
|
RenderPrimitive(RHICmdList, View, PrimitiveSceneInfo, ViewRelevance, TranslucentSelfShadow, bSeparateTranslucencyPass);
|
|
}
|
|
}
|
|
|
|
View.SimpleElementCollector.DrawBatchedElements(RHICmdList, View, FTexture2DRHIRef(), EBlendModeFilter::Translucent);
|
|
}
|
|
|
|
void FTranslucentPrimSet::RenderPrimitive(
|
|
FRHICommandList& RHICmdList,
|
|
const FViewInfo& View,
|
|
FPrimitiveSceneInfo* PrimitiveSceneInfo,
|
|
const FPrimitiveViewRelevance& ViewRelevance,
|
|
const FProjectedShadowInfo* TranslucentSelfShadow,
|
|
bool bSeparateTranslucencyPass) const
|
|
{
|
|
checkSlow(ViewRelevance.HasTranslucency());
|
|
auto FeatureLevel = View.GetFeatureLevel();
|
|
|
|
if(ViewRelevance.bDrawRelevance)
|
|
{
|
|
FTranslucencyDrawingPolicyFactory::ContextType Context(TranslucentSelfShadow, bSeparateTranslucencyPass);
|
|
|
|
//@todo parallelrendering - come up with a better way to filter these by primitive
|
|
for (int32 MeshBatchIndex = 0; MeshBatchIndex < View.DynamicMeshElements.Num(); MeshBatchIndex++)
|
|
{
|
|
const FMeshBatchAndRelevance& MeshBatchAndRelevance = View.DynamicMeshElements[MeshBatchIndex];
|
|
|
|
if (MeshBatchAndRelevance.PrimitiveSceneProxy == PrimitiveSceneInfo->Proxy)
|
|
{
|
|
const FMeshBatch& MeshBatch = *MeshBatchAndRelevance.Mesh;
|
|
FTranslucencyDrawingPolicyFactory::DrawDynamicMesh(RHICmdList, View, Context, MeshBatch, false, false, MeshBatchAndRelevance.PrimitiveSceneProxy, MeshBatch.BatchHitProxyId);
|
|
}
|
|
}
|
|
|
|
// Render static scene prim
|
|
if( ViewRelevance.bStaticRelevance )
|
|
{
|
|
// Render static meshes from static scene prim
|
|
for( int32 StaticMeshIdx=0; StaticMeshIdx < PrimitiveSceneInfo->StaticMeshes.Num(); StaticMeshIdx++ )
|
|
{
|
|
FStaticMesh& StaticMesh = PrimitiveSceneInfo->StaticMeshes[StaticMeshIdx];
|
|
if (View.StaticMeshVisibilityMap[StaticMesh.Id]
|
|
// Only render static mesh elements using translucent materials
|
|
&& StaticMesh.IsTranslucent(FeatureLevel)
|
|
&& (StaticMesh.MaterialRenderProxy->GetMaterial(FeatureLevel)->IsSeparateTranslucencyEnabled() == bSeparateTranslucencyPass))
|
|
{
|
|
FTranslucencyDrawingPolicyFactory::DrawStaticMesh(
|
|
RHICmdList,
|
|
View,
|
|
FTranslucencyDrawingPolicyFactory::ContextType( TranslucentSelfShadow, bSeparateTranslucencyPass),
|
|
StaticMesh,
|
|
StaticMesh.Elements.Num() == 1 ? 1 : View.StaticMeshBatchVisibility[StaticMesh.Id],
|
|
false,
|
|
PrimitiveSceneInfo->Proxy,
|
|
StaticMesh.BatchHitProxyId
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
inline float CalculateTranslucentSortKey(FPrimitiveSceneInfo* PrimitiveSceneInfo, const FViewInfo& ViewInfo)
|
|
{
|
|
float SortKey = 0.0f;
|
|
if (ViewInfo.TranslucentSortPolicy == ETranslucentSortPolicy::SortByDistance)
|
|
{
|
|
//sort based on distance to the view position, view rotation is not a factor
|
|
SortKey = (PrimitiveSceneInfo->Proxy->GetBounds().Origin - ViewInfo.ViewMatrices.ViewOrigin).Size();
|
|
// UE4_TODO: also account for DPG in the sort key.
|
|
}
|
|
else if (ViewInfo.TranslucentSortPolicy == ETranslucentSortPolicy::SortAlongAxis)
|
|
{
|
|
// Sort based on enforced orthogonal distance
|
|
const FVector CameraToObject = PrimitiveSceneInfo->Proxy->GetBounds().Origin - ViewInfo.ViewMatrices.ViewOrigin;
|
|
SortKey = FVector::DotProduct(CameraToObject, ViewInfo.TranslucentSortAxis);
|
|
}
|
|
else
|
|
{
|
|
// Sort based on projected Z distance
|
|
check(ViewInfo.TranslucentSortPolicy == ETranslucentSortPolicy::SortByProjectedZ);
|
|
SortKey = ViewInfo.ViewMatrices.ViewMatrix.TransformPosition(PrimitiveSceneInfo->Proxy->GetBounds().Origin).Z;
|
|
}
|
|
|
|
return SortKey;
|
|
}
|
|
|
|
/**
|
|
* Add a new primitive to the list of sorted prims
|
|
* @param PrimitiveSceneInfo - primitive info to add. Origin of bounds is used for sort.
|
|
* @param ViewInfo - used to transform bounds to view space
|
|
*/
|
|
void FTranslucentPrimSet::AddScenePrimitive(FPrimitiveSceneInfo* PrimitiveSceneInfo, const FViewInfo& ViewInfo, bool bUseNormalTranslucency, bool bUseSeparateTranslucency)
|
|
{
|
|
const float SortKey = CalculateTranslucentSortKey(PrimitiveSceneInfo, ViewInfo);
|
|
|
|
const auto FeatureLevel = ViewInfo.GetFeatureLevel();
|
|
|
|
if(bUseSeparateTranslucency
|
|
&& FeatureLevel >= ERHIFeatureLevel::SM4)
|
|
{
|
|
// add to list of translucent prims that use scene color
|
|
new(SortedSeparateTranslucencyPrims) FSortedPrim(PrimitiveSceneInfo,SortKey,PrimitiveSceneInfo->Proxy->GetTranslucencySortPriority());
|
|
}
|
|
|
|
if (bUseNormalTranslucency
|
|
// Force separate translucency to be rendered normally if the feature level does not support separate translucency
|
|
|| (bUseSeparateTranslucency && FeatureLevel < ERHIFeatureLevel::SM4))
|
|
{
|
|
// add to list of translucent prims
|
|
new(SortedPrims) FSortedPrim(PrimitiveSceneInfo,SortKey,PrimitiveSceneInfo->Proxy->GetTranslucencySortPriority());
|
|
}
|
|
}
|
|
|
|
void FTranslucentPrimSet::AppendScenePrimitives(FSortedPrim* Normal, int32 NumNormal, FSortedPrim* Separate, int32 NumSeparate)
|
|
{
|
|
SortedPrims.Append(Normal, NumNormal);
|
|
SortedSeparateTranslucencyPrims.Append(Separate, NumSeparate);
|
|
}
|
|
|
|
void FTranslucentPrimSet::PlaceScenePrimitive(FPrimitiveSceneInfo* PrimitiveSceneInfo, const FViewInfo& ViewInfo, bool bUseNormalTranslucency, bool bUseSeparateTranslucency, void *NormalPlace, int32& NormalNum, void* SeparatePlace, int32& SeparateNum)
|
|
{
|
|
const float SortKey = CalculateTranslucentSortKey(PrimitiveSceneInfo, ViewInfo);
|
|
|
|
const auto FeatureLevel = ViewInfo.GetFeatureLevel();
|
|
|
|
if(bUseSeparateTranslucency
|
|
&& FeatureLevel >= ERHIFeatureLevel::SM4)
|
|
{
|
|
// add to list of translucent prims that use scene color
|
|
new (SeparatePlace) FSortedPrim(PrimitiveSceneInfo,SortKey,PrimitiveSceneInfo->Proxy->GetTranslucencySortPriority());
|
|
SeparateNum++;
|
|
}
|
|
|
|
if (bUseNormalTranslucency
|
|
// Force separate translucency to be rendered normally if the feature level does not support separate translucency
|
|
|| (bUseSeparateTranslucency && FeatureLevel < ERHIFeatureLevel::SM4))
|
|
{
|
|
// add to list of translucent prims
|
|
new (NormalPlace) FSortedPrim(PrimitiveSceneInfo,SortKey,PrimitiveSceneInfo->Proxy->GetTranslucencySortPriority());
|
|
NormalNum++;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sort any primitives that were added to the set back-to-front
|
|
*/
|
|
void FTranslucentPrimSet::SortPrimitives()
|
|
{
|
|
// sort prims based on depth
|
|
SortedPrims.Sort( FCompareFSortedPrim() );
|
|
SortedSeparateTranslucencyPrims.Sort( FCompareFSortedPrim() );
|
|
}
|
|
|
|
bool FSceneRenderer::ShouldRenderTranslucency() const
|
|
{
|
|
bool bRender = false;
|
|
|
|
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
|
|
{
|
|
const FViewInfo& View = Views[ViewIndex];
|
|
|
|
if (View.TranslucentPrimSet.NumPrims() > 0 || View.bHasTranslucentViewMeshElements || View.TranslucentPrimSet.NumSeparateTranslucencyPrims() > 0)
|
|
{
|
|
bRender = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return bRender;
|
|
}
|
|
|
|
class FDrawSortedTransAnyThreadTask
|
|
{
|
|
FDeferredShadingSceneRenderer& Renderer;
|
|
FRHICommandList& RHICmdList;
|
|
const FViewInfo& View;
|
|
bool bSeparateTranslucencyPass;
|
|
|
|
const int32 FirstIndex;
|
|
const int32 LastIndex;
|
|
|
|
public:
|
|
|
|
FDrawSortedTransAnyThreadTask(
|
|
FDeferredShadingSceneRenderer& InRenderer,
|
|
FRHICommandList& InRHICmdList,
|
|
const FViewInfo& InView,
|
|
bool InbSeparateTranslucencyPass,
|
|
int32 InFirstIndex,
|
|
int32 InLastIndex
|
|
)
|
|
: Renderer(InRenderer)
|
|
, RHICmdList(InRHICmdList)
|
|
, View(InView)
|
|
, bSeparateTranslucencyPass(InbSeparateTranslucencyPass)
|
|
, FirstIndex(InFirstIndex)
|
|
, LastIndex(InLastIndex)
|
|
{
|
|
}
|
|
|
|
FORCEINLINE TStatId GetStatId() const
|
|
{
|
|
RETURN_QUICK_DECLARE_CYCLE_STAT(FDrawSortedTransAnyThreadTask, STATGROUP_TaskGraphTasks);
|
|
}
|
|
|
|
ENamedThreads::Type GetDesiredThread()
|
|
{
|
|
return ENamedThreads::AnyThread;
|
|
}
|
|
|
|
static ESubsequentsMode::Type GetSubsequentsMode() { return ESubsequentsMode::TrackSubsequents; }
|
|
|
|
void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent)
|
|
{
|
|
View.TranslucentPrimSet.DrawPrimitivesParallel(RHICmdList, View, Renderer, bSeparateTranslucencyPass, FirstIndex, LastIndex);
|
|
RHICmdList.HandleRTThreadTaskCompletion(MyCompletionGraphEvent);
|
|
}
|
|
};
|
|
|
|
class FTranslucencyPassParallelCommandListSet : public FParallelCommandListSet
|
|
{
|
|
bool bSeparateTranslucency;
|
|
bool bFirstTimeThisFrame;
|
|
public:
|
|
FTranslucencyPassParallelCommandListSet(const FViewInfo& InView, FRHICommandList& InParentCmdList, bool* InOutDirty, bool bInParallelExecute, bool bInSeparateTranslucency)
|
|
: FParallelCommandListSet(InView, InParentCmdList, InOutDirty, bInParallelExecute)
|
|
, bSeparateTranslucency(bInSeparateTranslucency)
|
|
, bFirstTimeThisFrame(bInSeparateTranslucency)
|
|
{
|
|
SetStateOnCommandList(ParentCmdList);
|
|
}
|
|
|
|
virtual ~FTranslucencyPassParallelCommandListSet()
|
|
{
|
|
Dispatch();
|
|
}
|
|
|
|
virtual void SetStateOnCommandList(FRHICommandList& CmdList) override
|
|
{
|
|
SetTranslucentRenderTargetAndState(CmdList, View, bSeparateTranslucency, bFirstTimeThisFrame);
|
|
bFirstTimeThisFrame = false;
|
|
}
|
|
};
|
|
|
|
static TAutoConsoleVariable<int32> CVarRHICmdTranslucencyPassDeferredContexts(
|
|
TEXT("r.RHICmdTranslucencyPassDeferredContexts"),
|
|
1,
|
|
TEXT("True to use deferred contexts to parallelize base pass command list execution."));
|
|
|
|
void FDeferredShadingSceneRenderer::RenderTranslucencyParallel(FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
GSceneRenderTargets.AllocLightAttenuation(); // materials will attempt to get this texture before the deferred command to set it up executes
|
|
check(IsInRenderingThread());
|
|
|
|
|
|
FScopedCommandListWaitForTasks Flusher(RHICmdList);
|
|
FTranslucencyDrawingPolicyFactory::ContextType ThisContext;
|
|
|
|
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
|
|
{
|
|
SCOPED_CONDITIONAL_DRAW_EVENTF(RHICmdList, EventView, Views.Num() > 1, TEXT("View%d"), ViewIndex);
|
|
|
|
const FViewInfo& View = Views[ViewIndex];
|
|
|
|
{
|
|
const bool bSeparateTranslucency = false;
|
|
FTranslucencyPassParallelCommandListSet ParallelCommandListSet(View, RHICmdList, nullptr, CVarRHICmdTranslucencyPassDeferredContexts.GetValueOnRenderThread() > 0, bSeparateTranslucency);
|
|
|
|
{
|
|
int32 NumPrims = View.TranslucentPrimSet.NumPrims() - View.TranslucentPrimSet.NumSeparateTranslucencyPrims();
|
|
int32 EffectiveThreads = FMath::Min<int32>(NumPrims, ParallelCommandListSet.Width);
|
|
|
|
int32 Start = 0;
|
|
if (EffectiveThreads)
|
|
{
|
|
|
|
int32 NumPer = NumPrims / EffectiveThreads;
|
|
int32 Extra = NumPrims - NumPer * EffectiveThreads;
|
|
|
|
|
|
for (int32 ThreadIndex = 0; ThreadIndex < EffectiveThreads; ThreadIndex++)
|
|
{
|
|
int32 Last = Start + (NumPer - 1) + (ThreadIndex < Extra);
|
|
check(Last >= Start);
|
|
|
|
{
|
|
FRHICommandList* CmdList = ParallelCommandListSet.NewParallelCommandList();
|
|
|
|
FGraphEventRef AnyThreadCompletionEvent = TGraphTask<FDrawSortedTransAnyThreadTask>::CreateTask(nullptr, ENamedThreads::RenderThread)
|
|
.ConstructAndDispatchWhenReady(*this, *CmdList, View, false, Start, Last);
|
|
|
|
ParallelCommandListSet.AddParallelCommandList(CmdList, AnyThreadCompletionEvent);
|
|
}
|
|
Start = Last + 1;
|
|
}
|
|
}
|
|
}
|
|
// Draw the view's mesh elements with the translucent drawing policy.
|
|
DrawViewElementsParallel<FTranslucencyDrawingPolicyFactory>(ThisContext, SDPG_World, false, ParallelCommandListSet);
|
|
// Draw the view's mesh elements with the translucent drawing policy.
|
|
DrawViewElementsParallel<FTranslucencyDrawingPolicyFactory>(ThisContext, SDPG_Foreground, false, ParallelCommandListSet);
|
|
|
|
FinishTranslucentRenderTarget(RHICmdList, View, bSeparateTranslucency);
|
|
}
|
|
|
|
#if 0 // unsupported visualization in the parallel case
|
|
const FSceneViewState* ViewState = (const FSceneViewState*)View.State;
|
|
if (ViewState && View.Family->EngineShowFlags.VisualizeLPV)
|
|
{
|
|
FLightPropagationVolume* LightPropagationVolume = ViewState->GetLightPropagationVolume();
|
|
|
|
if (LightPropagationVolume)
|
|
{
|
|
LightPropagationVolume->Visualise(RHICmdList, View);
|
|
}
|
|
}
|
|
#endif
|
|
{
|
|
{
|
|
// always call BeginRenderingSeparateTranslucency() even if there are no primitives to we keep the RT allocated
|
|
FTranslucencyPassParallelCommandListSet ParallelCommandListSet(View, RHICmdList, nullptr, CVarRHICmdTranslucencyPassDeferredContexts.GetValueOnRenderThread() > 0, true);
|
|
|
|
// Draw only translucent prims that are in the SeparateTranslucency pass
|
|
if (View.TranslucentPrimSet.NumSeparateTranslucencyPrims() > 0)
|
|
{
|
|
int32 NumPrims = View.TranslucentPrimSet.NumSeparateTranslucencyPrims();
|
|
int32 EffectiveThreads = FMath::Min<int32>(NumPrims, ParallelCommandListSet.Width);
|
|
|
|
int32 Start = 0;
|
|
check(EffectiveThreads);
|
|
{
|
|
int32 NumPer = NumPrims / EffectiveThreads;
|
|
int32 Extra = NumPrims - NumPer * EffectiveThreads;
|
|
|
|
|
|
for (int32 ThreadIndex = 0; ThreadIndex < EffectiveThreads; ThreadIndex++)
|
|
{
|
|
int32 Last = Start + (NumPer - 1) + (ThreadIndex < Extra);
|
|
check(Last >= Start);
|
|
|
|
{
|
|
FRHICommandList* CmdList = ParallelCommandListSet.NewParallelCommandList();
|
|
|
|
FGraphEventRef AnyThreadCompletionEvent = TGraphTask<FDrawSortedTransAnyThreadTask>::CreateTask(nullptr, ENamedThreads::RenderThread)
|
|
.ConstructAndDispatchWhenReady(*this, *CmdList, View, true, Start, Last);
|
|
|
|
ParallelCommandListSet.AddParallelCommandList(CmdList, AnyThreadCompletionEvent);
|
|
}
|
|
Start = Last + 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
GSceneRenderTargets.FinishRenderingSeparateTranslucency(RHICmdList, View);
|
|
}
|
|
}
|
|
}
|
|
|
|
static TAutoConsoleVariable<int32> CVarParallelTranslucency(
|
|
TEXT("r.ParallelTranslucency"),
|
|
1,
|
|
TEXT("Toggles parallel translucency rendering. Parallel rendering must be enabled for this to have an effect."),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
void FDeferredShadingSceneRenderer::RenderTranslucency(FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
if (ShouldRenderTranslucency())
|
|
{
|
|
|
|
SCOPED_DRAW_EVENT(RHICmdList, Translucency);
|
|
|
|
if (GRHICommandList.UseParallelAlgorithms() && CVarParallelTranslucency.GetValueOnRenderThread())
|
|
{
|
|
RenderTranslucencyParallel(RHICmdList);
|
|
return;
|
|
}
|
|
|
|
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
|
|
{
|
|
SCOPED_CONDITIONAL_DRAW_EVENTF(RHICmdList, EventView, Views.Num() > 1, TEXT("View%d"), ViewIndex);
|
|
|
|
const FViewInfo& View = Views[ViewIndex];
|
|
|
|
SetTranslucentRenderTargetAndState(RHICmdList, View, false);
|
|
|
|
// Draw only translucent prims that don't read from scene color
|
|
View.TranslucentPrimSet.DrawPrimitives(RHICmdList, View, *this, false);
|
|
// Draw the view's mesh elements with the translucent drawing policy.
|
|
DrawViewElements<FTranslucencyDrawingPolicyFactory>(RHICmdList, View, FTranslucencyDrawingPolicyFactory::ContextType(), SDPG_World, false);
|
|
// Draw the view's mesh elements with the translucent drawing policy.
|
|
DrawViewElements<FTranslucencyDrawingPolicyFactory>(RHICmdList, View, FTranslucencyDrawingPolicyFactory::ContextType(), SDPG_Foreground, false);
|
|
|
|
const FSceneViewState* ViewState = (const FSceneViewState*)View.State;
|
|
|
|
if(ViewState && View.Family->EngineShowFlags.VisualizeLPV)
|
|
{
|
|
FLightPropagationVolume* LightPropagationVolume = ViewState->GetLightPropagationVolume();
|
|
|
|
if (LightPropagationVolume)
|
|
{
|
|
LightPropagationVolume->Visualise(RHICmdList, View);
|
|
}
|
|
}
|
|
|
|
FinishTranslucentRenderTarget(RHICmdList, View, false);
|
|
|
|
{
|
|
bool bRenderSeparateTranslucency = View.TranslucentPrimSet.NumSeparateTranslucencyPrims() > 0;
|
|
|
|
// always call BeginRenderingSeparateTranslucency() even if there are no primitives to we keep the RT allocated
|
|
bool bSetupTranslucency = GSceneRenderTargets.BeginRenderingSeparateTranslucency(RHICmdList, View, true);
|
|
|
|
// Draw only translucent prims that are in the SeparateTranslucency pass
|
|
if (bRenderSeparateTranslucency)
|
|
{
|
|
if (bSetupTranslucency)
|
|
{
|
|
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_DepthNearOrEqual>::GetRHI());
|
|
}
|
|
|
|
View.TranslucentPrimSet.DrawPrimitives(RHICmdList, View, *this, true);
|
|
}
|
|
|
|
GSceneRenderTargets.FinishRenderingSeparateTranslucency(RHICmdList, View);
|
|
}
|
|
}
|
|
}
|
|
}
|