2021-09-09 20:42:29 -04:00

158 lines
4.9 KiB
HLSL

#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)
{
return ComputeHeightFogMultiplier(height, _HeightFogBaseHeight, _HeightFogExponents);
}
bool SampleVolumeScatteringPosition(inout float theSample, inout float t, inout float pdf, out bool sampleLocalLights)
{
sampleLocalLights = false;
if (!_FogEnabled || !_EnableVolumetricFog)
return false;
// This will determin the interval in which volumetric scattering can occur
float tMin, tMax;
float pdfVol = 1.0;
float tFog = min(t, _MaxFogDistance);
#ifdef HAS_LIGHTLOOP
float localWeight = GetLocalLightsInterval(WorldRayOrigin(), WorldRayDirection(), tMin, tMax);
if (localWeight < 0.0)
return false;
sampleLocalLights = theSample < localWeight;
if (sampleLocalLights)
{
tMax = min(tMax, tFog);
if (tMin >= tMax)
return false;
theSample /= localWeight;
pdfVol *= localWeight;
}
else
{
tMin = 0.0;
tMax = tFog;
theSample -= localWeight;
theSample /= 1.0 - 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;
const float transmittanceTMax = max(exp(-tMax * sigmaT), 0.01);
const float transmittanceThreshold = t < FLT_MAX ? 1.0 - min(0.5, transmittanceTMax) : 1.0;
if (theSample >= transmittanceThreshold)
{
// Re-scale the sample
theSample -= transmittanceThreshold;
theSample /= 1.0 - transmittanceThreshold;
// Adjust the pdf
pdf *= 1.0 - transmittanceThreshold;
return false;
}
// Re-scale the sample
theSample /= transmittanceThreshold;
// Adjust the pdf
pdf *= pdfVol * transmittanceThreshold;
if (sampleLocalLights)
{
// Linear sampling
float deltaT = tMax - tMin;
t = tMin + theSample * deltaT;
// Adjust the pdf
pdf /= deltaT;
}
else
{
// Exponential sampling
float transmittance = transmittanceTMax + theSample * (1.0 - transmittanceTMax);
t = -log(transmittance) / sigmaT;
// Adjust the pdf
pdf *= sigmaT * transmittance;
}
return true;
}
// Function responsible for volume scattering
void ComputeVolumeScattering(inout PathIntersection pathIntersection : SV_RayPayload, float3 inputSample, bool sampleLocalLights)
{
// 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;
// Check if we want to compute direct and emissive lighting for current depth
bool computeDirect = currentDepth >= _RaytracingMinRecursion - 1;
// Compute the scattering position
float3 scatteringPosition = WorldRayOrigin() + pathIntersection.t * WorldRayDirection();
// Create the list of active lights
LightList lightList = CreateLightList(scatteringPosition, sampleLocalLights);
// Bunch of variables common to material and light sampling
float pdf;
float3 value;
RayDesc ray;
ray.Origin = scatteringPosition;
ray.TMin = 0.0;
PathIntersection nextPathIntersection;
// Light sampling
if (computeDirect)
{
if (SampleLights(lightList, inputSample, scatteringPosition, 0.0, ray.Direction, value, pdf, ray.TMax))
{
// 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;
if (Luminance(value) > 0.001)
{
// Shoot a transmission ray (to mark it as such, purposedly set remaining depth to an invalid value)
nextPathIntersection.remainingDepth = _RaytracingMaxRecursion + 1;
ray.TMax -= _RaytracingRayBias;
nextPathIntersection.value = 1.0;
// FIXME: For the time being, we choose not to apply any back/front-face culling for shadows, will possibly change in the future
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;
}
}
}
#endif // HAS_LIGHTLOOP
}
#endif // UNITY_PATH_TRACING_VOLUME_INCLUDED