Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions com.unity.render-pipelines.high-definition/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Fixed double contribution from the clear coat when having SSR or RTR on the Lit and StackLit shaders (case 1352424).
- Fixed texture fields for volume parameters accepting textures with wrong dimensions.
- Fixed Realtime lightmap not working correctly in player with various lit shader (case 1360021)
- Fixed unexpectedly strong contribution from directional lights in path-traced volumetric scattering (case 1304688).

### Changed
- Visual Environment ambient mode is now Dynamic by default.
- Surface ReflectionTypeLoadExceptions in HDUtils.GetRenderPipelineMaterialList(). Without surfacing these exceptions, developers cannot act on any underlying reflection errors in the HDRP assembly.
- Improved the DynamicArray class by adding several utility APIs.
- Moved AMD FidelityFX shaders to core
- Improved sampling of overlapping point/area lights in path-traced volumetric scattering (case 1358777).
- Path-traced volumetric scattering now takes fog color into account, adding scattered contribution on top of the non-scattered result (cases 1346105, 1358783).

## [12.0.0] - 2021-01-11

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ bool IsDistantLightActive(DirectionalLightData lightData, float3 normal)
return dot(normal, lightData.forward) <= sin(lightData.angularDiameter * 0.5);
}

LightList CreateLightList(float3 position, float3 normal, uint lightLayers = DEFAULT_LIGHT_LAYERS, bool withLocal = true, bool withDistant = true)
LightList CreateLightList(float3 position, float3 normal, uint lightLayers = DEFAULT_LIGHT_LAYERS, bool withLocal = true, bool withDistant = true, float3 lightPosition = FLT_MAX)
{
LightList list;
uint i;
Expand All @@ -118,53 +118,62 @@ LightList CreateLightList(float3 position, float3 normal, uint lightLayers = DEF
list.localCount = 0;
list.localPointCount = 0;

if (withLocal)
{
uint localPointCount, localCount;
if (withLocal)
{
uint localPointCount, localCount;

#ifdef USE_LIGHT_CLUSTER
if (PointInsideCluster(position))
{
list.cellIndex = GetClusterCellIndex(position);
localPointCount = GetPunctualLightClusterCellCount(list.cellIndex);
localCount = GetAreaLightClusterCellCount(list.cellIndex);
}
else
{
localPointCount = 0;
localCount = 0;
}
if (PointInsideCluster(position))
{
list.cellIndex = GetClusterCellIndex(position);
localPointCount = GetPunctualLightClusterCellCount(list.cellIndex);
localCount = GetAreaLightClusterCellCount(list.cellIndex);
}
else
{
localPointCount = 0;
localCount = 0;
}
#else
localPointCount = _PunctualLightCountRT;
localCount = _PunctualLightCountRT + _AreaLightCountRT;
localPointCount = _PunctualLightCountRT;
localCount = _PunctualLightCountRT + _AreaLightCountRT;
#endif

// First point lights (including spot lights)
for (i = 0; i < localPointCount && list.localPointCount < MAX_LOCAL_LIGHT_COUNT; i++)
{
// Do we have an imposed local light (identificed by position), for volumetric scattering?
bool forceLightPosition = (lightPosition.x != FLT_MAX);

// First point lights (including spot lights)
for (i = 0; i < localPointCount && list.localPointCount < MAX_LOCAL_LIGHT_COUNT; i++)
{
#ifdef USE_LIGHT_CLUSTER
const LightData lightData = FetchClusterLightIndex(list.cellIndex, i);
const LightData lightData = FetchClusterLightIndex(list.cellIndex, i);
#else
const LightData lightData = _LightDatasRT[i];
const LightData lightData = _LightDatasRT[i];
#endif

if (IsMatchingLightLayer(lightData.lightLayers, lightLayers) && IsPointLightActive(lightData, position, normal))
list.localIndex[list.localPointCount++] = i;
}
if (forceLightPosition && any(lightPosition - lightData.positionRWS))
continue;

// Then rect area lights
for (list.localCount = list.localPointCount; i < localCount && list.localCount < MAX_LOCAL_LIGHT_COUNT; i++)
{
if (IsMatchingLightLayer(lightData.lightLayers, lightLayers) && IsPointLightActive(lightData, position, normal))
list.localIndex[list.localPointCount++] = i;
}

// Then rect area lights
for (list.localCount = list.localPointCount; i < localCount && list.localCount < MAX_LOCAL_LIGHT_COUNT; i++)
{
#ifdef USE_LIGHT_CLUSTER
const LightData lightData = FetchClusterLightIndex(list.cellIndex, i);
const LightData lightData = FetchClusterLightIndex(list.cellIndex, i);
#else
const LightData lightData = _LightDatasRT[i];
const LightData lightData = _LightDatasRT[i];
#endif

if (IsMatchingLightLayer(lightData.lightLayers, lightLayers) && IsRectAreaLightActive(lightData, position, normal))
list.localIndex[list.localCount++] = i;
if (forceLightPosition && any(lightPosition - lightData.positionRWS))
continue;

if (IsMatchingLightLayer(lightData.lightLayers, lightLayers) && IsRectAreaLightActive(lightData, position, normal))
list.localIndex[list.localCount++] = i;
}
}
}

// Then filter the active distant lights (directional)
list.distantCount = 0;
Expand Down Expand Up @@ -673,22 +682,94 @@ bool GetPointLightInterval(LightData lightData, float3 rayOrigin, float3 rayDire
return tMin < tMax;
}

float GetLocalLightsInterval(float3 rayOrigin, float3 rayDirection, out float tMin, out float tMax)
// This function has been deprecated in favor of PickLocalLightInterval() right below
// float GetLocalLightsInterval(float3 rayOrigin, float3 rayDirection, out float tMin, out float tMax)
// {
// tMin = FLT_MAX;
// tMax = 0.0;

// float tLightMin, tLightMax;

// // First process point lights
// uint i = 0, n = _PunctualLightCountRT, localCount = 0;
// for (; i < n; i++)
// {
// if (GetPointLightInterval(_LightDatasRT[i], rayOrigin, rayDirection, tLightMin, tLightMax))
// {
// tMin = min(tMin, tLightMin);
// tMax = max(tMax, tLightMax);
// localCount++;
// }
// }

// // Then area lights
// n += _AreaLightCountRT;
// for (; i < n; i++)
// {
// if (GetRectAreaLightInterval(_LightDatasRT[i], rayOrigin, rayDirection, tLightMin, tLightMax))
// {
// tMin = min(tMin, tLightMin);
// tMax = max(tMax, tLightMax);
// localCount++;
// }
// }

// uint lightCount = localCount + _DirectionalLightCount;

// return lightCount ? float(localCount) / lightCount : -1.0;
// }

float GetLocalLightWeight(LightData lightData, float3 rayOrigin, float3 rayDirection, float tMin, float tMax)
{
float tDist = clamp(dot(lightData.positionRWS - rayOrigin, rayDirection), tMin, tMax);
float3 vDist = rayOrigin + tDist * rayDirection - lightData.positionRWS;

// By offsetting the square distance by 1.0, we reduce the range of the weight to ]0.0, 1.0],
// while avoiding a singularity when distance goes towards 0.0.
float distSq = 1.0 + Length2(vDist);

return rcp(distSq);
}

float PickLocalLightInterval(float3 rayOrigin, float3 rayDirection, inout float inputSample, out float3 lightPosition, out float lightWeight, out float tMin, out float tMax)
{
tMin = FLT_MAX;
tMax = 0.0;

float tLightMin, tLightMax;
float wLight, wSum = 0.0;

// First process point lights
uint i = 0, n = _PunctualLightCountRT, localCount = 0;
for (; i < n; i++)
{
if (GetPointLightInterval(_LightDatasRT[i], rayOrigin, rayDirection, tLightMin, tLightMax))
{
tMin = min(tMin, tLightMin);
tMax = max(tMax, tLightMax);
localCount++;
wLight = GetLocalLightWeight(_LightDatasRT[i], rayOrigin, rayDirection, tLightMin, tLightMax);

if (wLight > 0.0)
{
wSum += wLight;
wLight /= wSum;

if (inputSample < wLight)
{
lightPosition = _LightDatasRT[i].positionRWS;
lightWeight = wLight;
tMin = tLightMin;
tMax = tLightMax;

inputSample /= wLight;
}
else
{
lightWeight *= 1.0 - wLight;

inputSample = (inputSample - wLight) / (1.0 - wLight);
}

localCount++;
}
}
}

Expand All @@ -698,9 +779,31 @@ float GetLocalLightsInterval(float3 rayOrigin, float3 rayDirection, out float tM
{
if (GetRectAreaLightInterval(_LightDatasRT[i], rayOrigin, rayDirection, tLightMin, tLightMax))
{
tMin = min(tMin, tLightMin);
tMax = max(tMax, tLightMax);
localCount++;
wLight = GetLocalLightWeight(_LightDatasRT[i], rayOrigin, rayDirection, tLightMin, tLightMax);

if (wLight > 0.0)
{
wSum += wLight;
wLight /= wSum;

if (inputSample < wLight)
{
lightPosition = _LightDatasRT[i].positionRWS;
lightWeight = wLight;
tMin = tLightMin;
tMax = tLightMax;

inputSample /= wLight;
}
else
{
lightWeight *= 1.0 - wLight;

inputSample = (inputSample - wLight) / (1.0 - wLight);
}

localCount++;
}
}
}

Expand All @@ -709,9 +812,9 @@ float GetLocalLightsInterval(float3 rayOrigin, float3 rayDirection, out float tM
return lightCount ? float(localCount) / lightCount : -1.0;
}

LightList CreateLightList(float3 position, bool sampleLocalLights)
LightList CreateLightList(float3 position, bool sampleLocalLights, float3 lightPosition = FLT_MAX)
{
return CreateLightList(position, 0.0, DEFAULT_LIGHT_LAYERS, sampleLocalLights, !sampleLocalLights);
return CreateLightList(position, 0.0, DEFAULT_LIGHT_LAYERS, sampleLocalLights, !sampleLocalLights, lightPosition);
}

#endif // UNITY_PATH_TRACING_LIGHT_INCLUDED
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ void MissCamera(inout PathIntersection pathIntersection : SV_RayPayload)

if (_EnableVolumetricFog && _RaytracingMinRecursion <= 1)
{
float3 envValue = pathIntersection.value;
float3 lightPosition, envValue = pathIntersection.value;

// Generate a 4D unit-square sample for this depth, from our QMC sequence
float4 inputSample = GetSample4D(pathIntersection.pixelCoord, _RaytracingSampleIndex, 0);
Expand All @@ -56,15 +56,15 @@ void MissCamera(inout PathIntersection pathIntersection : SV_RayPayload)
pathIntersection.t = FLT_MAX;
float pdf = 1.0;
bool sampleLocalLights;
if (SampleVolumeScatteringPosition(inputSample.w, pathIntersection.t, pdf, sampleLocalLights))
if (SampleVolumeScatteringPosition(pathIntersection.pixelCoord, inputSample.w, pathIntersection.t, pdf, sampleLocalLights, lightPosition))
{
ComputeVolumeScattering(pathIntersection, inputSample.xyz, sampleLocalLights);
ComputeVolumeScattering(pathIntersection, inputSample.xyz, sampleLocalLights, lightPosition);

// Apply the pdf
pathIntersection.value /= pdf;

// Apply volumetric attenuation
ApplyFogAttenuation(WorldRayOrigin(), WorldRayDirection(), pathIntersection.t, pathIntersection.value);
ApplyFogAttenuation(WorldRayOrigin(), WorldRayDirection(), pathIntersection.t, pathIntersection.value, false);
}

// Reinject the environment value
Expand Down
Loading