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.
150 lines
5.5 KiB
150 lines
5.5 KiB
#ifndef UNITY_RAY_TRACING_LIGHT_CLUSTER_INCLUDED
|
|
#define UNITY_RAY_TRACING_LIGHT_CLUSTER_INCLUDED
|
|
|
|
// This allows us to either use the light cluster to pick which lights should be used, or use all the lights available
|
|
|
|
uint GetTotalLightClusterCellCount(int cellIndex)
|
|
{
|
|
return _RaytracingLightCluster[cellIndex * (_LightPerCellCount + CELL_META_DATA_SIZE) + CELL_META_DATA_TOTAL_INDEX];
|
|
}
|
|
|
|
uint GetPunctualLightEndIndexInClusterCell(int cellIndex)
|
|
{
|
|
return _RaytracingLightCluster[cellIndex * (_LightPerCellCount + CELL_META_DATA_SIZE) + CELL_META_DATA_PUNCTUAL_END_INDEX];
|
|
}
|
|
|
|
uint GetAreaLightEndIndexInClusterCell(int cellIndex)
|
|
{
|
|
return _RaytracingLightCluster[cellIndex * (_LightPerCellCount + CELL_META_DATA_SIZE) + CELL_META_DATA_AREA_END_INDEX];
|
|
}
|
|
|
|
uint GetEnvLightEndIndexInClusterCell(int cellIndex)
|
|
{
|
|
return _RaytracingLightCluster[cellIndex * (_LightPerCellCount + CELL_META_DATA_SIZE) + CELL_META_DATA_ENV_END_INDEX];
|
|
}
|
|
|
|
uint GetDecalEndIndexInClusterCell(int cellIndex)
|
|
{
|
|
return _RaytracingLightCluster[cellIndex * (_LightPerCellCount + CELL_META_DATA_SIZE) + CELL_META_DATA_DECAL_END_INDEX];
|
|
}
|
|
|
|
uint GetLightClusterCellLightByIndex(int cellIndex, int lightIndex)
|
|
{
|
|
return _RaytracingLightCluster[cellIndex * (_LightPerCellCount + CELL_META_DATA_SIZE) + CELL_META_DATA_SIZE + lightIndex];
|
|
}
|
|
|
|
bool PointInsideCluster(float3 positionWS)
|
|
{
|
|
return !(positionWS.x < _MinClusterPos.x || positionWS.y < _MinClusterPos.y || positionWS.z < _MinClusterPos.z
|
|
|| positionWS.x > _MaxClusterPos.x || positionWS.y > _MaxClusterPos.y || positionWS.z > _MaxClusterPos.z);
|
|
}
|
|
|
|
uint GetClusterCellIndex(uint width, uint height, uint depth)
|
|
{
|
|
return depth + height * CLUSTER_SIZE.z + width * CLUSTER_SIZE.z * CLUSTER_SIZE.y;
|
|
}
|
|
|
|
uint GetClusterCellIndex(float3 positionWS)
|
|
{
|
|
uint3 gridPosition = (uint3)((positionWS - _MinClusterPos) / (_MaxClusterPos - _MinClusterPos) * (float3)CLUSTER_SIZE);
|
|
return GetClusterCellIndex(gridPosition.x, gridPosition.y, gridPosition.z);
|
|
}
|
|
|
|
|
|
void GetLightCountAndStartCluster(float3 positionWS, uint lightCategory, out uint lightStart, out uint lightEnd, out uint cellIndex)
|
|
{
|
|
lightStart = 0;
|
|
lightEnd = 0;
|
|
cellIndex = 0;
|
|
|
|
// If this point is inside the cluster, get lights
|
|
if(PointInsideCluster(positionWS))
|
|
{
|
|
// Deduce the cell index
|
|
cellIndex = GetClusterCellIndex(positionWS);
|
|
|
|
// Grab the light count -- in principle all invocations take the same branch
|
|
switch (lightCategory)
|
|
{
|
|
case 0: // LIGHTCATEGORY_PUNCTUAL
|
|
lightStart = 0;
|
|
lightEnd = GetPunctualLightEndIndexInClusterCell(cellIndex);
|
|
break;
|
|
case 1: // LIGHTCATEGORY_AREA
|
|
lightStart = GetPunctualLightEndIndexInClusterCell(cellIndex);
|
|
lightEnd = GetAreaLightEndIndexInClusterCell(cellIndex);
|
|
break;
|
|
case 2: // LIGHTCATEGORY_ENV
|
|
lightStart = GetAreaLightEndIndexInClusterCell(cellIndex);
|
|
lightEnd = GetEnvLightEndIndexInClusterCell(cellIndex);
|
|
break;
|
|
case 3: // LIGHTCATEGORY_DECAL
|
|
lightStart = GetEnvLightEndIndexInClusterCell(cellIndex);
|
|
lightEnd = GetDecalEndIndexInClusterCell(cellIndex);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
LightData FetchClusterLightIndex(int cellIndex, uint lightIndex)
|
|
{
|
|
int absoluteLightIndex = GetLightClusterCellLightByIndex(cellIndex, lightIndex);
|
|
return _WorldLightDatas[absoluteLightIndex];
|
|
}
|
|
|
|
EnvLightData FetchClusterEnvLightIndex(int cellIndex, uint lightIndex)
|
|
{
|
|
int absoluteLightIndex = GetLightClusterCellLightByIndex(cellIndex, lightIndex);
|
|
return _WorldEnvLightDatas[absoluteLightIndex];
|
|
}
|
|
|
|
#if defined(HAS_LIGHTLOOP) && (SHADERPASS != SHADERPASS_PATH_TRACING) && !defined(PATH_TRACING_CLUSTERED_DECALS)
|
|
float3 RayTraceReflectionProbes(float3 rayOrigin, float3 rayDirection, inout float totalWeight)
|
|
{
|
|
float3 result = 0.0;
|
|
totalWeight = 0.0;
|
|
|
|
uint lightStart = 0, lightEnd = 0, cellIndex = 0;
|
|
#ifdef USE_LIGHT_CLUSTER
|
|
// Get the punctual light count
|
|
GetLightCountAndStartCluster(rayOrigin, LIGHTCATEGORY_ENV, lightStart, lightEnd, cellIndex);
|
|
#else
|
|
lightStart = 0;
|
|
lightEnd = _WorldEnvLightCount;
|
|
#endif
|
|
// Scalarized loop, same rationale of the punctual light version
|
|
uint envLightIdx = lightStart;
|
|
while (envLightIdx < lightEnd)
|
|
{
|
|
#ifdef USE_LIGHT_CLUSTER
|
|
EnvLightData envLightData = FetchClusterEnvLightIndex(cellIndex, envLightIdx);
|
|
#else
|
|
EnvLightData envLightData = _WorldEnvLightDatas[envLightIdx];
|
|
#endif
|
|
|
|
if (IsEnvIndexCubemap(envLightData.envIndex) && totalWeight < 1.0)
|
|
{
|
|
float weight = 1.0;
|
|
float3 R = rayDirection;
|
|
float intersectionDistance = EvaluateLight_EnvIntersection(rayOrigin, rayDirection, envLightData, envLightData.influenceShapeType, R, weight);
|
|
|
|
int index = abs(envLightData.envIndex) - 1;
|
|
|
|
float2 atlasCoords = GetReflectionAtlasCoordsCube(CUBE_SCALE_OFFSET[index], R, 0);
|
|
|
|
float3 probeResult = SAMPLE_TEXTURE2D_ARRAY_LOD(_ReflectionAtlas, s_trilinear_clamp_sampler, atlasCoords, 0, 0).rgb * envLightData.rangeCompressionFactorCompensation;
|
|
probeResult = ClampToFloat16Max(probeResult);
|
|
|
|
UpdateLightingHierarchyWeights(totalWeight, weight);
|
|
result += weight * probeResult * envLightData.multiplier;
|
|
}
|
|
|
|
envLightIdx++;
|
|
}
|
|
totalWeight = saturate(totalWeight);
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
|
|
#endif
|