// Copyright Epic Games, Inc. All Rights Reserved. /*============================================================================= LightMapRendering.cpp: Light map rendering implementations. =============================================================================*/ #include "LightMapRendering.h" #include "LightMap.h" #include "ScenePrivate.h" #include "PrecomputedVolumetricLightmap.h" #include "RenderCore.h" #include "DataDrivenShaderPlatformInfo.h" IMPLEMENT_TYPE_LAYOUT(FUniformLightMapPolicyShaderParametersType); IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FIndirectLightingCacheUniformParameters, "IndirectLightingCache"); bool MobileUseCSMShaderBranch() { static const auto* CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.Mobile.UseCSMShaderBranch")); return (CVar && CVar->GetValueOnAnyThread() != 0); } // One of these per lightmap quality const TCHAR* GLightmapDefineName[2] = { TEXT("LQ_TEXTURE_LIGHTMAP"), TEXT("HQ_TEXTURE_LIGHTMAP") }; int32 GNumLightmapCoefficients[2] = { NUM_LQ_LIGHTMAP_COEF, NUM_HQ_LIGHTMAP_COEF }; void LightMapPolicyImpl::ModifyCompilationEnvironment(ELightmapQuality LightmapQuality, const FMaterialShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) { OutEnvironment.SetDefine(GLightmapDefineName[LightmapQuality], TEXT("1")); OutEnvironment.SetDefine(TEXT("NUM_LIGHTMAP_COEFFICIENTS"), GNumLightmapCoefficients[LightmapQuality]); const bool VirtualTextureLightmaps = UseVirtualTextureLightmap(Parameters.Platform); OutEnvironment.SetDefine(TEXT("LIGHTMAP_VT_ENABLED"), VirtualTextureLightmaps); } bool LightMapPolicyImpl::ShouldCompilePermutation(ELightmapQuality LightmapQuality, const FMeshMaterialShaderPermutationParameters& Parameters) { static const auto CVarProjectCanHaveLowQualityLightmaps = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.SupportLowQualityLightmaps")); static const auto CVarSupportAllShadersPermutations = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.SupportAllShaderPermutations")); const bool bForceAllPermutations = CVarSupportAllShadersPermutations && CVarSupportAllShadersPermutations->GetValueOnAnyThread() != 0; // if GEngine doesn't exist yet to have the project flag then we should be conservative and cache the LQ lightmap policy const bool bProjectCanHaveLowQualityLightmaps = bForceAllPermutations || (!CVarProjectCanHaveLowQualityLightmaps) || (CVarProjectCanHaveLowQualityLightmaps->GetValueOnAnyThread() != 0); const bool bShouldCacheQuality = (LightmapQuality != ELightmapQuality::LQ_LIGHTMAP) || bProjectCanHaveLowQualityLightmaps; // GetValueOnAnyThread() as it's possible that ShouldCache is called from rendering thread. That is to output some error message. return (Parameters.MaterialParameters.ShadingModels.IsLit()) && bShouldCacheQuality && Parameters.VertexFactoryType->SupportsStaticLighting() && IsStaticLightingAllowed() && (Parameters.MaterialParameters.bIsUsedWithStaticLighting || Parameters.MaterialParameters.bIsSpecialEngineMaterial); } void DistanceFieldShadowsAndLightMapPolicyImpl::ModifyCompilationEnvironment(ELightmapQuality LightmapQuality, const FMaterialShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) { OutEnvironment.SetDefine(TEXT("STATICLIGHTING_TEXTUREMASK"), 1); OutEnvironment.SetDefine(TEXT("STATICLIGHTING_SIGNEDDISTANCEFIELD"), 1); LightMapPolicyImpl::ModifyCompilationEnvironment(LightmapQuality, Parameters, OutEnvironment); } bool FDummyLightMapPolicy::ShouldCompilePermutation(const FMeshMaterialShaderPermutationParameters& Parameters) { return Parameters.MaterialParameters.ShadingModels.IsLit() && Parameters.VertexFactoryType->SupportsStaticLighting(); } bool FSelfShadowedTranslucencyPolicy::ShouldCompilePermutation(const FMeshMaterialShaderPermutationParameters& Parameters) { return Parameters.MaterialParameters.ShadingModels.IsLit() && IsTranslucentBlendMode(Parameters.MaterialParameters) && IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5); } void FSelfShadowedTranslucencyPolicy::ModifyCompilationEnvironment(const FMaterialShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) { OutEnvironment.SetDefine(TEXT("TRANSLUCENT_SELF_SHADOWING"), TEXT("1")); } FSelfShadowedTranslucencyPolicy::FSelfShadowedTranslucencyPolicy() { } void FSelfShadowedTranslucencyPolicy::GetVertexShaderBindings( const FPrimitiveSceneProxy* PrimitiveSceneProxy, const ElementDataType& ShaderElementData, const VertexParametersType* VertexShaderParameters, FMeshDrawSingleShaderBindings& ShaderBindings) { } void FSelfShadowedTranslucencyPolicy::GetPixelShaderBindings( const FPrimitiveSceneProxy* PrimitiveSceneProxy, const ElementDataType& ShaderElementData, const PixelParametersType* PixelShaderParameters, FMeshDrawSingleShaderBindings& ShaderBindings) { ShaderBindings.Add(PixelShaderParameters->TranslucentSelfShadowBufferParameter, ShaderElementData); } void FSelfShadowedTranslucencyPolicy::GetComputeShaderBindings( const FPrimitiveSceneProxy* PrimitiveSceneProxy, const ElementDataType& ShaderElementData, const ComputeParametersType* ComputeShaderParameters, FMeshDrawSingleShaderBindings& ShaderBindings) { ShaderBindings.Add(ComputeShaderParameters->TranslucentSelfShadowBufferParameter, ShaderElementData); } bool FPrecomputedVolumetricLightmapLightingPolicy::ShouldCompilePermutation(const FMeshMaterialShaderPermutationParameters& Parameters) { return Parameters.MaterialParameters.ShadingModels.IsLit() && IsStaticLightingAllowed(); } void FPrecomputedVolumetricLightmapLightingPolicy::ModifyCompilationEnvironment(const FMaterialShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) { OutEnvironment.SetDefine(TEXT("PRECOMPUTED_IRRADIANCE_VOLUME_LIGHTING"), TEXT("1")); } bool FCachedVolumeIndirectLightingPolicy::ShouldCompilePermutation(const FMeshMaterialShaderPermutationParameters& Parameters) { return Parameters.MaterialParameters.ShadingModels.IsLit() && !IsTranslucentBlendMode(Parameters.MaterialParameters) && IsStaticLightingAllowed() && IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5); } void FCachedVolumeIndirectLightingPolicy::ModifyCompilationEnvironment(const FMaterialShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) { OutEnvironment.SetDefine(TEXT("CACHED_VOLUME_INDIRECT_LIGHTING"), TEXT("1")); } bool FCachedPointIndirectLightingPolicy::ShouldCompilePermutation(const FMeshMaterialShaderPermutationParameters& Parameters) { return Parameters.MaterialParameters.ShadingModels.IsLit() && IsStaticLightingAllowed(); } void FCachedPointIndirectLightingPolicy::ModifyCompilationEnvironment(const FMaterialShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) { OutEnvironment.SetDefine(TEXT("CACHED_POINT_INDIRECT_LIGHTING"),TEXT("1")); } void FMobileDirectionalLightAndCSMPolicy::ModifyCompilationEnvironment(const FMaterialShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) { OutEnvironment.SetDefine(TEXT("DIRECTIONAL_LIGHT_CSM"), TEXT("1")); } bool FMobileDirectionalLightAndCSMPolicy::ShouldCompilePermutation(const FMeshMaterialShaderPermutationParameters& Parameters) { if (IsMobileDeferredShadingEnabled(Parameters.Platform) && !Parameters.MaterialParameters.ShadingModels.HasShadingModel(MSM_SingleLayerWater)) { return false; } if (!IsStaticLightingAllowed() && MobileUseCSMShaderBranch()) { // CSM will be handled by FNoLightMapPolicy with a branch inside shader return false; } return Parameters.MaterialParameters.ShadingModels.IsLit() && !IsTranslucentBlendMode(Parameters.MaterialParameters) && (!IsStaticLightingAllowed() || FReadOnlyCVARCache::MobileEnableStaticAndCSMShadowReceivers()); } bool FMobileDistanceFieldShadowsAndLQLightMapPolicy::ShouldCompilePermutation(const FMeshMaterialShaderPermutationParameters& Parameters) { static auto* CVarMobileAllowDistanceFieldShadows = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.Mobile.AllowDistanceFieldShadows")); const bool bMobileAllowDistanceFieldShadows = CVarMobileAllowDistanceFieldShadows->GetValueOnAnyThread() == 1; return bMobileAllowDistanceFieldShadows && !IsTranslucentBlendMode(Parameters.MaterialParameters) && Super::ShouldCompilePermutation(Parameters); } void FMobileDistanceFieldShadowsAndLQLightMapPolicy::ModifyCompilationEnvironment(const FMaterialShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) { Super::ModifyCompilationEnvironment(Parameters, OutEnvironment); } bool FMobileDistanceFieldShadowsLightMapAndCSMLightingPolicy::ShouldCompilePermutation(const FMeshMaterialShaderPermutationParameters& Parameters) { if (IsMobileDeferredShadingEnabled(Parameters.Platform)) { return false; } return FReadOnlyCVARCache::MobileEnableStaticAndCSMShadowReceivers() && Super::ShouldCompilePermutation(Parameters); } void FMobileDistanceFieldShadowsLightMapAndCSMLightingPolicy::ModifyCompilationEnvironment(const FMaterialShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) { OutEnvironment.SetDefine(TEXT("DIRECTIONAL_LIGHT_CSM"), TEXT("1")); Super::ModifyCompilationEnvironment(Parameters, OutEnvironment); } bool FMobileDirectionalLightCSMAndLightMapPolicy::ShouldCompilePermutation(const FMeshMaterialShaderPermutationParameters& Parameters) { if (IsMobileDeferredShadingEnabled(Parameters.Platform)) { return false; } return !IsTranslucentBlendMode(Parameters.MaterialParameters) && Super::ShouldCompilePermutation(Parameters); } void FMobileDirectionalLightCSMAndLightMapPolicy::ModifyCompilationEnvironment(const FMaterialShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) { OutEnvironment.SetDefine(TEXT("DIRECTIONAL_LIGHT_CSM"), TEXT("1")); Super::ModifyCompilationEnvironment(Parameters, OutEnvironment); } bool FMobileDirectionalLightAndSHIndirectPolicy::ShouldCompilePermutation(const FMeshMaterialShaderPermutationParameters& Parameters) { return IsStaticLightingAllowed() && Parameters.MaterialParameters.ShadingModels.IsLit() && FCachedPointIndirectLightingPolicy::ShouldCompilePermutation(Parameters); } void FMobileDirectionalLightAndSHIndirectPolicy::ModifyCompilationEnvironment(const FMaterialShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) { FCachedPointIndirectLightingPolicy::ModifyCompilationEnvironment(Parameters, OutEnvironment); } bool FMobileDirectionalLightCSMAndSHIndirectPolicy::ShouldCompilePermutation(const FMeshMaterialShaderPermutationParameters& Parameters) { if (IsMobileDeferredShadingEnabled(Parameters.Platform) && !Parameters.MaterialParameters.ShadingModels.HasShadingModel(MSM_SingleLayerWater)) { return false; } return FReadOnlyCVARCache::MobileEnableStaticAndCSMShadowReceivers() && !IsTranslucentBlendMode(Parameters.MaterialParameters) && Super::ShouldCompilePermutation(Parameters); } void FMobileDirectionalLightCSMAndSHIndirectPolicy::ModifyCompilationEnvironment(const FMaterialShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) { OutEnvironment.SetDefine(TEXT("DIRECTIONAL_LIGHT_CSM"), TEXT("1")); Super::ModifyCompilationEnvironment(Parameters, OutEnvironment); } bool FSelfShadowedCachedPointIndirectLightingPolicy::ShouldCompilePermutation(const FMeshMaterialShaderPermutationParameters& Parameters) { return Parameters.MaterialParameters.ShadingModels.IsLit() && IsTranslucentBlendMode(Parameters.MaterialParameters) && IsStaticLightingAllowed() && FSelfShadowedTranslucencyPolicy::ShouldCompilePermutation(Parameters); } void FSelfShadowedCachedPointIndirectLightingPolicy::ModifyCompilationEnvironment(const FMaterialShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) { OutEnvironment.SetDefine(TEXT("CACHED_POINT_INDIRECT_LIGHTING"),TEXT("1")); FSelfShadowedTranslucencyPolicy::ModifyCompilationEnvironment(Parameters, OutEnvironment); } void SetupLCIUniformBuffers(const FPrimitiveSceneProxy* PrimitiveSceneProxy, const FLightCacheInterface* LCI, FRHIUniformBuffer*& PrecomputedLightingBuffer, FRHIUniformBuffer*& LightmapResourceClusterBuffer, FRHIUniformBuffer*& IndirectLightingCacheBuffer) { if (LCI) { PrecomputedLightingBuffer = LCI->GetPrecomputedLightingBuffer(); } if (LCI && LCI->GetResourceCluster()) { check(LCI->GetResourceCluster()->UniformBuffer); LightmapResourceClusterBuffer = LCI->GetResourceCluster()->UniformBuffer; } if (!PrecomputedLightingBuffer) { PrecomputedLightingBuffer = GEmptyPrecomputedLightingUniformBuffer.GetUniformBufferRHI(); } if (!LightmapResourceClusterBuffer) { LightmapResourceClusterBuffer = GDefaultLightmapResourceClusterUniformBuffer.GetUniformBufferRHI(); } if (PrimitiveSceneProxy && PrimitiveSceneProxy->GetPrimitiveSceneInfo()) { IndirectLightingCacheBuffer = PrimitiveSceneProxy->GetPrimitiveSceneInfo()->IndirectLightingCacheUniformBuffer; } if (!IndirectLightingCacheBuffer) { IndirectLightingCacheBuffer = GEmptyIndirectLightingCacheUniformBuffer.GetUniformBufferRHI(); } } void FSelfShadowedCachedPointIndirectLightingPolicy::GetPixelShaderBindings( const FPrimitiveSceneProxy* PrimitiveSceneProxy, const ElementDataType& ShaderElementData, const PixelParametersType* PixelShaderParameters, FMeshDrawSingleShaderBindings& ShaderBindings) { FRHIUniformBuffer* PrecomputedLightingBuffer = nullptr; FRHIUniformBuffer* LightmapResourceClusterBuffer = nullptr; FRHIUniformBuffer* IndirectLightingCacheBuffer = nullptr; SetupLCIUniformBuffers(PrimitiveSceneProxy, ShaderElementData.LCI, PrecomputedLightingBuffer, LightmapResourceClusterBuffer, IndirectLightingCacheBuffer); ShaderBindings.Add(PixelShaderParameters->PrecomputedLightingBufferParameter, PrecomputedLightingBuffer); ShaderBindings.Add(PixelShaderParameters->IndirectLightingCacheParameter, IndirectLightingCacheBuffer); ShaderBindings.Add(PixelShaderParameters->LightmapResourceCluster, LightmapResourceClusterBuffer); FSelfShadowedTranslucencyPolicy::GetPixelShaderBindings(PrimitiveSceneProxy, ShaderElementData.SelfShadowTranslucencyUniformBuffer, PixelShaderParameters, ShaderBindings); } void FSelfShadowedCachedPointIndirectLightingPolicy::GetComputeShaderBindings( const FPrimitiveSceneProxy* PrimitiveSceneProxy, const ElementDataType& ShaderElementData, const ComputeParametersType* ComputeShaderParameters, FMeshDrawSingleShaderBindings& ShaderBindings) { FRHIUniformBuffer* PrecomputedLightingBuffer = nullptr; FRHIUniformBuffer* LightmapResourceClusterBuffer = nullptr; FRHIUniformBuffer* IndirectLightingCacheBuffer = nullptr; SetupLCIUniformBuffers(PrimitiveSceneProxy, ShaderElementData.LCI, PrecomputedLightingBuffer, LightmapResourceClusterBuffer, IndirectLightingCacheBuffer); ShaderBindings.Add(ComputeShaderParameters->PrecomputedLightingBufferParameter, PrecomputedLightingBuffer); ShaderBindings.Add(ComputeShaderParameters->IndirectLightingCacheParameter, IndirectLightingCacheBuffer); ShaderBindings.Add(ComputeShaderParameters->LightmapResourceCluster, LightmapResourceClusterBuffer); FSelfShadowedTranslucencyPolicy::GetComputeShaderBindings(PrimitiveSceneProxy, ShaderElementData.SelfShadowTranslucencyUniformBuffer, ComputeShaderParameters, ShaderBindings); } bool FSelfShadowedVolumetricLightmapPolicy::ShouldCompilePermutation(const FMeshMaterialShaderPermutationParameters& Parameters) { return Parameters.MaterialParameters.ShadingModels.IsLit() && IsTranslucentBlendMode(Parameters.MaterialParameters) && IsStaticLightingAllowed() && FSelfShadowedTranslucencyPolicy::ShouldCompilePermutation(Parameters); } void FSelfShadowedVolumetricLightmapPolicy::ModifyCompilationEnvironment(const FMaterialShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) { OutEnvironment.SetDefine(TEXT("PRECOMPUTED_IRRADIANCE_VOLUME_LIGHTING"), TEXT("1")); FSelfShadowedTranslucencyPolicy::ModifyCompilationEnvironment(Parameters, OutEnvironment); } /** Initialization constructor. */ FSelfShadowedVolumetricLightmapPolicy::FSelfShadowedVolumetricLightmapPolicy() {} void FSelfShadowedVolumetricLightmapPolicy::GetPixelShaderBindings( const FPrimitiveSceneProxy* PrimitiveSceneProxy, const ElementDataType& ShaderElementData, const PixelParametersType* PixelShaderParameters, FMeshDrawSingleShaderBindings& ShaderBindings) { FRHIUniformBuffer* PrecomputedLightingBuffer = nullptr; FRHIUniformBuffer* LightmapResourceClusterBuffer = nullptr; FRHIUniformBuffer* IndirectLightingCacheBuffer = nullptr; SetupLCIUniformBuffers(PrimitiveSceneProxy, ShaderElementData.LCI, PrecomputedLightingBuffer, LightmapResourceClusterBuffer, IndirectLightingCacheBuffer); ShaderBindings.Add(PixelShaderParameters->PrecomputedLightingBufferParameter, PrecomputedLightingBuffer); ShaderBindings.Add(PixelShaderParameters->IndirectLightingCacheParameter, IndirectLightingCacheBuffer); ShaderBindings.Add(PixelShaderParameters->LightmapResourceCluster, LightmapResourceClusterBuffer); FSelfShadowedTranslucencyPolicy::GetPixelShaderBindings(PrimitiveSceneProxy, ShaderElementData.SelfShadowTranslucencyUniformBuffer, PixelShaderParameters, ShaderBindings); } void FSelfShadowedVolumetricLightmapPolicy::GetComputeShaderBindings( const FPrimitiveSceneProxy* PrimitiveSceneProxy, const ElementDataType& ShaderElementData, const ComputeParametersType* ComputeShaderParameters, FMeshDrawSingleShaderBindings& ShaderBindings) { FRHIUniformBuffer* PrecomputedLightingBuffer = nullptr; FRHIUniformBuffer* LightmapResourceClusterBuffer = nullptr; FRHIUniformBuffer* IndirectLightingCacheBuffer = nullptr; SetupLCIUniformBuffers(PrimitiveSceneProxy, ShaderElementData.LCI, PrecomputedLightingBuffer, LightmapResourceClusterBuffer, IndirectLightingCacheBuffer); ShaderBindings.Add(ComputeShaderParameters->PrecomputedLightingBufferParameter, PrecomputedLightingBuffer); ShaderBindings.Add(ComputeShaderParameters->IndirectLightingCacheParameter, IndirectLightingCacheBuffer); ShaderBindings.Add(ComputeShaderParameters->LightmapResourceCluster, LightmapResourceClusterBuffer); FSelfShadowedTranslucencyPolicy::GetComputeShaderBindings(PrimitiveSceneProxy, ShaderElementData.SelfShadowTranslucencyUniformBuffer, ComputeShaderParameters, ShaderBindings); } bool FUniformLightMapPolicy::ShouldCompilePermutation(ELightMapPolicyType Policy, const FMeshMaterialShaderPermutationParameters& Parameters) { CA_SUPPRESS(6326); switch (Policy) { case LMP_NO_LIGHTMAP: return FNoLightMapPolicy::ShouldCompilePermutation(Parameters); case LMP_PRECOMPUTED_IRRADIANCE_VOLUME_INDIRECT_LIGHTING: return FPrecomputedVolumetricLightmapLightingPolicy::ShouldCompilePermutation(Parameters); case LMP_CACHED_VOLUME_INDIRECT_LIGHTING: return FCachedVolumeIndirectLightingPolicy::ShouldCompilePermutation(Parameters); case LMP_CACHED_POINT_INDIRECT_LIGHTING: return FCachedPointIndirectLightingPolicy::ShouldCompilePermutation(Parameters); case LMP_LQ_LIGHTMAP: return TLightMapPolicy::ShouldCompilePermutation(Parameters); case LMP_HQ_LIGHTMAP: return TLightMapPolicy::ShouldCompilePermutation(Parameters); case LMP_DISTANCE_FIELD_SHADOWS_AND_HQ_LIGHTMAP: return TDistanceFieldShadowsAndLightMapPolicy::ShouldCompilePermutation(Parameters); // Mobile specific case LMP_MOBILE_DISTANCE_FIELD_SHADOWS_AND_LQ_LIGHTMAP: return FMobileDistanceFieldShadowsAndLQLightMapPolicy::ShouldCompilePermutation(Parameters); case LMP_MOBILE_DISTANCE_FIELD_SHADOWS_LIGHTMAP_AND_CSM: return FMobileDistanceFieldShadowsLightMapAndCSMLightingPolicy::ShouldCompilePermutation(Parameters); case LMP_MOBILE_DIRECTIONAL_LIGHT_CSM_AND_LIGHTMAP: return FMobileDirectionalLightCSMAndLightMapPolicy::ShouldCompilePermutation(Parameters); case LMP_MOBILE_DIRECTIONAL_LIGHT_AND_SH_INDIRECT: return FMobileDirectionalLightAndSHIndirectPolicy::ShouldCompilePermutation(Parameters); case LMP_MOBILE_DIRECTIONAL_LIGHT_CSM_AND_SH_INDIRECT: return FMobileDirectionalLightCSMAndSHIndirectPolicy::ShouldCompilePermutation(Parameters); case LMP_MOBILE_DIRECTIONAL_LIGHT_CSM: return FMobileDirectionalLightAndCSMPolicy::ShouldCompilePermutation(Parameters); // LightMapDensity case LMP_DUMMY: return FDummyLightMapPolicy::ShouldCompilePermutation(Parameters); default: check(false); return false; }; } void FUniformLightMapPolicy::ModifyCompilationEnvironment(ELightMapPolicyType Policy, const FMaterialShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) { OutEnvironment.SetDefine(TEXT("MAX_NUM_LIGHTMAP_COEF"), MAX_NUM_LIGHTMAP_COEF); CA_SUPPRESS(6326); switch (Policy) { case LMP_NO_LIGHTMAP: FNoLightMapPolicy::ModifyCompilationEnvironment(Parameters, OutEnvironment); break; case LMP_PRECOMPUTED_IRRADIANCE_VOLUME_INDIRECT_LIGHTING: FPrecomputedVolumetricLightmapLightingPolicy::ModifyCompilationEnvironment(Parameters, OutEnvironment); break; case LMP_CACHED_VOLUME_INDIRECT_LIGHTING: FCachedVolumeIndirectLightingPolicy::ModifyCompilationEnvironment(Parameters, OutEnvironment); break; case LMP_CACHED_POINT_INDIRECT_LIGHTING: FCachedPointIndirectLightingPolicy::ModifyCompilationEnvironment(Parameters, OutEnvironment); break; case LMP_LQ_LIGHTMAP: TLightMapPolicy::ModifyCompilationEnvironment(Parameters, OutEnvironment); break; case LMP_HQ_LIGHTMAP: TLightMapPolicy::ModifyCompilationEnvironment(Parameters, OutEnvironment); break; case LMP_DISTANCE_FIELD_SHADOWS_AND_HQ_LIGHTMAP: TDistanceFieldShadowsAndLightMapPolicy::ModifyCompilationEnvironment(Parameters, OutEnvironment); break; // Mobile specific case LMP_MOBILE_DISTANCE_FIELD_SHADOWS_AND_LQ_LIGHTMAP: FMobileDistanceFieldShadowsAndLQLightMapPolicy::ModifyCompilationEnvironment(Parameters, OutEnvironment); break; case LMP_MOBILE_DISTANCE_FIELD_SHADOWS_LIGHTMAP_AND_CSM: FMobileDistanceFieldShadowsLightMapAndCSMLightingPolicy::ModifyCompilationEnvironment(Parameters, OutEnvironment); break; case LMP_MOBILE_DIRECTIONAL_LIGHT_CSM_AND_LIGHTMAP: FMobileDirectionalLightCSMAndLightMapPolicy::ModifyCompilationEnvironment(Parameters, OutEnvironment); break; case LMP_MOBILE_DIRECTIONAL_LIGHT_AND_SH_INDIRECT: FMobileDirectionalLightAndSHIndirectPolicy::ModifyCompilationEnvironment(Parameters, OutEnvironment); break; case LMP_MOBILE_DIRECTIONAL_LIGHT_CSM_AND_SH_INDIRECT: FMobileDirectionalLightCSMAndSHIndirectPolicy::ModifyCompilationEnvironment(Parameters, OutEnvironment); break; case LMP_MOBILE_DIRECTIONAL_LIGHT_CSM: FMobileDirectionalLightAndCSMPolicy::ModifyCompilationEnvironment(Parameters, OutEnvironment); break; // LightMapDensity case LMP_DUMMY: FDummyLightMapPolicy::ModifyCompilationEnvironment(Parameters, OutEnvironment); break; default: check(false); break; } } void FUniformLightMapPolicy::GetVertexShaderBindings( const FPrimitiveSceneProxy* PrimitiveSceneProxy, const ElementDataType& ShaderElementData, const VertexParametersType* VertexShaderParameters, FMeshDrawSingleShaderBindings& ShaderBindings) { FRHIUniformBuffer* PrecomputedLightingBuffer = nullptr; FRHIUniformBuffer* LightmapResourceClusterBuffer = nullptr; FRHIUniformBuffer* IndirectLightingCacheBuffer = nullptr; SetupLCIUniformBuffers(PrimitiveSceneProxy, ShaderElementData, PrecomputedLightingBuffer, LightmapResourceClusterBuffer, IndirectLightingCacheBuffer); ShaderBindings.Add(VertexShaderParameters->PrecomputedLightingBufferParameter, PrecomputedLightingBuffer); ShaderBindings.Add(VertexShaderParameters->IndirectLightingCacheParameter, IndirectLightingCacheBuffer); ShaderBindings.Add(VertexShaderParameters->LightmapResourceCluster, LightmapResourceClusterBuffer); } void FUniformLightMapPolicy::GetPixelShaderBindings( const FPrimitiveSceneProxy* PrimitiveSceneProxy, const ElementDataType& ShaderElementData, const PixelParametersType* PixelShaderParameters, FMeshDrawSingleShaderBindings& ShaderBindings) { FRHIUniformBuffer* PrecomputedLightingBuffer = nullptr; FRHIUniformBuffer* LightmapResourceClusterBuffer = nullptr; FRHIUniformBuffer* IndirectLightingCacheBuffer = nullptr; SetupLCIUniformBuffers(PrimitiveSceneProxy, ShaderElementData, PrecomputedLightingBuffer, LightmapResourceClusterBuffer, IndirectLightingCacheBuffer); ShaderBindings.Add(PixelShaderParameters->PrecomputedLightingBufferParameter, PrecomputedLightingBuffer); ShaderBindings.Add(PixelShaderParameters->IndirectLightingCacheParameter, IndirectLightingCacheBuffer); ShaderBindings.Add(PixelShaderParameters->LightmapResourceCluster, LightmapResourceClusterBuffer); } #if RHI_RAYTRACING void FUniformLightMapPolicy::GetRayHitGroupShaderBindings( const FPrimitiveSceneProxy* PrimitiveSceneProxy, const FLightCacheInterface* LCI, const RayHitGroupParametersType* RayHitGroupShaderParameters, FMeshDrawSingleShaderBindings& RayHitGroupBindings ) const { FRHIUniformBuffer* PrecomputedLightingBuffer = nullptr; FRHIUniformBuffer* LightmapResourceClusterBuffer = nullptr; FRHIUniformBuffer* IndirectLightingCacheBuffer = nullptr; SetupLCIUniformBuffers(PrimitiveSceneProxy, LCI, PrecomputedLightingBuffer, LightmapResourceClusterBuffer, IndirectLightingCacheBuffer); RayHitGroupBindings.Add(RayHitGroupShaderParameters->PrecomputedLightingBufferParameter, PrecomputedLightingBuffer); RayHitGroupBindings.Add(RayHitGroupShaderParameters->IndirectLightingCacheParameter, IndirectLightingCacheBuffer); RayHitGroupBindings.Add(RayHitGroupShaderParameters->LightmapResourceCluster, LightmapResourceClusterBuffer); } #endif void FUniformLightMapPolicy::GetComputeShaderBindings( const FPrimitiveSceneProxy* PrimitiveSceneProxy, const ElementDataType& ShaderElementData, const ComputeParametersType* ComputeShaderParameters, FMeshDrawSingleShaderBindings& ShaderBindings) { FRHIUniformBuffer* PrecomputedLightingBuffer = nullptr; FRHIUniformBuffer* LightmapResourceClusterBuffer = nullptr; FRHIUniformBuffer* IndirectLightingCacheBuffer = nullptr; SetupLCIUniformBuffers(PrimitiveSceneProxy, ShaderElementData, PrecomputedLightingBuffer, LightmapResourceClusterBuffer, IndirectLightingCacheBuffer); ShaderBindings.Add(ComputeShaderParameters->PrecomputedLightingBufferParameter, PrecomputedLightingBuffer); ShaderBindings.Add(ComputeShaderParameters->IndirectLightingCacheParameter, IndirectLightingCacheBuffer); ShaderBindings.Add(ComputeShaderParameters->LightmapResourceCluster, LightmapResourceClusterBuffer); } void InterpolateVolumetricLightmap( FVector LookupPosition, const FVolumetricLightmapSceneData& VolumetricLightmapSceneData, FVolumetricLightmapInterpolation& OutInterpolation) { SCOPE_CYCLE_COUNTER(STAT_InterpolateVolumetricLightmapOnCPU); checkSlow(VolumetricLightmapSceneData.HasData()); const FPrecomputedVolumetricLightmapData& GlobalVolumetricLightmapData = *VolumetricLightmapSceneData.GetLevelVolumetricLightmap()->Data; const FVector IndirectionDataSourceCoordinate = ComputeIndirectionCoordinate(LookupPosition, GlobalVolumetricLightmapData.GetBounds(), GlobalVolumetricLightmapData.IndirectionTextureDimensions); check(GlobalVolumetricLightmapData.IndirectionTexture.Data.Num() > 0); checkSlow(GPixelFormats[GlobalVolumetricLightmapData.IndirectionTexture.Format].BlockBytes == sizeof(uint8) * 4); const int32 NumIndirectionTexels = GlobalVolumetricLightmapData.IndirectionTextureDimensions.X * GlobalVolumetricLightmapData.IndirectionTextureDimensions.Y * GlobalVolumetricLightmapData.IndirectionTextureDimensions.Z; check(GlobalVolumetricLightmapData.IndirectionTexture.Data.Num() * GlobalVolumetricLightmapData.IndirectionTexture.Data.GetTypeSize() == NumIndirectionTexels * sizeof(uint8) * 4); FIntVector IndirectionBrickOffset; int32 IndirectionBrickSize; int32 SubLevelIndex; SampleIndirectionTextureWithSubLevel(IndirectionDataSourceCoordinate, GlobalVolumetricLightmapData.IndirectionTextureDimensions, GlobalVolumetricLightmapData.IndirectionTexture.Data.GetData(), GlobalVolumetricLightmapData.CPUSubLevelIndirectionTable, IndirectionBrickOffset, IndirectionBrickSize, SubLevelIndex); const FPrecomputedVolumetricLightmapData& VolumetricLightmapData = *GlobalVolumetricLightmapData.CPUSubLevelBrickDataList[SubLevelIndex]; const FVector BrickTextureCoordinate = ComputeBrickTextureCoordinate(IndirectionDataSourceCoordinate, IndirectionBrickOffset, IndirectionBrickSize, VolumetricLightmapData.BrickSize); const FVector AmbientVector = (FVector)FilteredVolumeLookup(BrickTextureCoordinate, VolumetricLightmapData.BrickDataDimensions, (const FFloat3Packed*)VolumetricLightmapData.BrickData.AmbientVector.Data.GetData()); auto ReadSHCoefficient = [&BrickTextureCoordinate, &VolumetricLightmapData, &AmbientVector](uint32 CoefficientIndex) { check(CoefficientIndex < UE_ARRAY_COUNT(VolumetricLightmapData.BrickData.SHCoefficients)); // Undo normalization done in FIrradianceBrickData::SetFromVolumeLightingSample const FLinearColor SHDenormalizationScales0( 0.488603f / 0.282095f, 0.488603f / 0.282095f, 0.488603f / 0.282095f, 1.092548f / 0.282095f); const FLinearColor SHDenormalizationScales1( 1.092548f / 0.282095f, 4.0f * 0.315392f / 0.282095f, 1.092548f / 0.282095f, 2.0f * 0.546274f / 0.282095f); FLinearColor SHCoefficientEncoded = FilteredVolumeLookup(BrickTextureCoordinate, VolumetricLightmapData.BrickDataDimensions, (const FColor*)VolumetricLightmapData.BrickData.SHCoefficients[CoefficientIndex].Data.GetData()); //Swap R and B channel because it was swapped at ImportVolumetricLightmap for changing format from BGRA to RGBA Swap(SHCoefficientEncoded.R, SHCoefficientEncoded.B); const FLinearColor& DenormalizationScales = ((CoefficientIndex & 1) == 0) ? SHDenormalizationScales0 : SHDenormalizationScales1; return FVector4f((SHCoefficientEncoded * 2.0f - FLinearColor(1.0f, 1.0f, 1.0f, 1.0f)) * AmbientVector[CoefficientIndex / 2] * DenormalizationScales); }; auto GetSHVector3 = [](float Ambient, const FVector4f& Coeffs0, const FVector4f& Coeffs1 ) { FSHVector3 Result; Result.V[0] = Ambient; FMemory::Memcpy(&Result.V[1], &Coeffs0, sizeof(Coeffs0)); FMemory::Memcpy(&Result.V[5], &Coeffs1, sizeof(Coeffs1)); return Result; }; FSHVectorRGB3 LQSH; LQSH.R = GetSHVector3(AmbientVector.X, ReadSHCoefficient(0), ReadSHCoefficient(1)); LQSH.G = GetSHVector3(AmbientVector.Y, ReadSHCoefficient(2), ReadSHCoefficient(3)); LQSH.B = GetSHVector3(AmbientVector.Z, ReadSHCoefficient(4), ReadSHCoefficient(5)); // Pack the 3rd order SH as the shader expects OutInterpolation.IndirectLightingSHCoefficients0[0] = FVector4f(LQSH.R.V[0], LQSH.R.V[1], LQSH.R.V[2], LQSH.R.V[3]) * INV_PI; OutInterpolation.IndirectLightingSHCoefficients0[1] = FVector4f(LQSH.G.V[0], LQSH.G.V[1], LQSH.G.V[2], LQSH.G.V[3]) * INV_PI; OutInterpolation.IndirectLightingSHCoefficients0[2] = FVector4f(LQSH.B.V[0], LQSH.B.V[1], LQSH.B.V[2], LQSH.B.V[3]) * INV_PI; OutInterpolation.IndirectLightingSHCoefficients1[0] = FVector4f(LQSH.R.V[4], LQSH.R.V[5], LQSH.R.V[6], LQSH.R.V[7]) * INV_PI; OutInterpolation.IndirectLightingSHCoefficients1[1] = FVector4f(LQSH.G.V[4], LQSH.G.V[5], LQSH.G.V[6], LQSH.G.V[7]) * INV_PI; OutInterpolation.IndirectLightingSHCoefficients1[2] = FVector4f(LQSH.B.V[4], LQSH.B.V[5], LQSH.B.V[6], LQSH.B.V[7]) * INV_PI; OutInterpolation.IndirectLightingSHCoefficients2 = FVector4f(LQSH.R.V[8], LQSH.G.V[8], LQSH.B.V[8], 0.0f) * INV_PI; //The IndirectLightingSHSingleCoefficient should be DotSH1(AmbientVector, CalcDiffuseTransferSH1(1)) / PI, and CalcDiffuseTransferSH1(1) / PI equals to 1 / (2 * sqrt(PI)) and FSHVector2::ConstantBasisIntegral is 2 * sqrt(PI) OutInterpolation.IndirectLightingSHSingleCoefficient = FVector4f(AmbientVector.X, AmbientVector.Y, AmbientVector.Z) / FSHVector2::ConstantBasisIntegral; if (VolumetricLightmapData.BrickData.SkyBentNormal.Data.Num() > 0) { const FLinearColor SkyBentNormalUnpacked = FilteredVolumeLookup(BrickTextureCoordinate, VolumetricLightmapData.BrickDataDimensions, (const FColor*)VolumetricLightmapData.BrickData.SkyBentNormal.Data.GetData()); const FVector SkyBentNormal(SkyBentNormalUnpacked.R, SkyBentNormalUnpacked.G, SkyBentNormalUnpacked.B); const float BentNormalLength = SkyBentNormal.Size(); OutInterpolation.PointSkyBentNormal = FVector4f((FVector3f)SkyBentNormal / FMath::Max(BentNormalLength, .0001f), BentNormalLength); //Swap X and Z channel because it was swapped at ImportVolumetricLightmap for changing format from BGRA to RGBA Swap(OutInterpolation.PointSkyBentNormal.X, OutInterpolation.PointSkyBentNormal.Z); } else { OutInterpolation.PointSkyBentNormal = FVector4f(0, 0, 1, 1); } const FLinearColor DirectionalLightShadowingUnpacked = FilteredVolumeLookup(BrickTextureCoordinate, VolumetricLightmapData.BrickDataDimensions, (const uint8*)VolumetricLightmapData.BrickData.DirectionalLightShadowing.Data.GetData()); OutInterpolation.DirectionalLightShadowing = DirectionalLightShadowingUnpacked.R; } void FEmptyPrecomputedLightingUniformBuffer::InitRHI(FRHICommandListBase& RHICmdList) { FPrecomputedLightingUniformParameters Parameters; GetPrecomputedLightingParameters(GMaxRHIFeatureLevel, Parameters, NULL); SetContentsNoUpdate(Parameters); Super::InitRHI(RHICmdList); } /** Global uniform buffer containing the default precomputed lighting data. */ TGlobalResource< FEmptyPrecomputedLightingUniformBuffer > GEmptyPrecomputedLightingUniformBuffer; void GetIndirectLightingCacheParameters( ERHIFeatureLevel::Type FeatureLevel, FIndirectLightingCacheUniformParameters& Parameters, const FIndirectLightingCache* LightingCache, const FIndirectLightingCacheAllocation* LightingAllocation, FVector VolumetricLightmapLookupPosition, uint32 SceneFrameNumber, FVolumetricLightmapSceneData* VolumetricLightmapSceneData ) { // FCachedVolumeIndirectLightingPolicy, FCachedPointIndirectLightingPolicy { if (VolumetricLightmapSceneData && VolumetricLightmapSceneData->HasData()) { FVolumetricLightmapInterpolation* Interpolation = VolumetricLightmapSceneData->CPUInterpolationCache.Find(VolumetricLightmapLookupPosition); if (!Interpolation) { Interpolation = &VolumetricLightmapSceneData->CPUInterpolationCache.Add(VolumetricLightmapLookupPosition); InterpolateVolumetricLightmap(VolumetricLightmapLookupPosition, *VolumetricLightmapSceneData, *Interpolation); } Interpolation->LastUsedSceneFrameNumber = SceneFrameNumber; Parameters.PointSkyBentNormal = Interpolation->PointSkyBentNormal; Parameters.DirectionalLightShadowing = Interpolation->DirectionalLightShadowing; for (int32 i = 0; i < 3; i++) { Parameters.IndirectLightingSHCoefficients0[i] = Interpolation->IndirectLightingSHCoefficients0[i]; Parameters.IndirectLightingSHCoefficients1[i] = Interpolation->IndirectLightingSHCoefficients1[i]; } Parameters.IndirectLightingSHCoefficients2 = Interpolation->IndirectLightingSHCoefficients2; Parameters.IndirectLightingSHSingleCoefficient = Interpolation->IndirectLightingSHSingleCoefficient; // Unused Parameters.IndirectLightingCachePrimitiveAdd = FVector3f::ZeroVector; Parameters.IndirectLightingCachePrimitiveScale = FVector3f::OneVector; Parameters.IndirectLightingCacheMinUV = FVector3f::ZeroVector; Parameters.IndirectLightingCacheMaxUV = FVector3f::OneVector; } else if (LightingAllocation) { Parameters.IndirectLightingCachePrimitiveAdd = (FVector3f)LightingAllocation->Add; Parameters.IndirectLightingCachePrimitiveScale = (FVector3f)LightingAllocation->Scale; Parameters.IndirectLightingCacheMinUV = (FVector3f)LightingAllocation->MinUV; Parameters.IndirectLightingCacheMaxUV = (FVector3f)LightingAllocation->MaxUV; Parameters.PointSkyBentNormal = LightingAllocation->CurrentSkyBentNormal; Parameters.DirectionalLightShadowing = LightingAllocation->CurrentDirectionalShadowing; for (uint32 i = 0; i < 3; ++i) // RGB { Parameters.IndirectLightingSHCoefficients0[i] = LightingAllocation->SingleSamplePacked0[i]; Parameters.IndirectLightingSHCoefficients1[i] = LightingAllocation->SingleSamplePacked1[i]; } Parameters.IndirectLightingSHCoefficients2 = LightingAllocation->SingleSamplePacked2; //The IndirectLightingSHSingleCoefficient should be DotSH1(LightingAllocation->SingleSamplePacked0[0], CalcDiffuseTransferSH1(1)) / PI, and CalcDiffuseTransferSH1(1) / PI equals to 1 / (2 * sqrt(PI)) and FSHVector2::ConstantBasisIntegral is 2 * sqrt(PI) Parameters.IndirectLightingSHSingleCoefficient = FVector4f(LightingAllocation->SingleSamplePacked0[0].X, LightingAllocation->SingleSamplePacked0[1].X, LightingAllocation->SingleSamplePacked0[2].X) / FSHVector2::ConstantBasisIntegral; } else { Parameters.IndirectLightingCachePrimitiveAdd = FVector3f::ZeroVector; Parameters.IndirectLightingCachePrimitiveScale = FVector3f::OneVector; Parameters.IndirectLightingCacheMinUV = FVector3f::ZeroVector; Parameters.IndirectLightingCacheMaxUV = FVector3f::OneVector; Parameters.PointSkyBentNormal = FVector4f(0, 0, 1, 1); Parameters.DirectionalLightShadowing = 1; for (uint32 i = 0; i < 3; ++i) // RGB { Parameters.IndirectLightingSHCoefficients0[i] = FVector4f(0, 0, 0, 0); Parameters.IndirectLightingSHCoefficients1[i] = FVector4f(0, 0, 0, 0); } Parameters.IndirectLightingSHCoefficients2 = FVector4f(0, 0, 0, 0); Parameters.IndirectLightingSHSingleCoefficient = FVector4f(0, 0, 0, 0); } // If we are using FCachedVolumeIndirectLightingPolicy then InitViews should have updated the lighting cache which would have initialized it // However the conditions for updating the lighting cache are complex and fail very occasionally in non-reproducible ways // Silently skipping setting the cache texture under failure for now if (FeatureLevel >= ERHIFeatureLevel::SM5 && LightingCache && LightingCache->IsInitialized() && RHISupportsVolumeTextureRendering(GetFeatureLevelShaderPlatform(FeatureLevel))) { Parameters.IndirectLightingCacheTexture0 = const_cast(LightingCache)->GetTexture0(); Parameters.IndirectLightingCacheTexture1 = const_cast(LightingCache)->GetTexture1(); Parameters.IndirectLightingCacheTexture2 = const_cast(LightingCache)->GetTexture2(); Parameters.IndirectLightingCacheTextureSampler0 = TStaticSamplerState::GetRHI(); Parameters.IndirectLightingCacheTextureSampler1 = TStaticSamplerState::GetRHI(); Parameters.IndirectLightingCacheTextureSampler2 = TStaticSamplerState::GetRHI(); } else { Parameters.IndirectLightingCacheTexture0 = GBlackVolumeTexture->TextureRHI; Parameters.IndirectLightingCacheTexture1 = GBlackVolumeTexture->TextureRHI; Parameters.IndirectLightingCacheTexture2 = GBlackVolumeTexture->TextureRHI; Parameters.IndirectLightingCacheTextureSampler0 = GBlackVolumeTexture->SamplerStateRHI; Parameters.IndirectLightingCacheTextureSampler1 = GBlackVolumeTexture->SamplerStateRHI; Parameters.IndirectLightingCacheTextureSampler2 = GBlackVolumeTexture->SamplerStateRHI; } } } void FEmptyIndirectLightingCacheUniformBuffer::InitRHI(FRHICommandListBase& RHICmdList) { FIndirectLightingCacheUniformParameters Parameters; GetIndirectLightingCacheParameters(GMaxRHIFeatureLevel, Parameters, nullptr, nullptr, FVector(0, 0, 0), 0, nullptr); SetContentsNoUpdate(Parameters); Super::InitRHI(RHICmdList); } /** */ TGlobalResource< FEmptyIndirectLightingCacheUniformBuffer > GEmptyIndirectLightingCacheUniformBuffer; bool FNoLightMapPolicy::ShouldCompilePermutation(const FMeshMaterialShaderPermutationParameters& Parameters) { return true; } void FNoLightMapPolicy::ModifyCompilationEnvironment(const FMaterialShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) { if (IsMobilePlatform(Parameters.Platform) && !IsStaticLightingAllowed() && MobileUseCSMShaderBranch()) { OutEnvironment.SetDefine(TEXT("DIRECTIONAL_LIGHT_CSM"), TEXT("1")); OutEnvironment.SetDefine(TEXT("MOBILE_USE_CSM_BRANCH"), TEXT("1")); } }