You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

144 lines
5.5 KiB

#ifndef UNITY_PATH_TRACING_VOLUME_INCLUDED
#define UNITY_PATH_TRACING_VOLUME_INCLUDED
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingLight.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/VolumeRendering.hlsl"
float ComputeHeightFogMultiplier(float height)
{
return ComputeHeightFogMultiplier(height, _HeightFogBaseHeight, _HeightFogExponents);
}
bool SampleVolumeScatteringPosition(uint2 pixelCoord, inout float inputSample, inout float t, inout float pdf, out bool sampleLocalLights, out float3 lightPosition)
{
sampleLocalLights = false;
if (!_FogEnabled || !_EnableVolumetricFog)
return false;
// This will determine the interval in which volumetric scattering can occur
float tMin, tMax;
float pdfVol = 1.0;
float tFog = min(t, _MaxFogDistance);
if (_FogDirectionalOnly)
{
if (!_DirectionalLightCount)
return false;
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;
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;
}
}
// FIXME: not quite sure what the sigmaT value is supposed to be...
const float sigmaT = _HeightFogBaseExtinction;
const float transmittanceTMin = max(exp(-tMin * sigmaT), 0.01);
const float transmittanceTMax = max(exp(-tMax * sigmaT), 0.01);
const float transmittanceThreshold = t < FLT_MAX ? 1.0 - min(0.5, transmittanceTMax) : 1.0;
if (inputSample >= transmittanceThreshold)
{
inputSample = RescaleSampleOver(inputSample, transmittanceThreshold);
pdf *= 1.0 - transmittanceThreshold;
return false;
}
inputSample = RescaleSampleUnder(inputSample, transmittanceThreshold);
pdf *= pdfVol * transmittanceThreshold;
// Exponential sampling
float transmittance = transmittanceTMax + inputSample * (transmittanceTMin - transmittanceTMax);
t = -log(transmittance) / sigmaT;
pdf *= sigmaT * transmittance / (transmittanceTMin - transmittanceTMax);
return true;
}
// Function responsible for volume scattering
void ComputeVolumeScattering(inout PathPayload payload : SV_RayPayload, float3 inputSample, bool sampleLocalLights, float3 lightPosition)
{
// Reset the payload color, which will store our final result
payload.value = 0.0;
SetPathTracingFlag(payload, PATHTRACING_FLAG_VOLUME_INTERACTION);
// Check if we want to compute direct lighting for current depth
bool minDepthAllowsDirect = payload.segmentID + 1 >= _RaytracingMinRecursion - 1;
// Check if we want to send more rays after this segment
bool haveReachedMaxDepth = payload.segmentID + 1 > _RaytracingMaxRecursion - 1;
// Compute the scattering position
float3 scatteringPosition = WorldRayOrigin() + payload.rayTHit * WorldRayDirection();
float3 incomingDirection = WorldRayDirection();
// Create the list of active lights (a local light can be forced by providing its position)
LightList lightList = CreateLightList(scatteringPosition, sampleLocalLights, lightPosition);
payload.lightListParams = float4(lightPosition, sampleLocalLights ? 1 : 0);
float pdf, shadowOpacity;
float3 value;
float3 sampleRayDirection;
float sampleRayDistance;
if (minDepthAllowsDirect && !haveReachedMaxDepth)
{
float scatteringHeight = dot(scatteringPosition, _PlanetUp);
// Light sampling
if (SampleLights(lightList, inputSample, scatteringPosition, 0.0, true, sampleRayDirection, value, pdf, sampleRayDistance, shadowOpacity))
{
// Apply phase function and divide by PDF
float phasePdf = HenyeyGreensteinPhaseFunction(_GlobalFogAnisotropy, dot(incomingDirection, sampleRayDirection));
value *= _HeightFogBaseScattering.xyz * ComputeHeightFogMultiplier(scatteringPosition.y) * phasePdf / pdf;
if (GetCurrentExposureMultiplier() * Luminance(value) > 0.0001)
{
PushLightSampleQuery(scatteringPosition, sampleRayDirection, sampleRayDistance - _RayTracingRayBias, PowerHeuristic(pdf, phasePdf) * value, shadowOpacity, payload);
}
}
// Phase function sampling
if (SampleHenyeyGreenstein(incomingDirection, _GlobalFogAnisotropy, inputSample, sampleRayDirection, pdf))
{
// Applying phase function and dividing by PDF cancels out
value = _HeightFogBaseScattering.xyz * ComputeHeightFogMultiplier(scatteringHeight);
if (Luminance(value) > 0.001)
{
payload.throughput *= value;
payload.interactionThroughput *= value;
payload.materialSamplePdf = pdf;
PushMaterialSampleQuery(scatteringPosition, sampleRayDirection, payload);
}
}
}
}
#endif // UNITY_PATH_TRACING_VOLUME_INCLUDED