You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#lockdown Nick.Penwarden #rb none ========================== MAJOR FEATURES + CHANGES ========================== Change 3045482 on 2016/07/11 by Zabir.Hoque DX12 Quries need to individually track their syncpoints. Only when resolving a query on the same frame should be stall. Change 3045929 on 2016/07/12 by Simon.Tovey Removing some deprecated node types from Niagara Change 3045951 on 2016/07/12 by Ben.Woodhouse D3D11 Log detailed live device info on shutdown if the debug layer is enabled (including resource types) Change3046019on 2016/07/12 by Chris.Bunner Fixed typo in material input name. #jira UE-5575 Change 3046053 on 2016/07/12 by Rolando.Caloca DR - Fix GL4 shutdown #jira UE-32799 Change 3046055 on 2016/07/12 by Rolando.Caloca DR - vk - Fix NumInstances=0 Change 3046063 on 2016/07/12 by Rolando.Caloca DR - vk - Added flat to uint layouts per glslang - Fix bad extension on dumped shaders Change 3046067 on 2016/07/12 by Rolando.Caloca DR - vk - Fix check when not using color RT - Added queue submit & present counters Change3046088on 2016/07/12 by Ben.Woodhouse Live GPU stats A non-hierarchical realtime high level GPU profiler with support for cumulative stat recording. Stats are added with SCOPED_GPU_STAT macros, e.g. SCOPED_GPU_STAT(RHICmdList, Stat_GPU_Distortion) The bulk of the files in this change are simply instrumentation for the renderer. The core changes are in SceneUtils.cpp/h and D3D11Query.cpp (this is the XB1/DX11X implementation of timestamp RHI queries, which was missing) Note: this is currently disabled by default. Enable with the cvar r.gpustatsenabled Tested on PC, XB1, PS4 Change 3046128 on 2016/07/12 by Olaf.Piesche Max draw distance and fade range for lights, requested by JonL Change 3046183 on 2016/07/12 by Ben.Woodhouse PR #2532: Fix SSAO being applied in unlit viewmode (Contributed by nick-penwarden) Change 3046223 on 2016/07/12 by Luke.Thatcher Fix Scene Cube Captures. SceneCaptureSource flag on the ViewFamily was not set for cube components. #jira UE-32345 Change 3046228 on 2016/07/12 by Marc.Olano Add Voronoi noise to Noise material node. Four versions with differing speed/quality levels accessed through the Quality value in the material node. Tooltips give estimates of the cost of each. Also includes spiffy new Rand3DPCG16 and Rand3DPCG32 int3 to int3 hash functions, and a 20% improvement on the computed gradient noise. Change 3046269 on 2016/07/12 by Rolando.Caloca DR - Skip flush on RHIDiscardRenderTargets and only use it on platforms that need it (ie OpenGL) Change 3046294 on 2016/07/12 by Rolando.Caloca DR - Fix static analyisis warning C6326: Potential comparison of a constant with another constant. Change 3046295 on 2016/07/12 by Rolando.Caloca DR - Fix the previous fix Change 3046731 on 2016/07/12 by Marc.Olano Fix typo in shader random number constant: repeated extra digit made it too big. Change 3046796 on 2016/07/12 by Uriel.Doyon The texture streaming manager now keeps a set of all valid textures. This is used to prevent from indirecting deleted memory upon SetTexturesRemovedTimestamp. #jira UE-33048 Change 3046800 on 2016/07/12 by Rolando.Caloca DR - vk - Added create image & renderpass dump Change 3046845 on 2016/07/12 by John.Billon Forgot to apply MaxGPUSkinBones Cvar access changes in a few locations. Change 3047023 on 2016/07/12 by Olaf.Piesche Niagara: -a bit of cleanup -now store and double buffer attributes individually, eliminating unnecessary copy of unused attributes -removed FNiagaraConstantMap, replaced with an instance of FNiagaraConstants -some code simplification -removed some deprecated structs and code used only by old content Change 3047052 on 2016/07/12 by Zabir.Hoque Unshelved from pending changelist '3044062': PR #2588: Adding blend mode BLEND_AlphaComposite (4.12) (Contributed by moritz-wundke) Change 3047727 on 2016/07/13 by Luke.Thatcher Fix Scene Capture Components only updating every other frame. #jira UE-32581 Change 3047919 on 2016/07/13 by Olaf.Piesche CMask decode, use in deferred decals, for PS4 Change 3047921 on 2016/07/13 by Uriel.Doyon "Build Texture Streaming" will now remove duplicate error msg when computing texcoord scales. Also, several texture messages are packed on the same line if they relate to the same material. Change 3047952 on 2016/07/13 by Rolando.Caloca DR - vk - Initial prep pass for separating combined images & samplers Change 3048648 on 2016/07/13 by Marcus.Wassmer Fix rare GPU hang when asynctexture reallocs would overlap with EndFrame Change 3049058 on 2016/07/13 by Rolando.Caloca DR - vk - timestamps Change 3049725 on 2016/07/14 by Marcus.Wassmer Fix autosdk bug where not having a platform directory sync'd at all would break manual SDK detection Change 3049742 on 2016/07/14 by Rolando.Caloca DR - Fix warning Change 3049902 on 2016/07/14 by Rolando.Caloca DR - Fix typo Change 3050345 on 2016/07/14 by Olaf.Piesche UE-23925 Clamping noise tessellation for beams at a high but sensible value; also making sure during beam index buffer building that we never get over 2^16 indices; this is a bit hokey, but there are so many variables that can influence triangle/index count, that this is the only way to be sure (short of nuking the entire site from orbit). Change 3050409 on 2016/07/14 by Olaf.Piesche Replicating 3049049; missing break and check for active particles when resolving a source point to avoid a potential crash Change 3050809 on 2016/07/14 by Rolando.Caloca DR - vk - Remove redundant validation layers Change 3051319 on 2016/07/15 by Ben.Woodhouse Fix for world space camera position not being exposed in decal pixel shaders; also fixes decal lighting missing spec and reflection The fix was to calculate ResolvedView at the top of the shader. Previously this was not initialized #jira UE-31976 Change 3051692 on 2016/07/15 by Rolando.Caloca DR - vk - Enable RHI thread by default Change 3052103 on 2016/07/15 by Uriel.Doyon Disabled depth offset in depth only pixel shaders when using debug view shaders (to prevent Z fighting). #jira UE-32765 Change 3052140 on 2016/07/15 by Rolando.Caloca DR - vk - Fix shader snafu Change 3052495 on 2016/07/15 by Rolando.Caloca DR - Fix for Win32 compile #jira UE-33349 Change 3052536 on 2016/07/15 by Uriel.Doyon Fixed texture streaming overbudget warning when using per texture bias. [CL 3054554 by Gil Gribb in Main branch]
2036 lines
84 KiB
C++
2036 lines
84 KiB
C++
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
TranslucentLighting.cpp: Translucent lighting implementation.
|
|
=============================================================================*/
|
|
|
|
#include "RendererPrivate.h"
|
|
#include "ScenePrivate.h"
|
|
#include "OneColorShader.h"
|
|
#include "LightRendering.h"
|
|
#include "SceneFilterRendering.h"
|
|
#include "ScreenRendering.h"
|
|
#include "AmbientCubemapParameters.h"
|
|
#include "SceneUtils.h"
|
|
|
|
class FMaterial;
|
|
|
|
/** Whether to allow rendering translucency shadow depths. */
|
|
bool GUseTranslucencyShadowDepths = true;
|
|
|
|
DECLARE_FLOAT_COUNTER_STAT(TEXT("Translucent Lighting"), Stat_GPU_TranslucentLighting, STATGROUP_GPU);
|
|
|
|
int32 GUseTranslucentLightingVolumes = 1;
|
|
FAutoConsoleVariableRef CVarUseTranslucentLightingVolumes(
|
|
TEXT("r.TranslucentLightingVolume"),
|
|
GUseTranslucentLightingVolumes,
|
|
TEXT("Whether to allow updating the translucent lighting volumes.\n")
|
|
TEXT("0:off, otherwise on, default is 1"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
float GTranslucentVolumeMinFOV = 45;
|
|
static FAutoConsoleVariableRef CVarTranslucentVolumeMinFOV(
|
|
TEXT("r.TranslucentVolumeMinFOV"),
|
|
GTranslucentVolumeMinFOV,
|
|
TEXT("Minimum FOV for translucent lighting volume. Prevents popping in lighting when zooming in."),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
float GTranslucentVolumeFOVSnapFactor = 10;
|
|
static FAutoConsoleVariableRef CTranslucentVolumeFOVSnapFactor(
|
|
TEXT("r.TranslucentVolumeFOVSnapFactor"),
|
|
GTranslucentVolumeFOVSnapFactor,
|
|
TEXT("FOV will be snapped to a factor of this before computing volume bounds."),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
int32 GUseTranslucencyVolumeBlur = 1;
|
|
FAutoConsoleVariableRef CVarUseTranslucentLightingVolumeBlur(
|
|
TEXT("r.TranslucencyVolumeBlur"),
|
|
GUseTranslucencyVolumeBlur,
|
|
TEXT("Whether to blur the translucent lighting volumes.\n")
|
|
TEXT("0:off, otherwise on, default is 1"),
|
|
ECVF_Scalability | ECVF_RenderThreadSafe
|
|
);
|
|
|
|
int32 GTranslucencyLightingVolumeDim = 64;
|
|
FAutoConsoleVariableRef CVarTranslucencyLightingVolumeDim(
|
|
TEXT("r.TranslucencyLightingVolumeDim"),
|
|
GTranslucencyLightingVolumeDim,
|
|
TEXT("Dimensions of the volume textures used for translucency lighting. Larger textures result in higher resolution but lower performance."),
|
|
ECVF_Scalability | ECVF_RenderThreadSafe
|
|
);
|
|
|
|
static TAutoConsoleVariable<float> CVarTranslucencyLightingVolumeInnerDistance(
|
|
TEXT("r.TranslucencyLightingVolumeInnerDistance"),
|
|
1500.0f,
|
|
TEXT("Distance from the camera that the first volume cascade should end"),
|
|
ECVF_RenderThreadSafe);
|
|
|
|
static TAutoConsoleVariable<float> CVarTranslucencyLightingVolumeOuterDistance(
|
|
TEXT("r.TranslucencyLightingVolumeOuterDistance"),
|
|
5000.0f,
|
|
TEXT("Distance from the camera that the second volume cascade should end"),
|
|
ECVF_RenderThreadSafe);
|
|
|
|
void FViewInfo::CalcTranslucencyLightingVolumeBounds(FBox* InOutCascadeBoundsArray, int32 NumCascades) const
|
|
{
|
|
for (int32 CascadeIndex = 0; CascadeIndex < NumCascades; CascadeIndex++)
|
|
{
|
|
float InnerDistance = CVarTranslucencyLightingVolumeInnerDistance.GetValueOnRenderThread();
|
|
float OuterDistance = CVarTranslucencyLightingVolumeOuterDistance.GetValueOnRenderThread();
|
|
|
|
const float FrustumStartDistance = CascadeIndex == 0 ? 0 : InnerDistance;
|
|
const float FrustumEndDistance = CascadeIndex == 0 ? InnerDistance : OuterDistance;
|
|
|
|
float FOV = PI / 4.0f;
|
|
float AspectRatio = 1.0f;
|
|
|
|
if (IsPerspectiveProjection())
|
|
{
|
|
// Derive FOV and aspect ratio from the perspective projection matrix
|
|
FOV = FMath::Atan(1.0f / ShadowViewMatrices.ProjMatrix.M[0][0]);
|
|
// Clamp to prevent shimmering when zooming in
|
|
FOV = FMath::Max(FOV, GTranslucentVolumeMinFOV * (float)PI / 180.0f);
|
|
const float RoundFactorRadians = GTranslucentVolumeFOVSnapFactor * (float)PI / 180.0f;
|
|
// Round up to a fixed factor
|
|
// This causes the volume lighting to make discreet jumps as the FOV animates, instead of slowly crawling over a long period
|
|
FOV = FOV + RoundFactorRadians - FMath::Fmod(FOV, RoundFactorRadians);
|
|
AspectRatio = ShadowViewMatrices.ProjMatrix.M[1][1] / ShadowViewMatrices.ProjMatrix.M[0][0];
|
|
}
|
|
|
|
const float StartHorizontalLength = FrustumStartDistance * FMath::Tan(FOV);
|
|
const FVector StartCameraRightOffset = ShadowViewMatrices.ViewMatrix.GetColumn(0) * StartHorizontalLength;
|
|
const float StartVerticalLength = StartHorizontalLength / AspectRatio;
|
|
const FVector StartCameraUpOffset = ShadowViewMatrices.ViewMatrix.GetColumn(1) * StartVerticalLength;
|
|
|
|
const float EndHorizontalLength = FrustumEndDistance * FMath::Tan(FOV);
|
|
const FVector EndCameraRightOffset = ShadowViewMatrices.ViewMatrix.GetColumn(0) * EndHorizontalLength;
|
|
const float EndVerticalLength = EndHorizontalLength / AspectRatio;
|
|
const FVector EndCameraUpOffset = ShadowViewMatrices.ViewMatrix.GetColumn(1) * EndVerticalLength;
|
|
|
|
FVector SplitVertices[8];
|
|
SplitVertices[0] = ShadowViewMatrices.ViewOrigin + GetViewDirection() * FrustumStartDistance + StartCameraRightOffset + StartCameraUpOffset;
|
|
SplitVertices[1] = ShadowViewMatrices.ViewOrigin + GetViewDirection() * FrustumStartDistance + StartCameraRightOffset - StartCameraUpOffset;
|
|
SplitVertices[2] = ShadowViewMatrices.ViewOrigin + GetViewDirection() * FrustumStartDistance - StartCameraRightOffset + StartCameraUpOffset;
|
|
SplitVertices[3] = ShadowViewMatrices.ViewOrigin + GetViewDirection() * FrustumStartDistance - StartCameraRightOffset - StartCameraUpOffset;
|
|
|
|
SplitVertices[4] = ShadowViewMatrices.ViewOrigin + GetViewDirection() * FrustumEndDistance + EndCameraRightOffset + EndCameraUpOffset;
|
|
SplitVertices[5] = ShadowViewMatrices.ViewOrigin + GetViewDirection() * FrustumEndDistance + EndCameraRightOffset - EndCameraUpOffset;
|
|
SplitVertices[6] = ShadowViewMatrices.ViewOrigin + GetViewDirection() * FrustumEndDistance - EndCameraRightOffset + EndCameraUpOffset;
|
|
SplitVertices[7] = ShadowViewMatrices.ViewOrigin + GetViewDirection() * FrustumEndDistance - EndCameraRightOffset - EndCameraUpOffset;
|
|
|
|
FVector Center(0,0,0);
|
|
// Weight the far vertices more so that the bounding sphere will be further from the camera
|
|
// This minimizes wasted shadowmap space behind the viewer
|
|
const float FarVertexWeightScale = 10.0f;
|
|
for (int32 VertexIndex = 0; VertexIndex < 8; VertexIndex++)
|
|
{
|
|
const float Weight = VertexIndex > 3 ? 1 / (4.0f + 4.0f / FarVertexWeightScale) : 1 / (4.0f + 4.0f * FarVertexWeightScale);
|
|
Center += SplitVertices[VertexIndex] * Weight;
|
|
}
|
|
|
|
float RadiusSquared = 0;
|
|
for (int32 VertexIndex = 0; VertexIndex < 8; VertexIndex++)
|
|
{
|
|
RadiusSquared = FMath::Max(RadiusSquared, (Center - SplitVertices[VertexIndex]).SizeSquared());
|
|
}
|
|
|
|
FSphere SphereBounds(Center, FMath::Sqrt(RadiusSquared));
|
|
|
|
// Snap the center to a multiple of the volume dimension for stability
|
|
SphereBounds.Center.X = SphereBounds.Center.X - FMath::Fmod(SphereBounds.Center.X, SphereBounds.W * 2 / GTranslucencyLightingVolumeDim);
|
|
SphereBounds.Center.Y = SphereBounds.Center.Y - FMath::Fmod(SphereBounds.Center.Y, SphereBounds.W * 2 / GTranslucencyLightingVolumeDim);
|
|
SphereBounds.Center.Z = SphereBounds.Center.Z - FMath::Fmod(SphereBounds.Center.Z, SphereBounds.W * 2 / GTranslucencyLightingVolumeDim);
|
|
|
|
InOutCascadeBoundsArray[CascadeIndex] = FBox(SphereBounds.Center - SphereBounds.W, SphereBounds.Center + SphereBounds.W);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Vertex shader used to render shadow maps for translucency.
|
|
*/
|
|
class FTranslucencyShadowDepthVS : public FMeshMaterialShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FTranslucencyShadowDepthVS,MeshMaterial);
|
|
public:
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform,const FMaterial* Material,const FVertexFactoryType* VertexFactoryType)
|
|
{
|
|
return IsTranslucentBlendMode(Material->GetBlendMode()) && IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4);
|
|
}
|
|
|
|
FTranslucencyShadowDepthVS() {}
|
|
FTranslucencyShadowDepthVS(const FMeshMaterialShaderType::CompiledShaderInitializerType& Initializer) :
|
|
FMeshMaterialShader(Initializer)
|
|
{
|
|
ShadowParameters.Bind(Initializer.ParameterMap);
|
|
}
|
|
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FMeshMaterialShader::Serialize(Ar);
|
|
Ar << ShadowParameters;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
void SetParameters(
|
|
FRHICommandList& RHICmdList,
|
|
const FMaterialRenderProxy* MaterialRenderProxy,
|
|
const FSceneView& View,
|
|
const FProjectedShadowInfo* ShadowInfo
|
|
)
|
|
{
|
|
FMeshMaterialShader::SetParameters(RHICmdList, GetVertexShader(), MaterialRenderProxy, *MaterialRenderProxy->GetMaterial(View.GetFeatureLevel()), View, ESceneRenderTargetsMode::DontSet);
|
|
ShadowParameters.SetVertexShader(RHICmdList, this, View, ShadowInfo, MaterialRenderProxy);
|
|
}
|
|
|
|
void SetMesh(FRHICommandList& RHICmdList, const FVertexFactory* VertexFactory,const FSceneView& View,const FPrimitiveSceneProxy* Proxy,const FMeshBatchElement& BatchElement,const FMeshDrawingRenderState& DrawRenderState)
|
|
{
|
|
FMeshMaterialShader::SetMesh(RHICmdList, GetVertexShader(),VertexFactory,View,Proxy,BatchElement,DrawRenderState);
|
|
}
|
|
|
|
private:
|
|
FShadowDepthShaderParameters ShadowParameters;
|
|
};
|
|
|
|
enum ETranslucencyShadowDepthShaderMode
|
|
{
|
|
TranslucencyShadowDepth_PerspectiveCorrect,
|
|
TranslucencyShadowDepth_Standard,
|
|
};
|
|
|
|
template <ETranslucencyShadowDepthShaderMode ShaderMode>
|
|
class TTranslucencyShadowDepthVS : public FTranslucencyShadowDepthVS
|
|
{
|
|
DECLARE_SHADER_TYPE(TTranslucencyShadowDepthVS,MeshMaterial);
|
|
public:
|
|
|
|
TTranslucencyShadowDepthVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer):
|
|
FTranslucencyShadowDepthVS(Initializer)
|
|
{
|
|
}
|
|
|
|
TTranslucencyShadowDepthVS() {}
|
|
|
|
static void ModifyCompilationEnvironment( EShaderPlatform Platform, const FMaterial* Material, FShaderCompilerEnvironment& OutEnvironment )
|
|
{
|
|
FTranslucencyShadowDepthVS::ModifyCompilationEnvironment(Platform, Material, OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("PERSPECTIVE_CORRECT_DEPTH"), (uint32)(ShaderMode == TranslucencyShadowDepth_PerspectiveCorrect ? 1 : 0));
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TTranslucencyShadowDepthVS<TranslucencyShadowDepth_PerspectiveCorrect>,TEXT("TranslucentShadowDepthShaders"),TEXT("MainVS"),SF_Vertex);
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TTranslucencyShadowDepthVS<TranslucencyShadowDepth_Standard>,TEXT("TranslucentShadowDepthShaders"),TEXT("MainVS"),SF_Vertex);
|
|
|
|
/**
|
|
* Pixel shader used for accumulating translucency layer densities
|
|
*/
|
|
class FTranslucencyShadowDepthPS : public FMeshMaterialShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FTranslucencyShadowDepthPS,MeshMaterial);
|
|
public:
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform,const FMaterial* Material,const FVertexFactoryType* VertexFactoryType)
|
|
{
|
|
return IsTranslucentBlendMode(Material->GetBlendMode()) && IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4);
|
|
}
|
|
|
|
FTranslucencyShadowDepthPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer):
|
|
FMeshMaterialShader(Initializer)
|
|
{
|
|
TranslInvMaxSubjectDepth.Bind(Initializer.ParameterMap,TEXT("TranslInvMaxSubjectDepth"));
|
|
TranslucentShadowStartOffset.Bind(Initializer.ParameterMap,TEXT("TranslucentShadowStartOffset"));
|
|
TranslucencyProjectionParameters.Bind(Initializer.ParameterMap);
|
|
}
|
|
|
|
FTranslucencyShadowDepthPS() {}
|
|
|
|
void SetParameters(
|
|
FRHICommandList& RHICmdList,
|
|
const FMaterialRenderProxy* MaterialRenderProxy,
|
|
const FSceneView& View,
|
|
const FProjectedShadowInfo* ShadowInfo
|
|
)
|
|
{
|
|
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();
|
|
const auto FeatureLevel = View.GetFeatureLevel();
|
|
|
|
//@todo - scene depth can be bound by the material for use in depth fades
|
|
// This is incorrect when rendering a shadowmap as it's not from the camera's POV
|
|
// Set the scene depth texture to something safe when rendering shadow depths
|
|
FMeshMaterialShader::SetParameters(RHICmdList, ShaderRHI, MaterialRenderProxy, *MaterialRenderProxy->GetMaterial(FeatureLevel), View, ESceneRenderTargetsMode::DontSet);
|
|
|
|
SetShaderValue(RHICmdList, ShaderRHI, TranslInvMaxSubjectDepth, ShadowInfo->InvMaxSubjectDepth);
|
|
|
|
const float LocalToWorldScale = ShadowInfo->GetParentSceneInfo()->Proxy->GetLocalToWorld().GetScaleVector().GetMax();
|
|
const float TranslucentShadowStartOffsetValue = MaterialRenderProxy->GetMaterial(FeatureLevel)->GetTranslucentShadowStartOffset() * LocalToWorldScale;
|
|
SetShaderValue(RHICmdList, ShaderRHI,TranslucentShadowStartOffset, TranslucentShadowStartOffsetValue / (ShadowInfo->MaxSubjectZ - ShadowInfo->MinSubjectZ));
|
|
TranslucencyProjectionParameters.Set(RHICmdList, this, ShadowInfo);
|
|
}
|
|
|
|
void SetMesh(FRHICommandList& RHICmdList, const FVertexFactory* VertexFactory,const FSceneView& View,const FPrimitiveSceneProxy* Proxy,const FMeshBatchElement& BatchElement,const FMeshDrawingRenderState& DrawRenderState)
|
|
{
|
|
FMeshMaterialShader::SetMesh(RHICmdList, GetPixelShader(),VertexFactory,View,Proxy,BatchElement,DrawRenderState);
|
|
}
|
|
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FMeshMaterialShader::Serialize(Ar);
|
|
Ar << TranslInvMaxSubjectDepth;
|
|
Ar << TranslucentShadowStartOffset;
|
|
Ar << TranslucencyProjectionParameters;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
FShaderParameter TranslInvMaxSubjectDepth;
|
|
FShaderParameter TranslucentShadowStartOffset;
|
|
FTranslucencyShadowProjectionShaderParameters TranslucencyProjectionParameters;
|
|
};
|
|
|
|
template <ETranslucencyShadowDepthShaderMode ShaderMode>
|
|
class TTranslucencyShadowDepthPS : public FTranslucencyShadowDepthPS
|
|
{
|
|
DECLARE_SHADER_TYPE(TTranslucencyShadowDepthPS,MeshMaterial);
|
|
public:
|
|
|
|
TTranslucencyShadowDepthPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer):
|
|
FTranslucencyShadowDepthPS(Initializer)
|
|
{
|
|
}
|
|
|
|
TTranslucencyShadowDepthPS() {}
|
|
|
|
static void ModifyCompilationEnvironment( EShaderPlatform Platform, const FMaterial* Material, FShaderCompilerEnvironment& OutEnvironment )
|
|
{
|
|
FTranslucencyShadowDepthPS::ModifyCompilationEnvironment(Platform, Material, OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("PERSPECTIVE_CORRECT_DEPTH"), (uint32)(ShaderMode == TranslucencyShadowDepth_PerspectiveCorrect ? 1 : 0));
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TTranslucencyShadowDepthPS<TranslucencyShadowDepth_PerspectiveCorrect>,TEXT("TranslucentShadowDepthShaders"),TEXT("MainOpacityPS"),SF_Pixel);
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TTranslucencyShadowDepthPS<TranslucencyShadowDepth_Standard>,TEXT("TranslucentShadowDepthShaders"),TEXT("MainOpacityPS"),SF_Pixel);
|
|
|
|
/**
|
|
* Drawing policy used to create Fourier opacity maps
|
|
*/
|
|
class FTranslucencyShadowDepthDrawingPolicy : public FMeshDrawingPolicy
|
|
{
|
|
public:
|
|
|
|
struct ContextDataType : public FMeshDrawingPolicy::ContextDataType
|
|
{
|
|
const FProjectedShadowInfo* ShadowInfo;
|
|
|
|
explicit ContextDataType(const FProjectedShadowInfo* InShadowInfo)
|
|
: ShadowInfo(InShadowInfo)
|
|
{}
|
|
};
|
|
|
|
FTranslucencyShadowDepthDrawingPolicy(
|
|
const FVertexFactory* InVertexFactory,
|
|
const FMaterialRenderProxy* InMaterialRenderProxy,
|
|
const FMaterial& InMaterialResource,
|
|
bool bInDirectionalLight
|
|
):
|
|
FMeshDrawingPolicy(InVertexFactory,InMaterialRenderProxy,InMaterialResource)
|
|
{
|
|
const bool bUsePerspectiveCorrectShadowDepths = !bInDirectionalLight;
|
|
|
|
if (bUsePerspectiveCorrectShadowDepths)
|
|
{
|
|
VertexShader = InMaterialResource.GetShader<TTranslucencyShadowDepthVS<TranslucencyShadowDepth_PerspectiveCorrect> >(InVertexFactory->GetType());
|
|
PixelShader = InMaterialResource.GetShader<TTranslucencyShadowDepthPS<TranslucencyShadowDepth_PerspectiveCorrect> >(InVertexFactory->GetType());
|
|
}
|
|
else
|
|
{
|
|
VertexShader = InMaterialResource.GetShader<TTranslucencyShadowDepthVS<TranslucencyShadowDepth_Standard> >(InVertexFactory->GetType());
|
|
PixelShader = InMaterialResource.GetShader<TTranslucencyShadowDepthPS<TranslucencyShadowDepth_Standard> >(InVertexFactory->GetType());
|
|
}
|
|
}
|
|
|
|
void SetSharedState(FRHICommandList& RHICmdList, const FSceneView* View, const ContextDataType PolicyContext) const
|
|
{
|
|
// Set the shared mesh resources.
|
|
FMeshDrawingPolicy::SetSharedState(RHICmdList, View, PolicyContext);
|
|
|
|
VertexShader->SetParameters(RHICmdList, MaterialRenderProxy, *View, PolicyContext.ShadowInfo);
|
|
PixelShader->SetParameters(RHICmdList, MaterialRenderProxy, *View, PolicyContext.ShadowInfo);
|
|
}
|
|
|
|
/**
|
|
* Create bound shader state using the vertex decl from the mesh draw policy
|
|
* as well as the shaders needed to draw the mesh
|
|
* @return new bound shader state object
|
|
*/
|
|
FBoundShaderStateInput GetBoundShaderStateInput(ERHIFeatureLevel::Type InFeatureLevel)
|
|
{
|
|
return FBoundShaderStateInput(
|
|
FMeshDrawingPolicy::GetVertexDeclaration(),
|
|
VertexShader->GetVertexShader(),
|
|
NULL,
|
|
NULL,
|
|
PixelShader->GetPixelShader(),
|
|
NULL);
|
|
}
|
|
|
|
void SetMeshRenderState(
|
|
FRHICommandList& RHICmdList,
|
|
const FSceneView& View,
|
|
const FPrimitiveSceneProxy* PrimitiveSceneProxy,
|
|
const FMeshBatch& Mesh,
|
|
int32 BatchElementIndex,
|
|
bool bBackFace,
|
|
const FMeshDrawingRenderState& DrawRenderState,
|
|
const ElementDataType& ElementData,
|
|
const ContextDataType PolicyContext
|
|
) const
|
|
{
|
|
const FMeshBatchElement& BatchElement = Mesh.Elements[BatchElementIndex];
|
|
VertexShader->SetMesh(RHICmdList, VertexFactory,View,PrimitiveSceneProxy,BatchElement,DrawRenderState);
|
|
PixelShader->SetMesh(RHICmdList, VertexFactory,View,PrimitiveSceneProxy,BatchElement,DrawRenderState);
|
|
|
|
FMeshDrawingPolicy::SetMeshRenderState(RHICmdList, View,PrimitiveSceneProxy,Mesh,BatchElementIndex,bBackFace,DrawRenderState,ElementData,PolicyContext);
|
|
}
|
|
|
|
private:
|
|
FTranslucencyShadowDepthVS* VertexShader;
|
|
FTranslucencyShadowDepthPS* PixelShader;
|
|
};
|
|
|
|
class FTranslucencyShadowDepthDrawingPolicyFactory
|
|
{
|
|
public:
|
|
|
|
enum { bAllowSimpleElements = false };
|
|
struct ContextType
|
|
{
|
|
ContextType(const FProjectedShadowInfo* InShadowInfo, bool bInDirectionalLight)
|
|
: ShadowInfo(InShadowInfo)
|
|
, bDirectionalLight(bInDirectionalLight)
|
|
{}
|
|
|
|
const FProjectedShadowInfo* ShadowInfo;
|
|
bool bDirectionalLight;
|
|
};
|
|
|
|
static bool DrawDynamicMesh(
|
|
FRHICommandList& RHICmdList,
|
|
const FSceneView& View,
|
|
ContextType DrawingContext,
|
|
const FMeshBatch& Mesh,
|
|
bool bBackFace,
|
|
bool bPreFog,
|
|
const FPrimitiveSceneProxy* PrimitiveSceneProxy,
|
|
FHitProxyId HitProxyId
|
|
)
|
|
{
|
|
bool bDirty = false;
|
|
const auto FeatureLevel = View.GetFeatureLevel();
|
|
|
|
if (Mesh.CastShadow)
|
|
{
|
|
const FMaterialRenderProxy* MaterialRenderProxy = Mesh.MaterialRenderProxy;
|
|
const EBlendMode BlendMode = MaterialRenderProxy->GetMaterial(FeatureLevel)->GetBlendMode();
|
|
|
|
// Only render translucent meshes into the Fourier opacity maps
|
|
if (IsTranslucentBlendMode(BlendMode))
|
|
{
|
|
FTranslucencyShadowDepthDrawingPolicy DrawingPolicy(Mesh.VertexFactory, MaterialRenderProxy, *MaterialRenderProxy->GetMaterial(FeatureLevel), DrawingContext.bDirectionalLight);
|
|
RHICmdList.BuildAndSetLocalBoundShaderState(DrawingPolicy.GetBoundShaderStateInput(View.GetFeatureLevel()));
|
|
DrawingPolicy.SetSharedState(RHICmdList, &View, FTranslucencyShadowDepthDrawingPolicy::ContextDataType(DrawingContext.ShadowInfo));
|
|
const FMeshDrawingRenderState DrawRenderState(Mesh.DitheredLODTransitionAlpha);
|
|
|
|
for (int32 BatchElementIndex = 0; BatchElementIndex < Mesh.Elements.Num(); BatchElementIndex++)
|
|
{
|
|
TDrawEvent<FRHICommandList> MeshEvent;
|
|
BeginMeshDrawEvent(RHICmdList, PrimitiveSceneProxy, Mesh, MeshEvent);
|
|
|
|
DrawingPolicy.SetMeshRenderState(RHICmdList, View,PrimitiveSceneProxy,Mesh,BatchElementIndex,bBackFace,DrawRenderState,
|
|
FTranslucencyShadowDepthDrawingPolicy::ElementDataType(),
|
|
FTranslucencyShadowDepthDrawingPolicy::ContextDataType(DrawingContext.ShadowInfo)
|
|
);
|
|
DrawingPolicy.DrawMesh(RHICmdList, Mesh,BatchElementIndex);
|
|
}
|
|
bDirty = true;
|
|
}
|
|
}
|
|
|
|
return bDirty;
|
|
}
|
|
|
|
static bool DrawStaticMesh(
|
|
FRHICommandList& RHICmdList,
|
|
const FViewInfo& View,
|
|
ContextType DrawingContext,
|
|
const FStaticMesh& StaticMesh,
|
|
bool bPreFog,
|
|
const FPrimitiveSceneProxy* PrimitiveSceneProxy,
|
|
FHitProxyId HitProxyId
|
|
)
|
|
{
|
|
bool bDirty = false;
|
|
|
|
bDirty |= DrawDynamicMesh(
|
|
RHICmdList,
|
|
View,
|
|
DrawingContext,
|
|
StaticMesh,
|
|
false,
|
|
bPreFog,
|
|
PrimitiveSceneProxy,
|
|
HitProxyId
|
|
);
|
|
|
|
return bDirty;
|
|
}
|
|
};
|
|
|
|
void FProjectedShadowInfo::RenderTranslucencyDepths(FRHICommandList& RHICmdList, FSceneRenderer* SceneRenderer)
|
|
{
|
|
check(IsInRenderingThread());
|
|
checkSlow(!bWholeSceneShadow);
|
|
SCOPE_CYCLE_COUNTER(STAT_RenderPerObjectShadowDepthsTime);
|
|
|
|
{
|
|
#if WANTS_DRAW_MESH_EVENTS
|
|
FString EventName;
|
|
GetShadowTypeNameForDrawEvent(EventName);
|
|
SCOPED_DRAW_EVENTF(RHICmdList, EventShadowDepthActor, *EventName);
|
|
#endif
|
|
// Clear the shadow and its border
|
|
RHICmdList.SetViewport(
|
|
X,
|
|
Y,
|
|
0.0f,
|
|
(X + BorderSize * 2 + ResolutionX),
|
|
(Y + BorderSize * 2 + ResolutionY),
|
|
1.0f
|
|
);
|
|
|
|
FLinearColor ClearColors[2] = {FLinearColor(0,0,0,0), FLinearColor(0,0,0,0)};
|
|
DrawClearQuadMRT(RHICmdList, SceneRenderer->FeatureLevel, true, ARRAY_COUNT(ClearColors), ClearColors, false, 1.0f, false, 0);
|
|
|
|
// Set the viewport for the shadow.
|
|
RHICmdList.SetViewport(
|
|
(X + BorderSize),
|
|
(Y + BorderSize),
|
|
0.0f,
|
|
(X + BorderSize + ResolutionX),
|
|
(Y + BorderSize + ResolutionY),
|
|
1.0f
|
|
);
|
|
|
|
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
|
|
RHICmdList.SetBlendState(TStaticBlendState<
|
|
CW_RGBA, BO_Add, BF_One, BF_One, BO_Add, BF_One, BF_One,
|
|
CW_RGBA, BO_Add, BF_One, BF_One, BO_Add, BF_One, BF_One>::GetRHI());
|
|
|
|
FTranslucencyShadowDepthDrawingPolicyFactory::ContextType DrawingContext(this,bDirectionalLight);
|
|
|
|
for (int32 MeshBatchIndex = 0; MeshBatchIndex < DynamicSubjectTranslucentMeshElements.Num(); MeshBatchIndex++)
|
|
{
|
|
const FMeshBatchAndRelevance& MeshBatchAndRelevance = DynamicSubjectTranslucentMeshElements[MeshBatchIndex];
|
|
const FMeshBatch& MeshBatch = *MeshBatchAndRelevance.Mesh;
|
|
FTranslucencyShadowDepthDrawingPolicyFactory::DrawDynamicMesh(RHICmdList, *ShadowDepthView, DrawingContext, MeshBatch, false, true, MeshBatchAndRelevance.PrimitiveSceneProxy, MeshBatch.BatchHitProxyId);
|
|
}
|
|
|
|
for (int32 PrimitiveIndex = 0; PrimitiveIndex < SubjectTranslucentPrimitives.Num(); PrimitiveIndex++)
|
|
{
|
|
const FPrimitiveSceneInfo* PrimitiveSceneInfo = SubjectTranslucentPrimitives[PrimitiveIndex];
|
|
int32 PrimitiveId = PrimitiveSceneInfo->GetIndex();
|
|
FPrimitiveViewRelevance ViewRelevance = ShadowDepthView->PrimitiveViewRelevanceMap[PrimitiveId];
|
|
|
|
if (!ViewRelevance.bInitializedThisFrame)
|
|
{
|
|
// Compute the subject primitive's view relevance since it wasn't cached
|
|
ViewRelevance = PrimitiveSceneInfo->Proxy->GetViewRelevance(ShadowDepthView);
|
|
}
|
|
|
|
if (ViewRelevance.bDrawRelevance && ViewRelevance.bStaticRelevance)
|
|
{
|
|
for (int32 MeshIndex = 0; MeshIndex < PrimitiveSceneInfo->StaticMeshes.Num(); MeshIndex++)
|
|
{
|
|
FTranslucencyShadowDepthDrawingPolicyFactory::DrawStaticMesh(
|
|
RHICmdList,
|
|
*ShadowDepthView,
|
|
DrawingContext,
|
|
PrimitiveSceneInfo->StaticMeshes[MeshIndex],
|
|
true,
|
|
PrimitiveSceneInfo->Proxy,
|
|
FHitProxyId());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
IMPLEMENT_SHADER_TYPE(,FWriteToSliceGS,TEXT("TranslucentLightingShaders"),TEXT("WriteToSliceMainGS"),SF_Geometry);
|
|
IMPLEMENT_SHADER_TYPE(,FWriteToSliceVS,TEXT("TranslucentLightingShaders"),TEXT("WriteToSliceMainVS"),SF_Vertex);
|
|
|
|
/** Pixel shader used to filter a single volume lighting cascade. */
|
|
class FFilterTranslucentVolumePS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FFilterTranslucentVolumePS,Global);
|
|
public:
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform)
|
|
{
|
|
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4);
|
|
}
|
|
|
|
FFilterTranslucentVolumePS(const ShaderMetaType::CompiledShaderInitializerType& Initializer):
|
|
FGlobalShader(Initializer)
|
|
{
|
|
TexelSize.Bind(Initializer.ParameterMap, TEXT("TexelSize"));
|
|
TranslucencyLightingVolumeAmbient.Bind(Initializer.ParameterMap, TEXT("TranslucencyLightingVolumeAmbient"));
|
|
TranslucencyLightingVolumeAmbientSampler.Bind(Initializer.ParameterMap, TEXT("TranslucencyLightingVolumeAmbientSampler"));
|
|
TranslucencyLightingVolumeDirectional.Bind(Initializer.ParameterMap, TEXT("TranslucencyLightingVolumeDirectional"));
|
|
TranslucencyLightingVolumeDirectionalSampler.Bind(Initializer.ParameterMap, TEXT("TranslucencyLightingVolumeDirectionalSampler"));
|
|
}
|
|
FFilterTranslucentVolumePS() {}
|
|
|
|
void SetParameters(FRHICommandList& RHICmdList, const FViewInfo& View, int32 VolumeCascadeIndex)
|
|
{
|
|
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
|
|
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();
|
|
|
|
FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View);
|
|
|
|
SetShaderValue(RHICmdList, ShaderRHI, TexelSize, 1.0f / GTranslucencyLightingVolumeDim);
|
|
|
|
const IPooledRenderTarget* RT0 = SceneContext.TranslucencyLightingVolumeAmbient[VolumeCascadeIndex];
|
|
const IPooledRenderTarget* RT1 = SceneContext.TranslucencyLightingVolumeDirectional[VolumeCascadeIndex];
|
|
|
|
//Checks to detect/prevent UE-31578
|
|
ensure(RT0);
|
|
ensure(RT1);
|
|
|
|
if (RT0)
|
|
{
|
|
SetTextureParameter(
|
|
RHICmdList,
|
|
ShaderRHI,
|
|
TranslucencyLightingVolumeAmbient,
|
|
TranslucencyLightingVolumeAmbientSampler,
|
|
TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI(),
|
|
RT0->GetRenderTargetItem().ShaderResourceTexture);
|
|
}
|
|
|
|
if (RT1)
|
|
{
|
|
SetTextureParameter(
|
|
RHICmdList,
|
|
ShaderRHI,
|
|
TranslucencyLightingVolumeDirectional,
|
|
TranslucencyLightingVolumeDirectionalSampler,
|
|
TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI(),
|
|
RT1->GetRenderTargetItem().ShaderResourceTexture);
|
|
}
|
|
}
|
|
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
Ar << TexelSize;
|
|
Ar << TranslucencyLightingVolumeAmbient;
|
|
Ar << TranslucencyLightingVolumeAmbientSampler;
|
|
Ar << TranslucencyLightingVolumeDirectional;
|
|
Ar << TranslucencyLightingVolumeDirectionalSampler;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
FShaderParameter TexelSize;
|
|
FShaderResourceParameter TranslucencyLightingVolumeAmbient;
|
|
FShaderResourceParameter TranslucencyLightingVolumeAmbientSampler;
|
|
FShaderResourceParameter TranslucencyLightingVolumeDirectional;
|
|
FShaderResourceParameter TranslucencyLightingVolumeDirectionalSampler;
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(,FFilterTranslucentVolumePS,TEXT("TranslucentLightingShaders"),TEXT("FilterMainPS"),SF_Pixel);
|
|
|
|
/** Shader parameters needed to inject direct lighting into a volume. */
|
|
class FTranslucentInjectParameters
|
|
{
|
|
public:
|
|
|
|
void Bind(const FShaderParameterMap& ParameterMap)
|
|
{
|
|
WorldToShadowMatrix.Bind(ParameterMap,TEXT("WorldToShadowMatrix"));
|
|
ShadowmapMinMax.Bind(ParameterMap,TEXT("ShadowmapMinMax"));
|
|
VolumeCascadeIndex.Bind(ParameterMap,TEXT("VolumeCascadeIndex"));
|
|
}
|
|
|
|
template<typename ShaderRHIParamRef>
|
|
void Set(
|
|
FRHICommandList& RHICmdList,
|
|
const ShaderRHIParamRef ShaderRHI,
|
|
FShader* Shader,
|
|
const FViewInfo& View,
|
|
const FLightSceneInfo* LightSceneInfo,
|
|
const FProjectedShadowInfo* ShadowMap,
|
|
uint32 VolumeCascadeIndexValue,
|
|
bool bDynamicallyShadowed) const
|
|
{
|
|
SetDeferredLightParameters(RHICmdList, ShaderRHI, Shader->GetUniformBufferParameter<FDeferredLightUniformStruct>(), LightSceneInfo, View);
|
|
|
|
if (bDynamicallyShadowed)
|
|
{
|
|
FVector4 ShadowmapMinMaxValue;
|
|
FMatrix WorldToShadowMatrixValue = ShadowMap->GetWorldToShadowMatrix(ShadowmapMinMaxValue);
|
|
|
|
SetShaderValue(RHICmdList, ShaderRHI, WorldToShadowMatrix, WorldToShadowMatrixValue);
|
|
SetShaderValue(RHICmdList, ShaderRHI, ShadowmapMinMax, ShadowmapMinMaxValue);
|
|
}
|
|
|
|
SetShaderValue(RHICmdList, ShaderRHI, VolumeCascadeIndex, VolumeCascadeIndexValue);
|
|
}
|
|
|
|
/** Serializer. */
|
|
friend FArchive& operator<<(FArchive& Ar,FTranslucentInjectParameters& P)
|
|
{
|
|
Ar << P.WorldToShadowMatrix;
|
|
Ar << P.ShadowmapMinMax;
|
|
Ar << P.VolumeCascadeIndex;
|
|
return Ar;
|
|
}
|
|
|
|
private:
|
|
|
|
FShaderParameter WorldToShadowMatrix;
|
|
FShaderParameter ShadowmapMinMax;
|
|
FShaderParameter VolumeCascadeIndex;
|
|
};
|
|
|
|
/** Pixel shader used to accumulate per-object translucent shadows into a volume texture. */
|
|
class FTranslucentObjectShadowingPS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FTranslucentObjectShadowingPS,Global);
|
|
public:
|
|
|
|
static void ModifyCompilationEnvironment( EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment )
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Platform, OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("INJECTION_PIXEL_SHADER"), 1);
|
|
}
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform)
|
|
{
|
|
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4);
|
|
}
|
|
|
|
FTranslucentObjectShadowingPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer):
|
|
FGlobalShader(Initializer)
|
|
{
|
|
TranslucencyProjectionParameters.Bind(Initializer.ParameterMap);
|
|
TranslucentInjectParameters.Bind(Initializer.ParameterMap);
|
|
}
|
|
FTranslucentObjectShadowingPS() {}
|
|
|
|
void SetParameters(FRHICommandList& RHICmdList, const FViewInfo& View, const FLightSceneInfo* LightSceneInfo, const FProjectedShadowInfo* ShadowMap, uint32 VolumeCascadeIndex)
|
|
{
|
|
FGlobalShader::SetParameters(RHICmdList, GetPixelShader(), View);
|
|
TranslucencyProjectionParameters.Set(RHICmdList, this, ShadowMap);
|
|
TranslucentInjectParameters.Set(RHICmdList, GetPixelShader(), this, View, LightSceneInfo, ShadowMap, VolumeCascadeIndex, true);
|
|
}
|
|
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
Ar << TranslucencyProjectionParameters;
|
|
Ar << TranslucentInjectParameters;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
FTranslucencyShadowProjectionShaderParameters TranslucencyProjectionParameters;
|
|
FTranslucentInjectParameters TranslucentInjectParameters;
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(,FTranslucentObjectShadowingPS,TEXT("TranslucentLightingShaders"),TEXT("PerObjectShadowingMainPS"),SF_Pixel);
|
|
|
|
/** Shader that adds direct lighting contribution from the given light to the current volume lighting cascade. */
|
|
template<ELightComponentType InjectionType, bool bDynamicallyShadowed, bool bApplyLightFunction, bool bInverseSquared>
|
|
class TTranslucentLightingInjectPS : public FMaterialShader
|
|
{
|
|
DECLARE_SHADER_TYPE(TTranslucentLightingInjectPS,Material);
|
|
public:
|
|
|
|
static void ModifyCompilationEnvironment( EShaderPlatform Platform, const FMaterial* Material, FShaderCompilerEnvironment& OutEnvironment )
|
|
{
|
|
FMaterialShader::ModifyCompilationEnvironment(Platform, Material, OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("RADIAL_ATTENUATION"), (uint32)(InjectionType != LightType_Directional));
|
|
OutEnvironment.SetDefine(TEXT("INJECTION_PIXEL_SHADER"), 1);
|
|
OutEnvironment.SetDefine(TEXT("DYNAMICALLY_SHADOWED"), (uint32)bDynamicallyShadowed);
|
|
OutEnvironment.SetDefine(TEXT("APPLY_LIGHT_FUNCTION"), (uint32)bApplyLightFunction);
|
|
OutEnvironment.SetDefine(TEXT("INVERSE_SQUARED_FALLOFF"), (uint32)bInverseSquared);
|
|
}
|
|
|
|
/**
|
|
* Makes sure only shaders for materials that are explicitly flagged
|
|
* as 'UsedAsLightFunction' in the Material Editor gets compiled into
|
|
* the shader cache.
|
|
*/
|
|
static bool ShouldCache(EShaderPlatform Platform, const FMaterial* Material)
|
|
{
|
|
return (Material->IsLightFunction() || Material->IsSpecialEngineMaterial()) && IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4);
|
|
}
|
|
|
|
TTranslucentLightingInjectPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer):
|
|
FMaterialShader(Initializer)
|
|
{
|
|
DepthBiasParameters.Bind(Initializer.ParameterMap, TEXT("DepthBiasParameters"));
|
|
CascadeBounds.Bind(Initializer.ParameterMap, TEXT("CascadeBounds"));
|
|
InnerCascadeBounds.Bind(Initializer.ParameterMap, TEXT("InnerCascadeBounds"));
|
|
ClippingPlanes.Bind(Initializer.ParameterMap, TEXT("ClippingPlanes"));
|
|
ShadowInjectParams.Bind(Initializer.ParameterMap, TEXT("ShadowInjectParams"));
|
|
SpotlightMask.Bind(Initializer.ParameterMap, TEXT("SpotlightMask"));
|
|
ShadowDepthTexture.Bind(Initializer.ParameterMap, TEXT("ShadowDepthTexture"));
|
|
ShadowDepthTextureSampler.Bind(Initializer.ParameterMap, TEXT("ShadowDepthTextureSampler"));
|
|
OnePassShadowParameters.Bind(Initializer.ParameterMap);
|
|
LightFunctionParameters.Bind(Initializer.ParameterMap);
|
|
TranslucentInjectParameters.Bind(Initializer.ParameterMap);
|
|
LightFunctionWorldToLight.Bind(Initializer.ParameterMap, TEXT("LightFunctionWorldToLight"));
|
|
bStaticallyShadowed.Bind(Initializer.ParameterMap, TEXT("bStaticallyShadowed"));
|
|
StaticShadowDepthTexture.Bind(Initializer.ParameterMap, TEXT("StaticShadowDepthTexture"));
|
|
StaticShadowDepthTextureSampler.Bind(Initializer.ParameterMap, TEXT("StaticShadowDepthTextureSampler"));
|
|
WorldToStaticShadowMatrix.Bind(Initializer.ParameterMap, TEXT("WorldToStaticShadowMatrix"));
|
|
}
|
|
TTranslucentLightingInjectPS() {}
|
|
|
|
// @param InnerSplitIndex which CSM shadow map level, INDEX_NONE if no directional light
|
|
// @param VolumeCascadeIndexValue which volume we render to
|
|
void SetParameters(
|
|
FRHICommandList& RHICmdList,
|
|
const FViewInfo& View,
|
|
const FLightSceneInfo* LightSceneInfo,
|
|
const FMaterialRenderProxy* MaterialProxy,
|
|
const FProjectedShadowInfo* ShadowMap,
|
|
int32 InnerSplitIndex,
|
|
int32 VolumeCascadeIndexValue)
|
|
{
|
|
check(ShadowMap || !bDynamicallyShadowed);
|
|
|
|
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();
|
|
|
|
FMaterialShader::SetParameters(RHICmdList, ShaderRHI, MaterialProxy, *MaterialProxy->GetMaterial(View.GetFeatureLevel()), View, false, ESceneRenderTargetsMode::SetTextures);
|
|
|
|
FSphere ShadowBounds = ShadowMap ? ShadowMap->ShadowBounds : FSphere(FVector(0,0,0), HALF_WORLD_MAX);
|
|
SetShaderValue(RHICmdList, ShaderRHI, CascadeBounds, ShadowBounds);
|
|
|
|
FSphere InnerBounds(0);
|
|
// default to ignore the plane
|
|
FVector4 Planes[2] = { FVector4(0, 0, 0, -1), FVector4(0, 0, 0, -1) };
|
|
// .zw:DistanceFadeMAD to use MAD for efficiency in the shader, default to ignore the plane
|
|
FVector4 ShadowInjectParamValue(1, 1, 0, 0);
|
|
|
|
if (InnerSplitIndex >= 0)
|
|
{
|
|
FShadowCascadeSettings ShadowCascadeSettings;
|
|
|
|
// todo: optimize, not all computed data is needed
|
|
InnerBounds = LightSceneInfo->Proxy->GetShadowSplitBounds(View, (uint32)InnerSplitIndex, LightSceneInfo->IsPrecomputedLightingValid(), &ShadowCascadeSettings);
|
|
|
|
// near cascade plane
|
|
{
|
|
ShadowInjectParamValue.X = ShadowCascadeSettings.SplitNearFadeRegion == 0 ? 1.0f : 1.0f / ShadowCascadeSettings.SplitNearFadeRegion;
|
|
Planes[0] = FVector4((FVector)(ShadowCascadeSettings.NearFrustumPlane), -ShadowCascadeSettings.NearFrustumPlane.W);
|
|
}
|
|
|
|
uint32 CascadeCount = LightSceneInfo->Proxy->GetNumViewDependentWholeSceneShadows(View, LightSceneInfo->IsPrecomputedLightingValid());
|
|
|
|
// far cascade plane
|
|
if(InnerSplitIndex != CascadeCount - 1)
|
|
{
|
|
ShadowInjectParamValue.Y = 1.0f / ShadowCascadeSettings.SplitFarFadeRegion;
|
|
Planes[1] = FVector4((FVector)(ShadowCascadeSettings.FarFrustumPlane), -ShadowCascadeSettings.FarFrustumPlane.W);
|
|
}
|
|
|
|
const FVector2D FadeParams = LightSceneInfo->Proxy->GetDirectionalLightDistanceFadeParameters(View.GetFeatureLevel(), LightSceneInfo->IsPrecomputedLightingValid());
|
|
|
|
// setup constants for the MAD in shader
|
|
ShadowInjectParamValue.Z = FadeParams.Y;
|
|
ShadowInjectParamValue.W = -FadeParams.X * FadeParams.Y;
|
|
}
|
|
|
|
SetShaderValue(RHICmdList, ShaderRHI, ShadowInjectParams, ShadowInjectParamValue);
|
|
SetShaderValue(RHICmdList, ShaderRHI, InnerCascadeBounds, InnerBounds);
|
|
|
|
SetShaderValueArray(RHICmdList, ShaderRHI, ClippingPlanes, Planes, ARRAY_COUNT(Planes));
|
|
|
|
bool bIsSpotlight = LightSceneInfo->Proxy->GetLightType() == LightType_Spot;
|
|
//@todo - needs to be a permutation to reduce shadow filtering work
|
|
SetShaderValue(RHICmdList, ShaderRHI, SpotlightMask, (bIsSpotlight ? 1.0f : 0.0f));
|
|
|
|
if (bDynamicallyShadowed)
|
|
{
|
|
SetShaderValue(RHICmdList, ShaderRHI, DepthBiasParameters, FVector2D(ShadowMap->GetShaderDepthBias(), 1.0f / (ShadowMap->MaxSubjectZ - ShadowMap->MinSubjectZ)));
|
|
|
|
FTextureRHIParamRef ShadowDepthTextureResource = nullptr;
|
|
if (InjectionType == LightType_Point && !bIsSpotlight)
|
|
{
|
|
if (GBlackTexture && GBlackTexture->TextureRHI)
|
|
{
|
|
ShadowDepthTextureResource = GBlackTexture->TextureRHI->GetTexture2D();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ShadowDepthTextureResource = ShadowMap->RenderTargets.DepthTarget->GetRenderTargetItem().ShaderResourceTexture.GetReference();
|
|
}
|
|
|
|
SetTextureParameter(
|
|
RHICmdList,
|
|
ShaderRHI,
|
|
ShadowDepthTexture,
|
|
ShadowDepthTextureSampler,
|
|
TStaticSamplerState<SF_Point,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(),
|
|
ShadowDepthTextureResource
|
|
);
|
|
}
|
|
|
|
OnePassShadowParameters.Set(RHICmdList, ShaderRHI, bDynamicallyShadowed && InjectionType == LightType_Point ? ShadowMap : NULL);
|
|
|
|
LightFunctionParameters.Set(RHICmdList, ShaderRHI, LightSceneInfo, 1);
|
|
TranslucentInjectParameters.Set(RHICmdList, ShaderRHI, this, View, LightSceneInfo, ShadowMap, VolumeCascadeIndexValue, bDynamicallyShadowed);
|
|
|
|
if (LightFunctionWorldToLight.IsBound())
|
|
{
|
|
const FVector Scale = LightSceneInfo->Proxy->GetLightFunctionScale();
|
|
// Switch x and z so that z of the user specified scale affects the distance along the light direction
|
|
const FVector InverseScale = FVector( 1.f / Scale.Z, 1.f / Scale.Y, 1.f / Scale.X );
|
|
const FMatrix WorldToLight = LightSceneInfo->Proxy->GetWorldToLight() * FScaleMatrix(FVector(InverseScale));
|
|
|
|
SetShaderValue(RHICmdList, ShaderRHI, LightFunctionWorldToLight, WorldToLight);
|
|
}
|
|
|
|
const FStaticShadowDepthMap* StaticShadowDepthMap = LightSceneInfo->Proxy->GetStaticShadowDepthMap();
|
|
const uint32 bStaticallyShadowedValue = LightSceneInfo->IsPrecomputedLightingValid() && StaticShadowDepthMap && StaticShadowDepthMap->TextureRHI ? 1 : 0;
|
|
FTextureRHIParamRef StaticShadowDepthMapTexture = bStaticallyShadowedValue ? StaticShadowDepthMap->TextureRHI : GWhiteTexture->TextureRHI;
|
|
const FMatrix WorldToStaticShadow = bStaticallyShadowedValue ? StaticShadowDepthMap->Data.WorldToLight : FMatrix::Identity;
|
|
|
|
SetShaderValue(RHICmdList, ShaderRHI, bStaticallyShadowed, bStaticallyShadowedValue);
|
|
|
|
SetTextureParameter(
|
|
RHICmdList,
|
|
ShaderRHI,
|
|
StaticShadowDepthTexture,
|
|
StaticShadowDepthTextureSampler,
|
|
TStaticSamplerState<SF_Point,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI(),
|
|
StaticShadowDepthMapTexture
|
|
);
|
|
|
|
SetShaderValue(RHICmdList, ShaderRHI, WorldToStaticShadowMatrix, WorldToStaticShadow);
|
|
}
|
|
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FMaterialShader::Serialize(Ar);
|
|
Ar << DepthBiasParameters;
|
|
Ar << CascadeBounds;
|
|
Ar << InnerCascadeBounds;
|
|
Ar << ClippingPlanes;
|
|
Ar << ShadowInjectParams;
|
|
Ar << SpotlightMask;
|
|
Ar << ShadowDepthTexture;
|
|
Ar << ShadowDepthTextureSampler;
|
|
Ar << OnePassShadowParameters;
|
|
Ar << LightFunctionParameters;
|
|
Ar << TranslucentInjectParameters;
|
|
Ar << LightFunctionWorldToLight;
|
|
Ar << bStaticallyShadowed;
|
|
Ar << StaticShadowDepthTexture;
|
|
Ar << StaticShadowDepthTextureSampler;
|
|
Ar << WorldToStaticShadowMatrix;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
FShaderParameter DepthBiasParameters;
|
|
FShaderParameter CascadeBounds;
|
|
FShaderParameter InnerCascadeBounds;
|
|
FShaderParameter ClippingPlanes;
|
|
FShaderParameter ShadowInjectParams;
|
|
FShaderParameter SpotlightMask;
|
|
FShaderResourceParameter ShadowDepthTexture;
|
|
FShaderResourceParameter ShadowDepthTextureSampler;
|
|
FOnePassPointShadowProjectionShaderParameters OnePassShadowParameters;
|
|
FLightFunctionSharedParameters LightFunctionParameters;
|
|
FTranslucentInjectParameters TranslucentInjectParameters;
|
|
FShaderParameter LightFunctionWorldToLight;
|
|
FShaderParameter bStaticallyShadowed;
|
|
FShaderResourceParameter StaticShadowDepthTexture;
|
|
FShaderResourceParameter StaticShadowDepthTextureSampler;
|
|
FShaderParameter WorldToStaticShadowMatrix;
|
|
};
|
|
|
|
#define IMPLEMENT_INJECTION_PIXELSHADER_TYPE(LightType,bDynamicallyShadowed,bApplyLightFunction,bInverseSquared) \
|
|
typedef TTranslucentLightingInjectPS<LightType,bDynamicallyShadowed,bApplyLightFunction,bInverseSquared> TTranslucentLightingInjectPS##LightType##bDynamicallyShadowed##bApplyLightFunction##bInverseSquared; \
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(template<>,TTranslucentLightingInjectPS##LightType##bDynamicallyShadowed##bApplyLightFunction##bInverseSquared,TEXT("TranslucentLightInjectionShaders"),TEXT("InjectMainPS"),SF_Pixel);
|
|
|
|
/** Versions with a light function. */
|
|
IMPLEMENT_INJECTION_PIXELSHADER_TYPE(LightType_Directional,true,true,false);
|
|
IMPLEMENT_INJECTION_PIXELSHADER_TYPE(LightType_Directional,false,true,false);
|
|
IMPLEMENT_INJECTION_PIXELSHADER_TYPE(LightType_Point,true,true,true);
|
|
IMPLEMENT_INJECTION_PIXELSHADER_TYPE(LightType_Point,false,true,true);
|
|
IMPLEMENT_INJECTION_PIXELSHADER_TYPE(LightType_Point,true,true,false);
|
|
IMPLEMENT_INJECTION_PIXELSHADER_TYPE(LightType_Point,false,true,false);
|
|
|
|
/** Versions without a light function. */
|
|
IMPLEMENT_INJECTION_PIXELSHADER_TYPE(LightType_Directional,true,false,false);
|
|
IMPLEMENT_INJECTION_PIXELSHADER_TYPE(LightType_Directional,false,false,false);
|
|
IMPLEMENT_INJECTION_PIXELSHADER_TYPE(LightType_Point,true,false,true);
|
|
IMPLEMENT_INJECTION_PIXELSHADER_TYPE(LightType_Point,false,false,true);
|
|
IMPLEMENT_INJECTION_PIXELSHADER_TYPE(LightType_Point,true,false,false);
|
|
IMPLEMENT_INJECTION_PIXELSHADER_TYPE(LightType_Point,false,false,false);
|
|
|
|
/** Vertex buffer used for rendering into a volume texture. */
|
|
class FVolumeRasterizeVertexBuffer : public FVertexBuffer
|
|
{
|
|
public:
|
|
|
|
virtual void InitRHI() override
|
|
{
|
|
// Used as a non-indexed triangle strip, so 4 vertices per quad
|
|
const uint32 Size = 4 * sizeof(FScreenVertex);
|
|
FRHIResourceCreateInfo CreateInfo;
|
|
void* Buffer = nullptr;
|
|
VertexBufferRHI = RHICreateAndLockVertexBuffer(Size, BUF_Static, CreateInfo, Buffer);
|
|
FScreenVertex* DestVertex = (FScreenVertex*)Buffer;
|
|
|
|
// Setup a full - render target quad
|
|
// A viewport and UVScaleBias will be used to implement rendering to a sub region
|
|
DestVertex[0].Position = FVector2D(1, -GProjectionSignY);
|
|
DestVertex[0].UV = FVector2D(1, 1);
|
|
DestVertex[1].Position = FVector2D(1, GProjectionSignY);
|
|
DestVertex[1].UV = FVector2D(1, 0);
|
|
DestVertex[2].Position = FVector2D(-1, -GProjectionSignY);
|
|
DestVertex[2].UV = FVector2D(0, 1);
|
|
DestVertex[3].Position = FVector2D(-1, GProjectionSignY);
|
|
DestVertex[3].UV = FVector2D(0, 0);
|
|
|
|
RHIUnlockVertexBuffer(VertexBufferRHI);
|
|
}
|
|
};
|
|
|
|
TGlobalResource<FVolumeRasterizeVertexBuffer> GVolumeRasterizeVertexBuffer;
|
|
|
|
/** Draws a quad per volume texture slice to the subregion of the volume texture specified. */
|
|
void RasterizeToVolumeTexture(FRHICommandList& RHICmdList, FVolumeBounds VolumeBounds)
|
|
{
|
|
// Setup the viewport to only render to the given bounds
|
|
RHICmdList.SetViewport(VolumeBounds.MinX, VolumeBounds.MinY, 0, VolumeBounds.MaxX, VolumeBounds.MaxY, 0);
|
|
RHICmdList.SetStreamSource(0, GVolumeRasterizeVertexBuffer.VertexBufferRHI, sizeof(FScreenVertex), 0);
|
|
const int32 NumInstances = VolumeBounds.MaxZ - VolumeBounds.MinZ;
|
|
// Render a quad per slice affected by the given bounds
|
|
RHICmdList.DrawPrimitive(PT_TriangleStrip, 0, 2, NumInstances);
|
|
}
|
|
|
|
/** Helper function that clears the given volume texture render targets. */
|
|
template<int32 NumRenderTargets>
|
|
void ClearVolumeTextures(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, const FTextureRHIParamRef* RenderTargets, const FLinearColor* ClearColors)
|
|
{
|
|
SetRenderTargets(RHICmdList, NumRenderTargets, RenderTargets, FTextureRHIRef(), 0, NULL, true);
|
|
#if PLATFORM_XBOXONE
|
|
// ClearMRT is faster on Xbox
|
|
if (true)
|
|
#else
|
|
// Currently using a manual clear, which is ~10x faster than a hardware clear of the volume textures on AMD PC GPU's
|
|
if (false)
|
|
#endif
|
|
{
|
|
RHICmdList.ClearMRT(true, NumRenderTargets, ClearColors, false, 0, false, 0, FIntRect());
|
|
}
|
|
else
|
|
{
|
|
static FGlobalBoundShaderState VolumeClearBoundShaderState;
|
|
|
|
RHICmdList.SetRasterizerState(TStaticRasterizerState<FM_Solid, CM_None>::GetRHI());
|
|
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
|
|
RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI());
|
|
|
|
const FVolumeBounds VolumeBounds(GTranslucencyLightingVolumeDim);
|
|
auto ShaderMap = GetGlobalShaderMap(FeatureLevel);
|
|
TShaderMapRef<FWriteToSliceVS> VertexShader(ShaderMap);
|
|
TOptionalShaderMapRef<FWriteToSliceGS> GeometryShader(ShaderMap);
|
|
TShaderMapRef<TOneColorPixelShaderMRT<NumRenderTargets> > PixelShader(ShaderMap);
|
|
|
|
SetGlobalBoundShaderState(RHICmdList, FeatureLevel, VolumeClearBoundShaderState, GScreenVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader, *GeometryShader);
|
|
|
|
VertexShader->SetParameters(RHICmdList, VolumeBounds, GTranslucencyLightingVolumeDim);
|
|
if(GeometryShader.IsValid())
|
|
{
|
|
GeometryShader->SetParameters(RHICmdList, VolumeBounds);
|
|
}
|
|
PixelShader->SetColors(RHICmdList, ClearColors, NumRenderTargets);
|
|
|
|
RasterizeToVolumeTexture(RHICmdList, VolumeBounds);
|
|
}
|
|
RHICmdList.TransitionResources(EResourceTransitionAccess::EReadable, (FTextureRHIParamRef*)RenderTargets, NumRenderTargets);
|
|
}
|
|
|
|
void FDeferredShadingSceneRenderer::ClearTranslucentVolumeLighting(FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
if (GUseTranslucentLightingVolumes && GSupportsVolumeTextureRendering)
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, ClearTranslucentVolumeLighting);
|
|
SCOPED_GPU_STAT(RHICmdList, Stat_GPU_TranslucentLighting);
|
|
|
|
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
|
|
|
|
// to track down Jira UE-22073
|
|
ensure(SceneContext.GetCurrentFeatureLevel() >= ERHIFeatureLevel::SM4);
|
|
ensure(SceneContext.TranslucencyLightingVolumeAmbient[0]);
|
|
ensure(SceneContext.TranslucencyLightingVolumeDirectional[0]);
|
|
ensure(SceneContext.TranslucencyLightingVolumeAmbient[1]);
|
|
ensure(SceneContext.TranslucencyLightingVolumeDirectional[1]);
|
|
// if to prevent crash (Jira UE-22073) but it happen later
|
|
if( SceneContext.TranslucencyLightingVolumeAmbient[0] &&
|
|
SceneContext.TranslucencyLightingVolumeDirectional[0] &&
|
|
SceneContext.TranslucencyLightingVolumeAmbient[1] &&
|
|
SceneContext.TranslucencyLightingVolumeDirectional[1])
|
|
{
|
|
// Clear all volume textures in the same draw with MRT, which is faster than individually
|
|
|
|
static_assert(TVC_MAX == 2, "Only expecting two translucency lighting cascades.");
|
|
FTextureRHIParamRef RenderTargets[4];
|
|
RenderTargets[0] = SceneContext.TranslucencyLightingVolumeAmbient[0]->GetRenderTargetItem().TargetableTexture;
|
|
RenderTargets[1] = SceneContext.TranslucencyLightingVolumeDirectional[0]->GetRenderTargetItem().TargetableTexture;
|
|
RenderTargets[2] = SceneContext.TranslucencyLightingVolumeAmbient[1]->GetRenderTargetItem().TargetableTexture;
|
|
RenderTargets[3] = SceneContext.TranslucencyLightingVolumeDirectional[1]->GetRenderTargetItem().TargetableTexture;
|
|
|
|
FLinearColor ClearColors[4];
|
|
ClearColors[0] = FLinearColor(0, 0, 0, 0);
|
|
ClearColors[1] = FLinearColor(0, 0, 0, 0);
|
|
ClearColors[2] = FLinearColor(0, 0, 0, 0);
|
|
ClearColors[3] = FLinearColor(0, 0, 0, 0);
|
|
|
|
ClearVolumeTextures<ARRAY_COUNT(RenderTargets)>(RHICmdList, FeatureLevel, RenderTargets, ClearColors);
|
|
}
|
|
}
|
|
}
|
|
|
|
class FClearTranslucentLightingVolumeCS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FClearTranslucentLightingVolumeCS, Global)
|
|
public:
|
|
|
|
static const int32 CLEAR_BLOCK_SIZE = 4;
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform)
|
|
{
|
|
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Platform, OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("CLEAR_COMPUTE_SHADER"), 1);
|
|
OutEnvironment.SetDefine(TEXT("CLEAR_BLOCK_SIZE"), CLEAR_BLOCK_SIZE);
|
|
}
|
|
|
|
FClearTranslucentLightingVolumeCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FGlobalShader(Initializer)
|
|
{
|
|
Ambient0.Bind(Initializer.ParameterMap, TEXT("Ambient0"));
|
|
Directional0.Bind(Initializer.ParameterMap, TEXT("Directional0"));
|
|
Ambient1.Bind(Initializer.ParameterMap, TEXT("Ambient1"));
|
|
Directional1.Bind(Initializer.ParameterMap, TEXT("Directional1"));
|
|
}
|
|
|
|
FClearTranslucentLightingVolumeCS()
|
|
{
|
|
}
|
|
|
|
void SetParameters(
|
|
FRHIAsyncComputeCommandListImmediate& RHICmdList,
|
|
FUnorderedAccessViewRHIParamRef* VolumeUAVs,
|
|
int32 NumUAVs
|
|
)
|
|
{
|
|
check(NumUAVs == 4);
|
|
const FComputeShaderRHIParamRef ShaderRHI = GetComputeShader();
|
|
Ambient0.SetTexture(RHICmdList, ShaderRHI, NULL, VolumeUAVs[0]);
|
|
Directional0.SetTexture(RHICmdList, ShaderRHI, NULL, VolumeUAVs[1]);
|
|
Ambient1.SetTexture(RHICmdList, ShaderRHI, NULL, VolumeUAVs[2]);
|
|
Directional1.SetTexture(RHICmdList, ShaderRHI, NULL, VolumeUAVs[3]);
|
|
}
|
|
|
|
void UnsetParameters(FRHIAsyncComputeCommandListImmediate& RHICmdList)
|
|
{
|
|
const FComputeShaderRHIParamRef ShaderRHI = GetComputeShader();
|
|
Ambient0.UnsetUAV(RHICmdList, ShaderRHI);
|
|
Directional0.UnsetUAV(RHICmdList, ShaderRHI);
|
|
Ambient1.UnsetUAV(RHICmdList, ShaderRHI);
|
|
Directional1.UnsetUAV(RHICmdList, ShaderRHI);
|
|
}
|
|
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
Ar << Ambient0;
|
|
Ar << Directional0;
|
|
Ar << Ambient1;
|
|
Ar << Directional1;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
FRWShaderParameter Ambient0;
|
|
FRWShaderParameter Directional0;
|
|
FRWShaderParameter Ambient1;
|
|
FRWShaderParameter Directional1;
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(, FClearTranslucentLightingVolumeCS, TEXT("TranslucentLightInjectionShaders"), TEXT("ClearTranslucentLightingVolumeCS"), SF_Compute)
|
|
|
|
void FDeferredShadingSceneRenderer::ClearTranslucentVolumeLightingAsyncCompute(FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
|
|
|
|
ensure(FeatureLevel >= ERHIFeatureLevel::SM5);
|
|
ensure(SceneContext.TranslucencyLightingVolumeAmbient[0]);
|
|
ensure(SceneContext.TranslucencyLightingVolumeDirectional[0]);
|
|
ensure(SceneContext.TranslucencyLightingVolumeAmbient[1]);
|
|
ensure(SceneContext.TranslucencyLightingVolumeDirectional[1]);
|
|
|
|
FUnorderedAccessViewRHIParamRef VolumeUAVs[4] = {
|
|
SceneContext.TranslucencyLightingVolumeAmbient[0]->GetRenderTargetItem().UAV,
|
|
SceneContext.TranslucencyLightingVolumeDirectional[0]->GetRenderTargetItem().UAV,
|
|
SceneContext.TranslucencyLightingVolumeAmbient[1]->GetRenderTargetItem().UAV,
|
|
SceneContext.TranslucencyLightingVolumeDirectional[1]->GetRenderTargetItem().UAV
|
|
};
|
|
|
|
FClearTranslucentLightingVolumeCS* ComputeShader = *TShaderMapRef<FClearTranslucentLightingVolumeCS>(GetGlobalShaderMap(FeatureLevel));
|
|
static const FName EndComputeFenceName(TEXT("TranslucencyLightingVolumeClearEndComputeFence"));
|
|
TranslucencyLightingVolumeClearEndFence = RHICmdList.CreateComputeFence(EndComputeFenceName);
|
|
|
|
static const FName BeginComputeFenceName(TEXT("TranslucencyLightingVolumeClearBeginComputeFence"));
|
|
FComputeFenceRHIRef ClearBeginFence = RHICmdList.CreateComputeFence(BeginComputeFenceName);
|
|
|
|
//Grab the async compute commandlist.
|
|
FRHIAsyncComputeCommandListImmediate& RHICmdListComputeImmediate = FRHICommandListExecutor::GetImmediateAsyncComputeCommandList();
|
|
{
|
|
SCOPED_COMPUTE_EVENTF(RHICmdListComputeImmediate, ClearTranslucencyLightingVolume, TEXT("Translucency lighting volume clear compute shader. %d"), GTranslucencyLightingVolumeDim);
|
|
|
|
RHICmdListComputeImmediate.TransitionResources(EResourceTransitionAccess::ERWBarrier, EResourceTransitionPipeline::EGfxToCompute, VolumeUAVs, 4, ClearBeginFence);
|
|
|
|
//we must wait on the fence written from the Gfx pipe to let us know all our dependencies are ready.
|
|
RHICmdListComputeImmediate.WaitComputeFence(ClearBeginFence);
|
|
|
|
//standard compute setup, but on the async commandlist.
|
|
RHICmdListComputeImmediate.SetComputeShader(ComputeShader->GetComputeShader());
|
|
|
|
ComputeShader->SetParameters(RHICmdListComputeImmediate, VolumeUAVs, 4);
|
|
|
|
int32 GroupsPerDim = GTranslucencyLightingVolumeDim / FClearTranslucentLightingVolumeCS::CLEAR_BLOCK_SIZE;
|
|
DispatchComputeShader(RHICmdListComputeImmediate, ComputeShader, GroupsPerDim, GroupsPerDim, GroupsPerDim);
|
|
|
|
ComputeShader->UnsetParameters(RHICmdListComputeImmediate);
|
|
|
|
//transition the output to readable and write the fence to allow the Gfx pipe to carry on.
|
|
RHICmdListComputeImmediate.TransitionResources(EResourceTransitionAccess::EReadable, EResourceTransitionPipeline::EComputeToGfx, VolumeUAVs, 4, TranslucencyLightingVolumeClearEndFence);
|
|
}
|
|
|
|
//immediately dispatch our async compute commands to the RHI thread to be submitted to the GPU as soon as possible.
|
|
//dispatch after the scope so the drawevent pop is inside the dispatch
|
|
FRHIAsyncComputeCommandListImmediate::ImmediateDispatch(RHICmdListComputeImmediate);
|
|
}
|
|
|
|
/** Encapsulates a pixel shader that is adding ambient cubemap to the volume. */
|
|
class FInjectAmbientCubemapPS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FInjectAmbientCubemapPS, Global);
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform)
|
|
{
|
|
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4);
|
|
}
|
|
|
|
/** Default constructor. */
|
|
FInjectAmbientCubemapPS() {}
|
|
|
|
public:
|
|
FCubemapShaderParameters CubemapShaderParameters;
|
|
|
|
/** Initialization constructor. */
|
|
FInjectAmbientCubemapPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FGlobalShader(Initializer)
|
|
{
|
|
CubemapShaderParameters.Bind(Initializer.ParameterMap);
|
|
}
|
|
|
|
// FShader interface.
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
Ar << CubemapShaderParameters;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
void SetParameters(FRHICommandList& RHICmdList, const FViewInfo& View, const FFinalPostProcessSettings::FCubemapEntry& CubemapEntry)
|
|
{
|
|
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();
|
|
|
|
FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View);
|
|
|
|
CubemapShaderParameters.SetParameters(RHICmdList, ShaderRHI, CubemapEntry);
|
|
}
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(,FInjectAmbientCubemapPS,TEXT("TranslucentLightingShaders"),TEXT("InjectAmbientCubemapMainPS"),SF_Pixel);
|
|
|
|
void FDeferredShadingSceneRenderer::InjectAmbientCubemapTranslucentVolumeLighting(FRHICommandList& RHICmdList)
|
|
{
|
|
//@todo - support multiple views
|
|
const FViewInfo& View = Views[0];
|
|
|
|
if (GUseTranslucentLightingVolumes && GSupportsVolumeTextureRendering && View.FinalPostProcessSettings.ContributingCubemaps.Num())
|
|
{
|
|
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
|
|
|
|
// to track down Jira UE-22073
|
|
ensure(SceneContext.GetCurrentFeatureLevel() >= ERHIFeatureLevel::SM4);
|
|
|
|
SCOPED_DRAW_EVENT(RHICmdList, InjectAmbientCubemapTranslucentVolumeLighting);
|
|
SCOPED_GPU_STAT(RHICmdList, Stat_GPU_TranslucentLighting);
|
|
|
|
const FVolumeBounds VolumeBounds(GTranslucencyLightingVolumeDim);
|
|
|
|
auto ShaderMap = GetGlobalShaderMap(FeatureLevel);
|
|
|
|
for (int32 VolumeCascadeIndex = 0; VolumeCascadeIndex < TVC_MAX; VolumeCascadeIndex++)
|
|
{
|
|
//Checks to detect/prevent UE-31578
|
|
const IPooledRenderTarget* RT0 = SceneContext.TranslucencyLightingVolumeAmbient[VolumeCascadeIndex];
|
|
ensure(RT0);
|
|
|
|
if (!RT0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// we don't update the directional volume (could be a HQ option)
|
|
SetRenderTarget(RHICmdList, RT0->GetRenderTargetItem().TargetableTexture, FTextureRHIRef(), true);
|
|
|
|
RHICmdList.SetRasterizerState(TStaticRasterizerState<FM_Solid, CM_None>::GetRHI());
|
|
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
|
|
RHICmdList.SetBlendState(TStaticBlendState<CW_RGBA, BO_Add, BF_One, BF_One, BO_Add, BF_One, BF_One>::GetRHI());
|
|
|
|
TShaderMapRef<FWriteToSliceVS> VertexShader(ShaderMap);
|
|
TOptionalShaderMapRef<FWriteToSliceGS> GeometryShader(ShaderMap);
|
|
TShaderMapRef<FInjectAmbientCubemapPS> PixelShader(ShaderMap);
|
|
|
|
static FGlobalBoundShaderState BoundShaderState;
|
|
|
|
SetGlobalBoundShaderState(RHICmdList, FeatureLevel, BoundShaderState, GScreenVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader, *GeometryShader);
|
|
|
|
VertexShader->SetParameters(RHICmdList, VolumeBounds, GTranslucencyLightingVolumeDim);
|
|
if(GeometryShader.IsValid())
|
|
{
|
|
GeometryShader->SetParameters(RHICmdList, VolumeBounds);
|
|
}
|
|
|
|
uint32 Count = View.FinalPostProcessSettings.ContributingCubemaps.Num();
|
|
for(uint32 i = 0; i < Count; ++i)
|
|
{
|
|
const FFinalPostProcessSettings::FCubemapEntry& CubemapEntry = View.FinalPostProcessSettings.ContributingCubemaps[i];
|
|
|
|
PixelShader->SetParameters(RHICmdList, View, CubemapEntry);
|
|
|
|
RasterizeToVolumeTexture(RHICmdList, VolumeBounds);
|
|
}
|
|
|
|
RHICmdList.CopyToResolveTarget(RT0->GetRenderTargetItem().TargetableTexture,
|
|
RT0->GetRenderTargetItem().ShaderResourceTexture, true, FResolveParams());
|
|
}
|
|
}
|
|
}
|
|
|
|
void FDeferredShadingSceneRenderer::ClearTranslucentVolumePerObjectShadowing(FRHICommandList& RHICmdList)
|
|
{
|
|
if (GUseTranslucentLightingVolumes && GSupportsVolumeTextureRendering)
|
|
{
|
|
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
|
|
SCOPED_DRAW_EVENT(RHICmdList, ClearTranslucentVolumePerLightShadowing);
|
|
SCOPED_GPU_STAT(RHICmdList, Stat_GPU_TranslucentLighting);
|
|
|
|
static_assert(TVC_MAX == 2, "Only expecting two translucency lighting cascades.");
|
|
FTextureRHIParamRef RenderTargets[2];
|
|
RenderTargets[0] = SceneContext.GetTranslucencyVolumeAmbient(TVC_Inner)->GetRenderTargetItem().TargetableTexture;
|
|
RenderTargets[1] = SceneContext.GetTranslucencyVolumeDirectional(TVC_Inner)->GetRenderTargetItem().TargetableTexture;
|
|
|
|
FLinearColor ClearColors[2];
|
|
ClearColors[0] = FLinearColor(1, 1, 1, 1);
|
|
ClearColors[1] = FLinearColor(1, 1, 1, 1);
|
|
|
|
ClearVolumeTextures<ARRAY_COUNT(RenderTargets)>(RHICmdList, FeatureLevel, RenderTargets, ClearColors);
|
|
}
|
|
}
|
|
|
|
/** Calculates volume texture bounds for the given light in the given translucent lighting volume cascade. */
|
|
FVolumeBounds CalculateLightVolumeBounds(const FSphere& LightBounds, const FViewInfo& View, uint32 VolumeCascadeIndex, bool bDirectionalLight)
|
|
{
|
|
FVolumeBounds VolumeBounds;
|
|
|
|
if (bDirectionalLight)
|
|
{
|
|
VolumeBounds = FVolumeBounds(GTranslucencyLightingVolumeDim);
|
|
}
|
|
else
|
|
{
|
|
// Determine extents in the volume texture
|
|
const FVector MinPosition = (LightBounds.Center - LightBounds.W - View.TranslucencyLightingVolumeMin[VolumeCascadeIndex]) / View.TranslucencyVolumeVoxelSize[VolumeCascadeIndex];
|
|
const FVector MaxPosition = (LightBounds.Center + LightBounds.W - View.TranslucencyLightingVolumeMin[VolumeCascadeIndex]) / View.TranslucencyVolumeVoxelSize[VolumeCascadeIndex];
|
|
|
|
VolumeBounds.MinX = FMath::Max(FMath::TruncToInt(MinPosition.X), 0);
|
|
VolumeBounds.MinY = FMath::Max(FMath::TruncToInt(MinPosition.Y), 0);
|
|
VolumeBounds.MinZ = FMath::Max(FMath::TruncToInt(MinPosition.Z), 0);
|
|
|
|
VolumeBounds.MaxX = FMath::Min(FMath::TruncToInt(MaxPosition.X) + 1, GTranslucencyLightingVolumeDim);
|
|
VolumeBounds.MaxY = FMath::Min(FMath::TruncToInt(MaxPosition.Y) + 1, GTranslucencyLightingVolumeDim);
|
|
VolumeBounds.MaxZ = FMath::Min(FMath::TruncToInt(MaxPosition.Z) + 1, GTranslucencyLightingVolumeDim);
|
|
}
|
|
|
|
return VolumeBounds;
|
|
}
|
|
|
|
FGlobalBoundShaderState ObjectShadowingBoundShaderState;
|
|
|
|
void FDeferredShadingSceneRenderer::AccumulateTranslucentVolumeObjectShadowing(FRHICommandList& RHICmdList, const FProjectedShadowInfo* InProjectedShadowInfo, bool bClearVolume)
|
|
{
|
|
const FLightSceneInfo* LightSceneInfo = &InProjectedShadowInfo->GetLightSceneInfo();
|
|
|
|
if (bClearVolume)
|
|
{
|
|
ClearTranslucentVolumePerObjectShadowing(RHICmdList);
|
|
}
|
|
|
|
if (GUseTranslucentLightingVolumes && GSupportsVolumeTextureRendering)
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, AccumulateTranslucentVolumeShadowing);
|
|
SCOPED_GPU_STAT(RHICmdList, Stat_GPU_TranslucentLighting);
|
|
|
|
auto ShaderMap = GetGlobalShaderMap(FeatureLevel);
|
|
|
|
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
|
|
// Inject into each volume cascade
|
|
for (uint32 VolumeCascadeIndex = 0; VolumeCascadeIndex < TVC_MAX; VolumeCascadeIndex++)
|
|
{
|
|
//@todo - support multiple views
|
|
const FViewInfo& View = Views[0];
|
|
const bool bDirectionalLight = LightSceneInfo->Proxy->GetLightType() == LightType_Directional;
|
|
const FVolumeBounds VolumeBounds = CalculateLightVolumeBounds(LightSceneInfo->Proxy->GetBoundingSphere(), View, VolumeCascadeIndex, bDirectionalLight);
|
|
|
|
if (VolumeBounds.IsValid())
|
|
{
|
|
FTextureRHIParamRef RenderTarget;
|
|
|
|
if (VolumeCascadeIndex == 0)
|
|
{
|
|
RenderTarget = SceneContext.GetTranslucencyVolumeAmbient(TVC_Inner)->GetRenderTargetItem().TargetableTexture;
|
|
}
|
|
else
|
|
{
|
|
RenderTarget = SceneContext.GetTranslucencyVolumeDirectional(TVC_Inner)->GetRenderTargetItem().TargetableTexture;
|
|
}
|
|
|
|
SetRenderTarget(RHICmdList, RenderTarget, FTextureRHIRef());
|
|
|
|
RHICmdList.SetRasterizerState(TStaticRasterizerState<FM_Solid, CM_None>::GetRHI());
|
|
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
|
|
|
|
// Modulate the contribution of multiple object shadows in rgb
|
|
RHICmdList.SetBlendState(TStaticBlendState<CW_RGB, BO_Add, BF_DestColor, BF_Zero>::GetRHI());
|
|
|
|
TShaderMapRef<FWriteToSliceVS> VertexShader(ShaderMap);
|
|
TOptionalShaderMapRef<FWriteToSliceGS> GeometryShader(ShaderMap);
|
|
TShaderMapRef<FTranslucentObjectShadowingPS> PixelShader(ShaderMap);
|
|
|
|
SetGlobalBoundShaderState(RHICmdList, FeatureLevel, ObjectShadowingBoundShaderState, GScreenVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader, *GeometryShader);
|
|
VertexShader->SetParameters(RHICmdList, VolumeBounds, GTranslucencyLightingVolumeDim);
|
|
if(GeometryShader.IsValid())
|
|
{
|
|
GeometryShader->SetParameters(RHICmdList, VolumeBounds);
|
|
}
|
|
PixelShader->SetParameters(RHICmdList, View, LightSceneInfo, InProjectedShadowInfo, VolumeCascadeIndex);
|
|
|
|
RasterizeToVolumeTexture(RHICmdList, VolumeBounds);
|
|
|
|
RHICmdList.CopyToResolveTarget(SceneContext.GetTranslucencyVolumeAmbient((ETranslucencyVolumeCascade)VolumeCascadeIndex)->GetRenderTargetItem().TargetableTexture,
|
|
SceneContext.GetTranslucencyVolumeAmbient((ETranslucencyVolumeCascade)VolumeCascadeIndex)->GetRenderTargetItem().ShaderResourceTexture, true, FResolveParams());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper function for finding and setting the right version of TTranslucentLightingInjectPS given template parameters.
|
|
* @param MaterialProxy must not be 0
|
|
* @param InnerSplitIndex todo: get from ShadowMap, INDEX_NONE if no directional light
|
|
*/
|
|
template<ELightComponentType InjectionType, bool bDynamicallyShadowed>
|
|
void SetInjectionShader(
|
|
FRHICommandList& RHICmdList,
|
|
const FViewInfo& View,
|
|
const FMaterialRenderProxy* MaterialProxy,
|
|
const FLightSceneInfo* LightSceneInfo,
|
|
const FProjectedShadowInfo* ShadowMap,
|
|
int32 InnerSplitIndex,
|
|
int32 VolumeCascadeIndexValue,
|
|
FWriteToSliceVS* VertexShader,
|
|
FWriteToSliceGS* GeometryShader,
|
|
bool bApplyLightFunction,
|
|
bool bInverseSquared)
|
|
{
|
|
check(ShadowMap || !bDynamicallyShadowed);
|
|
|
|
const FMaterialShaderMap* MaterialShaderMap = MaterialProxy->GetMaterial(View.GetFeatureLevel())->GetRenderingThreadShaderMap();
|
|
FMaterialShader* PixelShader = NULL;
|
|
|
|
const bool Directional = InjectionType == LightType_Directional;
|
|
|
|
if (bApplyLightFunction)
|
|
{
|
|
if( bInverseSquared )
|
|
{
|
|
auto InjectionPixelShader = MaterialShaderMap->GetShader< TTranslucentLightingInjectPS<InjectionType, bDynamicallyShadowed, true, true && !Directional> >();
|
|
|
|
check(InjectionPixelShader);
|
|
PixelShader = InjectionPixelShader;
|
|
}
|
|
else
|
|
{
|
|
auto InjectionPixelShader = MaterialShaderMap->GetShader< TTranslucentLightingInjectPS<InjectionType, bDynamicallyShadowed, true, false> >();
|
|
|
|
check(InjectionPixelShader);
|
|
PixelShader = InjectionPixelShader;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( bInverseSquared )
|
|
{
|
|
auto InjectionPixelShader = MaterialShaderMap->GetShader< TTranslucentLightingInjectPS<InjectionType, bDynamicallyShadowed, false, true && !Directional> >();
|
|
|
|
check(InjectionPixelShader);
|
|
PixelShader = InjectionPixelShader;
|
|
}
|
|
else
|
|
{
|
|
auto InjectionPixelShader = MaterialShaderMap->GetShader< TTranslucentLightingInjectPS<InjectionType, bDynamicallyShadowed, false, false> >();
|
|
|
|
check(InjectionPixelShader);
|
|
PixelShader = InjectionPixelShader;
|
|
}
|
|
}
|
|
|
|
FBoundShaderStateRHIRef& BoundShaderState = LightSceneInfo->TranslucentInjectBoundShaderState[InjectionType][bDynamicallyShadowed][bApplyLightFunction][bInverseSquared];
|
|
const FMaterialShaderMap*& CachedShaderMap = LightSceneInfo->TranslucentInjectCachedShaderMaps[InjectionType][bDynamicallyShadowed][bApplyLightFunction][bInverseSquared];
|
|
|
|
// Recreate the bound shader state if the shader map has changed since the last cache
|
|
// This can happen due to async shader compiling
|
|
|
|
if (!IsValidRef(BoundShaderState) || CachedShaderMap != MaterialShaderMap)
|
|
{
|
|
CachedShaderMap = MaterialShaderMap;
|
|
check(IsInRenderingThread()); // I didn't know quite how to deal with this caching. It won't work with threads.
|
|
BoundShaderState =
|
|
RHICreateBoundShaderState( GScreenVertexDeclaration.VertexDeclarationRHI, VertexShader->GetVertexShader(), FHullShaderRHIRef(), FDomainShaderRHIRef(), PixelShader->GetPixelShader(), GeometryShader ? GeometryShader->GetGeometryShader() : nullptr);
|
|
}
|
|
|
|
RHICmdList.SetBoundShaderState(BoundShaderState);
|
|
|
|
// Now shader is set, bind parameters
|
|
if (bApplyLightFunction)
|
|
{
|
|
if( bInverseSquared )
|
|
{
|
|
auto InjectionPixelShader = MaterialShaderMap->GetShader< TTranslucentLightingInjectPS<InjectionType, bDynamicallyShadowed, true, true && !Directional> >();
|
|
check(InjectionPixelShader);
|
|
InjectionPixelShader->SetParameters(RHICmdList, View, LightSceneInfo, MaterialProxy, ShadowMap, InnerSplitIndex, VolumeCascadeIndexValue);
|
|
}
|
|
else
|
|
{
|
|
auto InjectionPixelShader = MaterialShaderMap->GetShader< TTranslucentLightingInjectPS<InjectionType, bDynamicallyShadowed, true, false> >();
|
|
check(InjectionPixelShader);
|
|
InjectionPixelShader->SetParameters(RHICmdList, View, LightSceneInfo, MaterialProxy, ShadowMap, InnerSplitIndex, VolumeCascadeIndexValue);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( bInverseSquared )
|
|
{
|
|
auto InjectionPixelShader = MaterialShaderMap->GetShader< TTranslucentLightingInjectPS<InjectionType, bDynamicallyShadowed, false, true && !Directional> >();
|
|
check(InjectionPixelShader);
|
|
InjectionPixelShader->SetParameters(RHICmdList, View, LightSceneInfo, MaterialProxy, ShadowMap, InnerSplitIndex, VolumeCascadeIndexValue);
|
|
}
|
|
else
|
|
{
|
|
auto InjectionPixelShader = MaterialShaderMap->GetShader< TTranslucentLightingInjectPS<InjectionType, bDynamicallyShadowed, false, false> >();
|
|
check(InjectionPixelShader);
|
|
InjectionPixelShader->SetParameters(RHICmdList, View, LightSceneInfo, MaterialProxy, ShadowMap, InnerSplitIndex, VolumeCascadeIndexValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Information about a light to be injected.
|
|
* Cached in this struct to avoid recomputing multiple times (multiple cascades).
|
|
*/
|
|
struct FTranslucentLightInjectionData
|
|
{
|
|
// must not be 0
|
|
const FLightSceneInfo* LightSceneInfo;
|
|
// can be 0
|
|
const FProjectedShadowInfo* ProjectedShadowInfo;
|
|
//
|
|
bool bApplyLightFunction;
|
|
// must not be 0
|
|
const FMaterialRenderProxy* LightFunctionMaterialProxy;
|
|
};
|
|
|
|
/**
|
|
* Adds a light to LightInjectionData if it should be injected into the translucent volume, and caches relevant information in a FTranslucentLightInjectionData.
|
|
* @param InProjectedShadowInfo is 0 for unshadowed lights
|
|
*/
|
|
static void AddLightForInjection(
|
|
FDeferredShadingSceneRenderer& SceneRenderer,
|
|
const FLightSceneInfo& LightSceneInfo,
|
|
const FProjectedShadowInfo* InProjectedShadowInfo,
|
|
TArray<FTranslucentLightInjectionData, SceneRenderingAllocator>& LightInjectionData)
|
|
{
|
|
if (LightSceneInfo.Proxy->AffectsTranslucentLighting())
|
|
{
|
|
const FVisibleLightInfo& VisibleLightInfo = SceneRenderer.VisibleLightInfos[LightSceneInfo.Id];
|
|
|
|
const ERHIFeatureLevel::Type FeatureLevel = SceneRenderer.Scene->GetFeatureLevel();
|
|
|
|
const bool bApplyLightFunction = (SceneRenderer.ViewFamily.EngineShowFlags.LightFunctions &&
|
|
LightSceneInfo.Proxy->GetLightFunctionMaterial() &&
|
|
LightSceneInfo.Proxy->GetLightFunctionMaterial()->GetMaterial(FeatureLevel)->IsLightFunction());
|
|
|
|
const FMaterialRenderProxy* MaterialProxy = bApplyLightFunction ?
|
|
LightSceneInfo.Proxy->GetLightFunctionMaterial() :
|
|
UMaterial::GetDefaultMaterial(MD_LightFunction)->GetRenderProxy(false);
|
|
|
|
// Skip rendering if the DefaultLightFunctionMaterial isn't compiled yet
|
|
if (MaterialProxy->GetMaterial(FeatureLevel)->IsLightFunction())
|
|
{
|
|
FTranslucentLightInjectionData InjectionData;
|
|
InjectionData.LightSceneInfo = &LightSceneInfo;
|
|
InjectionData.ProjectedShadowInfo = InProjectedShadowInfo;
|
|
InjectionData.bApplyLightFunction = bApplyLightFunction;
|
|
InjectionData.LightFunctionMaterialProxy = MaterialProxy;
|
|
LightInjectionData.Add(InjectionData);
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Injects all the lights in LightInjectionData into the translucent lighting volume textures. */
|
|
static void InjectTranslucentLightArray(FRHICommandListImmediate& RHICmdList, const FViewInfo& View, const TArray<FTranslucentLightInjectionData, SceneRenderingAllocator>& LightInjectionData)
|
|
{
|
|
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
|
|
INC_DWORD_STAT_BY(STAT_NumLightsInjectedIntoTranslucency, LightInjectionData.Num());
|
|
|
|
// to track down Jira UE-22073
|
|
ensure(SceneContext.GetCurrentFeatureLevel() >= ERHIFeatureLevel::SM4);
|
|
|
|
// Inject into each volume cascade
|
|
// Operate on one cascade at a time to reduce render target switches
|
|
for (uint32 VolumeCascadeIndex = 0; VolumeCascadeIndex < TVC_MAX; VolumeCascadeIndex++)
|
|
{
|
|
const IPooledRenderTarget* RT0 = SceneContext.TranslucencyLightingVolumeAmbient[VolumeCascadeIndex];
|
|
const IPooledRenderTarget* RT1 = SceneContext.TranslucencyLightingVolumeDirectional[VolumeCascadeIndex];
|
|
|
|
//Checks to detect/prevent UE-31578
|
|
ensure(RT0);
|
|
ensure(RT1);
|
|
|
|
if (!RT0 || !RT1)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, RT0);
|
|
GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, RT1);
|
|
|
|
FTextureRHIParamRef RenderTargets[2];
|
|
RenderTargets[0] = RT0->GetRenderTargetItem().TargetableTexture;
|
|
RenderTargets[1] = RT1->GetRenderTargetItem().TargetableTexture;
|
|
|
|
SetRenderTargets(RHICmdList, ARRAY_COUNT(RenderTargets), RenderTargets, FTextureRHIRef(), 0, NULL, true);
|
|
|
|
RHICmdList.SetRasterizerState(TStaticRasterizerState<FM_Solid, CM_None>::GetRHI());
|
|
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
|
|
|
|
for (int32 LightIndex = 0; LightIndex < LightInjectionData.Num(); LightIndex++)
|
|
{
|
|
const FTranslucentLightInjectionData& InjectionData = LightInjectionData[LightIndex];
|
|
const FLightSceneInfo* const LightSceneInfo = InjectionData.LightSceneInfo;
|
|
const bool bInverseSquared = LightSceneInfo->Proxy->IsInverseSquared();
|
|
const bool bDirectionalLight = LightSceneInfo->Proxy->GetLightType() == LightType_Directional;
|
|
const FVolumeBounds VolumeBounds = CalculateLightVolumeBounds(LightSceneInfo->Proxy->GetBoundingSphere(), View, VolumeCascadeIndex, bDirectionalLight);
|
|
|
|
if (VolumeBounds.IsValid())
|
|
{
|
|
TShaderMapRef<FWriteToSliceVS> VertexShader(View.ShaderMap);
|
|
TOptionalShaderMapRef<FWriteToSliceGS> GeometryShader(View.ShaderMap);
|
|
|
|
if (bDirectionalLight)
|
|
{
|
|
// Accumulate the contribution of multiple lights
|
|
// Directional lights write their shadowing into alpha of the ambient texture
|
|
RHICmdList.SetBlendState(TStaticBlendState<
|
|
CW_RGBA, BO_Add, BF_One, BF_One, BO_Add, BF_One, BF_One,
|
|
CW_RGB, BO_Add, BF_One, BF_One, BO_Add, BF_One, BF_One>::GetRHI());
|
|
|
|
if (InjectionData.ProjectedShadowInfo)
|
|
{
|
|
// shadows, restricting light contribution to the cascade bounds (except last cascade far to get light functions and no shadows there)
|
|
SetInjectionShader<LightType_Directional, true>(RHICmdList, View, InjectionData.LightFunctionMaterialProxy, LightSceneInfo,
|
|
InjectionData.ProjectedShadowInfo, InjectionData.ProjectedShadowInfo->CascadeSettings.ShadowSplitIndex, VolumeCascadeIndex,
|
|
*VertexShader, *GeometryShader, InjectionData.bApplyLightFunction, false);
|
|
}
|
|
else
|
|
{
|
|
// no shadows
|
|
SetInjectionShader<LightType_Directional, false>(RHICmdList, View, InjectionData.LightFunctionMaterialProxy, LightSceneInfo,
|
|
InjectionData.ProjectedShadowInfo, -1, VolumeCascadeIndex,
|
|
*VertexShader, *GeometryShader, InjectionData.bApplyLightFunction, false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Accumulate the contribution of multiple lights
|
|
RHICmdList.SetBlendState(TStaticBlendState<
|
|
CW_RGB, BO_Add, BF_One, BF_One, BO_Add, BF_Zero, BF_One,
|
|
CW_RGB, BO_Add, BF_One, BF_One, BO_Add, BF_Zero, BF_One>::GetRHI());
|
|
|
|
if (InjectionData.ProjectedShadowInfo)
|
|
{
|
|
SetInjectionShader<LightType_Point, true>(RHICmdList, View, InjectionData.LightFunctionMaterialProxy, LightSceneInfo,
|
|
InjectionData.ProjectedShadowInfo, -1, VolumeCascadeIndex,
|
|
*VertexShader, *GeometryShader, InjectionData.bApplyLightFunction, bInverseSquared);
|
|
}
|
|
else
|
|
{
|
|
SetInjectionShader<LightType_Point, false>(RHICmdList, View, InjectionData.LightFunctionMaterialProxy, LightSceneInfo,
|
|
InjectionData.ProjectedShadowInfo, -1, VolumeCascadeIndex,
|
|
*VertexShader, *GeometryShader, InjectionData.bApplyLightFunction, bInverseSquared);
|
|
}
|
|
}
|
|
|
|
VertexShader->SetParameters(RHICmdList, VolumeBounds, GTranslucencyLightingVolumeDim);
|
|
if(GeometryShader.IsValid())
|
|
{
|
|
GeometryShader->SetParameters(RHICmdList, VolumeBounds);
|
|
}
|
|
RasterizeToVolumeTexture(RHICmdList, VolumeBounds);
|
|
}
|
|
}
|
|
|
|
RHICmdList.CopyToResolveTarget(RT0->GetRenderTargetItem().TargetableTexture, RT0->GetRenderTargetItem().ShaderResourceTexture, true, FResolveParams());
|
|
RHICmdList.CopyToResolveTarget(RT1->GetRenderTargetItem().TargetableTexture, RT1->GetRenderTargetItem().ShaderResourceTexture, true, FResolveParams());
|
|
}
|
|
}
|
|
|
|
void FDeferredShadingSceneRenderer::InjectTranslucentVolumeLighting(FRHICommandListImmediate& RHICmdList, const FLightSceneInfo& LightSceneInfo, const FProjectedShadowInfo* InProjectedShadowInfo)
|
|
{
|
|
if (GUseTranslucentLightingVolumes && GSupportsVolumeTextureRendering)
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_TranslucentInjectTime);
|
|
|
|
//@todo - support multiple views
|
|
const FViewInfo& View = Views[0];
|
|
|
|
TArray<FTranslucentLightInjectionData, SceneRenderingAllocator> LightInjectionData;
|
|
|
|
AddLightForInjection(*this, LightSceneInfo, InProjectedShadowInfo, LightInjectionData);
|
|
|
|
// shadowed or unshadowed (InProjectedShadowInfo==0)
|
|
InjectTranslucentLightArray(RHICmdList, View, LightInjectionData);
|
|
}
|
|
}
|
|
|
|
void FDeferredShadingSceneRenderer::InjectTranslucentVolumeLightingArray(FRHICommandListImmediate& RHICmdList, const TArray<FSortedLightSceneInfo, SceneRenderingAllocator>& SortedLights, int32 NumLights)
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_TranslucentInjectTime);
|
|
|
|
//@todo - support multiple views
|
|
const FViewInfo& View = Views[0];
|
|
|
|
TArray<FTranslucentLightInjectionData, SceneRenderingAllocator> LightInjectionData;
|
|
LightInjectionData.Empty(NumLights);
|
|
|
|
for (int32 LightIndex = 0; LightIndex < NumLights; LightIndex++)
|
|
{
|
|
const FSortedLightSceneInfo& SortedLightInfo = SortedLights[LightIndex];
|
|
const FLightSceneInfoCompact& LightSceneInfoCompact = SortedLightInfo.SceneInfo;
|
|
const FLightSceneInfo* const LightSceneInfo = LightSceneInfoCompact.LightSceneInfo;
|
|
|
|
AddLightForInjection(*this, *LightSceneInfo, NULL, LightInjectionData);
|
|
}
|
|
|
|
// non-shadowed, non-light function lights
|
|
InjectTranslucentLightArray(RHICmdList, View, LightInjectionData);
|
|
}
|
|
|
|
/** Pixel shader used to inject simple lights into the translucent lighting volume */
|
|
class FSimpleLightTranslucentLightingInjectPS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FSimpleLightTranslucentLightingInjectPS,Global);
|
|
public:
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform)
|
|
{
|
|
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM4);
|
|
}
|
|
|
|
FSimpleLightTranslucentLightingInjectPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer):
|
|
FGlobalShader(Initializer)
|
|
{
|
|
VolumeCascadeIndex.Bind(Initializer.ParameterMap, TEXT("VolumeCascadeIndex"));
|
|
SimpleLightPositionAndRadius.Bind(Initializer.ParameterMap, TEXT("SimpleLightPositionAndRadius"));
|
|
SimpleLightColorAndExponent.Bind(Initializer.ParameterMap, TEXT("SimpleLightColorAndExponent"));
|
|
}
|
|
FSimpleLightTranslucentLightingInjectPS() {}
|
|
|
|
void SetParameters(FRHICommandList& RHICmdList, const FViewInfo& View, const FSimpleLightEntry& SimpleLight, const FSimpleLightPerViewEntry& SimpleLightPerViewData, int32 VolumeCascadeIndexValue)
|
|
{
|
|
FGlobalShader::SetParameters(RHICmdList, GetPixelShader(), View);
|
|
|
|
FVector4 PositionAndRadius(SimpleLightPerViewData.Position, SimpleLight.Radius);
|
|
SetShaderValue(RHICmdList, GetPixelShader(), VolumeCascadeIndex, VolumeCascadeIndexValue);
|
|
SetShaderValue(RHICmdList, GetPixelShader(), SimpleLightPositionAndRadius, PositionAndRadius);
|
|
|
|
FVector4 LightColorAndExponent(SimpleLight.Color, SimpleLight.Exponent);
|
|
|
|
if (SimpleLight.Exponent == 0)
|
|
{
|
|
// Correction for lumen units
|
|
LightColorAndExponent.X *= 16.0f;
|
|
LightColorAndExponent.Y *= 16.0f;
|
|
LightColorAndExponent.Z *= 16.0f;
|
|
}
|
|
|
|
SetShaderValue(RHICmdList, GetPixelShader(), SimpleLightColorAndExponent, LightColorAndExponent);
|
|
}
|
|
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
Ar << VolumeCascadeIndex;
|
|
Ar << SimpleLightPositionAndRadius;
|
|
Ar << SimpleLightColorAndExponent;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
FShaderParameter VolumeCascadeIndex;
|
|
FShaderParameter SimpleLightPositionAndRadius;
|
|
FShaderParameter SimpleLightColorAndExponent;
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(,FSimpleLightTranslucentLightingInjectPS,TEXT("TranslucentLightInjectionShaders"),TEXT("SimpleLightInjectMainPS"),SF_Pixel);
|
|
|
|
FGlobalBoundShaderState InjectSimpleLightBoundShaderState;
|
|
|
|
void FDeferredShadingSceneRenderer::InjectSimpleTranslucentVolumeLightingArray(FRHICommandListImmediate& RHICmdList, const FSimpleLightArray& SimpleLights)
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_TranslucentInjectTime);
|
|
|
|
int32 NumLightsToInject = 0;
|
|
|
|
for (int32 LightIndex = 0; LightIndex < SimpleLights.InstanceData.Num(); LightIndex++)
|
|
{
|
|
if (SimpleLights.InstanceData[LightIndex].bAffectTranslucency)
|
|
{
|
|
NumLightsToInject++;
|
|
}
|
|
}
|
|
|
|
if (NumLightsToInject > 0)
|
|
{
|
|
//@todo - support multiple views
|
|
const FViewInfo& View = Views[0];
|
|
const int32 ViewIndex = 0;
|
|
|
|
INC_DWORD_STAT_BY(STAT_NumLightsInjectedIntoTranslucency, NumLightsToInject);
|
|
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
|
|
|
|
// Inject into each volume cascade
|
|
// Operate on one cascade at a time to reduce render target switches
|
|
for (int32 VolumeCascadeIndex = 0; VolumeCascadeIndex < TVC_MAX; VolumeCascadeIndex++)
|
|
{
|
|
const IPooledRenderTarget* RT0 = SceneContext.TranslucencyLightingVolumeAmbient[VolumeCascadeIndex];
|
|
const IPooledRenderTarget* RT1 = SceneContext.TranslucencyLightingVolumeDirectional[VolumeCascadeIndex];
|
|
|
|
//Checks to detect/prevent UE-31578
|
|
ensure(RT0);
|
|
ensure(RT1);
|
|
|
|
if (!RT0 || !RT1)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, RT0);
|
|
GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, RT1);
|
|
|
|
FTextureRHIParamRef RenderTargets[2];
|
|
RenderTargets[0] = RT0->GetRenderTargetItem().TargetableTexture;
|
|
RenderTargets[1] = RT1->GetRenderTargetItem().TargetableTexture;
|
|
|
|
SetRenderTargets(RHICmdList, ARRAY_COUNT(RenderTargets), RenderTargets, FTextureRHIRef(), 0, NULL, true);
|
|
|
|
RHICmdList.SetRasterizerState(TStaticRasterizerState<FM_Solid, CM_None>::GetRHI());
|
|
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
|
|
|
|
|
|
for (int32 LightIndex = 0; LightIndex < SimpleLights.InstanceData.Num(); LightIndex++)
|
|
{
|
|
const FSimpleLightEntry& SimpleLight = SimpleLights.InstanceData[LightIndex];
|
|
const FSimpleLightPerViewEntry& SimpleLightPerViewData = SimpleLights.GetViewDependentData(LightIndex, ViewIndex, Views.Num());
|
|
|
|
if (SimpleLight.bAffectTranslucency)
|
|
{
|
|
const FSphere LightBounds(SimpleLightPerViewData.Position, SimpleLight.Radius);
|
|
const FVolumeBounds VolumeBounds = CalculateLightVolumeBounds(LightBounds, View, VolumeCascadeIndex, false);
|
|
|
|
if (VolumeBounds.IsValid())
|
|
{
|
|
TShaderMapRef<FWriteToSliceVS> VertexShader(View.ShaderMap);
|
|
TOptionalShaderMapRef<FWriteToSliceGS> GeometryShader(View.ShaderMap);
|
|
TShaderMapRef<FSimpleLightTranslucentLightingInjectPS> PixelShader(View.ShaderMap);
|
|
SetGlobalBoundShaderState(RHICmdList, FeatureLevel, InjectSimpleLightBoundShaderState, GScreenVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader, *GeometryShader);
|
|
|
|
VertexShader->SetParameters(RHICmdList, VolumeBounds, GTranslucencyLightingVolumeDim);
|
|
if(GeometryShader.IsValid())
|
|
{
|
|
GeometryShader->SetParameters(RHICmdList, VolumeBounds);
|
|
}
|
|
PixelShader->SetParameters(RHICmdList, View, SimpleLight, SimpleLightPerViewData, VolumeCascadeIndex);
|
|
|
|
// Accumulate the contribution of multiple lights
|
|
RHICmdList.SetBlendState(TStaticBlendState<
|
|
CW_RGB, BO_Add, BF_One, BF_One, BO_Add, BF_Zero, BF_One,
|
|
CW_RGB, BO_Add, BF_One, BF_One, BO_Add, BF_Zero, BF_One>::GetRHI());
|
|
|
|
RasterizeToVolumeTexture(RHICmdList, VolumeBounds);
|
|
}
|
|
}
|
|
}
|
|
|
|
RHICmdList.CopyToResolveTarget(RT0->GetRenderTargetItem().TargetableTexture, RT0->GetRenderTargetItem().ShaderResourceTexture, true, FResolveParams());
|
|
RHICmdList.CopyToResolveTarget(RT1->GetRenderTargetItem().TargetableTexture, RT1->GetRenderTargetItem().ShaderResourceTexture, true, FResolveParams());
|
|
}
|
|
}
|
|
}
|
|
|
|
FGlobalBoundShaderState FilterBoundShaderState;
|
|
|
|
void FDeferredShadingSceneRenderer::FilterTranslucentVolumeLighting(FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
if (GUseTranslucentLightingVolumes && GSupportsVolumeTextureRendering)
|
|
{
|
|
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
|
|
#if 0
|
|
// textures have to be finalized before reading.
|
|
for (int32 VolumeCascadeIndex = 0; VolumeCascadeIndex < TVC_MAX; VolumeCascadeIndex++)
|
|
{
|
|
const IPooledRenderTarget* RT0 = SceneContext.TranslucencyLightingVolumeAmbient[VolumeCascadeIndex];
|
|
const IPooledRenderTarget* RT1 = SceneContext.TranslucencyLightingVolumeDirectional[VolumeCascadeIndex];
|
|
FTextureRHIRef TargetTexture0 = RT0->GetRenderTargetItem().TargetableTexture;
|
|
FTextureRHIRef TargetTexture1 = RT1->GetRenderTargetItem().TargetableTexture;
|
|
RHICmdList.CopyToResolveTarget(TargetTexture0, TargetTexture0, true, FResolveParams());
|
|
RHICmdList.CopyToResolveTarget(TargetTexture1, TargetTexture1, true, FResolveParams());
|
|
}
|
|
#endif
|
|
|
|
if (GUseTranslucencyVolumeBlur)
|
|
{
|
|
//@todo - support multiple views
|
|
const FViewInfo& View = Views[0];
|
|
|
|
SCOPED_DRAW_EVENTF(RHICmdList, FilterTranslucentVolume, TEXT("FilterTranslucentVolume %dx%dx%d Cascades:%d"),
|
|
GTranslucencyLightingVolumeDim, GTranslucencyLightingVolumeDim, GTranslucencyLightingVolumeDim, TVC_MAX);
|
|
|
|
SCOPED_GPU_STAT(RHICmdList, Stat_GPU_TranslucentLighting);
|
|
|
|
// Filter each cascade
|
|
for (int32 VolumeCascadeIndex = 0; VolumeCascadeIndex < TVC_MAX; VolumeCascadeIndex++)
|
|
{
|
|
const IPooledRenderTarget* RT0 = SceneContext.GetTranslucencyVolumeAmbient((ETranslucencyVolumeCascade)VolumeCascadeIndex);
|
|
const IPooledRenderTarget* RT1 = SceneContext.GetTranslucencyVolumeDirectional((ETranslucencyVolumeCascade)VolumeCascadeIndex);
|
|
|
|
const IPooledRenderTarget* Input0 = SceneContext.TranslucencyLightingVolumeAmbient[VolumeCascadeIndex];
|
|
const IPooledRenderTarget* Input1 = SceneContext.TranslucencyLightingVolumeDirectional[VolumeCascadeIndex];
|
|
|
|
//Checks to detect/prevent UE-31578
|
|
ensure(RT0);
|
|
ensure(RT1);
|
|
ensure(Input0);
|
|
ensure(Input1);
|
|
|
|
if (!RT0 || !RT1 || !Input0 || !Input1)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, RT0);
|
|
GRenderTargetPool.VisualizeTexture.SetCheckPoint(RHICmdList, RT1);
|
|
|
|
FTextureRHIParamRef RenderTargets[2];
|
|
RenderTargets[0] = RT0->GetRenderTargetItem().TargetableTexture;
|
|
RenderTargets[1] = RT1->GetRenderTargetItem().TargetableTexture;
|
|
|
|
FTextureRHIParamRef Inputs[2];
|
|
Inputs[0] = Input0->GetRenderTargetItem().TargetableTexture;
|
|
Inputs[1] = Input1->GetRenderTargetItem().TargetableTexture;
|
|
|
|
static_assert(TVC_MAX == 2, "Final transition logic should change");
|
|
|
|
//the volume textures should still be writable from the injection phase on the first loop.
|
|
if (VolumeCascadeIndex > 0)
|
|
{
|
|
RHICmdList.TransitionResources(EResourceTransitionAccess::EWritable, RenderTargets, 2);
|
|
}
|
|
RHICmdList.TransitionResources(EResourceTransitionAccess::EReadable, Inputs, 2);
|
|
|
|
SetRenderTargets(RHICmdList, ARRAY_COUNT(RenderTargets), RenderTargets, FTextureRHIRef(), 0, NULL, true);
|
|
|
|
|
|
const FVolumeBounds VolumeBounds(GTranslucencyLightingVolumeDim);
|
|
TShaderMapRef<FWriteToSliceVS> VertexShader(View.ShaderMap);
|
|
TOptionalShaderMapRef<FWriteToSliceGS> GeometryShader(View.ShaderMap);
|
|
TShaderMapRef<FFilterTranslucentVolumePS> PixelShader(View.ShaderMap);
|
|
|
|
RHICmdList.SetRasterizerState(TStaticRasterizerState<FM_Solid, CM_None>::GetRHI());
|
|
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
|
|
RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI());
|
|
|
|
SetGlobalBoundShaderState(RHICmdList, FeatureLevel, FilterBoundShaderState, GScreenVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader, *GeometryShader);
|
|
|
|
VertexShader->SetParameters(RHICmdList, VolumeBounds, GTranslucencyLightingVolumeDim);
|
|
if(GeometryShader.IsValid())
|
|
{
|
|
GeometryShader->SetParameters(RHICmdList, VolumeBounds);
|
|
}
|
|
PixelShader->SetParameters(RHICmdList, View, VolumeCascadeIndex);
|
|
|
|
RasterizeToVolumeTexture(RHICmdList, VolumeBounds);
|
|
|
|
//only do readable transition on the final loop since the other ones will do this up front.
|
|
//if (VolumeCascadeIndex == TVC_MAX - 1)
|
|
{
|
|
RHICmdList.TransitionResources(EResourceTransitionAccess::EReadable, RenderTargets, 2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|