You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
- Also removed some unreferenced functions that adding 'override' revealed PR #1002 -- Thank you, Omar007! [CL 2498415 by Mike Fricker in Main branch]
1632 lines
66 KiB
C++
1632 lines
66 KiB
C++
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
HeightfieldLighting.cpp
|
|
=============================================================================*/
|
|
|
|
#include "RendererPrivate.h"
|
|
#include "ScenePrivate.h"
|
|
#include "UniformBuffer.h"
|
|
#include "ShaderParameters.h"
|
|
#include "PostProcessing.h"
|
|
#include "SceneFilterRendering.h"
|
|
#include "DistanceFieldLightingShared.h"
|
|
#include "DistanceFieldSurfaceCacheLighting.h"
|
|
#include "DistanceFieldGlobalIllumination.h"
|
|
#include "RHICommandList.h"
|
|
#include "SceneUtils.h"
|
|
#include "DistanceFieldAtlas.h"
|
|
#include "LightRendering.h"
|
|
|
|
int32 GAOHeightfieldOcclusion = 1;
|
|
FAutoConsoleVariableRef CVarAOHeightfieldOcclusion(
|
|
TEXT("r.AOHeightfieldOcclusion"),
|
|
GAOHeightfieldOcclusion,
|
|
TEXT("Whether to compute AO from heightfields (landscape)"),
|
|
ECVF_Cheat | ECVF_RenderThreadSafe
|
|
);
|
|
|
|
int32 GHeightfieldGlobalIllumination = 1;
|
|
FAutoConsoleVariableRef CVarHeightfieldGlobalIllumination(
|
|
TEXT("r.HeightfieldGlobalIllumination"),
|
|
GHeightfieldGlobalIllumination,
|
|
TEXT(""),
|
|
ECVF_Cheat | ECVF_RenderThreadSafe
|
|
);
|
|
|
|
float GHeightfieldInnerBounceDistance = 3000;
|
|
FAutoConsoleVariableRef CVarHeightfieldInnerBounceDistancer(
|
|
TEXT("r.HeightfieldInnerBounceDistance"),
|
|
GHeightfieldInnerBounceDistance,
|
|
TEXT(""),
|
|
ECVF_Cheat | ECVF_RenderThreadSafe
|
|
);
|
|
|
|
float GHeightfieldOuterBounceDistanceScale = 3;
|
|
FAutoConsoleVariableRef CVarHeightfieldOuterBounceDistanceScale(
|
|
TEXT("r.HeightfieldOuterBounceDistanceScale"),
|
|
GHeightfieldOuterBounceDistanceScale,
|
|
TEXT(""),
|
|
ECVF_Cheat | ECVF_RenderThreadSafe
|
|
);
|
|
|
|
float GetGHeightfieldBounceDistance()
|
|
{
|
|
return GHeightfieldInnerBounceDistance * GHeightfieldOuterBounceDistanceScale;
|
|
}
|
|
|
|
float GHeightfieldTargetUnitsPerTexel = 200;
|
|
FAutoConsoleVariableRef CVarHeightfieldTargetUnitsPerTexel(
|
|
TEXT("r.HeightfieldTargetUnitsPerTexel"),
|
|
GHeightfieldTargetUnitsPerTexel,
|
|
TEXT(""),
|
|
ECVF_Cheat | ECVF_RenderThreadSafe
|
|
);
|
|
|
|
void FHeightfieldLightingAtlas::InitDynamicRHI()
|
|
{
|
|
if (AtlasSize.GetMin() > 0)
|
|
{
|
|
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(
|
|
AtlasSize,
|
|
PF_G16,
|
|
TexCreate_None,
|
|
TexCreate_RenderTargetable,
|
|
false));
|
|
|
|
GRenderTargetPool.FindFreeElement(Desc, Height, TEXT("HeightAtlas"));
|
|
|
|
FPooledRenderTargetDesc Desc2(FPooledRenderTargetDesc::Create2DDesc(
|
|
AtlasSize,
|
|
PF_R8G8,
|
|
TexCreate_None,
|
|
TexCreate_RenderTargetable,
|
|
false));
|
|
|
|
GRenderTargetPool.FindFreeElement(Desc2, Normal, TEXT("NormalAtlas"));
|
|
|
|
FPooledRenderTargetDesc Desc3(FPooledRenderTargetDesc::Create2DDesc(
|
|
AtlasSize,
|
|
PF_R8G8B8A8,
|
|
TexCreate_None,
|
|
TexCreate_RenderTargetable,
|
|
false));
|
|
|
|
GRenderTargetPool.FindFreeElement(Desc3, DiffuseColor, TEXT("DiffuseColorAtlas"));
|
|
|
|
FPooledRenderTargetDesc Desc4(FPooledRenderTargetDesc::Create2DDesc(
|
|
AtlasSize,
|
|
PF_G8,
|
|
TexCreate_None,
|
|
TexCreate_RenderTargetable,
|
|
false));
|
|
|
|
GRenderTargetPool.FindFreeElement(Desc4, DirectionalLightShadowing, TEXT("HeightfieldShadowingAtlas"));
|
|
|
|
FPooledRenderTargetDesc Desc5(FPooledRenderTargetDesc::Create2DDesc(
|
|
AtlasSize,
|
|
PF_FloatR11G11B10,
|
|
TexCreate_None,
|
|
TexCreate_RenderTargetable,
|
|
false));
|
|
|
|
GRenderTargetPool.FindFreeElement(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 FHeightfieldTextureParameters
|
|
{
|
|
public:
|
|
void Bind(const FShaderParameterMap& ParameterMap)
|
|
{
|
|
HeightfieldTexture.Bind(ParameterMap,TEXT("HeightfieldTexture"));
|
|
HeightfieldSampler.Bind(ParameterMap,TEXT("HeightfieldSampler"));
|
|
DiffuseColorTexture.Bind(ParameterMap,TEXT("DiffuseColorTexture"));
|
|
DiffuseColorSampler.Bind(ParameterMap,TEXT("DiffuseColorSampler"));
|
|
}
|
|
|
|
friend FArchive& operator<<(FArchive& Ar,FHeightfieldTextureParameters& Parameters)
|
|
{
|
|
Ar << Parameters.HeightfieldTexture;
|
|
Ar << Parameters.HeightfieldSampler;
|
|
Ar << Parameters.DiffuseColorTexture;
|
|
Ar << Parameters.DiffuseColorSampler;
|
|
return Ar;
|
|
}
|
|
|
|
template<typename ShaderRHIParamRef>
|
|
void Set(FRHICommandList& RHICmdList, const ShaderRHIParamRef ShaderRHI, UTexture2D* HeightfieldTextureValue, UTexture2D* DiffuseColorTextureValue)
|
|
{
|
|
//@todo - shouldn't filter the heightfield, it's packed
|
|
SetTextureParameter(RHICmdList, ShaderRHI, HeightfieldTexture, HeightfieldSampler, TStaticSamplerState<SF_Bilinear>::GetRHI(), HeightfieldTextureValue->Resource->TextureRHI);
|
|
|
|
if (DiffuseColorTextureValue)
|
|
{
|
|
SetTextureParameter(RHICmdList, ShaderRHI, DiffuseColorTexture, DiffuseColorSampler, TStaticSamplerState<SF_Bilinear>::GetRHI(), DiffuseColorTextureValue->Resource->TextureRHI);
|
|
}
|
|
else
|
|
{
|
|
SetTextureParameter(RHICmdList, ShaderRHI, DiffuseColorTexture, DiffuseColorSampler, TStaticSamplerState<SF_Bilinear>::GetRHI(), GBlackTexture->TextureRHI);
|
|
}
|
|
}
|
|
|
|
private:
|
|
FShaderResourceParameter HeightfieldTexture;
|
|
FShaderResourceParameter HeightfieldSampler;
|
|
FShaderResourceParameter DiffuseColorTexture;
|
|
FShaderResourceParameter DiffuseColorSampler;
|
|
};
|
|
|
|
class FSubsectionHeightfieldDescriptionParameters
|
|
{
|
|
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:
|
|
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 = RHILockVertexBuffer(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);
|
|
RHIUnlockVertexBuffer(GSubsectionHeightfieldDescriptions.Data.Buffer);
|
|
|
|
return HeightfieldDescriptionData.Num() / GSubsectionHeightfieldDescriptions.Data.Stride;
|
|
}
|
|
|
|
class FHeightfieldSubsectionQuadVS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FHeightfieldSubsectionQuadVS, Global);
|
|
public:
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform)
|
|
{
|
|
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldGI(Platform);
|
|
}
|
|
|
|
/** Default constructor. */
|
|
FHeightfieldSubsectionQuadVS() {}
|
|
|
|
/** Initialization constructor. */
|
|
FHeightfieldSubsectionQuadVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FGlobalShader(Initializer)
|
|
{
|
|
SubsectionHeightfieldParameters.Bind(Initializer.ParameterMap);
|
|
}
|
|
|
|
void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View)
|
|
{
|
|
const FVertexShaderRHIParamRef ShaderRHI = GetVertexShader();
|
|
|
|
FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View);
|
|
SubsectionHeightfieldParameters.Set(RHICmdList, ShaderRHI);
|
|
}
|
|
|
|
// FShader interface.
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
Ar << SubsectionHeightfieldParameters;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
|
|
FSubsectionHeightfieldDescriptionParameters SubsectionHeightfieldParameters;
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(,FHeightfieldSubsectionQuadVS,TEXT("HeightfieldLighting"),TEXT("HeightfieldSubsectionQuadVS"),SF_Vertex);
|
|
|
|
class FInitializeHeightfieldsPS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FInitializeHeightfieldsPS, Global);
|
|
public:
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform)
|
|
{
|
|
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldGI(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)
|
|
{
|
|
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();
|
|
|
|
FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View);
|
|
HeightfieldTextureParameters.Set(RHICmdList, ShaderRHI, HeightfieldTextureValue, DiffuseColorTextureValue);
|
|
}
|
|
// FShader interface.
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
Ar << HeightfieldTextureParameters;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
|
|
FHeightfieldTextureParameters HeightfieldTextureParameters;
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(,FInitializeHeightfieldsPS,TEXT("HeightfieldLighting"),TEXT("InitializeHeightfieldsPS"),SF_Pixel);
|
|
|
|
class FQuadVertexBuffer : public FVertexBuffer
|
|
{
|
|
public:
|
|
|
|
FQuadVertexBuffer()
|
|
{
|
|
}
|
|
|
|
virtual void InitRHI() override
|
|
{
|
|
const uint32 Size = 6 * sizeof(FScreenVertex);
|
|
FRHIResourceCreateInfo CreateInfo;
|
|
VertexBufferRHI = RHICreateVertexBuffer(Size, BUF_Static, CreateInfo);
|
|
void* Buffer = RHILockVertexBuffer(VertexBufferRHI, 0, Size, RLM_WriteOnly);
|
|
FScreenVertex* DestVertex = (FScreenVertex*)Buffer;
|
|
|
|
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);
|
|
|
|
RHIUnlockVertexBuffer(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
|
|
&& GDistanceFieldGI
|
|
&& View.Family->EngineShowFlags.DistanceFieldGI;
|
|
}
|
|
|
|
void FHeightfieldLightingViewInfo::SetupVisibleHeightfields(const FViewInfo& View, FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
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()))
|
|
{
|
|
extern float GAOMaxViewDistance;
|
|
const float MaxDistanceSquared = FMath::Square(GAOMaxViewDistance + 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.ViewOrigin).SizeSquared();
|
|
|
|
if (View.ViewFrustum.IntersectSphere(PrimitiveBounds.Origin, PrimitiveBounds.SphereRadius + GetGHeightfieldBounceDistance())
|
|
&& DistanceToPrimitiveSq < MaxDistanceSquared)
|
|
{
|
|
UTexture2D* HeightfieldTexture = NULL;
|
|
UTexture2D* DiffuseColorTexture = NULL;
|
|
FHeightfieldComponentDescription NewComponentDescription(HeightfieldPrimitive->Proxy->GetLocalToWorld());
|
|
HeightfieldPrimitive->Proxy->GetHeightfieldRepresentation(HeightfieldTexture, DiffuseColorTexture, NewComponentDescription);
|
|
|
|
if (HeightfieldTexture && HeightfieldTexture->Resource->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));
|
|
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);
|
|
|
|
FTextureRHIParamRef RenderTargets[3] =
|
|
{
|
|
ExistingAtlas->Height->GetRenderTargetItem().TargetableTexture,
|
|
ExistingAtlas->Normal->GetRenderTargetItem().TargetableTexture,
|
|
ExistingAtlas->DiffuseColor->GetRenderTargetItem().TargetableTexture
|
|
};
|
|
|
|
SetRenderTargets(RHICmdList, ARRAY_COUNT(RenderTargets), RenderTargets, FTextureRHIParamRef(), 0, NULL);
|
|
|
|
FLinearColor ClearColors[3] = {FLinearColor(0, 0, 0, 0), FLinearColor(0, 0, 0, 0), FLinearColor(0, 0, 0, 0)};
|
|
RHICmdList.ClearMRT(true, ARRAY_COUNT(ClearColors), ClearColors, false, 0, false, 0, FIntRect());
|
|
|
|
RHICmdList.SetViewport(0, 0, 0.0f, LightingAtlasSize.X, LightingAtlasSize.Y, 1.0f);
|
|
RHICmdList.SetRasterizerState(TStaticRasterizerState<FM_Solid, CM_None>::GetRHI());
|
|
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
|
|
RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI());
|
|
RHICmdList.SetStreamSource(0, GQuadVertexBuffer.VertexBufferRHI, sizeof(FScreenVertex), 0);
|
|
|
|
TShaderMapRef<FHeightfieldSubsectionQuadVS> VertexShader(View.ShaderMap);
|
|
TShaderMapRef<FInitializeHeightfieldsPS> PixelShader(View.ShaderMap);
|
|
|
|
static FGlobalBoundShaderState BoundShaderState;
|
|
SetGlobalBoundShaderState(RHICmdList, View.GetFeatureLevel(), BoundShaderState, GScreenVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader);
|
|
|
|
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(PT_TriangleList, 0, 2, NumQuads);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
class FHeightfieldDescriptionsResource : public FRenderResource
|
|
{
|
|
public:
|
|
|
|
FCPUUpdatedBuffer Data;
|
|
|
|
FHeightfieldDescriptionsResource()
|
|
{
|
|
Data.Format = PF_A32B32G32R32F;
|
|
// In float4's, must match usf
|
|
Data.Stride = 12;
|
|
}
|
|
|
|
virtual void InitDynamicRHI() override
|
|
{
|
|
Data.Initialize();
|
|
}
|
|
|
|
virtual void ReleaseDynamicRHI() override
|
|
{
|
|
Data.Release();
|
|
}
|
|
};
|
|
|
|
TGlobalResource<FHeightfieldDescriptionsResource> GHeightfieldDescriptions;
|
|
|
|
void UploadHeightfieldDescriptions(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, InvLightingAtlasSize.X, InvLightingAtlasSize.Y));
|
|
|
|
const FMatrix WorldToLocal = Description.LocalToWorld.Inverse();
|
|
|
|
HeightfieldDescriptionData.Add(*(FVector4*)&WorldToLocal.M[0]);
|
|
HeightfieldDescriptionData.Add(*(FVector4*)&WorldToLocal.M[1]);
|
|
HeightfieldDescriptionData.Add(*(FVector4*)&WorldToLocal.M[2]);
|
|
HeightfieldDescriptionData.Add(*(FVector4*)&WorldToLocal.M[3]);
|
|
|
|
HeightfieldDescriptionData.Add(*(FVector4*)&Description.LocalToWorld.M[0]);
|
|
HeightfieldDescriptionData.Add(*(FVector4*)&Description.LocalToWorld.M[1]);
|
|
HeightfieldDescriptionData.Add(*(FVector4*)&Description.LocalToWorld.M[2]);
|
|
HeightfieldDescriptionData.Add(*(FVector4*)&Description.LocalToWorld.M[3]);
|
|
}
|
|
|
|
check(HeightfieldDescriptionData.Num() % GHeightfieldDescriptions.Data.Stride == 0);
|
|
|
|
if (HeightfieldDescriptionData.Num() > GHeightfieldDescriptions.Data.MaxElements)
|
|
{
|
|
GHeightfieldDescriptions.Data.MaxElements = HeightfieldDescriptionData.Num() * 5 / 4;
|
|
GHeightfieldDescriptions.Data.Release();
|
|
GHeightfieldDescriptions.Data.Initialize();
|
|
}
|
|
|
|
void* LockedBuffer = RHILockVertexBuffer(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);
|
|
RHIUnlockVertexBuffer(GHeightfieldDescriptions.Data.Buffer);
|
|
}
|
|
|
|
class FHeightfieldDescriptionParameters
|
|
{
|
|
public:
|
|
void Bind(const FShaderParameterMap& ParameterMap)
|
|
{
|
|
HeightfieldDescriptions.Bind(ParameterMap,TEXT("HeightfieldDescriptions"));
|
|
NumHeightfields.Bind(ParameterMap,TEXT("NumHeightfields"));
|
|
}
|
|
|
|
friend FArchive& operator<<(FArchive& Ar,FHeightfieldDescriptionParameters& Parameters)
|
|
{
|
|
Ar << Parameters.HeightfieldDescriptions;
|
|
Ar << Parameters.NumHeightfields;
|
|
return Ar;
|
|
}
|
|
|
|
template<typename ShaderRHIParamRef>
|
|
void Set(FRHICommandList& RHICmdList, const ShaderRHIParamRef ShaderRHI, int32 NumHeightfieldsValue)
|
|
{
|
|
SetSRVParameter(RHICmdList, ShaderRHI, HeightfieldDescriptions, GHeightfieldDescriptions.Data.BufferSRV);
|
|
SetShaderValue(RHICmdList, ShaderRHI, NumHeightfields, NumHeightfieldsValue);
|
|
}
|
|
|
|
private:
|
|
FShaderResourceParameter HeightfieldDescriptions;
|
|
FShaderParameter NumHeightfields;
|
|
};
|
|
|
|
class FGlobalHeightfieldParameters
|
|
{
|
|
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:
|
|
FShaderResourceParameter GlobalHeightfieldTexture;
|
|
FShaderResourceParameter GlobalNormalTexture;
|
|
FShaderResourceParameter GlobalDiffuseColorTexture;
|
|
FShaderResourceParameter GlobalHeightfieldSampler;
|
|
};
|
|
|
|
class FHeightfieldComponentQuadVS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FHeightfieldComponentQuadVS, Global);
|
|
public:
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform)
|
|
{
|
|
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldGI(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)
|
|
{
|
|
const FVertexShaderRHIParamRef ShaderRHI = GetVertexShader();
|
|
|
|
FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View);
|
|
HeightfieldDescriptionParameters.Set(RHICmdList, ShaderRHI, NumHeightfieldsValue);
|
|
}
|
|
|
|
// FShader interface.
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
Ar << HeightfieldDescriptionParameters;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
|
|
FHeightfieldDescriptionParameters HeightfieldDescriptionParameters;
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(,FHeightfieldComponentQuadVS,TEXT("HeightfieldLighting"),TEXT("HeightfieldComponentQuadVS"),SF_Vertex);
|
|
|
|
class FShadowHeightfieldsPS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FShadowHeightfieldsPS, Global);
|
|
public:
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform)
|
|
{
|
|
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldGI(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)
|
|
{
|
|
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();
|
|
|
|
FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View);
|
|
HeightfieldDescriptionParameters.Set(RHICmdList, ShaderRHI, NumHeightfieldsValue);
|
|
GlobalHeightfieldParameters.Set(RHICmdList, ShaderRHI, Atlas);
|
|
|
|
FVector4 ShadowmapMinMaxValue;
|
|
FMatrix 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));
|
|
|
|
FTexture2DRHIRef ShadowDepthTextureValue = GSceneRenderTargets.GetShadowDepthZTexture(ProjectedShadowInfo->bAllocatedInPreshadowCache);
|
|
FSamplerStateRHIParamRef DepthSamplerState = TStaticSamplerState<SF_Point,AM_Clamp,AM_Clamp,AM_Clamp>::GetRHI();
|
|
|
|
SetTextureParameter(RHICmdList, ShaderRHI, ShadowDepthTexture, ShadowDepthTextureSampler, DepthSamplerState, ShadowDepthTextureValue);
|
|
}
|
|
// FShader interface.
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
Ar << HeightfieldDescriptionParameters;
|
|
Ar << GlobalHeightfieldParameters;
|
|
Ar << WorldToShadow;
|
|
Ar << ShadowmapMinMax;
|
|
Ar << ShadowDepthBias;
|
|
Ar << CascadeDepthMinMax;
|
|
Ar << ShadowDepthTexture;
|
|
Ar << ShadowDepthTextureSampler;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
|
|
FHeightfieldDescriptionParameters HeightfieldDescriptionParameters;
|
|
FGlobalHeightfieldParameters GlobalHeightfieldParameters;
|
|
FShaderParameter WorldToShadow;
|
|
FShaderParameter ShadowmapMinMax;
|
|
FShaderParameter ShadowDepthBias;
|
|
FShaderParameter CascadeDepthMinMax;
|
|
FShaderResourceParameter ShadowDepthTexture;
|
|
FShaderResourceParameter ShadowDepthTextureSampler;
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(,FShadowHeightfieldsPS,TEXT("HeightfieldLighting"),TEXT("ShadowHeightfieldsPS"),SF_Pixel);
|
|
|
|
void FHeightfieldLightingViewInfo::ClearShadowing(const FViewInfo& View, FRHICommandListImmediate& RHICmdList, const FLightSceneInfo& LightSceneInfo) const
|
|
{
|
|
if (AllowHeightfieldGI(View)
|
|
&& SupportsHeightfieldLighting(View.GetFeatureLevel(), View.GetShaderPlatform())
|
|
&& Heightfield.ComponentDescriptions.Num() > 0
|
|
&& LightSceneInfo.Proxy->GetLightType() == LightType_Directional
|
|
&& LightSceneInfo.Proxy->CastsDynamicShadow())
|
|
{
|
|
FSceneViewState* ViewState = (FSceneViewState*)View.State;
|
|
const FHeightfieldLightingAtlas& Atlas = *ViewState->HeightfieldLightingAtlas;
|
|
SetRenderTarget(RHICmdList, Atlas.DirectionalLightShadowing->GetRenderTargetItem().TargetableTexture, NULL);
|
|
RHICmdList.Clear(true, FLinearColor(1, 1, 1), false, 0, false, 0, FIntRect());
|
|
}
|
|
}
|
|
|
|
void FHeightfieldLightingViewInfo::ComputeShadowMapShadowing(const FViewInfo& View, FRHICommandListImmediate& RHICmdList, const FProjectedShadowInfo* ProjectedShadowInfo) const
|
|
{
|
|
if (AllowHeightfieldGI(View)
|
|
&& SupportsHeightfieldLighting(View.GetFeatureLevel(), View.GetShaderPlatform())
|
|
&& Heightfield.ComponentDescriptions.Num() > 0
|
|
&& ProjectedShadowInfo->IsWholeSceneDirectionalShadow()
|
|
&& ProjectedShadowInfo->DependentView == &View
|
|
&& !ProjectedShadowInfo->CascadeSettings.bRayTracedDistanceField)
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, HeightfieldShadowMapShadowingForGI);
|
|
|
|
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);
|
|
SetRenderTarget(RHICmdList, Atlas.DirectionalLightShadowing->GetRenderTargetItem().TargetableTexture, NULL);
|
|
|
|
RHICmdList.SetViewport(0, 0, 0.0f, LightingAtlasSize.X, LightingAtlasSize.Y, 1.0f);
|
|
RHICmdList.SetRasterizerState(TStaticRasterizerState<FM_Solid, CM_None>::GetRHI());
|
|
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
|
|
// Combine with other shadow types with min (ray traced)
|
|
RHICmdList.SetBlendState(TStaticBlendState<CW_RED, BO_Min, BF_One, BF_One>::GetRHI());
|
|
RHICmdList.SetStreamSource(0, GQuadVertexBuffer.VertexBufferRHI, sizeof(FScreenVertex), 0);
|
|
|
|
TShaderMapRef<FHeightfieldComponentQuadVS> VertexShader(View.ShaderMap);
|
|
TShaderMapRef<FShadowHeightfieldsPS> PixelShader(View.ShaderMap);
|
|
|
|
static FGlobalBoundShaderState BoundShaderState;
|
|
SetGlobalBoundShaderState(RHICmdList, View.GetFeatureLevel(), BoundShaderState, GScreenVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader);
|
|
|
|
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(PT_TriangleList, 0, 2, HeightfieldDescriptions.Num());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
class FRayTracedShadowHeightfieldsPS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FRayTracedShadowHeightfieldsPS, Global);
|
|
public:
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform)
|
|
{
|
|
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldGI(Platform);
|
|
}
|
|
|
|
/** Default constructor. */
|
|
FRayTracedShadowHeightfieldsPS() {}
|
|
|
|
/** Initialization constructor. */
|
|
FRayTracedShadowHeightfieldsPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FGlobalShader(Initializer)
|
|
{
|
|
HeightfieldDescriptionParameters.Bind(Initializer.ParameterMap);
|
|
GlobalHeightfieldParameters.Bind(Initializer.ParameterMap);
|
|
ObjectParameters.Bind(Initializer.ParameterMap);
|
|
LightDirection.Bind(Initializer.ParameterMap, TEXT("LightDirection"));
|
|
TanLightAngle.Bind(Initializer.ParameterMap, TEXT("TanLightAngle"));
|
|
CascadeDepthMinMax.Bind(Initializer.ParameterMap, TEXT("CascadeDepthMinMax"));
|
|
ShadowTileHeadDataUnpacked.Bind(Initializer.ParameterMap, TEXT("ShadowTileHeadDataUnpacked"));
|
|
ShadowTileArrayData.Bind(Initializer.ParameterMap, TEXT("ShadowTileArrayData"));
|
|
ShadowTileListGroupSize.Bind(Initializer.ParameterMap, TEXT("ShadowTileListGroupSize"));
|
|
WorldToShadow.Bind(Initializer.ParameterMap, TEXT("WorldToShadow"));
|
|
TwoSidedMeshDistanceBias.Bind(Initializer.ParameterMap, TEXT("TwoSidedMeshDistanceBias"));
|
|
}
|
|
|
|
void SetParameters(
|
|
FRHICommandList& RHICmdList,
|
|
const FSceneView& View,
|
|
const FProjectedShadowInfo* ProjectedShadowInfo,
|
|
int32 NumHeightfieldsValue,
|
|
const FHeightfieldLightingAtlas& Atlas,
|
|
FLightTileIntersectionResources* TileIntersectionResources,
|
|
FDistanceFieldObjectBufferResource& CulledObjectBuffers)
|
|
{
|
|
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();
|
|
|
|
FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View);
|
|
HeightfieldDescriptionParameters.Set(RHICmdList, ShaderRHI, NumHeightfieldsValue);
|
|
GlobalHeightfieldParameters.Set(RHICmdList, ShaderRHI, Atlas);
|
|
ObjectParameters.Set(RHICmdList, ShaderRHI, CulledObjectBuffers.Buffers);
|
|
|
|
SetShaderValue(RHICmdList, ShaderRHI, LightDirection, ProjectedShadowInfo->GetLightSceneInfo().Proxy->GetDirection());
|
|
|
|
const float LightSourceAngle = FMath::Clamp(ProjectedShadowInfo->GetLightSceneInfo().Proxy->GetLightSourceAngle(), 0.001f, 5.0f) * PI / 180.0f;
|
|
SetShaderValue(RHICmdList, ShaderRHI, TanLightAngle, FMath::Tan(LightSourceAngle));
|
|
|
|
SetShaderValue(RHICmdList, ShaderRHI, CascadeDepthMinMax, FVector2D(ProjectedShadowInfo->CascadeSettings.SplitNear, ProjectedShadowInfo->CascadeSettings.SplitFar));
|
|
|
|
check(TileIntersectionResources || !ShadowTileHeadDataUnpacked.IsBound());
|
|
|
|
if (TileIntersectionResources)
|
|
{
|
|
SetSRVParameter(RHICmdList, ShaderRHI, ShadowTileHeadDataUnpacked, TileIntersectionResources->TileHeadDataUnpacked.SRV);
|
|
SetSRVParameter(RHICmdList, ShaderRHI, ShadowTileArrayData, TileIntersectionResources->TileArrayData.SRV);
|
|
SetShaderValue(RHICmdList, ShaderRHI, ShadowTileListGroupSize, TileIntersectionResources->TileDimensions);
|
|
}
|
|
|
|
FMatrix WorldToShadowMatrixValue = FTranslationMatrix(ProjectedShadowInfo->PreShadowTranslation) * ProjectedShadowInfo->SubjectAndReceiverMatrix;
|
|
SetShaderValue(RHICmdList, ShaderRHI, WorldToShadow, WorldToShadowMatrixValue);
|
|
|
|
extern float GTwoSidedMeshDistanceBias;
|
|
SetShaderValue(RHICmdList, ShaderRHI, TwoSidedMeshDistanceBias, GTwoSidedMeshDistanceBias);
|
|
}
|
|
// FShader interface.
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
Ar << HeightfieldDescriptionParameters;
|
|
Ar << GlobalHeightfieldParameters;
|
|
Ar << ObjectParameters;
|
|
Ar << LightDirection;
|
|
Ar << TanLightAngle;
|
|
Ar << CascadeDepthMinMax;
|
|
Ar << ShadowTileHeadDataUnpacked;
|
|
Ar << ShadowTileArrayData;
|
|
Ar << ShadowTileListGroupSize;
|
|
Ar << WorldToShadow;
|
|
Ar << TwoSidedMeshDistanceBias;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
|
|
FHeightfieldDescriptionParameters HeightfieldDescriptionParameters;
|
|
FGlobalHeightfieldParameters GlobalHeightfieldParameters;
|
|
FDistanceFieldCulledObjectBufferParameters ObjectParameters;
|
|
FShaderParameter LightDirection;
|
|
FShaderParameter TanLightAngle;
|
|
FShaderParameter CascadeDepthMinMax;
|
|
FShaderResourceParameter ShadowTileHeadDataUnpacked;
|
|
FShaderResourceParameter ShadowTileArrayData;
|
|
FShaderParameter ShadowTileListGroupSize;
|
|
FShaderParameter WorldToShadow;
|
|
FShaderParameter TwoSidedMeshDistanceBias;
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(,FRayTracedShadowHeightfieldsPS,TEXT("HeightfieldLighting"),TEXT("RayTracedShadowHeightfieldsPS"),SF_Pixel);
|
|
|
|
|
|
void FHeightfieldLightingViewInfo::ComputeRayTracedShadowing(
|
|
const FViewInfo& View,
|
|
FRHICommandListImmediate& RHICmdList,
|
|
const FProjectedShadowInfo* ProjectedShadowInfo,
|
|
FLightTileIntersectionResources* TileIntersectionResources,
|
|
FDistanceFieldObjectBufferResource& CulledObjectBuffers) const
|
|
{
|
|
if (AllowHeightfieldGI(View)
|
|
&& SupportsHeightfieldLighting(View.GetFeatureLevel(), View.GetShaderPlatform())
|
|
&& Heightfield.ComponentDescriptions.Num() > 0
|
|
&& ProjectedShadowInfo->IsWholeSceneDirectionalShadow()
|
|
&& ProjectedShadowInfo->DependentView == &View
|
|
&& ProjectedShadowInfo->CascadeSettings.bRayTracedDistanceField)
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, HeightfieldRayTracedShadowingForGI);
|
|
|
|
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);
|
|
SetRenderTarget(RHICmdList, Atlas.DirectionalLightShadowing->GetRenderTargetItem().TargetableTexture, NULL);
|
|
|
|
RHICmdList.SetViewport(0, 0, 0.0f, LightingAtlasSize.X, LightingAtlasSize.Y, 1.0f);
|
|
RHICmdList.SetRasterizerState(TStaticRasterizerState<FM_Solid, CM_None>::GetRHI());
|
|
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
|
|
// Combine with other shadow types with min (CSM)
|
|
RHICmdList.SetBlendState(TStaticBlendState<CW_RED, BO_Min, BF_One, BF_One>::GetRHI());
|
|
RHICmdList.SetStreamSource(0, GQuadVertexBuffer.VertexBufferRHI, sizeof(FScreenVertex), 0);
|
|
|
|
TShaderMapRef<FHeightfieldComponentQuadVS> VertexShader(View.ShaderMap);
|
|
TShaderMapRef<FRayTracedShadowHeightfieldsPS> PixelShader(View.ShaderMap);
|
|
|
|
static FGlobalBoundShaderState BoundShaderState;
|
|
SetGlobalBoundShaderState(RHICmdList, View.GetFeatureLevel(), BoundShaderState, GScreenVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader);
|
|
|
|
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);
|
|
|
|
VertexShader->SetParameters(RHICmdList, View, HeightfieldDescriptions.Num());
|
|
PixelShader->SetParameters(RHICmdList, View, ProjectedShadowInfo, HeightfieldDescriptions.Num(), Atlas, TileIntersectionResources, CulledObjectBuffers);
|
|
|
|
RHICmdList.DrawPrimitive(PT_TriangleList, 0, 2, HeightfieldDescriptions.Num());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class FLightHeightfieldsPS : public FMaterialShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FLightHeightfieldsPS, Material);
|
|
public:
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform, const FMaterial* Material)
|
|
{
|
|
return Material->IsLightFunction() && IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldGI(Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(EShaderPlatform Platform, const FMaterial* Material, 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)
|
|
{
|
|
const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader();
|
|
|
|
FMaterialShader::SetParameters(RHICmdList, ShaderRHI, MaterialProxy, *MaterialProxy->GetMaterial(View.GetFeatureLevel()), View, true, ESceneRenderTargetsMode::SetTextures);
|
|
|
|
HeightfieldDescriptionParameters.Set(RHICmdList, ShaderRHI, NumHeightfieldsValue);
|
|
GlobalHeightfieldParameters.Set(RHICmdList, ShaderRHI, Atlas);
|
|
|
|
SetShaderValue(RHICmdList, ShaderRHI, LightDirection, 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 FMatrix WorldToLightValue = LightSceneInfo.Proxy->GetWorldToLight() * FScaleMatrix(FVector(InverseScale));
|
|
|
|
SetShaderValue(RHICmdList, ShaderRHI, WorldToLight, WorldToLightValue);
|
|
|
|
LightFunctionParameters.Set(RHICmdList, ShaderRHI, &LightSceneInfo, 1);
|
|
}
|
|
|
|
// FShader interface.
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FMaterialShader::Serialize(Ar);
|
|
Ar << HeightfieldDescriptionParameters;
|
|
Ar << GlobalHeightfieldParameters;
|
|
Ar << LightDirection;
|
|
Ar << LightColor;
|
|
Ar << SkyLightIndirectScale;
|
|
Ar << HeightfieldShadowing;
|
|
Ar << HeightfieldShadowingSampler;
|
|
Ar << WorldToLight;
|
|
Ar << LightFunctionParameters;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
|
|
FHeightfieldDescriptionParameters HeightfieldDescriptionParameters;
|
|
FGlobalHeightfieldParameters GlobalHeightfieldParameters;
|
|
FShaderParameter LightDirection;
|
|
FShaderParameter LightColor;
|
|
FShaderParameter SkyLightIndirectScale;
|
|
FShaderResourceParameter HeightfieldShadowing;
|
|
FShaderResourceParameter HeightfieldShadowingSampler;
|
|
FShaderParameter WorldToLight;
|
|
FLightFunctionSharedParameters LightFunctionParameters;
|
|
};
|
|
|
|
IMPLEMENT_MATERIAL_SHADER_TYPE(,FLightHeightfieldsPS,TEXT("HeightfieldLighting"),TEXT("LightHeightfieldsPS"),SF_Pixel);
|
|
|
|
void FHeightfieldLightingViewInfo::ComputeLighting(const FViewInfo& View, FRHICommandListImmediate& RHICmdList, 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)
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, HeightfieldLightingForGI);
|
|
|
|
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);
|
|
|
|
SetRenderTarget(RHICmdList, Atlas.Lighting->GetRenderTargetItem().TargetableTexture, NULL);
|
|
|
|
// We will read outside the valid area later during light transfer
|
|
RHICmdList.Clear(true, FLinearColor(0, 0, 0), false, 0, false, 0, FIntRect());
|
|
|
|
const bool bApplyLightFunction = (View.Family->EngineShowFlags.LightFunctions &&
|
|
LightSceneInfo.Proxy->GetLightFunctionMaterial() &&
|
|
LightSceneInfo.Proxy->GetLightFunctionMaterial()->GetMaterial(FeatureLevel)->IsLightFunction());
|
|
|
|
const FMaterialRenderProxy* MaterialProxy = bApplyLightFunction ?
|
|
LightSceneInfo.Proxy->GetLightFunctionMaterial() :
|
|
UMaterial::GetDefaultMaterial(MD_LightFunction)->GetRenderProxy(false);
|
|
|
|
const FScene* Scene = (const FScene*)View.Family->Scene;
|
|
|
|
const float SkyLightIndirectScale = ShouldRenderDynamicSkyLight(Scene, *View.Family) ? Scene->SkyLight->IndirectLightingIntensity : 0;
|
|
|
|
// Skip rendering if the DefaultLightFunctionMaterial isn't compiled yet
|
|
if (MaterialProxy->GetMaterial(FeatureLevel)->IsLightFunction())
|
|
{
|
|
RHICmdList.SetViewport(0, 0, 0.0f, LightingAtlasSize.X, LightingAtlasSize.Y, 1.0f);
|
|
RHICmdList.SetRasterizerState(TStaticRasterizerState<FM_Solid, CM_None>::GetRHI());
|
|
RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false, CF_Always>::GetRHI());
|
|
RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI());
|
|
RHICmdList.SetStreamSource(0, GQuadVertexBuffer.VertexBufferRHI, sizeof(FScreenVertex), 0);
|
|
|
|
TShaderMapRef<FHeightfieldComponentQuadVS> VertexShader(View.ShaderMap);
|
|
|
|
const FMaterial* Material = MaterialProxy->GetMaterial(FeatureLevel);
|
|
const FMaterialShaderMap* MaterialShaderMap = Material->GetRenderingThreadShaderMap();
|
|
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);
|
|
|
|
FLocalBoundShaderState BoundShaderState = RHICmdList.BuildLocalBoundShaderState(GScreenVertexDeclaration.VertexDeclarationRHI, VertexShader->GetVertexShader(), FHullShaderRHIRef(), FDomainShaderRHIRef(), PixelShader->GetPixelShader(), FGeometryShaderRHIRef());
|
|
RHICmdList.SetLocalBoundShaderState(BoundShaderState);
|
|
|
|
VertexShader->SetParameters(RHICmdList, View, HeightfieldDescriptions.Num());
|
|
PixelShader->SetParameters(RHICmdList, View, LightSceneInfo, MaterialProxy, HeightfieldDescriptions.Num(), Atlas, SkyLightIndirectScale);
|
|
|
|
RHICmdList.DrawPrimitive(PT_TriangleList, 0, 2, HeightfieldDescriptions.Num());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class FCalculateHeightfieldOcclusionCS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FCalculateHeightfieldOcclusionCS,Global)
|
|
public:
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform)
|
|
{
|
|
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldGI(Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Platform,OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("NUM_CONE_DIRECTIONS"), NumConeSampleDirections);
|
|
|
|
// 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);
|
|
}
|
|
|
|
FCalculateHeightfieldOcclusionCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FGlobalShader(Initializer)
|
|
{
|
|
AOParameters.Bind(Initializer.ParameterMap);
|
|
HeightfieldDescriptionParameters.Bind(Initializer.ParameterMap);
|
|
HeightfieldTextureParameters.Bind(Initializer.ParameterMap);
|
|
OccluderRadius.Bind(Initializer.ParameterMap, TEXT("OccluderRadius"));
|
|
IrradianceCacheNormal.Bind(Initializer.ParameterMap, TEXT("IrradianceCacheNormal"));
|
|
IrradianceCachePositionRadius.Bind(Initializer.ParameterMap, TEXT("IrradianceCachePositionRadius"));
|
|
RecordConeVisibility.Bind(Initializer.ParameterMap, TEXT("RecordConeVisibility"));
|
|
ScatterDrawParameters.Bind(Initializer.ParameterMap, TEXT("ScatterDrawParameters"));
|
|
SavedStartIndex.Bind(Initializer.ParameterMap, TEXT("SavedStartIndex"));
|
|
BentNormalNormalizeFactor.Bind(Initializer.ParameterMap, TEXT("BentNormalNormalizeFactor"));
|
|
DistanceFieldNormalTexture.Bind(Initializer.ParameterMap, TEXT("DistanceFieldNormalTexture"));
|
|
DistanceFieldNormalSampler.Bind(Initializer.ParameterMap, TEXT("DistanceFieldNormalSampler"));
|
|
RecordRadiusScale.Bind(Initializer.ParameterMap, TEXT("RecordRadiusScale"));
|
|
TanConeHalfAngle.Bind(Initializer.ParameterMap, TEXT("TanConeHalfAngle"));
|
|
}
|
|
|
|
FCalculateHeightfieldOcclusionCS()
|
|
{
|
|
}
|
|
|
|
void SetParameters(
|
|
FRHICommandList& RHICmdList,
|
|
const FSceneView& View,
|
|
int32 DepthLevel,
|
|
UTexture2D* HeightfieldTextureValue,
|
|
int32 NumHeightfieldsValue,
|
|
const FTemporaryIrradianceCacheResources& TemporaryIrradianceCacheResources,
|
|
const FDistanceFieldAOParameters& Parameters)
|
|
{
|
|
FComputeShaderRHIParamRef ShaderRHI = GetComputeShader();
|
|
FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View);
|
|
|
|
AOParameters.Set(RHICmdList, ShaderRHI, Parameters);
|
|
HeightfieldDescriptionParameters.Set(RHICmdList, ShaderRHI, NumHeightfieldsValue);
|
|
HeightfieldTextureParameters.Set(RHICmdList, ShaderRHI, HeightfieldTextureValue, NULL);
|
|
|
|
const FScene* Scene = (const FScene*)View.Family->Scene;
|
|
FSurfaceCacheResources& SurfaceCacheResources = *Scene->SurfaceCacheResources;
|
|
|
|
SetSRVParameter(RHICmdList, ShaderRHI, IrradianceCacheNormal, SurfaceCacheResources.Level[DepthLevel]->Normal.SRV);
|
|
SetSRVParameter(RHICmdList, ShaderRHI, IrradianceCachePositionRadius, SurfaceCacheResources.Level[DepthLevel]->PositionAndRadius.SRV);
|
|
SetSRVParameter(RHICmdList, ShaderRHI, ScatterDrawParameters, SurfaceCacheResources.Level[DepthLevel]->ScatterDrawParameters.SRV);
|
|
SetSRVParameter(RHICmdList, ShaderRHI, SavedStartIndex, SurfaceCacheResources.Level[DepthLevel]->SavedStartIndex.SRV);
|
|
|
|
OccluderRadius.SetBuffer(RHICmdList, ShaderRHI, SurfaceCacheResources.Level[DepthLevel]->OccluderRadius);
|
|
RecordConeVisibility.SetBuffer(RHICmdList, ShaderRHI, TemporaryIrradianceCacheResources.ConeVisibility);
|
|
|
|
FAOSampleData2 AOSampleData;
|
|
|
|
TArray<FVector, TInlineAllocator<9> > SampleDirections;
|
|
GetSpacedVectors(SampleDirections);
|
|
|
|
for (int32 SampleIndex = 0; SampleIndex < NumConeSampleDirections; SampleIndex++)
|
|
{
|
|
AOSampleData.SampleDirections[SampleIndex] = FVector4(SampleDirections[SampleIndex]);
|
|
}
|
|
|
|
SetUniformBufferParameterImmediate(RHICmdList, ShaderRHI, GetUniformBufferParameter<FAOSampleData2>(), AOSampleData);
|
|
|
|
FVector UnoccludedVector(0);
|
|
|
|
for (int32 SampleIndex = 0; SampleIndex < NumConeSampleDirections; SampleIndex++)
|
|
{
|
|
UnoccludedVector += SampleDirections[SampleIndex];
|
|
}
|
|
|
|
float BentNormalNormalizeFactorValue = 1.0f / (UnoccludedVector / NumConeSampleDirections).Size();
|
|
SetShaderValue(RHICmdList, ShaderRHI, BentNormalNormalizeFactor, BentNormalNormalizeFactorValue);
|
|
|
|
extern float GAOConeHalfAngle;
|
|
SetShaderValue(RHICmdList, ShaderRHI, TanConeHalfAngle, FMath::Tan(GAOConeHalfAngle));
|
|
extern float GAORecordRadiusScale;
|
|
SetShaderValue(RHICmdList, ShaderRHI, RecordRadiusScale, GAORecordRadiusScale);
|
|
}
|
|
|
|
void UnsetParameters(FRHICommandList& RHICmdList)
|
|
{
|
|
OccluderRadius.UnsetUAV(RHICmdList, GetComputeShader());
|
|
RecordConeVisibility.UnsetUAV(RHICmdList, GetComputeShader());
|
|
}
|
|
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
Ar << AOParameters;
|
|
Ar << HeightfieldDescriptionParameters;
|
|
Ar << HeightfieldTextureParameters;
|
|
Ar << OccluderRadius;
|
|
Ar << IrradianceCacheNormal;
|
|
Ar << IrradianceCachePositionRadius;
|
|
Ar << RecordConeVisibility;
|
|
Ar << ScatterDrawParameters;
|
|
Ar << SavedStartIndex;
|
|
Ar << BentNormalNormalizeFactor;
|
|
Ar << DistanceFieldNormalTexture;
|
|
Ar << DistanceFieldNormalSampler;
|
|
Ar << RecordRadiusScale;
|
|
Ar << TanConeHalfAngle;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
|
|
FAOParameters AOParameters;
|
|
FHeightfieldDescriptionParameters HeightfieldDescriptionParameters;
|
|
FHeightfieldTextureParameters HeightfieldTextureParameters;
|
|
FRWShaderParameter OccluderRadius;
|
|
FShaderResourceParameter IrradianceCacheNormal;
|
|
FShaderResourceParameter IrradianceCachePositionRadius;
|
|
FRWShaderParameter RecordConeVisibility;
|
|
FShaderResourceParameter ScatterDrawParameters;
|
|
FShaderResourceParameter SavedStartIndex;
|
|
FShaderParameter BentNormalNormalizeFactor;
|
|
FShaderResourceParameter DistanceFieldNormalTexture;
|
|
FShaderResourceParameter DistanceFieldNormalSampler;
|
|
FShaderParameter RecordRadiusScale;
|
|
FShaderParameter TanConeHalfAngle;
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(,FCalculateHeightfieldOcclusionCS,TEXT("HeightfieldLighting"),TEXT("CalculateHeightfieldOcclusionCS"),SF_Compute);
|
|
|
|
|
|
void FHeightfieldLightingViewInfo::ComputeOcclusionForSamples(
|
|
const FViewInfo& View,
|
|
FRHICommandListImmediate& RHICmdList,
|
|
const FTemporaryIrradianceCacheResources& TemporaryIrradianceCacheResources,
|
|
int32 DepthLevel,
|
|
const FDistanceFieldAOParameters& Parameters) const
|
|
{
|
|
const FScene* Scene = (const FScene*)View.Family->Scene;
|
|
|
|
if (Heightfield.ComponentDescriptions.Num() > 0 && GAOHeightfieldOcclusion)
|
|
{
|
|
{
|
|
TShaderMapRef<TSetupFinalGatherIndirectArgumentsCS<false> > ComputeShader(View.ShaderMap);
|
|
|
|
RHICmdList.SetComputeShader(ComputeShader->GetComputeShader());
|
|
ComputeShader->SetParameters(RHICmdList, View, DepthLevel);
|
|
DispatchComputeShader(RHICmdList, *ComputeShader, 1, 1, 1);
|
|
|
|
ComputeShader->UnsetParameters(RHICmdList);
|
|
}
|
|
|
|
SCOPED_DRAW_EVENT(RHICmdList, HeightfieldOcclusion);
|
|
|
|
FSceneViewState* ViewState = (FSceneViewState*)View.State;
|
|
|
|
{
|
|
for (TMap<FHeightfieldComponentTextures, TArray<FHeightfieldComponentDescription>>::TConstIterator It(Heightfield.ComponentDescriptions); It; ++It)
|
|
{
|
|
const TArray<FHeightfieldComponentDescription>& HeightfieldDescriptions = It.Value();
|
|
|
|
if (HeightfieldDescriptions.Num() > 0)
|
|
{
|
|
UploadHeightfieldDescriptions(HeightfieldDescriptions, FVector2D(1, 1), 1.0f / Heightfield.DownsampleFactor);
|
|
|
|
UTexture2D* HeightfieldTexture = It.Key().HeightAndNormal;
|
|
|
|
{
|
|
TShaderMapRef<FCalculateHeightfieldOcclusionCS> ComputeShader(View.ShaderMap);
|
|
RHICmdList.SetComputeShader(ComputeShader->GetComputeShader());
|
|
ComputeShader->SetParameters(RHICmdList, View, DepthLevel, HeightfieldTexture, HeightfieldDescriptions.Num(), TemporaryIrradianceCacheResources, Parameters);
|
|
|
|
FSurfaceCacheResources& SurfaceCacheResources = *Scene->SurfaceCacheResources;
|
|
DispatchIndirectComputeShader(RHICmdList, *ComputeShader, SurfaceCacheResources.DispatchParameters.Buffer, 0);
|
|
|
|
ComputeShader->UnsetParameters(RHICmdList);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class FCalculateHeightfieldIrradianceCS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FCalculateHeightfieldIrradianceCS,Global)
|
|
public:
|
|
|
|
static bool ShouldCache(EShaderPlatform Platform)
|
|
{
|
|
return IsFeatureLevelSupported(Platform, ERHIFeatureLevel::SM5) && DoesPlatformSupportDistanceFieldGI(Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Platform,OutEnvironment);
|
|
OutEnvironment.SetDefine(TEXT("NUM_CONE_DIRECTIONS"), NumConeSampleDirections);
|
|
|
|
// 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);
|
|
}
|
|
|
|
FCalculateHeightfieldIrradianceCS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FGlobalShader(Initializer)
|
|
{
|
|
AOParameters.Bind(Initializer.ParameterMap);
|
|
HeightfieldDescriptionParameters.Bind(Initializer.ParameterMap);
|
|
GlobalHeightfieldParameters.Bind(Initializer.ParameterMap);
|
|
HeightfieldIrradiance.Bind(Initializer.ParameterMap, TEXT("HeightfieldIrradiance"));
|
|
IrradianceCacheNormal.Bind(Initializer.ParameterMap, TEXT("IrradianceCacheNormal"));
|
|
IrradianceCachePositionRadius.Bind(Initializer.ParameterMap, TEXT("IrradianceCachePositionRadius"));
|
|
ScatterDrawParameters.Bind(Initializer.ParameterMap, TEXT("ScatterDrawParameters"));
|
|
SavedStartIndex.Bind(Initializer.ParameterMap, TEXT("SavedStartIndex"));
|
|
BentNormalNormalizeFactor.Bind(Initializer.ParameterMap, TEXT("BentNormalNormalizeFactor"));
|
|
DistanceFieldNormalTexture.Bind(Initializer.ParameterMap, TEXT("DistanceFieldNormalTexture"));
|
|
DistanceFieldNormalSampler.Bind(Initializer.ParameterMap, TEXT("DistanceFieldNormalSampler"));
|
|
RecordRadiusScale.Bind(Initializer.ParameterMap, TEXT("RecordRadiusScale"));
|
|
TanConeHalfAngle.Bind(Initializer.ParameterMap, TEXT("TanConeHalfAngle"));
|
|
HeightfieldLighting.Bind(Initializer.ParameterMap, TEXT("HeightfieldLighting"));
|
|
HeightfieldLightingSampler.Bind(Initializer.ParameterMap, TEXT("HeightfieldLightingSampler"));
|
|
InnerLightTransferDistance.Bind(Initializer.ParameterMap, TEXT("InnerLightTransferDistance"));
|
|
OuterLightTransferDistanceScale.Bind(Initializer.ParameterMap, TEXT("OuterLightTransferDistanceScale"));
|
|
RecordConeVisibility.Bind(Initializer.ParameterMap, TEXT("RecordConeVisibility"));
|
|
}
|
|
|
|
FCalculateHeightfieldIrradianceCS()
|
|
{
|
|
}
|
|
|
|
void SetParameters(
|
|
FRHICommandList& RHICmdList,
|
|
const FSceneView& View,
|
|
int32 DepthLevel,
|
|
int32 NumHeightfieldsValue,
|
|
const FTemporaryIrradianceCacheResources& TemporaryIrradianceCacheResources,
|
|
const FDistanceFieldAOParameters& Parameters,
|
|
const FHeightfieldLightingAtlas& Atlas)
|
|
{
|
|
FComputeShaderRHIParamRef ShaderRHI = GetComputeShader();
|
|
FGlobalShader::SetParameters(RHICmdList, ShaderRHI, View);
|
|
|
|
AOParameters.Set(RHICmdList, ShaderRHI, Parameters);
|
|
HeightfieldDescriptionParameters.Set(RHICmdList, ShaderRHI, NumHeightfieldsValue);
|
|
GlobalHeightfieldParameters.Set(RHICmdList, ShaderRHI, Atlas);
|
|
|
|
const FScene* Scene = (const FScene*)View.Family->Scene;
|
|
FSurfaceCacheResources& SurfaceCacheResources = *Scene->SurfaceCacheResources;
|
|
|
|
SetSRVParameter(RHICmdList, ShaderRHI, IrradianceCacheNormal, SurfaceCacheResources.Level[DepthLevel]->Normal.SRV);
|
|
SetSRVParameter(RHICmdList, ShaderRHI, IrradianceCachePositionRadius, SurfaceCacheResources.Level[DepthLevel]->PositionAndRadius.SRV);
|
|
SetSRVParameter(RHICmdList, ShaderRHI, ScatterDrawParameters, SurfaceCacheResources.Level[DepthLevel]->ScatterDrawParameters.SRV);
|
|
SetSRVParameter(RHICmdList, ShaderRHI, SavedStartIndex, SurfaceCacheResources.Level[DepthLevel]->SavedStartIndex.SRV);
|
|
SetSRVParameter(RHICmdList, ShaderRHI, RecordConeVisibility, TemporaryIrradianceCacheResources.ConeVisibility.SRV);
|
|
|
|
HeightfieldIrradiance.SetBuffer(RHICmdList, ShaderRHI, TemporaryIrradianceCacheResources.HeightfieldIrradiance);
|
|
|
|
{
|
|
FAOSampleData2 AOSampleData;
|
|
|
|
TArray<FVector, TInlineAllocator<9> > SampleDirections;
|
|
GetSpacedVectors(SampleDirections);
|
|
|
|
for (int32 SampleIndex = 0; SampleIndex < NumConeSampleDirections; SampleIndex++)
|
|
{
|
|
AOSampleData.SampleDirections[SampleIndex] = FVector4(SampleDirections[SampleIndex]);
|
|
}
|
|
|
|
SetUniformBufferParameterImmediate(RHICmdList, ShaderRHI, GetUniformBufferParameter<FAOSampleData2>(), AOSampleData);
|
|
|
|
FVector UnoccludedVector(0);
|
|
|
|
for (int32 SampleIndex = 0; SampleIndex < NumConeSampleDirections; SampleIndex++)
|
|
{
|
|
UnoccludedVector += SampleDirections[SampleIndex];
|
|
}
|
|
|
|
float BentNormalNormalizeFactorValue = 1.0f / (UnoccludedVector / NumConeSampleDirections).Size();
|
|
SetShaderValue(RHICmdList, ShaderRHI, BentNormalNormalizeFactor, BentNormalNormalizeFactorValue);
|
|
}
|
|
|
|
extern float GAOConeHalfAngle;
|
|
SetShaderValue(RHICmdList, ShaderRHI, TanConeHalfAngle, FMath::Tan(GAOConeHalfAngle));
|
|
extern float GAORecordRadiusScale;
|
|
SetShaderValue(RHICmdList, ShaderRHI, RecordRadiusScale, GAORecordRadiusScale);
|
|
|
|
const FSceneViewState* ViewState = (const FSceneViewState*)View.State;
|
|
SetTextureParameter(RHICmdList, ShaderRHI, HeightfieldLighting, HeightfieldLightingSampler, TStaticSamplerState<SF_Bilinear>::GetRHI(), Atlas.Lighting->GetRenderTargetItem().ShaderResourceTexture);
|
|
|
|
SetShaderValue(RHICmdList, ShaderRHI, InnerLightTransferDistance, GHeightfieldInnerBounceDistance);
|
|
SetShaderValue(RHICmdList, ShaderRHI, OuterLightTransferDistanceScale, GHeightfieldOuterBounceDistanceScale);
|
|
}
|
|
|
|
void UnsetParameters(FRHICommandList& RHICmdList)
|
|
{
|
|
HeightfieldIrradiance.UnsetUAV(RHICmdList, GetComputeShader());
|
|
}
|
|
|
|
virtual bool Serialize(FArchive& Ar) override
|
|
{
|
|
bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
|
|
Ar << AOParameters;
|
|
Ar << HeightfieldDescriptionParameters;
|
|
Ar << GlobalHeightfieldParameters;
|
|
Ar << HeightfieldIrradiance;
|
|
Ar << IrradianceCacheNormal;
|
|
Ar << IrradianceCachePositionRadius;
|
|
Ar << ScatterDrawParameters;
|
|
Ar << SavedStartIndex;
|
|
Ar << BentNormalNormalizeFactor;
|
|
Ar << DistanceFieldNormalTexture;
|
|
Ar << DistanceFieldNormalSampler;
|
|
Ar << RecordRadiusScale;
|
|
Ar << TanConeHalfAngle;
|
|
Ar << HeightfieldLighting;
|
|
Ar << HeightfieldLightingSampler;
|
|
Ar << InnerLightTransferDistance;
|
|
Ar << OuterLightTransferDistanceScale;
|
|
Ar << RecordConeVisibility;
|
|
return bShaderHasOutdatedParameters;
|
|
}
|
|
|
|
private:
|
|
|
|
FAOParameters AOParameters;
|
|
FHeightfieldDescriptionParameters HeightfieldDescriptionParameters;
|
|
FGlobalHeightfieldParameters GlobalHeightfieldParameters;
|
|
FRWShaderParameter HeightfieldIrradiance;
|
|
FShaderResourceParameter IrradianceCacheNormal;
|
|
FShaderResourceParameter IrradianceCachePositionRadius;
|
|
FShaderResourceParameter ScatterDrawParameters;
|
|
FShaderResourceParameter SavedStartIndex;
|
|
FShaderParameter BentNormalNormalizeFactor;
|
|
FShaderResourceParameter DistanceFieldNormalTexture;
|
|
FShaderResourceParameter DistanceFieldNormalSampler;
|
|
FShaderParameter RecordRadiusScale;
|
|
FShaderParameter TanConeHalfAngle;
|
|
FShaderResourceParameter HeightfieldLighting;
|
|
FShaderResourceParameter HeightfieldLightingSampler;
|
|
FShaderParameter InnerLightTransferDistance;
|
|
FShaderParameter OuterLightTransferDistanceScale;
|
|
FShaderResourceParameter RecordConeVisibility;
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(,FCalculateHeightfieldIrradianceCS,TEXT("HeightfieldLighting"),TEXT("CalculateHeightfieldIrradianceCS"),SF_Compute);
|
|
|
|
void FHeightfieldLightingViewInfo::ComputeIrradianceForSamples(
|
|
const FViewInfo& View,
|
|
FRHICommandListImmediate& RHICmdList,
|
|
const FTemporaryIrradianceCacheResources& TemporaryIrradianceCacheResources,
|
|
int32 DepthLevel,
|
|
const FDistanceFieldAOParameters& Parameters) const
|
|
{
|
|
const FScene* Scene = (const FScene*)View.Family->Scene;
|
|
|
|
if (Heightfield.ComponentDescriptions.Num() > 0
|
|
&& AllowHeightfieldGI(View)
|
|
&& SupportsHeightfieldLighting(View.GetFeatureLevel(), View.GetShaderPlatform()))
|
|
{
|
|
{
|
|
TShaderMapRef<TSetupFinalGatherIndirectArgumentsCS<true> > ComputeShader(View.ShaderMap);
|
|
|
|
RHICmdList.SetComputeShader(ComputeShader->GetComputeShader());
|
|
ComputeShader->SetParameters(RHICmdList, View, DepthLevel);
|
|
DispatchComputeShader(RHICmdList, *ComputeShader, 1, 1, 1);
|
|
|
|
ComputeShader->UnsetParameters(RHICmdList);
|
|
}
|
|
|
|
SCOPED_DRAW_EVENT(RHICmdList, HeightfieldIrradiance);
|
|
|
|
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);
|
|
|
|
TArray<FHeightfieldComponentDescription> CombinedHeightfieldDescriptions;
|
|
|
|
for (TMap<FHeightfieldComponentTextures, TArray<FHeightfieldComponentDescription>>::TConstIterator It(Heightfield.ComponentDescriptions); It; ++It)
|
|
{
|
|
const TArray<FHeightfieldComponentDescription>& HeightfieldDescriptions = It.Value();
|
|
CombinedHeightfieldDescriptions.Append(HeightfieldDescriptions);
|
|
}
|
|
|
|
if (CombinedHeightfieldDescriptions.Num() > 0)
|
|
{
|
|
UploadHeightfieldDescriptions(CombinedHeightfieldDescriptions, InvLightingAtlasSize, 1.0f / Heightfield.DownsampleFactor);
|
|
|
|
{
|
|
TShaderMapRef<FCalculateHeightfieldIrradianceCS> ComputeShader(View.ShaderMap);
|
|
RHICmdList.SetComputeShader(ComputeShader->GetComputeShader());
|
|
ComputeShader->SetParameters(RHICmdList, View, DepthLevel, CombinedHeightfieldDescriptions.Num(), TemporaryIrradianceCacheResources, Parameters, Atlas);
|
|
|
|
FSurfaceCacheResources& SurfaceCacheResources = *Scene->SurfaceCacheResources;
|
|
DispatchIndirectComputeShader(RHICmdList, *ComputeShader, SurfaceCacheResources.DispatchParameters.Buffer, 0);
|
|
|
|
ComputeShader->UnsetParameters(RHICmdList);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|