You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
* Simplify hair resources binding for virtual shadow map. #rb andrew.lauritzen #jira none #ushell-cherrypick of 15622751 by Charles.deRousiers #ushell-cherrypick of 15622753 by Charles.deRousiers #preflight 6050c19723863e000112bdc7 #ROBOMERGE-OWNER: charles.derousiers #ROBOMERGE-AUTHOR: charles.derousiers #ROBOMERGE-SOURCE: CL 15711628 in //UE5/Release-5.0-EarlyAccess/... #ROBOMERGE-BOT: STARSHIP (Release-5.0-EarlyAccess -> Main) (v781-15675533) #ROBOMERGE-CONFLICT from-shelf [CL 15711785 by charles derousiers in ue5-main branch]
408 lines
16 KiB
C++
408 lines
16 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
VirtualShadowMapProjection.cpp
|
|
=============================================================================*/
|
|
|
|
#include "VirtualShadowMapProjection.h"
|
|
#include "CoreMinimal.h"
|
|
#include "Stats/Stats.h"
|
|
#include "RHI.h"
|
|
#include "RenderResource.h"
|
|
#include "RendererInterface.h"
|
|
#include "Shader.h"
|
|
#include "StaticBoundShaderState.h"
|
|
#include "SceneUtils.h"
|
|
#include "RHIStaticStates.h"
|
|
#include "LightSceneInfo.h"
|
|
#include "GlobalShader.h"
|
|
#include "SceneRenderTargetParameters.h"
|
|
#include "ShadowRendering.h"
|
|
#include "DeferredShadingRenderer.h"
|
|
#include "PixelShaderUtils.h"
|
|
#include "ShadowRendering.h"
|
|
#include "SceneRendering.h"
|
|
#include "VirtualShadowMapClipmap.h"
|
|
#include "HairStrands/HairStrandsData.h"
|
|
|
|
static TAutoConsoleVariable<float> CVarContactShadowLength(
|
|
TEXT( "r.Shadow.Virtual.ContactShadowLength" ),
|
|
0.02f,
|
|
TEXT( "Length of the screen space contact shadow trace (smart shadow bias) before the virtual shadow map lookup." ),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
static TAutoConsoleVariable<float> CVarNormalOffsetWorld(
|
|
TEXT( "r.Shadow.Virtual.NormalOffsetWorld" ),
|
|
0.1f,
|
|
TEXT( "World space offset along surface normal for shadow lookup." )
|
|
TEXT( "Higher values avoid artifacts on surfaces nearly parallel to the light, but also visibility offset shadows and increase the chance of hitting unmapped pages." ),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
static TAutoConsoleVariable<int32> CVarVirtualShadowMapDebugProjection(
|
|
TEXT( "r.Shadow.Virtual.DebugProjection" ),
|
|
0,
|
|
TEXT( "Projection pass debug output visualization for use with 'vis Shadow.Virtual.DebugProjection'." ),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
TAutoConsoleVariable<int32> CVarVirtualShadowOnePassProjection(
|
|
TEXT("r.Shadow.Virtual.OnePassProjection"),
|
|
0,
|
|
TEXT("Single pass projects all local VSMs culled with the light grid. Used in conjunction with clustered deferred shading."),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
static TAutoConsoleVariable<int32> CVarSMRTRayCountLocal(
|
|
TEXT( "r.Shadow.Virtual.SMRT.RayCountLocal" ),
|
|
7,
|
|
TEXT( "Ray count for shadow map tracing of local lights. 0 = disabled." ),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
static TAutoConsoleVariable<int32> CVarSMRTSamplesPerRayLocal(
|
|
TEXT( "r.Shadow.Virtual.SMRT.SamplesPerRayLocal" ),
|
|
8,
|
|
TEXT( "Shadow map samples per ray for local lights" ),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
static TAutoConsoleVariable<float> CVarSMRTMaxRayAngleFromLight(
|
|
TEXT( "r.Shadow.Virtual.SMRT.MaxRayAngleFromLight" ),
|
|
0.03f,
|
|
TEXT( "Max angle (in radians) a ray is allowed to span from the light's perspective for local lights." )
|
|
TEXT( "Smaller angles limit the screen space size of shadow penumbra. " )
|
|
TEXT( "Larger angles lead to more noise. " ),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
static TAutoConsoleVariable<int32> CVarSMRTRayCountDirectional(
|
|
TEXT( "r.Shadow.Virtual.SMRT.RayCountDirectional" ),
|
|
0,
|
|
TEXT( "Ray count for shadow map tracing of directional lights. 0 = disabled." ),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
static TAutoConsoleVariable<int32> CVarSMRTSamplesPerRayDirectional(
|
|
TEXT( "r.Shadow.Virtual.SMRT.SamplesPerRayDirectional" ),
|
|
8,
|
|
TEXT( "Shadow map samples per ray for directional lights" ),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
static TAutoConsoleVariable<float> CVarSMRTRayLengthScaleDirectional(
|
|
TEXT( "r.Shadow.Virtual.SMRT.RayLengthScaleDirectional" ),
|
|
1.5f,
|
|
TEXT( "Length of ray to shoot for directional lights, scaled by distance to camera." )
|
|
TEXT( "Shorter rays limit the screen space size of shadow penumbra. " )
|
|
TEXT( "Longer rays require more samples to avoid shadows disconnecting from contact points. " ),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
static TAutoConsoleVariable<int32> CVarSMRTAdaptiveRayCount(
|
|
TEXT( "r.Shadow.Virtual.SMRT.AdaptiveRayCount" ),
|
|
1,
|
|
TEXT( "Shoot fewer rays in fully shadowed and unshadowed regions. Currently only supported with OnePassProjection. " ),
|
|
ECVF_RenderThreadSafe
|
|
);
|
|
|
|
|
|
// Composite denoised shadow projection mask onto the light's shadow mask
|
|
// Basically just a copy shader with a special blend mode
|
|
class FVirtualShadowMapProjectionCompositePS : public FGlobalShader
|
|
{
|
|
DECLARE_GLOBAL_SHADER(FVirtualShadowMapProjectionCompositePS);
|
|
SHADER_USE_PARAMETER_STRUCT(FVirtualShadowMapProjectionCompositePS, FGlobalShader);
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<float4>, InputSignal)
|
|
RENDER_TARGET_BINDING_SLOTS()
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return DoesPlatformSupportNanite(Parameters.Platform);
|
|
}
|
|
|
|
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
|
|
{
|
|
// Required right now due to where the shader function lives, but not actually used
|
|
FVirtualShadowMapArray::SetShaderDefines(OutEnvironment);
|
|
}
|
|
};
|
|
IMPLEMENT_GLOBAL_SHADER(FVirtualShadowMapProjectionCompositePS, "/Engine/Private/VirtualShadowMaps/VirtualShadowMapProjection.usf", "VirtualShadowMapCompositePS", SF_Pixel);
|
|
|
|
void CompositeVirtualShadowMapMask(
|
|
FRDGBuilder& GraphBuilder,
|
|
const FIntRect ScissorRect,
|
|
const FRDGTextureRef Input,
|
|
FRDGTextureRef OutputShadowMaskTexture)
|
|
{
|
|
auto ShaderMap = GetGlobalShaderMap(GMaxRHIFeatureLevel);
|
|
|
|
FVirtualShadowMapProjectionCompositePS::FParameters* PassParameters = GraphBuilder.AllocParameters<FVirtualShadowMapProjectionCompositePS::FParameters>();
|
|
PassParameters->InputSignal = Input;
|
|
|
|
PassParameters->RenderTargets[0] = FRenderTargetBinding(OutputShadowMaskTexture, ERenderTargetLoadAction::ELoad);
|
|
|
|
// See FProjectedShadowInfo::GetBlendStateForProjection, but we don't want any of the special cascade behavior, etc. as this is a post-denoised mask.
|
|
FRHIBlendState* BlendState = TStaticBlendState<CW_BA, BO_Min, BF_One, BF_One, BO_Min, BF_One, BF_One>::GetRHI();
|
|
|
|
auto PixelShader = ShaderMap->GetShader<FVirtualShadowMapProjectionCompositePS>();
|
|
ValidateShaderParameters(PixelShader, *PassParameters);
|
|
|
|
FPixelShaderUtils::AddFullscreenPass(GraphBuilder,
|
|
ShaderMap,
|
|
RDG_EVENT_NAME("Mask Composite"),
|
|
PixelShader,
|
|
PassParameters,
|
|
ScissorRect,
|
|
BlendState);
|
|
}
|
|
|
|
|
|
class FVirtualShadowMapProjectionCS : public FGlobalShader
|
|
{
|
|
DECLARE_GLOBAL_SHADER(FVirtualShadowMapProjectionCS);
|
|
SHADER_USE_PARAMETER_STRUCT(FVirtualShadowMapProjectionCS, FGlobalShader)
|
|
|
|
class FDirectionalLightDim : SHADER_PERMUTATION_BOOL("DIRECTIONAL_LIGHT");
|
|
class FSMRTAdaptiveRayCountDim : SHADER_PERMUTATION_BOOL("SMRT_ADAPTIVE_RAY_COUNT");
|
|
class FTwoPhysicalTexturesDim : SHADER_PERMUTATION_BOOL("TWO_PHYSICAL_TEXTURES");
|
|
class FOnePassProjectionDim : SHADER_PERMUTATION_BOOL("ONE_PASS_PROJECTION");
|
|
|
|
using FPermutationDomain = TShaderPermutationDomain<
|
|
FDirectionalLightDim,
|
|
FOnePassProjectionDim,
|
|
FSMRTAdaptiveRayCountDim,
|
|
FTwoPhysicalTexturesDim >;
|
|
|
|
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
|
|
SHADER_PARAMETER_STRUCT_INCLUDE(FVirtualShadowMapSamplingParameters, SamplingParameters)
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FSceneTextureUniformParameters, SceneTexturesStruct)
|
|
SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FHairStrandsViewUniformParameters, HairStrands)
|
|
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View)
|
|
SHADER_PARAMETER(FIntVector4, ProjectionRect)
|
|
SHADER_PARAMETER(float, ContactShadowLength)
|
|
SHADER_PARAMETER(float, NormalOffsetWorld)
|
|
SHADER_PARAMETER(uint32, SMRTRayCount)
|
|
SHADER_PARAMETER(uint32, SMRTSamplesPerRay)
|
|
SHADER_PARAMETER(float, SMRTRayLengthScale)
|
|
SHADER_PARAMETER(float, SMRTCotMaxRayAngleFromLight)
|
|
SHADER_PARAMETER(int32, DebugOutputType)
|
|
SHADER_PARAMETER(uint32, InputType)
|
|
// One pass projection parameters
|
|
SHADER_PARAMETER_STRUCT_REF(FForwardLightData, ForwardLightData)
|
|
SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer< uint >, VirtualShadowMapIdRemap) // TODO: Move to VSM UB?
|
|
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D< uint >, RWShadowMaskBits)
|
|
// Pass per light parameters
|
|
SHADER_PARAMETER_STRUCT(FLightShaderParameters, Light)
|
|
SHADER_PARAMETER(int32, LightUniformVirtualShadowMapId)
|
|
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D, RWSignal)
|
|
END_SHADER_PARAMETER_STRUCT()
|
|
|
|
static void ModifyCompilationEnvironment( const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment )
|
|
{
|
|
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
|
|
|
|
FVirtualShadowMapArray::SetShaderDefines(OutEnvironment);
|
|
FForwardLightingParameters::ModifyCompilationEnvironment(Parameters.Platform, OutEnvironment);
|
|
|
|
FPermutationDomain PermutationVector(Parameters.PermutationId);
|
|
|
|
if (PermutationVector.Get<FSMRTAdaptiveRayCountDim>())
|
|
{
|
|
OutEnvironment.CompilerFlags.Add(CFLAG_WaveOperations);
|
|
}
|
|
|
|
OutEnvironment.CompilerFlags.Add( CFLAG_Wave32 );
|
|
OutEnvironment.CompilerFlags.Add( CFLAG_AllowRealTypes );
|
|
}
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
FPermutationDomain PermutationVector(Parameters.PermutationId);
|
|
|
|
// Directional lights are always in separate passes as forward light data structure currently
|
|
// only contains a single single directional light.
|
|
if( PermutationVector.Get< FDirectionalLightDim >() && PermutationVector.Get< FOnePassProjectionDim >() )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return DoesPlatformSupportNanite(Parameters.Platform);
|
|
}
|
|
};
|
|
IMPLEMENT_GLOBAL_SHADER(FVirtualShadowMapProjectionCS, "/Engine/Private/VirtualShadowMaps/VirtualShadowMapProjection.usf", "VirtualShadowMapProjection", SF_Compute);
|
|
|
|
extern int32 GVirtualShadowMapAtomicWrites;
|
|
|
|
static void RenderVirtualShadowMapProjectionCommon(
|
|
FRDGBuilder& GraphBuilder,
|
|
const FMinimalSceneTextures& SceneTextures,
|
|
const FViewInfo& View,
|
|
FVirtualShadowMapArray& VirtualShadowMapArray,
|
|
const FIntRect ProjectionRect,
|
|
EVirtualShadowMapProjectionInputType InputType,
|
|
FRDGTextureRef OutputTexture,
|
|
const FLightSceneProxy* LightProxy = nullptr,
|
|
int32 VirtualShadowMapId = INDEX_NONE)
|
|
{
|
|
FVirtualShadowMapProjectionCS::FParameters* PassParameters = GraphBuilder.AllocParameters< FVirtualShadowMapProjectionCS::FParameters >();
|
|
PassParameters->SamplingParameters = VirtualShadowMapArray.GetSamplingParameters(GraphBuilder);
|
|
PassParameters->SceneTexturesStruct = SceneTextures.UniformBuffer;
|
|
PassParameters->View = View.ViewUniformBuffer;
|
|
PassParameters->ProjectionRect = FIntVector4(ProjectionRect.Min.X, ProjectionRect.Min.Y, ProjectionRect.Max.X, ProjectionRect.Max.Y);
|
|
PassParameters->DebugOutputType = CVarVirtualShadowMapDebugProjection.GetValueOnRenderThread();
|
|
PassParameters->ContactShadowLength = CVarContactShadowLength.GetValueOnRenderThread();
|
|
PassParameters->NormalOffsetWorld = CVarNormalOffsetWorld.GetValueOnRenderThread();
|
|
PassParameters->InputType = uint32(InputType);
|
|
PassParameters->HairStrands = HairStrands::BindHairStrandsViewUniformParameters(View);
|
|
|
|
bool bDirectionalLight = false;
|
|
bool bOnePassProjection = LightProxy == nullptr;
|
|
if (bOnePassProjection)
|
|
{
|
|
// One pass projection
|
|
PassParameters->ForwardLightData = View.ForwardLightingResources->ForwardLightDataUniformBuffer;
|
|
PassParameters->VirtualShadowMapIdRemap = GraphBuilder.CreateSRV( VirtualShadowMapArray.VirtualShadowMapIdRemapRDG[0] ); // FIXME Index proper view
|
|
PassParameters->RWShadowMaskBits = GraphBuilder.CreateUAV( OutputTexture );
|
|
}
|
|
else
|
|
{
|
|
// Pass per light
|
|
bDirectionalLight = LightProxy->GetLightType() == LightType_Directional;
|
|
FLightShaderParameters LightParameters;
|
|
LightProxy->GetLightShaderParameters(LightParameters);
|
|
PassParameters->Light = LightParameters;
|
|
PassParameters->LightUniformVirtualShadowMapId = VirtualShadowMapId;
|
|
PassParameters->RWSignal = GraphBuilder.CreateUAV( OutputTexture );
|
|
}
|
|
|
|
if (bDirectionalLight)
|
|
{
|
|
PassParameters->SMRTRayCount = CVarSMRTRayCountDirectional.GetValueOnRenderThread();
|
|
PassParameters->SMRTSamplesPerRay = CVarSMRTSamplesPerRayDirectional.GetValueOnRenderThread();
|
|
PassParameters->SMRTRayLengthScale = CVarSMRTRayLengthScaleDirectional.GetValueOnRenderThread();
|
|
PassParameters->SMRTCotMaxRayAngleFromLight = 0.0f; // unused in this path
|
|
}
|
|
else
|
|
{
|
|
PassParameters->SMRTRayCount = CVarSMRTRayCountLocal.GetValueOnRenderThread();
|
|
PassParameters->SMRTSamplesPerRay = CVarSMRTSamplesPerRayLocal.GetValueOnRenderThread();
|
|
PassParameters->SMRTRayLengthScale = 0.0f; // unused in this path
|
|
PassParameters->SMRTCotMaxRayAngleFromLight = 1.0f / FMath::Tan(CVarSMRTMaxRayAngleFromLight.GetValueOnRenderThread());
|
|
}
|
|
|
|
bool bAdaptiveRayCount = GRHISupportsWaveOperations && CVarSMRTAdaptiveRayCount.GetValueOnRenderThread() != 0;
|
|
|
|
FVirtualShadowMapProjectionCS::FPermutationDomain PermutationVector;
|
|
PermutationVector.Set< FVirtualShadowMapProjectionCS::FDirectionalLightDim >( bDirectionalLight );
|
|
PermutationVector.Set< FVirtualShadowMapProjectionCS::FOnePassProjectionDim >( bOnePassProjection );
|
|
PermutationVector.Set< FVirtualShadowMapProjectionCS::FSMRTAdaptiveRayCountDim >( bAdaptiveRayCount );
|
|
PermutationVector.Set< FVirtualShadowMapProjectionCS::FTwoPhysicalTexturesDim >( GVirtualShadowMapAtomicWrites == 0 );
|
|
|
|
auto ComputeShader = View.ShaderMap->GetShader< FVirtualShadowMapProjectionCS >( PermutationVector );
|
|
ClearUnusedGraphResources( ComputeShader, PassParameters );
|
|
ValidateShaderParameters( ComputeShader, *PassParameters );
|
|
|
|
const FIntPoint GroupCount = FIntPoint::DivideAndRoundUp( ProjectionRect.Size(), 8 );
|
|
FComputeShaderUtils::AddPass(
|
|
GraphBuilder,
|
|
bAdaptiveRayCount ? RDG_EVENT_NAME("VirtualShadowMapProjection") : RDG_EVENT_NAME("VirtualShadowMapProjection_StaticRayCount"),
|
|
ComputeShader,
|
|
PassParameters,
|
|
FIntVector( GroupCount.X, GroupCount.Y, 1 )
|
|
);
|
|
}
|
|
|
|
FRDGTextureRef RenderVirtualShadowMapProjectionOnePass(
|
|
FRDGBuilder& GraphBuilder,
|
|
const FMinimalSceneTextures& SceneTextures,
|
|
const FViewInfo& View,
|
|
FVirtualShadowMapArray& VirtualShadowMapArray )
|
|
{
|
|
FIntRect ProjectionRect = View.ViewRect;
|
|
|
|
const FRDGTextureDesc ShadowMaskDesc = FRDGTextureDesc::Create2D(
|
|
SceneTextures.Config.Extent,
|
|
PF_R32_UINT,
|
|
FClearValueBinding::None,
|
|
TexCreate_ShaderResource | TexCreate_UAV );
|
|
|
|
FRDGTextureRef ShadowMaskBits = GraphBuilder.CreateTexture( ShadowMaskDesc, TEXT("ShadowMaskBits") );
|
|
|
|
RenderVirtualShadowMapProjectionCommon(
|
|
GraphBuilder,
|
|
SceneTextures,
|
|
View,
|
|
VirtualShadowMapArray,
|
|
ProjectionRect,
|
|
EVirtualShadowMapProjectionInputType::GBuffer, // TODO: Hair
|
|
ShadowMaskBits);
|
|
|
|
return ShadowMaskBits;
|
|
}
|
|
|
|
static FRDGTextureRef CreateSignalTexture(FRDGBuilder& GraphBuilder, FIntPoint Extent)
|
|
{
|
|
const FLinearColor ClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
|
|
|
FRDGTextureDesc Desc = FRDGTextureDesc::Create2D(
|
|
Extent,
|
|
PF_FloatRGBA,
|
|
FClearValueBinding(ClearColor),
|
|
TexCreate_ShaderResource | TexCreate_UAV);
|
|
|
|
FRDGTextureRef Texture = GraphBuilder.CreateTexture(Desc, TEXT("Shadow.Virtual.Signal"));
|
|
AddClearUAVPass(GraphBuilder, GraphBuilder.CreateUAV(Texture), ClearColor);
|
|
return Texture;
|
|
}
|
|
|
|
FRDGTextureRef RenderVirtualShadowMapProjection(
|
|
FRDGBuilder& GraphBuilder,
|
|
const FMinimalSceneTextures& SceneTextures,
|
|
const FViewInfo& View,
|
|
FVirtualShadowMapArray& VirtualShadowMapArray,
|
|
const FIntRect ScissorRect,
|
|
EVirtualShadowMapProjectionInputType InputType,
|
|
FProjectedShadowInfo* ShadowInfo)
|
|
{
|
|
FRDGTextureRef SignalTexture = CreateSignalTexture(GraphBuilder, SceneTextures.Config.Extent);
|
|
RenderVirtualShadowMapProjectionCommon(
|
|
GraphBuilder,
|
|
SceneTextures,
|
|
View,
|
|
VirtualShadowMapArray,
|
|
ScissorRect,
|
|
InputType,
|
|
SignalTexture,
|
|
ShadowInfo->GetLightSceneInfo().Proxy,
|
|
ShadowInfo->VirtualShadowMaps[0]->ID);
|
|
return SignalTexture;
|
|
}
|
|
|
|
FRDGTextureRef RenderVirtualShadowMapProjection(
|
|
FRDGBuilder& GraphBuilder,
|
|
const FMinimalSceneTextures& SceneTextures,
|
|
const FViewInfo& View,
|
|
FVirtualShadowMapArray& VirtualShadowMapArray,
|
|
const FIntRect ScissorRect,
|
|
EVirtualShadowMapProjectionInputType InputType,
|
|
const TSharedPtr<FVirtualShadowMapClipmap>& Clipmap)
|
|
{
|
|
FRDGTextureRef SignalTexture = CreateSignalTexture(GraphBuilder, SceneTextures.Config.Extent);
|
|
RenderVirtualShadowMapProjectionCommon(
|
|
GraphBuilder,
|
|
SceneTextures,
|
|
View,
|
|
VirtualShadowMapArray,
|
|
ScissorRect,
|
|
InputType,
|
|
SignalTexture,
|
|
Clipmap->GetLightSceneInfo().Proxy,
|
|
Clipmap->GetVirtualShadowMap()->ID);
|
|
return SignalTexture;
|
|
}
|