You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
- Resource state transitions handled by RDG. - FDistanceFieldObjectBufferResource replaced by FDistanceFieldCulledObjectBufferParameters to use RDG. - FTileIntersectionResources replaced by FTileIntersectionParameters to use RDG. - FAOScreenGridResources replaced by FAOScreenGridParameters to use RDG. - Don't store DFAO resources in View.State. - Split FDeferredShadingSceneRenderer::RenderDistanceFieldAOScreenGrid() into multiple passes. - Split BuildTileObjectLists() into multiple passes. #rb daniel.wright [CL 16660080 by tiago costa in ue5-main branch]
1229 lines
50 KiB
C++
1229 lines
50 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
HeightfieldLighting.cpp
|
|
=============================================================================*/
|
|
|
|
#include "HeightfieldLighting.h"
|
|
#include "StaticBoundShaderState.h"
|
|
#include "SceneUtils.h"
|
|
#include "Materials/Material.h"
|
|
#include "GlobalShader.h"
|
|
#include "MaterialShaderType.h"
|
|
#include "MaterialShader.h"
|
|
#include "DistanceFieldLightingShared.h"
|
|
#include "ScreenRendering.h"
|
|
#include "DistanceFieldAmbientOcclusion.h"
|
|
#include "LightRendering.h"
|
|
#include "PipelineStateCache.h"
|
|
|
|
IMPLEMENT_TYPE_LAYOUT(FHeightfieldDescriptionParameters);
|
|
IMPLEMENT_TYPE_LAYOUT(FHeightfieldTextureParameters);
|
|
|
|
// Currently disabled because the bHasHeightfieldRepresentation GBuffer bit has been reallocated, and self-shadowing artifacts are too severe without that bit
|
|
int32 GAOHeightfieldOcclusion = 0;
|
|
FAutoConsoleVariableRef CVarAOHeightfieldOcclusion(
|
|
TEXT("r.AOHeightfieldOcclusion"),
|
|
GAOHeightfieldOcclusion,
|
|
TEXT("Whether to compute AO from heightfields (landscape)"),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
int32 GHeightfieldGlobalIllumination = 1;
|
|
FAutoConsoleVariableRef CVarHeightfieldGlobalIllumination(
|
|
TEXT("r.HeightfieldGlobalIllumination"),
|
|
GHeightfieldGlobalIllumination,
|
|
TEXT(""),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
float GHeightfieldInnerBounceDistance = 3000;
|
|
FAutoConsoleVariableRef CVarHeightfieldInnerBounceDistancer(
|
|
TEXT("r.HeightfieldInnerBounceDistance"),
|
|
GHeightfieldInnerBounceDistance,
|
|
TEXT(""),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
float GHeightfieldOuterBounceDistanceScale = 3;
|
|
FAutoConsoleVariableRef CVarHeightfieldOuterBounceDistanceScale(
|
|
TEXT("r.HeightfieldOuterBounceDistanceScale"),
|
|
GHeightfieldOuterBounceDistanceScale,
|
|
TEXT(""),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
float GetGHeightfieldBounceDistance()
|
|
{
|
|
return GHeightfieldInnerBounceDistance * GHeightfieldOuterBounceDistanceScale;
|
|
}
|
|
|
|
float GHeightfieldTargetUnitsPerTexel = 200;
|
|
FAutoConsoleVariableRef CVarHeightfieldTargetUnitsPerTexel(
|
|
TEXT("r.HeightfieldTargetUnitsPerTexel"),
|
|
GHeightfieldTargetUnitsPerTexel,
|
|
TEXT(""),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
void FHeightfieldLightingAtlas::InitDynamicRHI()
|
|
{
|
|
FRHICommandListImmediate& RHICmdList = FRHICommandListExecutor::GetImmediateCommandList();
|
|
if (AtlasSize.GetMin() > 0)
|
|
{
|
|
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(
|
|
AtlasSize,
|
|
PF_G16,
|
|
FClearValueBinding::Transparent,
|
|
TexCreate_None,
|
|
TexCreate_RenderTargetable,
|
|
false));
|
|
|
|
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, Height, TEXT("HeightAtlas"));
|
|
|
|
FPooledRenderTargetDesc Desc2(FPooledRenderTargetDesc::Create2DDesc(
|
|
AtlasSize,
|
|
PF_R8G8,
|
|
FClearValueBinding::Transparent,
|
|
TexCreate_None,
|
|
TexCreate_RenderTargetable,
|
|
false));
|
|
|
|
GRenderTargetPool.FindFreeElement(RHICmdList, Desc2, Normal, TEXT("NormalAtlas"));
|
|
|
|
FPooledRenderTargetDesc Desc3(FPooledRenderTargetDesc::Create2DDesc(
|
|
AtlasSize,
|
|
PF_R8G8B8A8,
|
|
FClearValueBinding::Transparent,
|
|
TexCreate_None,
|
|
TexCreate_RenderTargetable,
|
|
false));
|
|
|
|
GRenderTargetPool.FindFreeElement(RHICmdList, Desc3, DiffuseColor, TEXT("DiffuseColorAtlas"));
|
|
|
|
FPooledRenderTargetDesc Desc4(FPooledRenderTargetDesc::Create2DDesc(
|
|
AtlasSize,
|
|
PF_G8,
|
|
FClearValueBinding::White,
|
|
TexCreate_None,
|
|
TexCreate_RenderTargetable,
|
|
false));
|
|
|
|
GRenderTargetPool.FindFreeElement(RHICmdList, Desc4, DirectionalLightShadowing, TEXT("HeightfieldShadowingAtlas"));
|
|
|
|
FPooledRenderTargetDesc Desc5(FPooledRenderTargetDesc::Create2DDesc(
|
|
AtlasSize,
|
|
PF_FloatR11G11B10,
|
|
FClearValueBinding::Black,
|
|
TexCreate_None,
|
|
TexCreate_RenderTargetable,
|
|
false));
|
|
Desc5.AutoWritable = false;
|
|
|
|
GRenderTargetPool.FindFreeElement(RHICmdList, Desc5, Lighting, TEXT("HeightfieldLightingAtlas"));
|
|
}
|
|
}
|
|
|
|
void FHeightfieldLightingAtlas::ReleaseDynamicRHI()
|
|
{
|
|
GRenderTargetPool.FreeUnusedResource(Height);
|
|
GRenderTargetPool.FreeUnusedResource(Normal);
|
|
GRenderTargetPool.FreeUnusedResource(DiffuseColor);
|
|
GRenderTargetPool.FreeUnusedResource(DirectionalLightShadowing);
|
|
GRenderTargetPool.FreeUnusedResource(Lighting);
|
|
}
|
|
|
|
void FHeightfieldLightingAtlas::InitializeForSize(FIntPoint InAtlasSize)
|
|
{
|
|
if (InAtlasSize.X > AtlasSize.X || InAtlasSize.Y > AtlasSize.Y)
|
|
{
|
|
AtlasSize.X = FMath::Max(InAtlasSize.X, AtlasSize.X);
|
|
AtlasSize.Y = FMath::Max(InAtlasSize.Y, AtlasSize.Y);
|
|
|
|
if (IsInitialized())
|
|
{
|
|
UpdateRHI();
|
|
}
|
|
else
|
|
{
|
|
InitResource();
|
|
}
|
|
}
|
|
}
|
|
|
|
class FSubsectionHeightfieldDescriptionsResource : public FRenderResource
|
|
{
|
|
public:
|
|
|
|
FCPUUpdatedBuffer Data;
|
|
|
|
FSubsectionHeightfieldDescriptionsResource()
|
|
{
|
|
Data.Format = PF_A32B32G32R32F;
|
|
// In float4's, must match usf
|
|
Data.Stride = 4;
|
|
}
|
|
|
|
virtual void InitDynamicRHI() override
|
|
{
|
|
Data.Initialize();
|
|
}
|
|
|
|
virtual void ReleaseDynamicRHI() override
|
|
{
|
|
Data.Release();
|
|
}
|
|
};
|
|
|
|
TGlobalResource<FSubsectionHeightfieldDescriptionsResource> GSubsectionHeightfieldDescriptions;
|
|
|
|
class FSubsectionHeightfieldDescriptionParameters
|
|
{
|
|
DECLARE_INLINE_TYPE_LAYOUT(FSubsectionHeightfieldDescriptionParameters, NonVirtual);
|
|
public:
|
|
void Bind(const FShaderParameterMap& ParameterMap)
|
|
{
|
|
SubsectionHeightfieldDescriptions.Bind(ParameterMap, TEXT("SubsectionHeightfieldDescriptions"));
|
|
}
|
|
|
|
friend FArchive& operator<<(FArchive& Ar, FSubsectionHeightfieldDescriptionParameters& Parameters)
|
|
{
|
|
Ar << Parameters.SubsectionHeightfieldDescriptions;
|
|
return Ar;
|
|
}
|
|
|
|
template<typename ShaderRHIParamRef>
|
|
void Set(FRHICommandList& RHICmdList, const ShaderRHIParamRef ShaderRHI)
|
|
{
|
|
SetSRVParameter(RHICmdList, ShaderRHI, SubsectionHeightfieldDescriptions, GSubsectionHeightfieldDescriptions.Data.BufferSRV);
|
|
}
|
|
|
|
private:
|
|
|
|
LAYOUT_FIELD(FShaderResourceParameter, SubsectionHeightfieldDescriptions)
|
|
|
|
};
|
|
|
|
int32 UploadSubsectionHeightfieldDescriptions(const TArray<FHeightfieldComponentDescription>& HeightfieldDescriptions, FVector2D InvLightingAtlasSize, float InvDownsampleFactor)
|
|
{
|
|
TArray<FVector4, SceneRenderingAllocator> HeightfieldDescriptionData;
|
|
HeightfieldDescriptionData.Empty(HeightfieldDescriptions.Num() * GSubsectionHeightfieldDescriptions.Data.Stride);
|
|
|
|
for (int32 DescriptionIndex = 0; DescriptionIndex < HeightfieldDescriptions.Num(); DescriptionIndex++)
|
|
{
|
|
const FHeightfieldComponentDescription& Description = HeightfieldDescriptions[DescriptionIndex];
|
|
|
|
for (int32 SubsectionY = 0; SubsectionY < Description.NumSubsections; SubsectionY++)
|
|
{
|
|
for (int32 SubsectionX = 0; SubsectionX < Description.NumSubsections; SubsectionX++)
|
|
{
|
|
HeightfieldDescriptionData.Add(FVector4(SubsectionX, SubsectionY, 0, 0));
|
|
HeightfieldDescriptionData.Add(Description.SubsectionScaleAndBias);
|
|
HeightfieldDescriptionData.Add(Description.HeightfieldScaleBias);
|
|
|
|
// GlobalUVScaleBias = SubsectionSizeQuads / AtlasSize, (SubsectionBase + SubsectionId * SubsectionSizeQuads - AtlasMin) / AtlasSize
|
|
const FVector4 GlobalUVScaleBias(
|
|
Description.SubsectionScaleAndBias.X * InvLightingAtlasSize.X * InvDownsampleFactor,
|
|
Description.SubsectionScaleAndBias.Y * InvLightingAtlasSize.Y * InvDownsampleFactor,
|
|
(Description.LightingAtlasLocation.X + SubsectionX * Description.SubsectionScaleAndBias.X * InvDownsampleFactor) * InvLightingAtlasSize.X,
|
|
(Description.LightingAtlasLocation.Y + SubsectionY * Description.SubsectionScaleAndBias.Y * InvDownsampleFactor) * InvLightingAtlasSize.Y);
|
|
|
|
HeightfieldDescriptionData.Add(GlobalUVScaleBias);
|
|
}
|
|
}
|
|
}
|
|
|
|
check(HeightfieldDescriptionData.Num() % GSubsectionHeightfieldDescriptions.Data.Stride == 0);
|
|
|
|
if (HeightfieldDescriptionData.Num() > GSubsectionHeightfieldDescriptions.Data.MaxElements)
|
|
{
|
|
GSubsectionHeightfieldDescriptions.Data.MaxElements = HeightfieldDescriptionData.Num() * 5 / 4;
|
|
GSubsectionHeightfieldDescriptions.Data.Release();
|
|
GSubsectionHeightfieldDescriptions.Data.Initialize();
|
|
}
|
|
|
|
void* LockedBuffer = RHILockBuffer(GSubsectionHeightfieldDescriptions.Data.Buffer, 0, GSubsectionHeightfieldDescriptions.Data.Buffer->GetSize(), RLM_WriteOnly);
|
|
const uint32 MemcpySize = HeightfieldDescriptionData.GetTypeSize() * HeightfieldDescriptionData.Num();
|
|
check(GSubsectionHeightfieldDescriptions.Data.Buffer->GetSize() >= MemcpySize);
|
|
FPlatformMemory::Memcpy(LockedBuffer, HeightfieldDescriptionData.GetData(), MemcpySize);
|
|
RHIUnlockBuffer(GSubsectionHeightfieldDescriptions.Data.Buffer);
|
|
|
|
return HeightfieldDescriptionData.Num() / GSubsectionHeightfieldDescriptions.Data.Stride;
|
|
}
|
|
|
|
bool DoesPlatformSupportDistanceFieldGI(EShaderPlatform Platform)
|
|
{
|
|
//@todo - remove remaining uses
|
|
return false;
|
|
}
|
|
|
|
class FHeightfieldSubsectionQuadVS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FHeightfieldSubsectionQuadVS, Global);
|
|
public:
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldGI(Parameters.Platform);
|
|
}
|
|
|
|
/** Default constructor. */
|
|
FHeightfieldSubsectionQuadVS() {}
|
|
|
|
/** Initialization constructor. */
|
|
FHeightfieldSubsectionQuadVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FGlobalShader(Initializer)
|
|
{
|
|
SubsectionHeightfieldParameters.Bind(Initializer.ParameterMap);
|
|
}
|
|
|
|
void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View)
|
|
{
|
|
FRHIVertexShader* ShaderRHI = RHICmdList.GetBoundVertexShader();
|
|
|
|
FGlobalShader::SetParameters<FViewUniformShaderParameters>(RHICmdList, ShaderRHI, View.ViewUniformBuffer);
|
|
SubsectionHeightfieldParameters.Set(RHICmdList, ShaderRHI);
|
|
}
|
|
|
|
private:
|
|
|
|
LAYOUT_FIELD(FSubsectionHeightfieldDescriptionParameters, SubsectionHeightfieldParameters);
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(, FHeightfieldSubsectionQuadVS, TEXT("/Engine/Private/HeightfieldLighting.usf"), TEXT("HeightfieldSubsectionQuadVS"), SF_Vertex);
|
|
|
|
class FInitializeHeightfieldsPS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FInitializeHeightfieldsPS, Global);
|
|
public:
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldGI(Parameters.Platform);
|
|
}
|
|
|
|
/** Default constructor. */
|
|
FInitializeHeightfieldsPS() {}
|
|
|
|
/** Initialization constructor. */
|
|
FInitializeHeightfieldsPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FGlobalShader(Initializer)
|
|
{
|
|
HeightfieldTextureParameters.Bind(Initializer.ParameterMap);
|
|
}
|
|
|
|
void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, UTexture2D* HeightfieldTextureValue, UTexture2D* DiffuseColorTextureValue)
|
|
{
|
|
FRHIPixelShader* ShaderRHI = RHICmdList.GetBoundPixelShader();
|
|
|
|
FGlobalShader::SetParameters<FViewUniformShaderParameters>(RHICmdList, ShaderRHI, View.ViewUniformBuffer);
|
|
HeightfieldTextureParameters.Set(RHICmdList, ShaderRHI, HeightfieldTextureValue, DiffuseColorTextureValue, nullptr);
|
|
}
|
|
|
|
private:
|
|
|
|
LAYOUT_FIELD(FHeightfieldTextureParameters, HeightfieldTextureParameters);
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(, FInitializeHeightfieldsPS, TEXT("/Engine/Private/HeightfieldLighting.usf"), TEXT("InitializeHeightfieldsPS"), SF_Pixel);
|
|
|
|
class FQuadVertexBuffer : public FVertexBuffer
|
|
{
|
|
public:
|
|
|
|
FQuadVertexBuffer()
|
|
{
|
|
}
|
|
|
|
virtual void InitRHI() override
|
|
{
|
|
const uint32 Size = 6 * sizeof(FScreenVertex);
|
|
FRHIResourceCreateInfo CreateInfo(TEXT("FQuadVertexBuffer"));
|
|
VertexBufferRHI = RHICreateBuffer(Size, BUF_Static | BUF_VertexBuffer, 0, ERHIAccess::VertexOrIndexBuffer, CreateInfo);
|
|
FScreenVertex* DestVertex = (FScreenVertex*)RHILockBuffer(VertexBufferRHI, 0, Size, RLM_WriteOnly);
|
|
|
|
DestVertex[0].Position = FVector2D(1, 1);
|
|
DestVertex[0].UV = FVector2D(1, 1);
|
|
|
|
DestVertex[1].Position = FVector2D(0, 1);
|
|
DestVertex[1].UV = FVector2D(0, 1);
|
|
|
|
DestVertex[2].Position = FVector2D(1, 0);
|
|
DestVertex[2].UV = FVector2D(1, 0);
|
|
|
|
DestVertex[3].Position = FVector2D(1, 0);
|
|
DestVertex[3].UV = FVector2D(1, 0);
|
|
|
|
DestVertex[4].Position = FVector2D(0, 1);
|
|
DestVertex[4].UV = FVector2D(0, 1);
|
|
|
|
DestVertex[5].Position = FVector2D(0, 0);
|
|
DestVertex[5].UV = FVector2D(0, 0);
|
|
|
|
RHIUnlockBuffer(VertexBufferRHI);
|
|
}
|
|
};
|
|
|
|
TGlobalResource<FQuadVertexBuffer> GQuadVertexBuffer;
|
|
|
|
bool SupportsHeightfieldLighting(ERHIFeatureLevel::Type FeatureLevel, EShaderPlatform ShaderPlatform)
|
|
{
|
|
return FeatureLevel >= ERHIFeatureLevel::SM5
|
|
&& DoesPlatformSupportDistanceFieldGI(ShaderPlatform);
|
|
}
|
|
|
|
bool AllowHeightfieldGI(const FViewInfo& View)
|
|
{
|
|
return GHeightfieldGlobalIllumination
|
|
&& View.State
|
|
//@todo - remove heightfield GI
|
|
&& false;
|
|
}
|
|
|
|
void FHeightfieldLightingViewInfo::SetupVisibleHeightfields(const FViewInfo& View, FRDGBuilder& GraphBuilder)
|
|
{
|
|
const FScene* Scene = (const FScene*)View.Family->Scene;
|
|
const int32 NumPrimitives = Scene->DistanceFieldSceneData.HeightfieldPrimitives.Num();
|
|
|
|
if ((!AllowHeightfieldGI(View) && !GAOHeightfieldOcclusion)
|
|
|| NumPrimitives == 0
|
|
|| !SupportsHeightfieldLighting(View.GetFeatureLevel(), View.GetShaderPlatform()))
|
|
{
|
|
return;
|
|
}
|
|
|
|
AddPass(GraphBuilder, [this, Scene, &View, NumPrimitives](FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
const float MaxDistanceSquared = FMath::Square(GetMaxAOViewDistance() + GetGHeightfieldBounceDistance());
|
|
float LocalToWorldScale = 1;
|
|
|
|
for (int32 HeightfieldPrimitiveIndex = 0; HeightfieldPrimitiveIndex < NumPrimitives; HeightfieldPrimitiveIndex++)
|
|
{
|
|
const FPrimitiveSceneInfo* HeightfieldPrimitive = Scene->DistanceFieldSceneData.HeightfieldPrimitives[HeightfieldPrimitiveIndex];
|
|
const FBoxSphereBounds& PrimitiveBounds = HeightfieldPrimitive->Proxy->GetBounds();
|
|
const float DistanceToPrimitiveSq = (PrimitiveBounds.Origin - View.ViewMatrices.GetViewOrigin()).SizeSquared();
|
|
|
|
if (View.ViewFrustum.IntersectSphere(PrimitiveBounds.Origin, PrimitiveBounds.SphereRadius + GetGHeightfieldBounceDistance())
|
|
&& DistanceToPrimitiveSq < MaxDistanceSquared)
|
|
{
|
|
UTexture2D* HeightfieldTexture = NULL;
|
|
UTexture2D* DiffuseColorTexture = NULL;
|
|
UTexture2D* VisibilityTexture = NULL;
|
|
|
|
FHeightfieldComponentDescription NewComponentDescription(HeightfieldPrimitive->Proxy->GetLocalToWorld());
|
|
HeightfieldPrimitive->Proxy->GetHeightfieldRepresentation(HeightfieldTexture, DiffuseColorTexture, VisibilityTexture, NewComponentDescription);
|
|
|
|
if (HeightfieldTexture && HeightfieldTexture->GetResource()->TextureRHI)
|
|
{
|
|
const FIntPoint HeightfieldSize = NewComponentDescription.HeightfieldRect.Size();
|
|
|
|
if (Heightfield.Rect.Area() == 0)
|
|
{
|
|
Heightfield.Rect = NewComponentDescription.HeightfieldRect;
|
|
LocalToWorldScale = NewComponentDescription.LocalToWorld.GetScaleVector().X;
|
|
}
|
|
else
|
|
{
|
|
Heightfield.Rect.Union(NewComponentDescription.HeightfieldRect);
|
|
}
|
|
|
|
TArray<FHeightfieldComponentDescription>& ComponentDescriptions = Heightfield.ComponentDescriptions.FindOrAdd(FHeightfieldComponentTextures(HeightfieldTexture, DiffuseColorTexture, VisibilityTexture));
|
|
ComponentDescriptions.Add(NewComponentDescription);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (AllowHeightfieldGI(View) && Heightfield.ComponentDescriptions.Num() > 0)
|
|
{
|
|
FSceneViewState* ViewState = (FSceneViewState*)View.State;
|
|
|
|
{
|
|
FHeightfieldLightingAtlas*& ExistingAtlas = ViewState->HeightfieldLightingAtlas;
|
|
|
|
if (!ExistingAtlas)
|
|
{
|
|
ExistingAtlas = new FHeightfieldLightingAtlas();
|
|
}
|
|
|
|
Heightfield.DownsampleFactor = FMath::Max(FMath::TruncToInt(GHeightfieldTargetUnitsPerTexel / LocalToWorldScale), 1);
|
|
Heightfield.DownsampledRect = Heightfield.Rect / Heightfield.DownsampleFactor;
|
|
Heightfield.Rect.Min = FIntPoint::DivideAndRoundDown(Heightfield.Rect.Min, Heightfield.DownsampleFactor) * Heightfield.DownsampleFactor;
|
|
ExistingAtlas->InitializeForSize(Heightfield.DownsampledRect.Size());
|
|
|
|
for (TMap<FHeightfieldComponentTextures, TArray<FHeightfieldComponentDescription>>::TIterator It(Heightfield.ComponentDescriptions); It; ++It)
|
|
{
|
|
TArray<FHeightfieldComponentDescription>& HeightfieldDescriptions = It.Value();
|
|
|
|
for (int32 ComponentIndex = 0; ComponentIndex < HeightfieldDescriptions.Num(); ComponentIndex++)
|
|
{
|
|
FIntPoint RelativeAtlasOffset = HeightfieldDescriptions[ComponentIndex].HeightfieldRect.Min - Heightfield.Rect.Min;
|
|
HeightfieldDescriptions[ComponentIndex].LightingAtlasLocation = FVector2D(RelativeAtlasOffset.X, RelativeAtlasOffset.Y) / Heightfield.DownsampleFactor;
|
|
}
|
|
}
|
|
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, InitializeHeightfield);
|
|
const FIntPoint LightingAtlasSize = ExistingAtlas->GetAtlasSize();
|
|
const FVector2D InvLightingAtlasSize(1.0f / LightingAtlasSize.X, 1.0f / LightingAtlasSize.Y);
|
|
|
|
FRHITexture* RenderTargets[3] =
|
|
{
|
|
ExistingAtlas->Height->GetRenderTargetItem().TargetableTexture,
|
|
ExistingAtlas->Normal->GetRenderTargetItem().TargetableTexture,
|
|
ExistingAtlas->DiffuseColor->GetRenderTargetItem().TargetableTexture
|
|
};
|
|
|
|
RHICmdList.SetViewport(0, 0, 0.0f, LightingAtlasSize.X, LightingAtlasSize.Y, 1.0f);
|
|
|
|
FRHIRenderPassInfo RPInfo(UE_ARRAY_COUNT(RenderTargets), RenderTargets, ERenderTargetActions::Clear_Store);
|
|
RHICmdList.BeginRenderPass(RPInfo, TEXT("SetupHeightfields"));
|
|
{
|
|
FGraphicsPipelineStateInitializer GraphicsPSOInit;
|
|
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
|
|
|
|
GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
|
|
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
|
|
GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI();
|
|
RHICmdList.SetStreamSource(0, GQuadVertexBuffer.VertexBufferRHI, 0);
|
|
|
|
TShaderMapRef<FHeightfieldSubsectionQuadVS> VertexShader(View.ShaderMap);
|
|
TShaderMapRef<FInitializeHeightfieldsPS> PixelShader(View.ShaderMap);
|
|
|
|
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GScreenVertexDeclaration.VertexDeclarationRHI;
|
|
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
|
|
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
|
|
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
|
|
|
|
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
|
|
|
|
for (TMap<FHeightfieldComponentTextures, TArray<FHeightfieldComponentDescription>>::TConstIterator It(Heightfield.ComponentDescriptions); It; ++It)
|
|
{
|
|
const TArray<FHeightfieldComponentDescription>& HeightfieldDescriptions = It.Value();
|
|
|
|
if (HeightfieldDescriptions.Num() > 0)
|
|
{
|
|
const int32 NumQuads = UploadSubsectionHeightfieldDescriptions(HeightfieldDescriptions, InvLightingAtlasSize, 1.0f / Heightfield.DownsampleFactor);
|
|
|
|
VertexShader->SetParameters(RHICmdList, View);
|
|
PixelShader->SetParameters(RHICmdList, View, It.Key().HeightAndNormal, It.Key().DiffuseColor);
|
|
|
|
RHICmdList.DrawPrimitive(0, 2, NumQuads);
|
|
}
|
|
}
|
|
}
|
|
RHICmdList.EndRenderPass();
|
|
|
|
TArray<FRHITransitionInfo, TInlineAllocator<3>> SRVTransitions;
|
|
for (FRHITexture* RHITexture : RenderTargets)
|
|
{
|
|
SRVTransitions.Add(FRHITransitionInfo(RHITexture, ERHIAccess::Unknown, ERHIAccess::SRVMask));
|
|
}
|
|
RHICmdList.Transition(MakeArrayView(SRVTransitions.GetData(), SRVTransitions.Num()));
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
void FHeightfieldLightingViewInfo::SetupHeightfieldsForScene(const FScene& Scene)
|
|
{
|
|
const int32 NumPrimitives = Scene.DistanceFieldSceneData.HeightfieldPrimitives.Num();
|
|
|
|
if (NumPrimitives > 0
|
|
&& SupportsHeightfieldLighting(Scene.GetFeatureLevel(), Scene.GetShaderPlatform()))
|
|
{
|
|
const float MaxDistanceSquared = FMath::Square(GetMaxAOViewDistance() + GetGHeightfieldBounceDistance());
|
|
float LocalToWorldScale = 1;
|
|
|
|
for (int32 HeightfieldPrimitiveIndex = 0; HeightfieldPrimitiveIndex < NumPrimitives; HeightfieldPrimitiveIndex++)
|
|
{
|
|
const FPrimitiveSceneInfo* HeightfieldPrimitive = Scene.DistanceFieldSceneData.HeightfieldPrimitives[HeightfieldPrimitiveIndex];
|
|
|
|
UTexture2D* HeightfieldTexture = NULL;
|
|
UTexture2D* DiffuseColorTexture = NULL;
|
|
UTexture2D* VisibilityTexture = NULL;
|
|
|
|
FHeightfieldComponentDescription NewComponentDescription(HeightfieldPrimitive->Proxy->GetLocalToWorld());
|
|
HeightfieldPrimitive->Proxy->GetHeightfieldRepresentation(HeightfieldTexture, DiffuseColorTexture, VisibilityTexture, NewComponentDescription);
|
|
|
|
if (HeightfieldTexture && HeightfieldTexture->GetResource()->TextureRHI)
|
|
{
|
|
const FIntPoint HeightfieldSize = NewComponentDescription.HeightfieldRect.Size();
|
|
|
|
if (Heightfield.Rect.Area() == 0)
|
|
{
|
|
Heightfield.Rect = NewComponentDescription.HeightfieldRect;
|
|
LocalToWorldScale = NewComponentDescription.LocalToWorld.GetScaleVector().X;
|
|
}
|
|
else
|
|
{
|
|
Heightfield.Rect.Union(NewComponentDescription.HeightfieldRect);
|
|
}
|
|
|
|
TArray<FHeightfieldComponentDescription>& ComponentDescriptions = Heightfield.ComponentDescriptions.FindOrAdd(FHeightfieldComponentTextures(HeightfieldTexture, DiffuseColorTexture, VisibilityTexture));
|
|
ComponentDescriptions.Add(NewComponentDescription);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class FHeightfieldDescriptionsResource : public FRenderResource
|
|
{
|
|
public:
|
|
|
|
FCPUUpdatedBuffer Data;
|
|
|
|
FHeightfieldDescriptionsResource()
|
|
{
|
|
// In float4's, must match usf
|
|
const int32 HEIGHTFIELD_DATA_STRIDE = 12;
|
|
|
|
Data.Format = PF_A32B32G32R32F;
|
|
Data.Stride = HEIGHTFIELD_DATA_STRIDE;
|
|
}
|
|
|
|
virtual void InitDynamicRHI() override
|
|
{
|
|
Data.Initialize();
|
|
}
|
|
|
|
virtual void ReleaseDynamicRHI() override
|
|
{
|
|
Data.Release();
|
|
}
|
|
};
|
|
|
|
TGlobalResource<FHeightfieldDescriptionsResource> GHeightfieldDescriptions;
|
|
|
|
FRHIShaderResourceView* GetHeightfieldDescriptionsSRV()
|
|
{
|
|
return GHeightfieldDescriptions.Data.BufferSRV;
|
|
}
|
|
|
|
void FillHeightfieldDescriptionData(const TArray<FHeightfieldComponentDescription>& HeightfieldDescriptions,
|
|
FVector2D InvLightingAtlasSize,
|
|
float InvDownsampleFactor,
|
|
TArray<FVector4, SceneRenderingAllocator>& HeightfieldDescriptionData)
|
|
{
|
|
HeightfieldDescriptionData.Empty(HeightfieldDescriptions.Num() * GHeightfieldDescriptions.Data.Stride);
|
|
|
|
for (int32 DescriptionIndex = 0; DescriptionIndex < HeightfieldDescriptions.Num(); DescriptionIndex++)
|
|
{
|
|
const FHeightfieldComponentDescription& Description = HeightfieldDescriptions[DescriptionIndex];
|
|
|
|
FVector4 HeightfieldScaleBias = Description.HeightfieldScaleBias;
|
|
check(HeightfieldScaleBias.X > 0);
|
|
|
|
// CalculateHeightfieldOcclusionCS needs to be fixed up if other values are ever supported
|
|
check(Description.NumSubsections == 1 || Description.NumSubsections == 2);
|
|
|
|
// Store the presence of subsections in the sign bit
|
|
HeightfieldScaleBias.X *= Description.NumSubsections > 1 ? -1 : 1;
|
|
|
|
HeightfieldDescriptionData.Add(HeightfieldScaleBias);
|
|
HeightfieldDescriptionData.Add(Description.MinMaxUV);
|
|
|
|
const FVector4 LightingUVScaleBias(
|
|
InvLightingAtlasSize.X * InvDownsampleFactor,
|
|
InvLightingAtlasSize.Y * InvDownsampleFactor,
|
|
Description.LightingAtlasLocation.X * InvLightingAtlasSize.X,
|
|
Description.LightingAtlasLocation.Y * InvLightingAtlasSize.Y);
|
|
|
|
HeightfieldDescriptionData.Add(LightingUVScaleBias);
|
|
|
|
HeightfieldDescriptionData.Add(FVector4(Description.HeightfieldRect.Size().X, Description.HeightfieldRect.Size().Y, 1.f / Description.HeightfieldRect.Size().X, 1.f / Description.HeightfieldRect.Size().Y));
|
|
HeightfieldDescriptionData.Add(FVector4(InvLightingAtlasSize.X, InvLightingAtlasSize.Y, 0.f, 0.f));
|
|
|
|
const FMatrix LocalToWorldT = Description.LocalToWorld.GetTransposed();
|
|
const FMatrix WorldToLocalT = Description.LocalToWorld.Inverse().GetTransposed();
|
|
|
|
HeightfieldDescriptionData.Add(*(FVector4*)&WorldToLocalT.M[0]);
|
|
HeightfieldDescriptionData.Add(*(FVector4*)&WorldToLocalT.M[1]);
|
|
HeightfieldDescriptionData.Add(*(FVector4*)&WorldToLocalT.M[2]);
|
|
|
|
HeightfieldDescriptionData.Add(*(FVector4*)&LocalToWorldT.M[0]);
|
|
HeightfieldDescriptionData.Add(*(FVector4*)&LocalToWorldT.M[1]);
|
|
HeightfieldDescriptionData.Add(*(FVector4*)&LocalToWorldT.M[2]);
|
|
|
|
FVector4 ChannelMask(0.f, 0.f, 0.f, 0.f);
|
|
if (Description.VisibilityChannel >= 0 && Description.VisibilityChannel < 4)
|
|
{
|
|
ChannelMask.Component(Description.VisibilityChannel) = 1.f;
|
|
}
|
|
HeightfieldDescriptionData.Add(ChannelMask);
|
|
}
|
|
|
|
check(HeightfieldDescriptionData.Num() % GHeightfieldDescriptions.Data.Stride == 0);
|
|
}
|
|
|
|
void UploadHeightfieldDescriptions(const TArray<FHeightfieldComponentDescription>& HeightfieldDescriptions, FVector2D InvLightingAtlasSize, float InvDownsampleFactor)
|
|
{
|
|
TArray<FVector4, SceneRenderingAllocator> HeightfieldDescriptionData;
|
|
|
|
FillHeightfieldDescriptionData(HeightfieldDescriptions,
|
|
InvLightingAtlasSize,
|
|
InvDownsampleFactor,
|
|
/*out*/ HeightfieldDescriptionData);
|
|
|
|
if (HeightfieldDescriptionData.Num() > GHeightfieldDescriptions.Data.MaxElements)
|
|
{
|
|
GHeightfieldDescriptions.Data.MaxElements = HeightfieldDescriptionData.Num() * 5 / 4;
|
|
GHeightfieldDescriptions.Data.Release();
|
|
GHeightfieldDescriptions.Data.Initialize();
|
|
}
|
|
|
|
void* LockedBuffer = RHILockBuffer(GHeightfieldDescriptions.Data.Buffer, 0, GHeightfieldDescriptions.Data.Buffer->GetSize(), RLM_WriteOnly);
|
|
const uint32 MemcpySize = HeightfieldDescriptionData.GetTypeSize() * HeightfieldDescriptionData.Num();
|
|
check(GHeightfieldDescriptions.Data.Buffer->GetSize() >= MemcpySize);
|
|
FPlatformMemory::Memcpy(LockedBuffer, HeightfieldDescriptionData.GetData(), MemcpySize);
|
|
RHIUnlockBuffer(GHeightfieldDescriptions.Data.Buffer);
|
|
}
|
|
|
|
FRDGBufferRef UploadHeightfieldDescriptions(FRDGBuilder& GraphBuilder, const TArray<FHeightfieldComponentDescription>& HeightfieldDescriptions, FVector2D InvLightingAtlasSize, float InvDownsampleFactor)
|
|
{
|
|
const uint32 BufferStride = GHeightfieldDescriptions.Data.Stride;
|
|
|
|
TArray<FVector4, SceneRenderingAllocator> HeightfieldDescriptionData;
|
|
|
|
FillHeightfieldDescriptionData(HeightfieldDescriptions,
|
|
InvLightingAtlasSize,
|
|
InvDownsampleFactor,
|
|
/*out*/ HeightfieldDescriptionData);
|
|
|
|
FRDGBufferRef HeightfieldDescriptionsBuffer =
|
|
CreateUploadBuffer(GraphBuilder, TEXT("HeightfieldDescriptionsBuffer"),
|
|
sizeof(FVector4), FMath::RoundUpToPowerOfTwo(FMath::Max(HeightfieldDescriptionData.Num(), 1)),
|
|
HeightfieldDescriptionData.GetData(), HeightfieldDescriptionData.Num() * HeightfieldDescriptionData.GetTypeSize());
|
|
|
|
return HeightfieldDescriptionsBuffer;
|
|
}
|
|
|
|
class FGlobalHeightfieldParameters
|
|
{
|
|
DECLARE_INLINE_TYPE_LAYOUT(FGlobalHeightfieldParameters, NonVirtual);
|
|
public:
|
|
void Bind(const FShaderParameterMap& ParameterMap)
|
|
{
|
|
GlobalHeightfieldTexture.Bind(ParameterMap, TEXT("GlobalHeightfieldTexture"));
|
|
GlobalNormalTexture.Bind(ParameterMap, TEXT("GlobalNormalTexture"));
|
|
GlobalDiffuseColorTexture.Bind(ParameterMap, TEXT("GlobalDiffuseColorTexture"));
|
|
GlobalHeightfieldSampler.Bind(ParameterMap, TEXT("GlobalHeightfieldSampler"));
|
|
}
|
|
|
|
friend FArchive& operator<<(FArchive& Ar, FGlobalHeightfieldParameters& Parameters)
|
|
{
|
|
Ar << Parameters.GlobalHeightfieldTexture;
|
|
Ar << Parameters.GlobalNormalTexture;
|
|
Ar << Parameters.GlobalDiffuseColorTexture;
|
|
Ar << Parameters.GlobalHeightfieldSampler;
|
|
return Ar;
|
|
}
|
|
|
|
template<typename ShaderRHIParamRef>
|
|
void Set(FRHICommandList& RHICmdList, const ShaderRHIParamRef ShaderRHI, const FHeightfieldLightingAtlas& Atlas)
|
|
{
|
|
SetTextureParameter(RHICmdList, ShaderRHI, GlobalHeightfieldTexture, GlobalHeightfieldSampler, TStaticSamplerState<SF_Bilinear>::GetRHI(), Atlas.Height->GetRenderTargetItem().ShaderResourceTexture);
|
|
SetTextureParameter(RHICmdList, ShaderRHI, GlobalNormalTexture, GlobalHeightfieldSampler, TStaticSamplerState<SF_Bilinear>::GetRHI(), Atlas.Normal->GetRenderTargetItem().ShaderResourceTexture);
|
|
SetTextureParameter(RHICmdList, ShaderRHI, GlobalDiffuseColorTexture, GlobalHeightfieldSampler, TStaticSamplerState<SF_Bilinear>::GetRHI(), Atlas.DiffuseColor->GetRenderTargetItem().ShaderResourceTexture);
|
|
}
|
|
|
|
private:
|
|
|
|
LAYOUT_FIELD(FShaderResourceParameter, GlobalHeightfieldTexture)
|
|
LAYOUT_FIELD(FShaderResourceParameter, GlobalNormalTexture)
|
|
LAYOUT_FIELD(FShaderResourceParameter, GlobalDiffuseColorTexture)
|
|
LAYOUT_FIELD(FShaderResourceParameter, GlobalHeightfieldSampler)
|
|
|
|
};
|
|
|
|
class FHeightfieldComponentQuadVS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FHeightfieldComponentQuadVS, Global);
|
|
public:
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldGI(Parameters.Platform);
|
|
}
|
|
|
|
/** Default constructor. */
|
|
FHeightfieldComponentQuadVS() {}
|
|
|
|
/** Initialization constructor. */
|
|
FHeightfieldComponentQuadVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FGlobalShader(Initializer)
|
|
{
|
|
HeightfieldDescriptionParameters.Bind(Initializer.ParameterMap);
|
|
}
|
|
|
|
void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, int32 NumHeightfieldsValue)
|
|
{
|
|
FRHIVertexShader* ShaderRHI = RHICmdList.GetBoundVertexShader();
|
|
|
|
FGlobalShader::SetParameters<FViewUniformShaderParameters>(RHICmdList, ShaderRHI, View.ViewUniformBuffer);
|
|
HeightfieldDescriptionParameters.Set(RHICmdList, ShaderRHI, GetHeightfieldDescriptionsSRV(), NumHeightfieldsValue);
|
|
}
|
|
|
|
private:
|
|
LAYOUT_FIELD(FHeightfieldDescriptionParameters, HeightfieldDescriptionParameters)
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(, FHeightfieldComponentQuadVS, TEXT("/Engine/Private/HeightfieldLighting.usf"), TEXT("HeightfieldComponentQuadVS"), SF_Vertex);
|
|
|
|
class FShadowHeightfieldsPS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FShadowHeightfieldsPS, Global);
|
|
public:
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldGI(Parameters.Platform);
|
|
}
|
|
|
|
/** Default constructor. */
|
|
FShadowHeightfieldsPS() {}
|
|
|
|
/** Initialization constructor. */
|
|
FShadowHeightfieldsPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FGlobalShader(Initializer)
|
|
{
|
|
HeightfieldDescriptionParameters.Bind(Initializer.ParameterMap);
|
|
GlobalHeightfieldParameters.Bind(Initializer.ParameterMap);
|
|
WorldToShadow.Bind(Initializer.ParameterMap, TEXT("WorldToShadow"));
|
|
ShadowmapMinMax.Bind(Initializer.ParameterMap, TEXT("ShadowmapMinMax"));
|
|
ShadowDepthBias.Bind(Initializer.ParameterMap, TEXT("ShadowDepthBias"));
|
|
CascadeDepthMinMax.Bind(Initializer.ParameterMap, TEXT("CascadeDepthMinMax"));
|
|
ShadowDepthTexture.Bind(Initializer.ParameterMap, TEXT("ShadowDepthTexture"));
|
|
ShadowDepthTextureSampler.Bind(Initializer.ParameterMap, TEXT("ShadowDepthTextureSampler"));
|
|
}
|
|
|
|
void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View, const FProjectedShadowInfo* ProjectedShadowInfo, int32 NumHeightfieldsValue, const FHeightfieldLightingAtlas& Atlas)
|
|
{
|
|
FRHIPixelShader* ShaderRHI = RHICmdList.GetBoundPixelShader();
|
|
|
|
FGlobalShader::SetParameters<FViewUniformShaderParameters>(RHICmdList, ShaderRHI, View.ViewUniformBuffer);
|
|
HeightfieldDescriptionParameters.Set(RHICmdList, ShaderRHI, GetHeightfieldDescriptionsSRV(), NumHeightfieldsValue);
|
|
GlobalHeightfieldParameters.Set(RHICmdList, ShaderRHI, Atlas);
|
|
|
|
FVector4 ShadowmapMinMaxValue;
|
|
FMatrix44f WorldToShadowMatrixValue = ProjectedShadowInfo->GetWorldToShadowMatrix(ShadowmapMinMaxValue);
|
|
|
|
SetShaderValue(RHICmdList, ShaderRHI, WorldToShadow, WorldToShadowMatrixValue);
|
|
SetShaderValue(RHICmdList, ShaderRHI, ShadowmapMinMax, ShadowmapMinMaxValue);
|
|
SetShaderValue(RHICmdList, ShaderRHI, ShadowDepthBias, ProjectedShadowInfo->GetShaderDepthBias());
|
|
SetShaderValue(RHICmdList, ShaderRHI, CascadeDepthMinMax, FVector2D(ProjectedShadowInfo->CascadeSettings.SplitNear, ProjectedShadowInfo->CascadeSettings.SplitFar));
|
|
|
|
FRHITexture* ShadowDepthTextureValue = ProjectedShadowInfo->RenderTargets.DepthTarget->GetRenderTargetItem().ShaderResourceTexture.GetReference();
|
|
FRHISamplerState* DepthSamplerState = TStaticSamplerState<SF_Point, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
|
|
|
|
SetTextureParameter(RHICmdList, ShaderRHI, ShadowDepthTexture, ShadowDepthTextureSampler, DepthSamplerState, ShadowDepthTextureValue);
|
|
}
|
|
|
|
private:
|
|
|
|
LAYOUT_FIELD(FHeightfieldDescriptionParameters, HeightfieldDescriptionParameters);
|
|
LAYOUT_FIELD(FGlobalHeightfieldParameters, GlobalHeightfieldParameters);
|
|
LAYOUT_FIELD(FShaderParameter, WorldToShadow);
|
|
LAYOUT_FIELD(FShaderParameter, ShadowmapMinMax);
|
|
LAYOUT_FIELD(FShaderParameter, ShadowDepthBias);
|
|
LAYOUT_FIELD(FShaderParameter, CascadeDepthMinMax);
|
|
LAYOUT_FIELD(FShaderResourceParameter, ShadowDepthTexture);
|
|
LAYOUT_FIELD(FShaderResourceParameter, ShadowDepthTextureSampler);
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(, FShadowHeightfieldsPS, TEXT("/Engine/Private/HeightfieldLighting.usf"), TEXT("ShadowHeightfieldsPS"), SF_Pixel);
|
|
|
|
void FHeightfieldLightingViewInfo::ClearShadowing(FRDGBuilder& GraphBuilder, const FViewInfo& View, const FLightSceneInfo& LightSceneInfo) const
|
|
{
|
|
if (AllowHeightfieldGI(View)
|
|
&& SupportsHeightfieldLighting(View.GetFeatureLevel(), View.GetShaderPlatform())
|
|
&& Heightfield.ComponentDescriptions.Num() > 0
|
|
&& LightSceneInfo.Proxy->GetLightType() == LightType_Directional
|
|
&& LightSceneInfo.Proxy->CastsDynamicShadow())
|
|
{
|
|
// TODO(RDG): Port this to RDG.
|
|
AddPass(GraphBuilder, [this, &View, &LightSceneInfo](FRHICommandList& RHICmdList)
|
|
{
|
|
FSceneViewState* ViewState = (FSceneViewState*)View.State;
|
|
const FHeightfieldLightingAtlas& Atlas = *ViewState->HeightfieldLightingAtlas;
|
|
|
|
FRHIRenderPassInfo RPInfo(Atlas.DirectionalLightShadowing->GetRenderTargetItem().TargetableTexture, ERenderTargetActions::Clear_Store);
|
|
RHICmdList.BeginRenderPass(RPInfo, TEXT("ClearShadowing"));
|
|
RHICmdList.EndRenderPass();
|
|
});
|
|
}
|
|
}
|
|
|
|
void FHeightfieldLightingViewInfo::ComputeShadowMapShadowing(FRDGBuilder& GraphBuilder, const FViewInfo& View, const FProjectedShadowInfo* ProjectedShadowInfo) const
|
|
{
|
|
if (AllowHeightfieldGI(View)
|
|
&& SupportsHeightfieldLighting(View.GetFeatureLevel(), View.GetShaderPlatform())
|
|
&& Heightfield.ComponentDescriptions.Num() > 0
|
|
&& ProjectedShadowInfo->IsWholeSceneDirectionalShadow()
|
|
&& ProjectedShadowInfo->DependentView == &View
|
|
&& !ProjectedShadowInfo->bRayTracedDistanceField)
|
|
{
|
|
// TODO(RDG): Port this to RDG.
|
|
AddPass(GraphBuilder, RDG_EVENT_NAME("HeightfieldShadowMapShadowingForGI"), [this, &View, ProjectedShadowInfo](FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
FSceneViewState* ViewState = (FSceneViewState*)View.State;
|
|
const FHeightfieldLightingAtlas& Atlas = *ViewState->HeightfieldLightingAtlas;
|
|
|
|
const FIntPoint LightingAtlasSize = Atlas.GetAtlasSize();
|
|
const FVector2D InvLightingAtlasSize(1.0f / LightingAtlasSize.X, 1.0f / LightingAtlasSize.Y);
|
|
|
|
FRHIRenderPassInfo RPInfo(Atlas.DirectionalLightShadowing->GetRenderTargetItem().TargetableTexture, ERenderTargetActions::Load_Store);
|
|
RHICmdList.BeginRenderPass(RPInfo, TEXT("ComputeShadowMapShadowing"));
|
|
{
|
|
FGraphicsPipelineStateInitializer GraphicsPSOInit;
|
|
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
|
|
|
|
RHICmdList.SetViewport(0, 0, 0.0f, LightingAtlasSize.X, LightingAtlasSize.Y, 1.0f);
|
|
GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
|
|
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
|
|
// Combine with other shadow types with min (ray traced)
|
|
GraphicsPSOInit.BlendState = TStaticBlendState<CW_RED, BO_Min, BF_One, BF_One>::GetRHI();
|
|
RHICmdList.SetStreamSource(0, GQuadVertexBuffer.VertexBufferRHI, 0);
|
|
|
|
TShaderMapRef<FHeightfieldComponentQuadVS> VertexShader(View.ShaderMap);
|
|
TShaderMapRef<FShadowHeightfieldsPS> PixelShader(View.ShaderMap);
|
|
|
|
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GScreenVertexDeclaration.VertexDeclarationRHI;
|
|
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
|
|
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
|
|
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
|
|
|
|
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
|
|
|
|
for (TMap<FHeightfieldComponentTextures, TArray<FHeightfieldComponentDescription>>::TConstIterator It(Heightfield.ComponentDescriptions); It; ++It)
|
|
{
|
|
const TArray<FHeightfieldComponentDescription>& HeightfieldDescriptions = It.Value();
|
|
|
|
if (HeightfieldDescriptions.Num() > 0)
|
|
{
|
|
//@todo - cull heightfield tiles with shadow bounds
|
|
UploadHeightfieldDescriptions(HeightfieldDescriptions, InvLightingAtlasSize, 1.0f / Heightfield.DownsampleFactor);
|
|
|
|
VertexShader->SetParameters(RHICmdList, View, HeightfieldDescriptions.Num());
|
|
PixelShader->SetParameters(RHICmdList, View, ProjectedShadowInfo, HeightfieldDescriptions.Num(), Atlas);
|
|
|
|
RHICmdList.DrawPrimitive(0, 2, HeightfieldDescriptions.Num());
|
|
}
|
|
}
|
|
}
|
|
RHICmdList.EndRenderPass();
|
|
});
|
|
}
|
|
}
|
|
|
|
class FLightHeightfieldsPS : public FMaterialShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FLightHeightfieldsPS, Material);
|
|
public:
|
|
|
|
static bool ShouldCompilePermutation(const FMaterialShaderPermutationParameters& Parameters)
|
|
{
|
|
return Parameters.MaterialParameters.MaterialDomain == MD_LightFunction && IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldGI(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FMaterialShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
OutEnvironment.SetDefine(TEXT("APPLY_LIGHT_FUNCTION"), 1);
|
|
}
|
|
|
|
/** Default constructor. */
|
|
FLightHeightfieldsPS() {}
|
|
|
|
/** Initialization constructor. */
|
|
FLightHeightfieldsPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FMaterialShader(Initializer)
|
|
{
|
|
HeightfieldDescriptionParameters.Bind(Initializer.ParameterMap);
|
|
GlobalHeightfieldParameters.Bind(Initializer.ParameterMap);
|
|
LightDirection.Bind(Initializer.ParameterMap, TEXT("LightDirection"));
|
|
LightColor.Bind(Initializer.ParameterMap, TEXT("LightColor"));
|
|
SkyLightIndirectScale.Bind(Initializer.ParameterMap, TEXT("SkyLightIndirectScale"));
|
|
HeightfieldShadowing.Bind(Initializer.ParameterMap, TEXT("HeightfieldShadowing"));
|
|
HeightfieldShadowingSampler.Bind(Initializer.ParameterMap, TEXT("HeightfieldShadowingSampler"));
|
|
WorldToLight.Bind(Initializer.ParameterMap, TEXT("WorldToLight"));
|
|
LightFunctionParameters.Bind(Initializer.ParameterMap);
|
|
}
|
|
|
|
void SetParameters(
|
|
FRHICommandList& RHICmdList,
|
|
const FSceneView& View,
|
|
const FLightSceneInfo& LightSceneInfo,
|
|
const FMaterialRenderProxy* MaterialProxy,
|
|
int32 NumHeightfieldsValue,
|
|
const FHeightfieldLightingAtlas& Atlas,
|
|
float SkyLightIndirectScaleValue)
|
|
{
|
|
FRHIPixelShader* ShaderRHI = RHICmdList.GetBoundPixelShader();
|
|
|
|
const FMaterial& Material = MaterialProxy->GetMaterialWithFallback(View.GetFeatureLevel(), MaterialProxy);
|
|
FMaterialShader::SetViewParameters(RHICmdList, ShaderRHI, View, View.ViewUniformBuffer);
|
|
FMaterialShader::SetParameters(RHICmdList, ShaderRHI, MaterialProxy, Material, View);
|
|
|
|
HeightfieldDescriptionParameters.Set(RHICmdList, ShaderRHI, GetHeightfieldDescriptionsSRV(), NumHeightfieldsValue);
|
|
GlobalHeightfieldParameters.Set(RHICmdList, ShaderRHI, Atlas);
|
|
|
|
SetShaderValue(RHICmdList, ShaderRHI, LightDirection, FVector3f(LightSceneInfo.Proxy->GetDirection()));
|
|
SetShaderValue(RHICmdList, ShaderRHI, LightColor, LightSceneInfo.Proxy->GetColor() * LightSceneInfo.Proxy->GetIndirectLightingScale());
|
|
|
|
SetShaderValue(RHICmdList, ShaderRHI, SkyLightIndirectScale, SkyLightIndirectScaleValue);
|
|
|
|
const FSceneViewState* ViewState = (const FSceneViewState*)View.State;
|
|
SetTextureParameter(RHICmdList, ShaderRHI, HeightfieldShadowing, HeightfieldShadowingSampler, TStaticSamplerState<SF_Bilinear>::GetRHI(), Atlas.DirectionalLightShadowing->GetRenderTargetItem().ShaderResourceTexture);
|
|
|
|
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 FMatrix44f WorldToLightValue = LightSceneInfo.Proxy->GetWorldToLight() * FScaleMatrix(FVector(InverseScale));
|
|
|
|
SetShaderValue(RHICmdList, ShaderRHI, WorldToLight, WorldToLightValue);
|
|
|
|
LightFunctionParameters.Set(RHICmdList, ShaderRHI, &LightSceneInfo, 1);
|
|
}
|
|
|
|
private:
|
|
|
|
LAYOUT_FIELD(FHeightfieldDescriptionParameters, HeightfieldDescriptionParameters);
|
|
LAYOUT_FIELD(FGlobalHeightfieldParameters, GlobalHeightfieldParameters);
|
|
LAYOUT_FIELD(FShaderParameter, LightDirection);
|
|
LAYOUT_FIELD(FShaderParameter, LightColor);
|
|
LAYOUT_FIELD(FShaderParameter, SkyLightIndirectScale);
|
|
LAYOUT_FIELD(FShaderResourceParameter, HeightfieldShadowing);
|
|
LAYOUT_FIELD(FShaderResourceParameter, HeightfieldShadowingSampler);
|
|
LAYOUT_FIELD(FShaderParameter, WorldToLight);
|
|
LAYOUT_FIELD(FLightFunctionSharedParameters, LightFunctionParameters);
|
|
};
|
|
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(, FLightHeightfieldsPS, TEXT("/Engine/Private/HeightfieldLighting.usf"), TEXT("LightHeightfieldsPS"), SF_Pixel);
|
|
|
|
void FHeightfieldLightingViewInfo::ComputeLighting(FRDGBuilder& GraphBuilder, const FViewInfo& View, const FLightSceneInfo& LightSceneInfo) const
|
|
{
|
|
const ERHIFeatureLevel::Type FeatureLevel = View.GetFeatureLevel();
|
|
|
|
if (!AllowHeightfieldGI(View)
|
|
|| !SupportsHeightfieldLighting(FeatureLevel, View.GetShaderPlatform())
|
|
//@todo - handle local lights
|
|
|| LightSceneInfo.Proxy->GetLightType() != LightType_Directional
|
|
|| !LightSceneInfo.Proxy->CastsDynamicShadow()
|
|
|| Heightfield.ComponentDescriptions.Num() == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
AddPass(GraphBuilder, RDG_EVENT_NAME("HeightfieldLightingForGI"), [this, &View, &LightSceneInfo, FeatureLevel](FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
FSceneViewState* ViewState = (FSceneViewState*)View.State;
|
|
const FHeightfieldLightingAtlas& Atlas = *ViewState->HeightfieldLightingAtlas;
|
|
|
|
const FIntPoint LightingAtlasSize = Atlas.GetAtlasSize();
|
|
const FVector2D InvLightingAtlasSize(1.0f / LightingAtlasSize.X, 1.0f / LightingAtlasSize.Y);
|
|
|
|
FRHIRenderPassInfo RPInfo(Atlas.Lighting->GetRenderTargetItem().TargetableTexture, ERenderTargetActions::Clear_Store);
|
|
RHICmdList.BeginRenderPass(RPInfo, TEXT("ComputeHeightfieldLighting"));
|
|
{
|
|
const bool bApplyLightFunction = (View.Family->EngineShowFlags.LightFunctions &&
|
|
LightSceneInfo.Proxy->GetLightFunctionMaterial() &&
|
|
LightSceneInfo.Proxy->GetLightFunctionMaterial()->GetIncompleteMaterialWithFallback(FeatureLevel).IsLightFunction());
|
|
|
|
const FMaterialRenderProxy* MaterialProxy = bApplyLightFunction ?
|
|
LightSceneInfo.Proxy->GetLightFunctionMaterial() :
|
|
UMaterial::GetDefaultMaterial(MD_LightFunction)->GetRenderProxy();
|
|
|
|
const FScene* Scene = (const FScene*)View.Family->Scene;
|
|
|
|
const float SkyLightIndirectScale = ShouldRenderDeferredDynamicSkyLight(Scene, *View.Family) ? Scene->SkyLight->IndirectLightingIntensity : 0;
|
|
|
|
// Skip rendering if the DefaultLightFunctionMaterial isn't compiled yet
|
|
if (MaterialProxy->GetIncompleteMaterialWithFallback(FeatureLevel).IsLightFunction())
|
|
{
|
|
RHICmdList.SetViewport(0, 0, 0.0f, LightingAtlasSize.X, LightingAtlasSize.Y, 1.0f);
|
|
|
|
FGraphicsPipelineStateInitializer GraphicsPSOInit;
|
|
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
|
|
|
|
GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
|
|
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
|
|
GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI();
|
|
|
|
RHICmdList.SetStreamSource(0, GQuadVertexBuffer.VertexBufferRHI, 0);
|
|
|
|
TShaderMapRef<FHeightfieldComponentQuadVS> VertexShader(View.ShaderMap);
|
|
|
|
const FMaterial& Material = MaterialProxy->GetMaterialWithFallback(FeatureLevel, MaterialProxy);
|
|
const FMaterialShaderMap* MaterialShaderMap = Material.GetRenderingThreadShaderMap();
|
|
TShaderRef<FLightHeightfieldsPS> PixelShader = MaterialShaderMap->GetShader<FLightHeightfieldsPS>();
|
|
|
|
for (TMap<FHeightfieldComponentTextures, TArray<FHeightfieldComponentDescription>>::TConstIterator It(Heightfield.ComponentDescriptions); It; ++It)
|
|
{
|
|
const TArray<FHeightfieldComponentDescription>& HeightfieldDescriptions = It.Value();
|
|
|
|
if (HeightfieldDescriptions.Num() > 0)
|
|
{
|
|
UploadHeightfieldDescriptions(HeightfieldDescriptions, InvLightingAtlasSize, 1.0f / Heightfield.DownsampleFactor);
|
|
|
|
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GScreenVertexDeclaration.VertexDeclarationRHI;
|
|
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
|
|
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
|
|
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
|
|
|
|
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit);
|
|
|
|
VertexShader->SetParameters(RHICmdList, View, HeightfieldDescriptions.Num());
|
|
PixelShader->SetParameters(RHICmdList, View, LightSceneInfo, MaterialProxy, HeightfieldDescriptions.Num(), Atlas, SkyLightIndirectScale);
|
|
|
|
RHICmdList.DrawPrimitive(0, 2, HeightfieldDescriptions.Num());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
RHICmdList.EndRenderPass();
|
|
});
|
|
}
|
|
|
|
const int32 GHeightfieldOcclusionDispatchSize = 8;
|
|
|
|
class FCalculateHeightfieldOcclusionScreenGridCS : public FGlobalShader
|
|
{
|
|
DECLARE_GLOBAL_SHADER(FCalculateHeightfieldOcclusionScreenGridCS);
|
|
|
|
public:
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FAOScreenGridParameters, AOScreenGridParameters)
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSceneTextureUniformParameters, SceneTextures)
|
|
RDG_TEXTURE_ACCESS(DistanceFieldNormal, ERHIAccess::SRVCompute)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldGI(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
|
|
|
|
OutEnvironment.SetDefine(TEXT("HEIGHTFIELD_OCCLUSION_DISPATCH_SIZEX"), GHeightfieldOcclusionDispatchSize);
|
|
extern int32 GConeTraceDownsampleFactor;
|
|
OutEnvironment.SetDefine(TEXT("TRACE_DOWNSAMPLE_FACTOR"), GConeTraceDownsampleFactor);
|
|
|
|
// To reduce shader compile time of compute shaders with shared memory, doesn't have an impact on generated code with current compiler (June 2010 DX SDK)
|
|
OutEnvironment.CompilerFlags.Add(CFLAG_StandardOptimization);
|
|
}
|
|
|
|
FCalculateHeightfieldOcclusionScreenGridCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FGlobalShader(Initializer)
|
|
{
|
|
BindForLegacyShaderParameters<FParameters>(this, Initializer.PermutationId, Initializer.ParameterMap, false);
|
|
AOParameters.Bind(Initializer.ParameterMap);
|
|
ScreenGridParameters.Bind(Initializer.ParameterMap);
|
|
HeightfieldDescriptionParameters.Bind(Initializer.ParameterMap);
|
|
HeightfieldTextureParameters.Bind(Initializer.ParameterMap);
|
|
TanConeHalfAngle.Bind(Initializer.ParameterMap, TEXT("TanConeHalfAngle"));
|
|
}
|
|
|
|
FCalculateHeightfieldOcclusionScreenGridCS()
|
|
{
|
|
}
|
|
|
|
void SetParameters(
|
|
FRHICommandList& RHICmdList,
|
|
const FViewInfo& View,
|
|
UTexture2D* HeightfieldTextureValue,
|
|
int32 NumHeightfieldsValue,
|
|
FRHITexture* DistanceFieldNormal,
|
|
const FDistanceFieldAOParameters& Parameters)
|
|
{
|
|
FRHIComputeShader* ShaderRHI = RHICmdList.GetBoundComputeShader();
|
|
FGlobalShader::SetParameters<FViewUniformShaderParameters>(RHICmdList, ShaderRHI, View.ViewUniformBuffer);
|
|
|
|
AOParameters.Set(RHICmdList, ShaderRHI, Parameters);
|
|
ScreenGridParameters.Set(RHICmdList, ShaderRHI, View, DistanceFieldNormal);
|
|
HeightfieldDescriptionParameters.Set(RHICmdList, ShaderRHI, GetHeightfieldDescriptionsSRV(), NumHeightfieldsValue);
|
|
HeightfieldTextureParameters.Set(RHICmdList, ShaderRHI, HeightfieldTextureValue, nullptr, nullptr);
|
|
|
|
FAOSampleData2 AOSampleData;
|
|
|
|
TArray<FVector, TInlineAllocator<9> > SampleDirections;
|
|
GetSpacedVectors(View.Family->FrameNumber, SampleDirections);
|
|
|
|
for (int32 SampleIndex = 0; SampleIndex < NumConeSampleDirections; SampleIndex++)
|
|
{
|
|
AOSampleData.SampleDirections[SampleIndex] = FVector4(SampleDirections[SampleIndex]);
|
|
}
|
|
|
|
SetUniformBufferParameterImmediate(RHICmdList, ShaderRHI, GetUniformBufferParameter<FAOSampleData2>(), AOSampleData);
|
|
|
|
extern float GAOConeHalfAngle;
|
|
SetShaderValue(RHICmdList, ShaderRHI, TanConeHalfAngle, FMath::Tan(GAOConeHalfAngle));
|
|
}
|
|
|
|
private:
|
|
|
|
LAYOUT_FIELD(FAOParameters, AOParameters);
|
|
LAYOUT_FIELD(FScreenGridParameters, ScreenGridParameters);
|
|
LAYOUT_FIELD(FHeightfieldDescriptionParameters, HeightfieldDescriptionParameters);
|
|
LAYOUT_FIELD(FHeightfieldTextureParameters, HeightfieldTextureParameters);
|
|
LAYOUT_FIELD(FShaderParameter, TanConeHalfAngle);
|
|
};
|
|
|
|
IMPLEMENT_GLOBAL_SHADER(FCalculateHeightfieldOcclusionScreenGridCS, "/Engine/Private/HeightfieldLighting.usf", "CalculateHeightfieldOcclusionScreenGridCS", SF_Compute);
|
|
|
|
|
|
void FHeightfieldLightingViewInfo::ComputeOcclusionForScreenGrid(
|
|
FRDGBuilder& GraphBuilder,
|
|
const FViewInfo& View,
|
|
const FSceneTextures& SceneTextures,
|
|
FRDGTextureRef DistanceFieldNormal,
|
|
const FAOScreenGridParameters& AOScreenGridParameters,
|
|
const FDistanceFieldAOParameters& Parameters) const
|
|
{
|
|
int32 DownsampleFactor = Heightfield.DownsampleFactor;
|
|
|
|
if (Heightfield.ComponentDescriptions.Num() > 0 && GAOHeightfieldOcclusion)
|
|
{
|
|
for (TMap<FHeightfieldComponentTextures, TArray<FHeightfieldComponentDescription>>::TConstIterator It(Heightfield.ComponentDescriptions); It; ++It)
|
|
{
|
|
UTexture2D* HeightfieldTexture = It.Key().HeightAndNormal;
|
|
const TArray<FHeightfieldComponentDescription>& HeightfieldDescriptions = It.Value();
|
|
|
|
if (HeightfieldDescriptions.Num() > 0)
|
|
{
|
|
auto* PassParameters = GraphBuilder.AllocParameters<FCalculateHeightfieldOcclusionScreenGridCS::FParameters>();
|
|
PassParameters->AOScreenGridParameters = AOScreenGridParameters;
|
|
PassParameters->SceneTextures = SceneTextures.UniformBuffer;
|
|
PassParameters->DistanceFieldNormal = DistanceFieldNormal;
|
|
|
|
auto ComputeShader = View.ShaderMap->GetShader<FCalculateHeightfieldOcclusionScreenGridCS>();
|
|
|
|
ClearUnusedGraphResources(ComputeShader, PassParameters);
|
|
|
|
GraphBuilder.AddPass(
|
|
RDG_EVENT_NAME("HeightfieldOcclusion"),
|
|
PassParameters,
|
|
ERDGPassFlags::Compute,
|
|
[PassParameters, ComputeShader, &View, Parameters, DistanceFieldNormal, &HeightfieldDescriptions, HeightfieldTexture, DownsampleFactor](FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
UploadHeightfieldDescriptions(HeightfieldDescriptions, FVector2D(1, 1), 1.0f / DownsampleFactor);
|
|
|
|
const uint32 GroupSizeX = FMath::DivideAndRoundUp(View.ViewRect.Size().X / GAODownsampleFactor, GHeightfieldOcclusionDispatchSize);
|
|
const uint32 GroupSizeY = FMath::DivideAndRoundUp(View.ViewRect.Size().Y / GAODownsampleFactor, GHeightfieldOcclusionDispatchSize);
|
|
|
|
RHICmdList.SetComputeShader(ComputeShader.GetComputeShader());
|
|
|
|
ComputeShader->SetParameters(RHICmdList, View, HeightfieldTexture, HeightfieldDescriptions.Num(), DistanceFieldNormal->GetRHI(), Parameters);
|
|
SetShaderParameters(RHICmdList, ComputeShader, ComputeShader.GetComputeShader(), *PassParameters);
|
|
|
|
DispatchComputeShader(RHICmdList, ComputeShader.GetShader(), GroupSizeX, GroupSizeY, 1);
|
|
|
|
UnsetShaderUAVs(RHICmdList, ComputeShader, ComputeShader.GetComputeShader());
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|