// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "../ReflectionEnvironmentShared.ush" #include "../HeightFogCommon.ush" #include "SurfaceCache/LumenSurfaceCacheSampling.ush" #ifndef ENABLE_DYNAMIC_SKY_LIGHT #define ENABLE_DYNAMIC_SKY_LIGHT 1 #endif struct FConeTraceResult { float3 Lighting; float Transparency; float NumSteps; float NumOverlaps; float OpaqueHitDistance; float ExpandSurfaceAmount; float3 Debug; float3 GeometryWorldNormal; float3 WorldVelocity; }; float TanConeAngleToRoughness(float TanConeAngle) { //@todo DynamicGI - derive roughness from cone angle return sqrt(saturate(TanConeAngle / (.5f * PI))); } float3 EvaluateSkyRadiance(float3 Direction) { float3 SkyRadiance = 0.0f; #if ENABLE_DYNAMIC_SKY_LIGHT if (ReflectionStruct.SkyLightParameters.y > 0) { float SkyAverageBrightness = 1.0f; float TanConeAngle = 0.0f; float Roughness = TanConeAngleToRoughness(TanConeAngle); SkyRadiance = GetSkyLightReflection(Direction, Roughness, SkyAverageBrightness); } #endif return SkyRadiance; } void ApplySkylightToTraceResult(float3 ConeDirection, inout FConeTraceResult TraceResult) { #if ENABLE_DYNAMIC_SKY_LIGHT if (ReflectionStruct.SkyLightParameters.y > 0) { float SkyAverageBrightness = 1.0f; float TanConeAngle = 0.0f; float Roughness = TanConeAngleToRoughness(TanConeAngle); TraceResult.Lighting += GetSkyLightReflection(ConeDirection, Roughness, SkyAverageBrightness) * TraceResult.Transparency; } #endif } float3 SkylightLeakingColor; float ReflectionSkylightLeakingAverageAlbedo; float SkylightLeakingRoughness; float InvFullSkylightLeakingDistance; uint SampleHeightFog; float CalculateSkylightLeakingDistanceFactor(float HitDistance) { return saturate(HitDistance * InvFullSkylightLeakingDistance); } float3 GetSkylightLeaking(float3 ConeDirection, float HitDistance) { float3 Lighting = 0; if (ReflectionStruct.SkyLightParameters.y > 0 && any(SkylightLeakingColor > 0.0f)) { float SkyAverageBrightness = 1.0f; Lighting = GetSkyLightReflection(ConeDirection, SkylightLeakingRoughness, SkyAverageBrightness) * SkylightLeakingColor * CalculateSkylightLeakingDistanceFactor(HitDistance); } return Lighting; } // Reflections should look exactly like primary view. // In order to achieve that, Skylight leaking approximates GetSkylightLeaking for the hit point. float3 GetSkylightLeakingForReflections(float3 ConeDirection, float3 HitNormal, float HitDistance) { float3 Lighting = 0; float3 SkylightLeakingMult = View.SkyLightColor.rgb * SkylightLeakingColor * ReflectionSkylightLeakingAverageAlbedo; if (and(ReflectionStruct.SkyLightParameters.y > 0.0f, any(SkylightLeakingMult > 0.0f))) { Lighting = GetSkySHDiffuse(HitNormal) * SkylightLeakingMult; } return Lighting; } float3 ClampMaxRayIntensity(float3 Radiance, float MaxRayIntensity) { float MaxLighting = max3(Radiance.x, Radiance.y, Radiance.z); if (MaxLighting > MaxRayIntensity * View.OneOverPreExposure) { Radiance *= MaxRayIntensity * View.OneOverPreExposure / MaxLighting; } return Radiance; } float3 GetFogOnLuminance(in float3 SurfaceLuminance, in float SurfaceCoverage, in float3 RayOrigin, in float3 RayDir, in float HitPosDistance) { const float ExcludeDistance = 0.0f; // We override the fog integration origin to match the traced ray. bool bOverrideOrigin = true; float4 HeightFogInscatteringAndTransmittance = GetExponentialHeightFog(0, ExcludeDistance, 0, GetPrimaryView(), bOverrideOrigin, RayOrigin, RayDir, HitPosDistance); HeightFogInscatteringAndTransmittance.rgb *= View.PreExposure; return SurfaceLuminance * HeightFogInscatteringAndTransmittance.a + HeightFogInscatteringAndTransmittance.rgb * SurfaceCoverage; }