diff --git a/com.unity.render-pipelines.high-definition/CHANGELOG.md b/com.unity.render-pipelines.high-definition/CHANGELOG.md index b0e7d0e957f..1429d8cc924 100644 --- a/com.unity.render-pipelines.high-definition/CHANGELOG.md +++ b/com.unity.render-pipelines.high-definition/CHANGELOG.md @@ -70,6 +70,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Fixed unexpectedly strong contribution from directional lights in path-traced volumetric scattering (case 1304688). - Fixed memory leak with XR combined occlusion meshes (case 1366173). - Fixed diffusion profile being reset to default on SpeedTree8 materials with subsurface scattering enabled during import. +- Fixed support for light/shadow dimmers (volumetric or not) in path tracing. ### Changed - Visual Environment ambient mode is now Dynamic by default. diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/AtmosphericScattering/Fog.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/AtmosphericScattering/Fog.cs index d879ea6c8ea..6a354faf4e0 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/AtmosphericScattering/Fog.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/AtmosphericScattering/Fog.cs @@ -239,6 +239,7 @@ void UpdateShaderVariablesGlobalCBFogParameters(ref ShaderVariablesGlobal cb, HD cb._HeightFogBaseHeight = crBaseHeight; cb._GlobalFogAnisotropy = anisotropy.value; cb._VolumetricFilteringEnabled = ((int)denoisingMode.value & (int)FogDenoisingMode.Gaussian) != 0 ? 1 : 0; + cb._FogDirectionalOnly = directionalLightsOnly.value ? 1 : 0; } } diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingLight.hlsl b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingLight.hlsl index faa8e3e75bf..f4a5cc2f65e 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingLight.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingLight.hlsl @@ -12,6 +12,7 @@ #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/ShaderVariablesRaytracingLightLoop.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Shadows/SphericalQuad.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Common/AtmosphericScatteringRayTracing.hlsl" +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingSampling.hlsl" // How many lights (at most) do we support at one given shading point // FIXME: hardcoded limits are evil, this LightList should instead be put together in C# @@ -327,6 +328,11 @@ float3 GetAreaEmission(LightData lightData, float centerU, float centerV, float return emission; } +float3 GetLightTransmission(float3 transmission, float shadowOpacity) +{ + return lerp(float3(1.0, 1.0, 1.0), transmission, shadowOpacity); +} + bool SampleLights(LightList lightList, float3 inputSample, float3 position, @@ -335,7 +341,8 @@ bool SampleLights(LightList lightList, out float3 outgoingDir, out float3 value, out float pdf, - out float dist) + out float dist, + out float shadowOpacity) { if (!GetLightCount(lightList)) return false; @@ -404,7 +411,15 @@ bool SampleLights(LightList lightList, } if (isVolume) + { value *= lightData.volumetricLightDimmer; + shadowOpacity = lightData.volumetricShadowDimmer; + } + else + { + value *= lightData.lightDimmer; + shadowOpacity = lightData.shadowDimmer; + } #ifndef LIGHT_EVALUATION_NO_HEIGHT_FOG ApplyFogAttenuation(position, outgoingDir, dist, value); @@ -435,7 +450,15 @@ bool SampleLights(LightList lightList, dist = FLT_INF; if (isVolume) + { value *= lightData.volumetricLightDimmer; + shadowOpacity = lightData.volumetricShadowDimmer; + } + else + { + value *= lightData.lightDimmer; + shadowOpacity = lightData.shadowDimmer; + } #ifndef LIGHT_EVALUATION_NO_HEIGHT_FOG ApplyFogAttenuation(position, outgoingDir, value); @@ -759,13 +782,13 @@ float PickLocalLightInterval(float3 rayOrigin, float3 rayDirection, inout float tMin = tLightMin; tMax = tLightMax; - inputSample /= wLight; + inputSample = RescaleSampleUnder(inputSample, wLight); } else { lightWeight *= 1.0 - wLight; - inputSample = (inputSample - wLight) / (1.0 - wLight); + inputSample = RescaleSampleOver(inputSample, wLight); } localCount++; @@ -793,13 +816,13 @@ float PickLocalLightInterval(float3 rayOrigin, float3 rayDirection, inout float tMin = tLightMin; tMax = tLightMax; - inputSample /= wLight; + inputSample = RescaleSampleUnder(inputSample, wLight); } else { lightWeight *= 1.0 - wLight; - inputSample = (inputSample - wLight) / (1.0 - wLight); + inputSample = RescaleSampleOver(inputSample, wLight); } localCount++; diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingSampling.hlsl b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingSampling.hlsl index 0f327d72cac..aaa48fbd0d9 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingSampling.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingSampling.hlsl @@ -44,4 +44,15 @@ bool RussianRouletteTest(float threshold, float value, float rand, out float fac return true; } +float RescaleSampleUnder(float inputSample, float threshold) +{ + return inputSample / threshold; +} + +float RescaleSampleOver(float inputSample, float threshold) +{ + // Make sure we never reach 1.0 due to numerical imprecision + return min((inputSample - threshold) / (1.0 - threshold), 0.99999); +} + #endif // UNITY_PATH_TRACING_SAMPLING_INCLUDED diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingVolume.hlsl b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingVolume.hlsl index f52a62edf15..58e699a74b2 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingVolume.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingVolume.hlsl @@ -1,9 +1,7 @@ #ifndef UNITY_PATH_TRACING_VOLUME_INCLUDED #define UNITY_PATH_TRACING_VOLUME_INCLUDED -#ifdef HAS_LIGHTLOOP #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingLight.hlsl" -#endif float ComputeHeightFogMultiplier(float height) { @@ -17,42 +15,46 @@ bool SampleVolumeScatteringPosition(uint2 pixelCoord, inout float inputSample, i if (!_FogEnabled || !_EnableVolumetricFog) return false; - // This will determin the interval in which volumetric scattering can occur + // This will determine the interval in which volumetric scattering can occur float tMin, tMax; float pdfVol = 1.0; float tFog = min(t, _MaxFogDistance); -#ifdef HAS_LIGHTLOOP - - float pickedLightWeight; - float localWeight = PickLocalLightInterval(WorldRayOrigin(), WorldRayDirection(), inputSample, lightPosition, pickedLightWeight, tMin, tMax); - - if (localWeight < 0.0) - return false; - - sampleLocalLights = inputSample < localWeight; - if (sampleLocalLights) + if (_FogDirectionalOnly) { - tMax = min(tMax, tFog); - if (tMin >= tMax) + if (!_DirectionalLightCount) return false; - inputSample /= localWeight; - pdfVol *= localWeight * pickedLightWeight; - } - else - { tMin = 0.0; tMax = tFog; + } + else // Directional and local lights + { + float pickedLightWeight; + float localWeight = PickLocalLightInterval(WorldRayOrigin(), WorldRayDirection(), inputSample, lightPosition, pickedLightWeight, tMin, tMax); + + if (localWeight < 0.0) + return false; - inputSample -= localWeight; - inputSample /= 1.0 - localWeight; - pdfVol *= 1.0 - localWeight; + sampleLocalLights = inputSample < localWeight; + if (sampleLocalLights) + { + tMax = min(tMax, tFog); + if (tMin >= tMax) + return false; + + inputSample = RescaleSampleUnder(inputSample, localWeight); + pdfVol *= localWeight * pickedLightWeight; + } + else + { + tMin = 0.0; + tMax = tFog; + + inputSample = RescaleSampleOver(inputSample, localWeight); + pdfVol *= 1.0 - localWeight; + } } -#else - tMin = 0.0; - tMax = tFog; -#endif // FIXME: not quite sure what the sigmaT value is supposed to be... const float sigmaT = _HeightFogBaseExtinction; @@ -62,27 +64,18 @@ bool SampleVolumeScatteringPosition(uint2 pixelCoord, inout float inputSample, i if (inputSample >= transmittanceThreshold) { - // Re-scale the sample - inputSample -= transmittanceThreshold; - inputSample /= 1.0 - transmittanceThreshold; - - // Adjust the pdf + inputSample = RescaleSampleOver(inputSample, transmittanceThreshold); pdf *= 1.0 - transmittanceThreshold; return false; } - // Re-scale the sample - inputSample /= transmittanceThreshold; - - // Adjust the pdf + inputSample = RescaleSampleUnder(inputSample, transmittanceThreshold); pdf *= pdfVol * transmittanceThreshold; // Exponential sampling float transmittance = transmittanceTMax + inputSample * (transmittanceTMin - transmittanceTMax); t = -log(transmittance) / sigmaT; - - // Adjust the pdf pdf *= sigmaT * transmittance / (transmittanceTMin - transmittanceTMax); return true; @@ -94,8 +87,6 @@ void ComputeVolumeScattering(inout PathIntersection pathIntersection : SV_RayPay // Reset the ray intersection color, which will store our final result pathIntersection.value = 0.0; -#ifdef HAS_LIGHTLOOP - // Grab depth information uint currentDepth = _RaytracingMaxRecursion - pathIntersection.remainingDepth; @@ -108,8 +99,7 @@ void ComputeVolumeScattering(inout PathIntersection pathIntersection : SV_RayPay // Create the list of active lights (a local light can be forced by providing its position) LightList lightList = CreateLightList(scatteringPosition, sampleLocalLights, lightPosition); - // Bunch of variables common to material and light sampling - float pdf; + float pdf, shadowOpacity; float3 value; RayDesc ray; @@ -121,7 +111,7 @@ void ComputeVolumeScattering(inout PathIntersection pathIntersection : SV_RayPay // Light sampling if (computeDirect) { - if (SampleLights(lightList, inputSample, scatteringPosition, 0.0, true, ray.Direction, value, pdf, ray.TMax)) + if (SampleLights(lightList, inputSample, scatteringPosition, 0.0, true, ray.Direction, value, pdf, ray.TMax, shadowOpacity)) { // FIXME: Apply phase function and divide by pdf (only isotropic for now, and not sure about sigmaS value) value *= _HeightFogBaseScattering.xyz * ComputeHeightFogMultiplier(scatteringPosition.y) * INV_FOUR_PI / pdf; @@ -137,12 +127,11 @@ void ComputeVolumeScattering(inout PathIntersection pathIntersection : SV_RayPay TraceRay(_RaytracingAccelerationStructure, RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH | RAY_FLAG_FORCE_NON_OPAQUE | RAY_FLAG_SKIP_CLOSEST_HIT_SHADER, RAYTRACINGRENDERERFLAG_CAST_SHADOW, 0, 1, 1, ray, nextPathIntersection); - pathIntersection.value += value * nextPathIntersection.value; + pathIntersection.value += value * GetLightTransmission(nextPathIntersection.value, shadowOpacity); } } } -#endif // HAS_LIGHTLOOP } #endif // UNITY_PATH_TRACING_VOLUME_INCLUDED diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassPathTracing.hlsl b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassPathTracing.hlsl index 1f34b464bb1..552a7276c75 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassPathTracing.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassPathTracing.hlsl @@ -4,10 +4,8 @@ // Path tracing includes #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingIntersection.hlsl" -#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingVolume.hlsl" #ifdef HAS_LIGHTLOOP -#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingLight.hlsl" -#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingSampling.hlsl" +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingVolume.hlsl" #endif float PowerHeuristic(float f, float b) @@ -36,9 +34,9 @@ float ComputeVisibility(float3 position, float3 normal, float3 inputSample) // We will ignore value and pdf here, as we only want to catch occluders (no distance falloffs, cosines, etc.) float3 value; - float pdf; + float pdf, shadowOpacity; - if (SampleLights(lightList, inputSample, rayDescriptor.Origin, normal, false, rayDescriptor.Direction, value, pdf, rayDescriptor.TMax)) + if (SampleLights(lightList, inputSample, rayDescriptor.Origin, normal, false, rayDescriptor.Direction, value, pdf, rayDescriptor.TMax, shadowOpacity)) { // Shoot a transmission ray (to mark it as such, purposedly set remaining depth to an invalid value) PathIntersection intersection; @@ -50,7 +48,7 @@ float ComputeVisibility(float3 position, float3 normal, float3 inputSample) TraceRay(_RaytracingAccelerationStructure, RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH | RAY_FLAG_FORCE_NON_OPAQUE | RAY_FLAG_SKIP_CLOSEST_HIT_SHADER, RAYTRACINGRENDERERFLAG_CAST_SHADOW, 0, 1, 1, rayDescriptor, intersection); - visibility = Luminance(intersection.value); + visibility = Luminance(GetLightTransmission(intersection.value, shadowOpacity)); } return visibility; @@ -143,8 +141,7 @@ void ComputeSurfaceScattering(inout PathIntersection pathIntersection : SV_RayPa #endif LightList lightList = CreateLightList(shadingPosition, lightNormal, builtinData.renderingLayers); - // Bunch of variables common to material and light sampling - float pdf; + float pdf, shadowOpacity; float3 value; MaterialResult mtlResult; @@ -157,7 +154,7 @@ void ComputeSurfaceScattering(inout PathIntersection pathIntersection : SV_RayPa // Light sampling if (computeDirect) { - if (SampleLights(lightList, inputSample.xyz, rayDescriptor.Origin, lightNormal, false, rayDescriptor.Direction, value, pdf, rayDescriptor.TMax)) + if (SampleLights(lightList, inputSample.xyz, rayDescriptor.Origin, lightNormal, false, rayDescriptor.Direction, value, pdf, rayDescriptor.TMax, shadowOpacity)) { EvaluateMaterial(mtlData, rayDescriptor.Direction, mtlResult); @@ -174,7 +171,7 @@ void ComputeSurfaceScattering(inout PathIntersection pathIntersection : SV_RayPa RAYTRACINGRENDERERFLAG_CAST_SHADOW, 0, 1, 1, rayDescriptor, nextPathIntersection); float misWeight = PowerHeuristic(pdf, mtlResult.diffPdf + mtlResult.specPdf); - pathIntersection.value += value * nextPathIntersection.value * misWeight; + pathIntersection.value += value * GetLightTransmission(nextPathIntersection.value, shadowOpacity) * misWeight; } } } diff --git a/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariablesGlobal.cs b/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariablesGlobal.cs index ee4c7a6ce4e..7b25f4a358d 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariablesGlobal.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariablesGlobal.cs @@ -130,7 +130,7 @@ unsafe struct ShaderVariablesGlobal public float _FogColorMode; public float _GlobalMipBias; public float _GlobalMipBiasPow2; - public float _Pad2; + public float _Pad0; public Vector4 _MipFogParameters; public Vector4 _HeightFogBaseScattering; public float _HeightFogBaseExtinction; @@ -138,8 +138,8 @@ unsafe struct ShaderVariablesGlobal public float _GlobalFogAnisotropy; public int _VolumetricFilteringEnabled; public Vector2 _HeightFogExponents; // { 1/H, H } - public float _Pad4; - public float _Pad5; + public int _FogDirectionalOnly; + public float _Pad1; // VBuffer public Vector4 _VBufferViewportSize; // { w, h, 1/w, 1/h } diff --git a/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariablesGlobal.cs.hlsl b/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariablesGlobal.cs.hlsl index c21c0b38fca..701c9f45e54 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariablesGlobal.cs.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariablesGlobal.cs.hlsl @@ -58,7 +58,7 @@ GLOBAL_CBUFFER_START(ShaderVariablesGlobal, b0) float _FogColorMode; float _GlobalMipBias; float _GlobalMipBiasPow2; - float _Pad2; + float _Pad0; float4 _MipFogParameters; float4 _HeightFogBaseScattering; float _HeightFogBaseExtinction; @@ -66,8 +66,8 @@ GLOBAL_CBUFFER_START(ShaderVariablesGlobal, b0) float _GlobalFogAnisotropy; int _VolumetricFilteringEnabled; float2 _HeightFogExponents; - float _Pad4; - float _Pad5; + int _FogDirectionalOnly; + float _Pad1; float4 _VBufferViewportSize; float4 _VBufferLightingViewportScale; float4 _VBufferLightingViewportLimit;