- D:\UnrealEngine426\Engine\Source\Runtime\Renderer\Private\DeferredShadingRenderer.cpp
- ?FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList) 中 RenderDeferredReflectionsAndSkyLighting();
- D:\UnrealEngine426\Engine\Source\Runtime\Renderer\Private\IndirectLightRendering.cpp
-
void FDeferredShadingSceneRenderer::RenderDeferredReflectionsAndSkyLighting(
FRDGBuilder& GraphBuilder,
TRDGUniformBufferRef<FSceneTextureUniformParameters> SceneTexturesUniformBuffer,
FRDGTextureMSAA SceneColorTexture,
FRDGTextureRef DynamicBentNormalAOTexture,
FRDGTextureRef VelocityTexture,
FHairStrandsRenderingData* HairDatas)
{
if (ViewFamily.EngineShowFlags.VisualizeLightCulling
|| ViewFamily.EngineShowFlags.RayTracingDebug
|| ViewFamily.EngineShowFlags.PathTracing
|| !ViewFamily.EngineShowFlags.Lighting)
{
return;
}
// If we're currently capturing a reflection capture, output SpecularColor * IndirectIrradiance for metals so they are not black in reflections,
// Since we don't have multiple bounce specular reflections
bool bReflectionCapture = false;
for (int32 ViewIndex = 0, Num = Views.Num(); ViewIndex < Num; ViewIndex++)
{
const FViewInfo& View = Views[ViewIndex];
bReflectionCapture = bReflectionCapture || View.bIsReflectionCapture;
}
if (bReflectionCapture)
{
// if we are rendering a reflection capture then we can skip this pass entirely (no reflection and no sky contribution evaluated in this pass)
return;
}
// The specular sky light contribution is also needed by RT Reflections as a fallback.
const bool bSkyLight = Scene->SkyLight
&& (Scene->SkyLight->ProcessedTexture || Scene->SkyLight->bRealTimeCaptureEnabled)
&& !Scene->SkyLight->bHasStaticLighting;
bool bDynamicSkyLight = ShouldRenderDeferredDynamicSkyLight(Scene, ViewFamily);
bool bApplySkyShadowing = false;
if (bDynamicSkyLight)
{
RDG_EVENT_SCOPE(GraphBuilder, "SkyLightDiffuse");
RDG_GPU_STAT_SCOPE(GraphBuilder, SkyLightDiffuse);
extern int32 GDistanceFieldAOApplyToStaticIndirect;
if (Scene->SkyLight->bCastShadows
&& !GDistanceFieldAOApplyToStaticIndirect
&& ShouldRenderDistanceFieldAO()
&& ShouldRenderDistanceFieldLighting()
&& ViewFamily.EngineShowFlags.AmbientOcclusion)
{
bApplySkyShadowing = true;
FDistanceFieldAOParameters Parameters(Scene->SkyLight->OcclusionMaxDistance, Scene->SkyLight->Contrast);
RenderDistanceFieldLighting(GraphBuilder, SceneTexturesUniformBuffer, Parameters, SceneColorTexture.Target, VelocityTexture, DynamicBentNormalAOTexture, false, false);
}
}
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(GraphBuilder.RHICmdList);
const bool bReflectionEnv = ShouldDoReflectionEnvironment();
FRDGTextureRef AmbientOcclusionTexture = GraphBuilder.RegisterExternalTexture(SceneContext.bScreenSpaceAOIsValid ? SceneContext.ScreenSpaceAO : GSystemTextures.WhiteDummy);
float DynamicBentNormalAO = 1.0f;
if (!DynamicBentNormalAOTexture)
{
DynamicBentNormalAOTexture = GraphBuilder.RegisterExternalTexture(GSystemTextures.WhiteDummy);
DynamicBentNormalAO = 0.0f;
}
FSceneTextureParameters SceneTextures = GetSceneTextureParameters(GraphBuilder);
uint32 ViewIndex = 0;
for (FViewInfo& View : Views)
{
const uint32 CurrentViewIndex = ViewIndex++;
const FRayTracingReflectionOptions RayTracingReflectionOptions = GetRayTracingReflectionOptions(View, *Scene);
const bool bScreenSpaceReflections = !RayTracingReflectionOptions.bEnabled && ShouldRenderScreenSpaceReflections(View);
const bool bComposePlanarReflections = !RayTracingReflectionOptions.bEnabled && HasDeferredPlanarReflections(View);
FRDGTextureRef ReflectionsColor = nullptr;
if (RayTracingReflectionOptions.bEnabled || bScreenSpaceReflections)
{
int32 DenoiserMode = GetReflectionsDenoiserMode();
bool bDenoise = false;
bool bTemporalFilter = false;
// Traces the reflections, either using screen space reflection, or ray tracing.
IScreenSpaceDenoiser::FReflectionsInputs DenoiserInputs;
IScreenSpaceDenoiser::FReflectionsRayTracingConfig DenoiserConfig;
if (RayTracingReflectionOptions.bEnabled)
{
RDG_EVENT_SCOPE(GraphBuilder, "RayTracingReflections");
RDG_GPU_STAT_SCOPE(GraphBuilder, RayTracingReflections);
bDenoise = DenoiserMode != 0;
DenoiserConfig.ResolutionFraction = RayTracingReflectionOptions.ResolutionFraction;
DenoiserConfig.RayCountPerPixel = RayTracingReflectionOptions.SamplesPerPixel;
check(RayTracingReflectionOptions.bReflectOnlyWater == false);
RenderRayTracingReflections(
GraphBuilder,
SceneTextures,
View,
DenoiserMode,
RayTracingReflectionOptions,
&DenoiserInputs);
}
else if (bScreenSpaceReflections)
{
bDenoise = DenoiserMode != 0 && CVarDenoiseSSR.GetValueOnRenderThread();
bTemporalFilter = !bDenoise && View.ViewState && IsSSRTemporalPassRequired(View);
ESSRQuality SSRQuality;
GetSSRQualityForView(View, &SSRQuality, &DenoiserConfig);
RDG_EVENT_SCOPE(GraphBuilder, "ScreenSpaceReflections(Quality=%d)", int32(SSRQuality));
RenderScreenSpaceReflections(
GraphBuilder, SceneTextures, SceneColorTexture.Resolve, View, SSRQuality, bDenoise, &DenoiserInputs);
}
else
{
check(0);
}
if (bDenoise)
{
const IScreenSpaceDenoiser* DefaultDenoiser = IScreenSpaceDenoiser::GetDefaultDenoiser();
const IScreenSpaceDenoiser* DenoiserToUse = DenoiserMode == 1 ? DefaultDenoiser : GScreenSpaceDenoiser;
// Standard event scope for denoiser to have all profiling information not matter what, and with explicit detection of third party.
RDG_EVENT_SCOPE(GraphBuilder, "%s%s(Reflections) %dx%d",
DenoiserToUse != DefaultDenoiser ? TEXT("ThirdParty ") : TEXT(""),
DenoiserToUse->GetDebugName(),
View.ViewRect.Width(), View.ViewRect.Height());
IScreenSpaceDenoiser::FReflectionsOutputs DenoiserOutputs = DenoiserToUse->DenoiseReflections(
GraphBuilder,
View,
&View.PrevViewInfo,
SceneTextures,
DenoiserInputs,
DenoiserConfig);
ReflectionsColor = DenoiserOutputs.Color;
}
else if (bTemporalFilter)
{
check(View.ViewState);
FTAAPassParameters TAASettings(View);
TAASettings.Pass = ETAAPassConfig::ScreenSpaceReflections;
TAASettings.SceneDepthTexture = SceneTextures.SceneDepthTexture;
TAASettings.SceneVelocityTexture = SceneTextures.GBufferVelocityTexture;
TAASettings.SceneColorInput = DenoiserInputs.Color;
TAASettings.bOutputRenderTargetable = bComposePlanarReflections;
FTAAOutputs TAAOutputs = AddTemporalAAPass(
GraphBuilder,
View,
TAASettings,
View.PrevViewInfo.SSRHistory,
&View.ViewState->PrevFrameViewInfo.SSRHistory);
ReflectionsColor = TAAOutputs.SceneColor;
}
else
{
if (RayTracingReflectionOptions.bEnabled && DenoiserInputs.RayHitDistance)
{
// The performance of ray tracing does not allow to run without a denoiser in real time.
// Multiple rays per pixel is unsupported by the denoiser that will most likely more bound by to
// many rays than exporting the hit distance buffer. Therefore no permutation of the ray generation
// shader has been judged required to be supported.
GraphBuilder.RemoveUnusedTextureWarning(DenoiserInputs.RayHitDistance);
}
ReflectionsColor = DenoiserInputs.Color;
}
} // if (RayTracingReflectionOptions.bEnabled || bScreenSpaceReflections)
if (bComposePlanarReflections)
{
check(!RayTracingReflectionOptions.bEnabled);
RenderDeferredPlanarReflections(GraphBuilder, SceneTextures, View, /* inout */ ReflectionsColor);
}
bool bRequiresApply = ReflectionsColor != nullptr || bSkyLight || bDynamicSkyLight || bReflectionEnv;
if (bRequiresApply)
{
RDG_GPU_STAT_SCOPE(GraphBuilder, ReflectionEnvironment);
// Render the reflection environment with tiled deferred culling
bool bHasBoxCaptures = (View.NumBoxReflectionCaptures > 0);
bool bHasSphereCaptures = (View.NumSphereReflectionCaptures > 0);
FReflectionEnvironmentSkyLightingPS::FParameters* PassParameters = GraphBuilder.AllocParameters<FReflectionEnvironmentSkyLightingPS::FParameters>();
// Setup the parameters of the shader.
{
// Setups all shader parameters related to skylight.
{
FSkyLightSceneProxy* SkyLight = Scene->SkyLight;
float SkyLightContrast = 0.01f;
float SkyLightOcclusionExponent = 1.0f;
FVector4 SkyLightOcclusionTintAndMinOcclusion(0.0f, 0.0f, 0.0f, 0.0f);
EOcclusionCombineMode SkyLightOcclusionCombineMode = EOcclusionCombineMode::OCM_MAX;
if (SkyLight)
{
FDistanceFieldAOParameters Parameters(SkyLight->OcclusionMaxDistance, SkyLight->Contrast);
SkyLightContrast = Parameters.Contrast;
SkyLightOcclusionExponent = SkyLight->OcclusionExponent;
SkyLightOcclusionTintAndMinOcclusion = FVector4(SkyLight->OcclusionTint);
SkyLightOcclusionTintAndMinOcclusion.W = SkyLight->MinOcclusion;
SkyLightOcclusionCombineMode = SkyLight->OcclusionCombineMode;
}
// Scale and bias to remap the contrast curve to [0,1]
const float Min = 1 / (1 + FMath::Exp(-SkyLightContrast * (0 * 10 - 5)));
const float Max = 1 / (1 + FMath::Exp(-SkyLightContrast * (1 * 10 - 5)));
const float Mul = 1.0f / (Max - Min);
const float Add = -Min / (Max - Min);
PassParameters->OcclusionTintAndMinOcclusion = SkyLightOcclusionTintAndMinOcclusion;
PassParameters->ContrastAndNormalizeMulAdd = FVector(SkyLightContrast, Mul, Add);
PassParameters->OcclusionExponent = SkyLightOcclusionExponent;
PassParameters->OcclusionCombineMode = SkyLightOcclusionCombineMode == OCM_Minimum ? 0.0f : 1.0f;
PassParameters->ApplyBentNormalAO = DynamicBentNormalAO;
PassParameters->InvSkySpecularOcclusionStrength = 1.0f / FMath::Max(CVarSkySpecularOcclusionStrength.GetValueOnRenderThread(), 0.1f);
}
// Setups all shader parameters related to distance field AO
{
FIntPoint AOBufferSize = GetBufferSizeForAO();
PassParameters->AOBufferBilinearUVMax = FVector2D(
(View.ViewRect.Width() / GAODownsampleFactor - 0.51f) / AOBufferSize.X, // 0.51 - so bilateral gather4 won't sample invalid texels
(View.ViewRect.Height() / GAODownsampleFactor - 0.51f) / AOBufferSize.Y);
extern float GAOViewFadeDistanceScale;
PassParameters->AOMaxViewDistance = GetMaxAOViewDistance();
PassParameters->DistanceFadeScale = 1.0f / ((1.0f - GAOViewFadeDistanceScale) * GetMaxAOViewDistance());
PassParameters->BentNormalAOTexture = DynamicBentNormalAOTexture;
PassParameters->BentNormalAOSampler = TStaticSamplerState<SF_Bilinear>::GetRHI();
}
PassParameters->AmbientOcclusionTexture = AmbientOcclusionTexture;
PassParameters->AmbientOcclusionSampler = TStaticSamplerState<SF_Point>::GetRHI();
PassParameters->ScreenSpaceReflectionsTexture = ReflectionsColor ? ReflectionsColor : GraphBuilder.RegisterExternalTexture(GSystemTextures.BlackDummy);
PassParameters->ScreenSpaceReflectionsSampler = TStaticSamplerState<SF_Point>::GetRHI();
if (Scene->HasVolumetricCloud())
{
FVolumetricCloudRenderSceneInfo* CloudInfo = Scene->GetVolumetricCloudSceneInfo();
PassParameters->CloudSkyAOTexture = GraphBuilder.RegisterExternalTexture(View.VolumetricCloudSkyAO.IsValid() ? View.VolumetricCloudSkyAO : GSystemTextures.BlackDummy);
PassParameters->CloudSkyAOWorldToLightClipMatrix = CloudInfo->GetVolumetricCloudCommonShaderParameters().CloudSkyAOWorldToLightClipMatrix;
PassParameters->CloudSkyAOFarDepthKm = CloudInfo->GetVolumetricCloudCommonShaderParameters().CloudSkyAOFarDepthKm;
PassParameters->CloudSkyAOEnabled = 1;
}
else
{
PassParameters->CloudSkyAOTexture = GraphBuilder.RegisterExternalTexture(GSystemTextures.BlackDummy);
PassParameters->CloudSkyAOEnabled = 0;
}
PassParameters->CloudSkyAOSampler = TStaticSamplerState<SF_Bilinear>::GetRHI();
PassParameters->PreIntegratedGF = GSystemTextures.PreintegratedGF->GetRenderTargetItem().ShaderResourceTexture;
PassParameters->PreIntegratedGFSampler = TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI();
PassParameters->SceneTextures = SceneTextures;
PassParameters->ViewUniformBuffer = View.ViewUniformBuffer;
PassParameters->ReflectionCaptureData = View.ReflectionCaptureUniformBuffer;
{
FReflectionUniformParameters ReflectionUniformParameters;
SetupReflectionUniformParameters(View, ReflectionUniformParameters);
PassParameters->ReflectionsParameters = CreateUniformBufferImmediate(ReflectionUniformParameters, UniformBuffer_SingleDraw);
}
PassParameters->ForwardLightData = View.ForwardLightingResources->ForwardLightDataUniformBuffer;
}
PassParameters->RenderTargets[0] = FRenderTargetBinding(SceneColorTexture.Target, ERenderTargetLoadAction::ELoad);
// Bind hair data
const bool bCheckerboardSubsurfaceRendering = IsSubsurfaceCheckerboardFormat(SceneColorTexture.Target->Desc.Format);
// ScreenSpace and SortedDeferred ray traced reflections use the same reflection environment shader,
// but main RT reflection shader requires a custom path as it evaluates the clear coat BRDF differently.
const bool bRequiresSpecializedReflectionEnvironmentShader = RayTracingReflectionOptions.bEnabled
&& RayTracingReflectionOptions.Algorithm != FRayTracingReflectionOptions::EAlgorithm::SortedDeferred;
auto PermutationVector = FReflectionEnvironmentSkyLightingPS::BuildPermutationVector(
View, bHasBoxCaptures, bHasSphereCaptures, DynamicBentNormalAO != 0.0f,
bSkyLight, bDynamicSkyLight, bApplySkyShadowing,
bRequiresSpecializedReflectionEnvironmentShader);
TShaderMapRef<FReflectionEnvironmentSkyLightingPS> PixelShader(View.ShaderMap, PermutationVector);
ClearUnusedGraphResources(PixelShader, PassParameters);
GraphBuilder.AddPass(
RDG_EVENT_NAME("ReflectionEnvironmentAndSky %dx%d", View.ViewRect.Width(), View.ViewRect.Height()),
PassParameters,
ERDGPassFlags::Raster,
[PassParameters, &View, PixelShader, bCheckerboardSubsurfaceRendering](FRHICommandList& InRHICmdList)
{
InRHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f);
FGraphicsPipelineStateInitializer GraphicsPSOInit;
FPixelShaderUtils::InitFullscreenPipelineState(InRHICmdList, View.ShaderMap, PixelShader, GraphicsPSOInit);
extern int32 GAOOverwriteSceneColor;
if (GetReflectionEnvironmentCVar() == 2 || GAOOverwriteSceneColor)
{
// override scene color for debugging
GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI();
}
else
{
if (bCheckerboardSubsurfaceRendering)
{
GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGB, BO_Add, BF_One, BF_One>::GetRHI();
}
else
{
GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGBA, BO_Add, BF_One, BF_One, BO_Add, BF_One, BF_One>::GetRHI();
}
}
SetGraphicsPipelineState(InRHICmdList, GraphicsPSOInit);
SetShaderParameters(InRHICmdList, PixelShader, PixelShader.GetPixelShader(), *PassParameters);
FPixelShaderUtils::DrawFullscreenTriangle(InRHICmdList);
});
}
const bool bIsHairSkyLightingEnabled = HairDatas && (bSkyLight || bDynamicSkyLight || bReflectionEnv);
if (bIsHairSkyLightingEnabled)
{
RDG_GPU_STAT_SCOPE(GraphBuilder, HairSkyLighting);
RenderHairStrandsEnvironmentLighting(GraphBuilder, Scene, CurrentViewIndex, Views, HairDatas);
}
}
AddResolveSceneColorPass(GraphBuilder, Views, SceneColorTexture);
} -
/** Pixel shader that does tiled deferred culling of reflection captures, then sorts and composites them. */
class FReflectionEnvironmentSkyLightingPS : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FReflectionEnvironmentSkyLightingPS);
SHADER_USE_PARAMETER_STRUCT(FReflectionEnvironmentSkyLightingPS, FGlobalShader)
class FHasBoxCaptures : SHADER_PERMUTATION_BOOL("REFLECTION_COMPOSITE_HAS_BOX_CAPTURES");
class FHasSphereCaptures : SHADER_PERMUTATION_BOOL("REFLECTION_COMPOSITE_HAS_SPHERE_CAPTURES");
class FDFAOIndirectOcclusion : SHADER_PERMUTATION_BOOL("SUPPORT_DFAO_INDIRECT_OCCLUSION");
class FSkyLight : SHADER_PERMUTATION_BOOL("ENABLE_SKY_LIGHT");
class FDynamicSkyLight : SHADER_PERMUTATION_BOOL("ENABLE_DYNAMIC_SKY_LIGHT");
class FSkyShadowing : SHADER_PERMUTATION_BOOL("APPLY_SKY_SHADOWING");
class FRayTracedReflections : SHADER_PERMUTATION_BOOL("RAY_TRACED_REFLECTIONS");
using FPermutationDomain = TShaderPermutationDomain<
FHasBoxCaptures,
FHasSphereCaptures,
FDFAOIndirectOcclusion,
FSkyLight,
FDynamicSkyLight,
FSkyShadowing,
FRayTracedReflections>;
static FPermutationDomain RemapPermutation(FPermutationDomain PermutationVector)
{
// FSkyLightingDynamicSkyLight requires FSkyLightingSkyLight.
if (!PermutationVector.Get<FSkyLight>())
{
PermutationVector.Set<FDynamicSkyLight>(false);
}
// FSkyLightingSkyShadowing requires FSkyLightingDynamicSkyLight.
if (!PermutationVector.Get<FDynamicSkyLight>())
{
PermutationVector.Set<FSkyShadowing>(false);
}
return PermutationVector;
}
static FPermutationDomain BuildPermutationVector(const FViewInfo& View, bool bBoxCapturesOnly, bool bSphereCapturesOnly, bool bSupportDFAOIndirectOcclusion, bool bEnableSkyLight, bool bEnableDynamicSkyLight, bool bApplySkyShadowing, bool bRayTracedReflections)
{
FPermutationDomain PermutationVector;
PermutationVector.Set<FHasBoxCaptures>(bBoxCapturesOnly);
PermutationVector.Set<FHasSphereCaptures>(bSphereCapturesOnly);
PermutationVector.Set<FDFAOIndirectOcclusion>(bSupportDFAOIndirectOcclusion);
PermutationVector.Set<FSkyLight>(bEnableSkyLight);
PermutationVector.Set<FDynamicSkyLight>(bEnableDynamicSkyLight);
PermutationVector.Set<FSkyShadowing>(bApplySkyShadowing);
PermutationVector.Set<FRayTracedReflections>(bRayTracedReflections);
return RemapPermutation(PermutationVector);
}
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
if (!IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5))
{
return false;
}
FPermutationDomain PermutationVector(Parameters.PermutationId);
return PermutationVector == RemapPermutation(PermutationVector);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
{
FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);
OutEnvironment.SetDefine(TEXT("MAX_CAPTURES"), GMaxNumReflectionCaptures);
OutEnvironment.CompilerFlags.Add(CFLAG_StandardOptimization);
FForwardLightingParameters::ModifyCompilationEnvironment(Parameters.Platform, OutEnvironment);
}
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
// Sky light parameters.
SHADER_PARAMETER(FVector4, OcclusionTintAndMinOcclusion)
SHADER_PARAMETER(FVector, ContrastAndNormalizeMulAdd)
SHADER_PARAMETER(float, ApplyBentNormalAO)
SHADER_PARAMETER(float, InvSkySpecularOcclusionStrength)
SHADER_PARAMETER(float, OcclusionExponent)
SHADER_PARAMETER(float, OcclusionCombineMode)
// Distance field AO parameters.
// TODO. FDFAOUpsampleParameters
SHADER_PARAMETER(FVector2D, AOBufferBilinearUVMax)
SHADER_PARAMETER(float, DistanceFadeScale)
SHADER_PARAMETER(float, AOMaxViewDistance)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, BentNormalAOTexture)
SHADER_PARAMETER_SAMPLER(SamplerState, BentNormalAOSampler)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, AmbientOcclusionTexture)
SHADER_PARAMETER_SAMPLER(SamplerState, AmbientOcclusionSampler)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D, ScreenSpaceReflectionsTexture)
SHADER_PARAMETER_SAMPLER(SamplerState, ScreenSpaceReflectionsSampler)
SHADER_PARAMETER_TEXTURE(Texture2D, PreIntegratedGF)
SHADER_PARAMETER_SAMPLER(SamplerState, PreIntegratedGFSampler)
SHADER_PARAMETER_RDG_TEXTURE(Texture2D<float2>, CloudSkyAOTexture)
SHADER_PARAMETER_SAMPLER(SamplerState, CloudSkyAOSampler)
SHADER_PARAMETER(FMatrix, CloudSkyAOWorldToLightClipMatrix)
SHADER_PARAMETER(float, CloudSkyAOFarDepthKm)
SHADER_PARAMETER(int32, CloudSkyAOEnabled)
SHADER_PARAMETER_STRUCT_INCLUDE(FSceneTextureParameters, SceneTextures)
SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, ViewUniformBuffer)
SHADER_PARAMETER_STRUCT_REF(FReflectionUniformParameters, ReflectionsParameters)
SHADER_PARAMETER_STRUCT_REF(FReflectionCaptureShaderData, ReflectionCaptureData)
SHADER_PARAMETER_STRUCT_REF(FForwardLightData, ForwardLightData)
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
}; // FReflectionEnvironmentSkyLightingPS
IMPLEMENT_GLOBAL_SHADER(FDiffuseIndirectCompositePS, "/Engine/Private/DiffuseIndirectComposite.usf", "MainPS", SF_Pixel);
IMPLEMENT_GLOBAL_SHADER(FAmbientCubemapCompositePS, "/Engine/Private/AmbientCubemapComposite.usf", "MainPS", SF_Pixel);
IMPLEMENT_GLOBAL_SHADER(FReflectionEnvironmentSkyLightingPS, "/Engine/Private/ReflectionEnvironmentPixelShader.usf", "ReflectionEnvironmentSkyLighting", SF_Pixel);
IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FReflectionUniformParameters, "ReflectionStruct");
BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT(FReflectionUniformParameters,)
SHADER_PARAMETER(FVector4, SkyLightParameters)
SHADER_PARAMETER(float, SkyLightCubemapBrightness)
SHADER_PARAMETER_TEXTURE(TextureCube, SkyLightCubemap)
SHADER_PARAMETER_SAMPLER(SamplerState, SkyLightCubemapSampler)
SHADER_PARAMETER_TEXTURE(TextureCube, SkyLightBlendDestinationCubemap)
SHADER_PARAMETER_SAMPLER(SamplerState, SkyLightBlendDestinationCubemapSampler)
SHADER_PARAMETER_TEXTURE(TextureCubeArray, ReflectionCubemap)
SHADER_PARAMETER_SAMPLER(SamplerState, ReflectionCubemapSampler)
SHADER_PARAMETER_TEXTURE(Texture2D, PreIntegratedGF)
SHADER_PARAMETER_SAMPLER(SamplerState, PreIntegratedGFSampler)
END_GLOBAL_SHADER_PARAMETER_STRUCT()
- ??D:\UnrealEngine426\Engine\Shaders\Private\ReflectionEnvironmentPixelShader.usf
-
void ReflectionEnvironmentSkyLighting(
in float4 SvPosition : SV_Position,
out float4 OutColor : SV_Target0)
{
float2 BufferUV = SvPositionToBufferUV(SvPosition);
float2 ScreenPosition = SvPositionToScreenPosition(SvPosition).xy;
// Sample scene textures.
FGBufferData GBuffer = GetGBufferDataFromSceneTextures(BufferUV);
float3 DiffuseColor = GBuffer.DiffuseColor;
float3 SpecularColor = GBuffer.SpecularColor;
RemapClearCoatDiffuseAndSpecularColor(GBuffer, ScreenPosition, DiffuseColor, SpecularColor);
// Sample the ambient occlusion that is dynamically generated every frame.
float AmbientOcclusion = AmbientOcclusionTexture.SampleLevel(AmbientOcclusionSampler, BufferUV, 0).r;
uint ShadingModelID = GBuffer.ShadingModelID;
float3 BentNormal = GBuffer.WorldNormal;
#if APPLY_SKY_SHADOWING
{
BentNormal = UpsampleDFAO(BufferUV, GBuffer.Depth, GBuffer.WorldNormal);
}
#endif
OutColor = 0.0f;
#if ENABLE_DYNAMIC_SKY_LIGHT
BRANCH
// Only light pixels marked as lit
if (ShadingModelID != SHADINGMODELID_UNLIT)
{
float CloudAmbientOcclusion = 1.0f;
// Ideally we would compute spatially how much of the sky+cloud is visible for each point in the world. But we evaluate the sky light only once at the sky light component position as of today.
// To add some spatial variation, we can affect the sky light diffuse contribution according to cloud occlusion from above.
// This is an approximation because clouds are also occluding the sky in the sky light capture (a bit of a double contribution then). but it does help by adding spatially varying details.
#if 0 // DISABLED for now because it has artefact with specular not being affected (and thus looking too bright which can be confusing for users).
if (CloudSkyAOEnabled)
{
float3 WorldPosition = mul(float4(ScreenPosition * GBuffer.Depth, GBuffer.Depth, 1), View.ScreenToWorld).xyz;
float OutOpticalDepth = 0.0f;
CloudAmbientOcclusion = GetCloudVolumetricShadow(WorldPosition, CloudSkyAOWorldToLightClipMatrix, CloudSkyAOFarDepthKm, CloudSkyAOTexture, CloudSkyAOSampler, OutOpticalDepth);
}
#endif
float3 SkyLighting = SkyLightDiffuse(GBuffer, AmbientOcclusion, BufferUV, ScreenPosition, BentNormal, DiffuseColor) * CloudAmbientOcclusion;
// Scene color alpha is used for ScreenSpaceSubsurfaceScattering (if that is not needed it can be disabled with SUBSURFACE_CHANNEL_MODE)
FLightAccumulator LightAccumulator = (FLightAccumulator)0;
const bool bNeedsSeparateSubsurfaceLightAccumulation = UseSubsurfaceProfile(ShadingModelID);
LightAccumulator_Add(LightAccumulator, SkyLighting, SkyLighting, 1.0f, bNeedsSeparateSubsurfaceLightAccumulation);
OutColor = LightAccumulator_GetResult(LightAccumulator);
}
#endif
BRANCH
if (ShadingModelID != SHADINGMODELID_UNLIT && ShadingModelID != SHADINGMODELID_HAIR)
{
OutColor.xyz += ReflectionEnvironment(GBuffer, AmbientOcclusion, BufferUV, ScreenPosition, SvPosition, BentNormal, SpecularColor);
}
}
-
?D:\UnrealEngine426\Engine\Shaders\Private\ReflectionEnvironmentPixelShader.usf
-
float3 SkyLightDiffuse(FGBufferData GBuffer, float AmbientOcclusion, float2 BufferUV, float2 ScreenPosition, float3 BentNormal, float3 DiffuseColor)
{
float2 UV = BufferUV;
float3 Lighting = 0;
float SkyVisibility = 1;
float DotProductFactor = 1;
float3 SkyLightingNormal = GBuffer.WorldNormal;
BRANCH if( GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT && CLEAR_COAT_BOTTOM_NORMAL)
{
const float2 oct1 = ((float2(GBuffer.CustomData.a, GBuffer.CustomData.z) * 2) - (256.0/255.0)) + UnitVectorToOctahedron(GBuffer.WorldNormal);
SkyLightingNormal = OctahedronToUnitVector(oct1);
}
#if APPLY_SKY_SHADOWING
#define USE_DIRECTIONAL_OCCLUSION_ON_SKY_DIFFUSE 1
#if USE_DIRECTIONAL_OCCLUSION_ON_SKY_DIFFUSE
{
SkyVisibility = length(BentNormal);
float3 NormalizedBentNormal = BentNormal / (max(SkyVisibility, .00001f));
// Use more bent normal in corners
float BentNormalWeightFactor = SkyVisibility;
SkyLightingNormal = lerp(NormalizedBentNormal, GBuffer.WorldNormal, BentNormalWeightFactor);
DotProductFactor = lerp(dot(NormalizedBentNormal, GBuffer.WorldNormal), 1, BentNormalWeightFactor);
}
#else
{
SkyVisibility = length(BentNormal);
}
#endif
float ContrastCurve = 1 / (1 + exp(-ContrastAndNormalizeMulAdd.x * (SkyVisibility * 10 - 5)));
SkyVisibility = saturate(ContrastCurve * ContrastAndNormalizeMulAdd.y + ContrastAndNormalizeMulAdd.z);
#endif
// Apply DFAO controls
SkyVisibility = pow(SkyVisibility, OcclusionExponent);
SkyVisibility = lerp(SkyVisibility, 1, OcclusionTintAndMinOcclusion.w);
// Combine with other AO sources
if (OcclusionCombineMode == 0)
{
// Combine with min which nicely avoids over-occlusion in cases where strong DFAO is present along with strong SSAO (distant trees)
SkyVisibility = min(SkyVisibility, min(GBuffer.GBufferAO, AmbientOcclusion));
}
else
{
// Combine with mul, which continues to add SSAO depth even indoors. SSAO will need to be tweaked to be less strong.
SkyVisibility = SkyVisibility * min(GBuffer.GBufferAO, AmbientOcclusion);
}
float ScalarFactors = SkyVisibility;
BRANCH
if (GBuffer.ShadingModelID == SHADINGMODELID_TWOSIDED_FOLIAGE)
{
float3 SubsurfaceLookup = GetSkySHDiffuse(-GBuffer.WorldNormal) * View.SkyLightColor.rgb;
float3 SubsurfaceColor = ExtractSubsurfaceColor(GBuffer);
Lighting += ScalarFactors * SubsurfaceLookup * SubsurfaceColor;
}
if (GBuffer.ShadingModelID == SHADINGMODELID_SUBSURFACE || GBuffer.ShadingModelID == SHADINGMODELID_PREINTEGRATED_SKIN)
{
float3 SubsurfaceColor = ExtractSubsurfaceColor(GBuffer);
// Add subsurface energy to diffuse
DiffuseColor += SubsurfaceColor;
}
BRANCH
if (GBuffer.ShadingModelID == SHADINGMODELID_HAIR)
{
float3 N = GBuffer.WorldNormal;
float3 V = -normalize(mul(float4(ScreenPosition, 1, 0), View.ScreenToWorld).xyz);
float3 L = normalize(V - N * dot(V, N));
SkyLightingNormal = L;
FHairTransmittanceData TransmittanceData = InitHairTransmittanceData(true);
DiffuseColor = PI * HairShading(GBuffer, L, V, N, 1, TransmittanceData, 0, 0.2, uint2(0, 0));
}
if (GBuffer.ShadingModelID == SHADINGMODELID_CLOTH)
{
float3 ClothFuzz = ExtractSubsurfaceColor(GBuffer);
DiffuseColor += ClothFuzz * GBuffer.CustomData.a;
}
// Compute the preconvolved incoming lighting with the bent normal direction
float3 DiffuseLookup = GetSkySHDiffuse(SkyLightingNormal) * View.SkyLightColor.rgb;
// Apply AO to the sky diffuse and account for darkening due to the geometry term
// apply the Diffuse color to the lighting (including OcclusionTintAndMinOcclusion as it's considered another light, that fixes SubsurfaceProfile being too dark)
Lighting += ((ScalarFactors * DotProductFactor) * DiffuseLookup + (1 - SkyVisibility) * OcclusionTintAndMinOcclusion.xyz) * DiffuseColor;
#if USE_PREEXPOSURE
Lighting *= View.PreExposure;
#endif
//Lighting = (Texture2DSampleLevel(BentNormalAOTexture, BentNormalAOSampler, UV, 0).xyz);
return Lighting;
}
-
D:\UnrealEngine426\Engine\Shaders\Private\ReflectionEnvironmentShared.ush
-
#if (FEATURE_LEVEL <= FEATURE_LEVEL_ES3_1)
#define SkyIrradianceEnvironmentMap View.MobileSkyIrradianceEnvironmentMap
#else
#define SkyIrradianceEnvironmentMap View.SkyIrradianceEnvironmentMap
#endif
/**
* Computes sky diffuse lighting from the SH irradiance map.
* This has the SH basis evaluation and diffuse convolution weights combined for minimal ALU's - see "Stupid Spherical Harmonics (SH) Tricks"
*/
float3 GetSkySHDiffuse(float3 Normal)
{
float4 NormalVector = float4(Normal, 1.0f);
float3 Intermediate0, Intermediate1, Intermediate2;
Intermediate0.x = dot(SkyIrradianceEnvironmentMap[0], NormalVector);
Intermediate0.y = dot(SkyIrradianceEnvironmentMap[1], NormalVector);
Intermediate0.z = dot(SkyIrradianceEnvironmentMap[2], NormalVector);
float4 vB = NormalVector.xyzz * NormalVector.yzzx;
Intermediate1.x = dot(SkyIrradianceEnvironmentMap[3], vB);
Intermediate1.y = dot(SkyIrradianceEnvironmentMap[4], vB);
Intermediate1.z = dot(SkyIrradianceEnvironmentMap[5], vB);
float vC = NormalVector.x * NormalVector.x - NormalVector.y * NormalVector.y;
Intermediate2 = SkyIrradianceEnvironmentMap[6].xyz * vC;
// max to not get negative colors
return max(0, Intermediate0 + Intermediate1 + Intermediate2);
}
- ?D:\UnrealEngine426\Engine\Shaders\Private\ReflectionEnvironmentPixelShader.usf
-
float3 ReflectionEnvironment(FGBufferData GBuffer, float AmbientOcclusion, float2 BufferUV, float2 ScreenPosition, float4 SvPosition, float3 BentNormal, float3 SpecularColor)
{
#if USE_PREEXPOSURE
const float PreExposure = View.PreExposure;
#else
const float PreExposure = 1.f;
#endif
float4 Color = float4(0, 0, 0, 1);
float3 WorldPosition = mul(float4(ScreenPosition * GBuffer.Depth, GBuffer.Depth, 1), View.ScreenToWorld).xyz;
float3 CameraToPixel = normalize(WorldPosition - View.WorldCameraOrigin);
float3 ReflectionVector = reflect(CameraToPixel, GBuffer.WorldNormal);
float IndirectIrradiance = GBuffer.IndirectIrradiance;
#if ENABLE_SKY_LIGHT && ALLOW_STATIC_LIGHTING
BRANCH
// Add in diffuse contribution from dynamic skylights so reflection captures will have something to mix with
if (ReflectionStruct.SkyLightParameters.y > 0 && ReflectionStruct.SkyLightParameters.z > 0)
{
IndirectIrradiance += GetDynamicSkyIndirectIrradiance(BentNormal, GBuffer.WorldNormal);
}
#endif
float3 N = GBuffer.WorldNormal;
float3 V = -CameraToPixel;
ModifyGGXAnisotropicNormalRoughness(GBuffer.WorldTangent, GBuffer.Anisotropy, GBuffer.Roughness, N, V);
float3 R = 2 * dot( V, N ) * N - V;
float NoV = saturate( dot( N, V ) );
// Point lobe in off-specular peak direction
R = GetOffSpecularPeakReflectionDir(N, R, GBuffer.Roughness);
#if 1
// Note: this texture may also contain planar reflections
float4 SSR = Texture2DSample(ScreenSpaceReflectionsTexture, ScreenSpaceReflectionsSampler, BufferUV);
Color.rgb = SSR.rgb;
Color.a = 1 - SSR.a;
#endif
#if RAY_TRACED_REFLECTIONS
float4 SavedColor = Color; // When a clear coat material is encountered, we save the reflection buffer color for it to not be affected by operations.
#endif
if(GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT )
{
#if RAY_TRACED_REFLECTIONS
Color = float4(0, 0, 0, 1); // Clear coat reflection is expected to be computed on a black background
#endif
const float ClearCoat = GBuffer.CustomData.x;
Color = lerp( Color, float4(0,0,0,1), ClearCoat );
#if CLEAR_COAT_BOTTOM_NORMAL
const float2 oct1 = ((float2(GBuffer.CustomData.a, GBuffer.CustomData.z) * 2) - (256.0/255.0)) + UnitVectorToOctahedron(GBuffer.WorldNormal);
const float3 ClearCoatUnderNormal = OctahedronToUnitVector(oct1);
const float3 BottomEffectiveNormal = ClearCoatUnderNormal;
R = 2 * dot( V, ClearCoatUnderNormal ) * ClearCoatUnderNormal - V;
#endif
}
float AO = GBuffer.GBufferAO * AmbientOcclusion;
float RoughnessSq = GBuffer.Roughness * GBuffer.Roughness;
float SpecularOcclusion = GetSpecularOcclusion(NoV, RoughnessSq, AO);
Color.a *= SpecularOcclusion;
#if FEATURE_LEVEL >= FEATURE_LEVEL_SM5
float2 LocalPosition = SvPosition.xy - View.ViewRectMin.xy;
uint GridIndex = ComputeLightGridCellIndex(uint2(LocalPosition.x, LocalPosition.y), GBuffer.Depth);
uint NumCulledEntryIndex = (ForwardLightData.NumGridCells + GridIndex) * NUM_CULLED_LIGHTS_GRID_STRIDE;
uint NumCulledReflectionCaptures = min(ForwardLightData.NumCulledLightsGrid[NumCulledEntryIndex + 0], ForwardLightData.NumReflectionCaptures);
uint DataStartIndex = ForwardLightData.NumCulledLightsGrid[NumCulledEntryIndex + 1];
#else
uint DataStartIndex = 0;
uint NumCulledReflectionCaptures = 0;
#endif
//Top of regular reflection or bottom layer of clear coat.
Color.rgb += PreExposure * GatherRadiance(Color.a, WorldPosition, R, GBuffer.Roughness, BentNormal, IndirectIrradiance, GBuffer.ShadingModelID, NumCulledReflectionCaptures, DataStartIndex);
BRANCH
if( GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT)
{
const float ClearCoat = GBuffer.CustomData.x;
const float ClearCoatRoughness = GBuffer.CustomData.y;
// TODO EnvBRDF should have a mask param
float2 AB = PreIntegratedGF.SampleLevel( PreIntegratedGFSampler, float2( NoV, GBuffer.Roughness ), 0 ).rg;
Color.rgb *= SpecularColor * AB.x + AB.y * saturate( 50 * SpecularColor.g ) * (1 - ClearCoat);
// F_Schlick
float F = EnvBRDF( 0.04, ClearCoatRoughness, NoV ).x;
F *= ClearCoat;
float LayerAttenuation = (1 - F);
Color.rgb *= LayerAttenuation;
Color.a = F;
#if !RAY_TRACED_REFLECTIONS
Color.rgb += SSR.rgb * F;
Color.a *= 1 - SSR.a;
#endif
Color.a *= SpecularOcclusion;
float3 TopLayerR = 2 * dot( V, N ) * N - V;
Color.rgb += PreExposure * GatherRadiance(Color.a, WorldPosition, TopLayerR, ClearCoatRoughness, BentNormal, IndirectIrradiance, GBuffer.ShadingModelID, NumCulledReflectionCaptures, DataStartIndex);
#if RAY_TRACED_REFLECTIONS
Color.rgb = SavedColor.rgb + Color.rgb * SavedColor.a; // Compose default clear coat reflection over regular refelction (using Premultiplied alpha where SaveColor.a=transmittance)
#endif
}
else
{
Color.rgb *= EnvBRDF( SpecularColor, GBuffer.Roughness, NoV );
}
// Transform NaNs to black, transform negative colors to black.
return -min(-Color.rgb, 0.0);
}
float3 GatherRadiance(float CompositeAlpha, float3 WorldPosition, float3 RayDirection, float Roughness, float3 BentNormal, float IndirectIrradiance, uint ShadingModelID, uint NumCulledReflectionCaptures, uint CaptureDataStartIndex)
{
// Indirect occlusion from DFAO, which should be applied to reflection captures and skylight specular, but not SSR
float IndirectSpecularOcclusion = 1.0f;
float3 ExtraIndirectSpecular = 0;
#if SUPPORT_DFAO_INDIRECT_OCCLUSION
float IndirectDiffuseOcclusion;
GetDistanceFieldAOSpecularOcclusion(BentNormal, RayDirection, Roughness, ShadingModelID == SHADINGMODELID_TWOSIDED_FOLIAGE, IndirectSpecularOcclusion, IndirectDiffuseOcclusion, ExtraIndirectSpecular);
// Apply DFAO to IndirectIrradiance before mixing with indirect specular
IndirectIrradiance *= IndirectDiffuseOcclusion;
#endif
const bool bCompositeSkylight = true;
return CompositeReflectionCapturesAndSkylight(
CompositeAlpha,
WorldPosition,
RayDirection,
Roughness,
IndirectIrradiance,
IndirectSpecularOcclusion,
ExtraIndirectSpecular,
NumCulledReflectionCaptures,
CaptureDataStartIndex,
0,
bCompositeSkylight);
} -
?D:\UnrealEngine426\Engine\Shaders\Private\ReflectionEnvironmentComposite.ush
-
// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
ReflectionEnvironmentComposite
=============================================================================*/
float3 CompositeReflectionCapturesAndSkylight(
float CompositeAlpha,
float3 WorldPosition,
float3 RayDirection,
float Roughness,
float IndirectIrradiance,
float IndirectSpecularOcclusion,
float3 ExtraIndirectSpecular,
uint NumCapturesAffectingTile,
uint CaptureDataStartIndex,
int SingleCaptureIndex,
bool bCompositeSkylight,
uint EyeIndex)
{
float Mip = ComputeReflectionCaptureMipFromRoughness(Roughness, View.ReflectionCubemapMaxMip);
float4 ImageBasedReflections = float4(0, 0, 0, CompositeAlpha);
float2 CompositedAverageBrightness = float2(0.0f, 1.0f);
#if REFLECTION_COMPOSITE_USE_BLENDED_REFLECTION_CAPTURES
// Accumulate reflections from captures affecting this tile, applying largest captures first so that the smallest ones display on top
LOOP
for (uint TileCaptureIndex = 0; TileCaptureIndex < NumCapturesAffectingTile; TileCaptureIndex++)
{
BRANCH
if (ImageBasedReflections.a < 0.001)
{
break;
}
uint CaptureIndex = 0;
#ifdef REFLECTION_COMPOSITE_NO_CULLING_DATA
CaptureIndex = TileCaptureIndex; // Go from 0 to NumCapturesAffectingTile as absolute index in capture array
#else
#if INSTANCED_STEREO
BRANCH
if (EyeIndex == 0)
{
#endif
CaptureIndex = ForwardLightData.CulledLightDataGrid[CaptureDataStartIndex + TileCaptureIndex];
#if INSTANCED_STEREO
}
else
{
CaptureIndex = ForwardLightDataISR.CulledLightDataGrid[CaptureDataStartIndex + TileCaptureIndex];
}
#endif
#endif
float4 CapturePositionAndRadius = ReflectionCapture.PositionAndRadius[CaptureIndex];
float4 CaptureProperties = ReflectionCapture.CaptureProperties[CaptureIndex];
float3 CaptureVector = WorldPosition - CapturePositionAndRadius.xyz;
float CaptureVectorLength = sqrt(dot(CaptureVector, CaptureVector));
float NormalizedDistanceToCapture = saturate(CaptureVectorLength / CapturePositionAndRadius.w);
BRANCH
if (CaptureVectorLength < CapturePositionAndRadius.w)
{
float3 ProjectedCaptureVector = RayDirection;
float4 CaptureOffsetAndAverageBrightness = ReflectionCapture.CaptureOffsetAndAverageBrightness[CaptureIndex];
// Fade out based on distance to capture
float DistanceAlpha = 0;
#define PROJECT_ONTO_SHAPE 1
#if PROJECT_ONTO_SHAPE
#if REFLECTION_COMPOSITE_HAS_BOX_CAPTURES
#if REFLECTION_COMPOSITE_HAS_SPHERE_CAPTURES
// Box
BRANCH if (CaptureProperties.b > 0)
#endif
{
ProjectedCaptureVector = GetLookupVectorForBoxCapture(RayDirection, WorldPosition, CapturePositionAndRadius, ReflectionCapture.BoxTransform[CaptureIndex], ReflectionCapture.BoxScales[CaptureIndex], CaptureOffsetAndAverageBrightness.xyz, DistanceAlpha);
}
#endif
#if REFLECTION_COMPOSITE_HAS_SPHERE_CAPTURES
// Sphere
#if REFLECTION_COMPOSITE_HAS_BOX_CAPTURES
else
#endif
{
ProjectedCaptureVector = GetLookupVectorForSphereCapture(RayDirection, WorldPosition, CapturePositionAndRadius, NormalizedDistanceToCapture, CaptureOffsetAndAverageBrightness.xyz, DistanceAlpha);
}
#endif
#else
DistanceAlpha = 1.0;
#endif //PROJECT_ONTO_SHAPE
float CaptureArrayIndex = CaptureProperties.g;
{
float4 Sample = ReflectionStruct.ReflectionCubemap.SampleLevel(ReflectionStruct.ReflectionCubemapSampler, float4(ProjectedCaptureVector, CaptureArrayIndex), Mip);
Sample.rgb *= CaptureProperties.r;
Sample *= DistanceAlpha;
// Under operator (back to front)
ImageBasedReflections.rgb += Sample.rgb * ImageBasedReflections.a * IndirectSpecularOcclusion;
ImageBasedReflections.a *= 1 - Sample.a;
float AverageBrightness = CaptureOffsetAndAverageBrightness.w;
CompositedAverageBrightness.x += AverageBrightness * DistanceAlpha * CompositedAverageBrightness.y;
CompositedAverageBrightness.y *= 1 - DistanceAlpha;
}
}
}
#else
float3 ProjectedCaptureVector = RayDirection;
float4 SingleCaptureOffsetAndAverageBrightness = ReflectionCapture.CaptureOffsetAndAverageBrightness[SingleCaptureIndex];
float4 SingleCapturePositionAndRadius = ReflectionCapture.PositionAndRadius[SingleCaptureIndex];
float SingleCaptureBrightness = ReflectionCapture.CaptureProperties[SingleCaptureIndex].x;
float SingleCaptureArrayIndex = ReflectionCapture.CaptureProperties[SingleCaptureIndex].y;
#define APPROXIMATE_CONTINUOUS_SINGLE_CAPTURE_PARALLAX 0
#if APPROXIMATE_CONTINUOUS_SINGLE_CAPTURE_PARALLAX
float3 CaptureVector = WorldPosition - SingleCapturePositionAndRadius.xyz;
float CaptureVectorLength = sqrt(dot(CaptureVector, CaptureVector));
float NormalizedDistanceToCapture = saturate(CaptureVectorLength / SingleCapturePositionAndRadius.w);
float UnusedDistanceAlpha = 0;
ProjectedCaptureVector = GetLookupVectorForSphereCapture(RayDirection, WorldPosition, SingleCapturePositionAndRadius, NormalizedDistanceToCapture, SingleCaptureOffsetAndAverageBrightness.xyz, UnusedDistanceAlpha);
float x = saturate(NormalizedDistanceToCapture);
float DistanceAlpha = 1 - x * x * (3 - 2 * x);
// Lerp between sphere parallax corrected and infinite based on distance to shape
ProjectedCaptureVector = lerp(RayDirection, normalize(ProjectedCaptureVector), DistanceAlpha);
#endif
float4 Sample = TextureCubeArraySampleLevel(ReflectionStruct.ReflectionCubemap, ReflectionStruct.ReflectionCubemapSampler, ProjectedCaptureVector, SingleCaptureArrayIndex, Mip);
Sample.rgb *= SingleCaptureBrightness;
ImageBasedReflections = float4(Sample.rgb, 1 - Sample.a);
float AverageBrightness = SingleCaptureOffsetAndAverageBrightness.w;
CompositedAverageBrightness.x += AverageBrightness * CompositedAverageBrightness.y;
CompositedAverageBrightness.y = 0;
#endif
// Apply indirect lighting scale while we have only accumulated reflection captures
ImageBasedReflections.rgb *= View.IndirectLightingColorScale;
CompositedAverageBrightness.x *= Luminance( View.IndirectLightingColorScale );
#if ENABLE_SKY_LIGHT
BRANCH
if (ReflectionStruct.SkyLightParameters.y > 0 && bCompositeSkylight)
{
float SkyAverageBrightness = 1.0f;
#if REFLECTION_COMPOSITE_SUPPORT_SKYLIGHT_BLEND
float3 SkyLighting = GetSkyLightReflectionSupportingBlend(RayDirection, Roughness, SkyAverageBrightness);
#else
float3 SkyLighting = GetSkyLightReflection(RayDirection, Roughness, SkyAverageBrightness);
#endif
// Normalize for static skylight types which mix with lightmaps
bool bNormalize = ReflectionStruct.SkyLightParameters.z < 1 && ALLOW_STATIC_LIGHTING;
FLATTEN
if (bNormalize)
{
ImageBasedReflections.rgb += ImageBasedReflections.a * SkyLighting * IndirectSpecularOcclusion;
CompositedAverageBrightness.x += SkyAverageBrightness * CompositedAverageBrightness.y;
}
else
{
ExtraIndirectSpecular += SkyLighting * IndirectSpecularOcclusion;
}
}
#endif
#if ALLOW_STATIC_LIGHTING
ImageBasedReflections.rgb *= ComputeMixingWeight(IndirectIrradiance, CompositedAverageBrightness.x, Roughness);
#endif
ImageBasedReflections.rgb += ImageBasedReflections.a * ExtraIndirectSpecular;
return ImageBasedReflections.rgb;
}
float3 CompositeReflectionCapturesAndSkylight(
float CompositeAlpha,
float3 WorldPosition,
float3 RayDirection,
float Roughness,
float IndirectIrradiance,
float IndirectSpecularOcclusion,
float3 ExtraIndirectSpecular,
uint NumCapturesAffectingTile,
uint CaptureDataStartIndex,
int SingleCaptureIndex,
bool bCompositeSkylight)
{
return CompositeReflectionCapturesAndSkylight(
CompositeAlpha,
WorldPosition,
RayDirection,
Roughness,
IndirectIrradiance,
IndirectSpecularOcclusion,
ExtraIndirectSpecular,
NumCapturesAffectingTile,
CaptureDataStartIndex,
SingleCaptureIndex,
bCompositeSkylight,
0);
} -
//
-
// ReflectionStruct.SkyLightParameters: X = max mip, Y = 1 if sky light should be rendered, 0 otherwise, Z = 1 if sky light is dynamic, 0 otherwise, W = blend fraction.
float3 GetSkyLightReflection(float3 ReflectionVector, float Roughness, out float OutSkyAverageBrightness)
{
float AbsoluteSpecularMip = ComputeReflectionCaptureMipFromRoughness(Roughness, ReflectionStruct.SkyLightParameters.x);
float3 Reflection = TextureCubeSampleLevel(ReflectionStruct.SkyLightCubemap, ReflectionStruct.SkyLightCubemapSampler, ReflectionVector, AbsoluteSpecularMip).rgb;
OutSkyAverageBrightness = ReflectionStruct.SkyLightCubemapBrightness * Luminance( View.SkyLightColor.rgb );
return Reflection * View.SkyLightColor.rgb;
}
float3 GetSkyLightReflectionSupportingBlend(float3 ReflectionVector, float Roughness, out float OutSkyAverageBrightness)
{
float3 Reflection = GetSkyLightReflection(ReflectionVector, Roughness, OutSkyAverageBrightness);
BRANCH
if (ReflectionStruct.SkyLightParameters.w > 0)
{
float AbsoluteSpecularMip = ComputeReflectionCaptureMipFromRoughness(Roughness, ReflectionStruct.SkyLightParameters.x);
float3 BlendDestinationReflection = TextureCubeSampleLevel(ReflectionStruct.SkyLightBlendDestinationCubemap, ReflectionStruct.SkyLightBlendDestinationCubemapSampler, ReflectionVector, AbsoluteSpecularMip).rgb;
Reflection = lerp(Reflection, BlendDestinationReflection * View.SkyLightColor.rgb, ReflectionStruct.SkyLightParameters.w);
}
return Reflection;
} ?
|