您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
273 行
9.1 KiB
273 行
9.1 KiB
#include "LightLoop.cs.hlsl"
|
|
#include "../../Sky/SkyVariables.hlsl"
|
|
|
|
StructuredBuffer<uint> g_vLightListGlobal; // don't support Buffer yet in unity
|
|
|
|
#define DWORD_PER_TILE 16 // See dwordsPerTile in LightLoop.cs, we have roomm for 31 lights and a number of light value all store on 16 bit (ushort)
|
|
#define MAX_ENV2D_LIGHT 32
|
|
|
|
CBUFFER_START(UnityTilePass)
|
|
uint _NumTileFtplX;
|
|
uint _NumTileFtplY;
|
|
|
|
// these uniforms are only needed for when OPAQUES_ONLY is NOT defined
|
|
// but there's a problem with our front-end compilation of compute shaders with multiple kernels causing it to error
|
|
//#ifdef USE_CLUSTERED_LIGHTLIST
|
|
float4x4 g_mInvScrProjection;
|
|
|
|
float g_fClustScale;
|
|
float g_fClustBase;
|
|
float g_fNearPlane;
|
|
float g_fFarPlane;
|
|
int g_iLog2NumClusters; // We need to always define these to keep constant buffer layouts compatible
|
|
|
|
uint g_isLogBaseBufferEnabled;
|
|
//#endif
|
|
|
|
//#ifdef USE_CLUSTERED_LIGHTLIST
|
|
uint _NumTileClusteredX;
|
|
uint _NumTileClusteredY;
|
|
CBUFFER_END
|
|
|
|
StructuredBuffer<uint> g_vLayeredOffsetsBuffer; // don't support Buffer yet in unity
|
|
StructuredBuffer<float> g_logBaseBuffer; // don't support Buffer yet in unity
|
|
//#endif
|
|
|
|
#ifdef USE_INDIRECT
|
|
StructuredBuffer<uint> g_TileFeatureFlags;
|
|
#endif
|
|
|
|
StructuredBuffer<DirectionalLightData> _DirectionalLightDatas;
|
|
StructuredBuffer<LightData> _LightDatas;
|
|
StructuredBuffer<EnvLightData> _EnvLightDatas;
|
|
StructuredBuffer<EnvProxyData> _EnvProxyDatas;
|
|
StructuredBuffer<ShadowData> _ShadowDatas;
|
|
|
|
// Used by directional and spot lights
|
|
TEXTURE2D_ARRAY(_CookieTextures);
|
|
|
|
// Used by point lights
|
|
TEXTURECUBE_ARRAY_ABSTRACT(_CookieCubeTextures);
|
|
|
|
// Use texture array for reflection (or LatLong 2D array for mobile)
|
|
TEXTURECUBE_ARRAY_ABSTRACT(_EnvCubemapTextures);
|
|
TEXTURE2D_ARRAY(_Env2DTextures);
|
|
float3 _Env2DCapturePositionWS[MAX_ENV2D_LIGHT];
|
|
float4x4 _Env2DCaptureVP[MAX_ENV2D_LIGHT];
|
|
|
|
TEXTURE2D(_DeferredShadowTexture);
|
|
|
|
CBUFFER_START(UnityPerLightLoop)
|
|
uint _DirectionalLightCount;
|
|
uint _PunctualLightCount;
|
|
uint _AreaLightCount;
|
|
uint _EnvLightCount;
|
|
uint _EnvProxyCount;
|
|
int _EnvLightSkyEnabled; // TODO: make it a bool
|
|
CBUFFER_END
|
|
|
|
// LightLoopContext is not visible from Material (user should not use these properties in Material file)
|
|
// It allow the lightloop to have transmit sampling information (do we use atlas, or texture array etc...)
|
|
struct LightLoopContext
|
|
{
|
|
int sampleReflection;
|
|
ShadowContext shadowContext;
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Cookie sampling functions
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// Used by directional and spot lights.
|
|
float3 SampleCookie2D(LightLoopContext lightLoopContext, float2 coord, int index)
|
|
{
|
|
// TODO: add MIP maps to combat aliasing?
|
|
return SAMPLE_TEXTURE2D_ARRAY_LOD(_CookieTextures, s_linear_clamp_sampler, coord, index, 0).rgb;
|
|
}
|
|
|
|
// Used by point lights.
|
|
float3 SampleCookieCube(LightLoopContext lightLoopContext, float3 coord, int index)
|
|
{
|
|
// TODO: add MIP maps to combat aliasing?
|
|
return SAMPLE_TEXTURECUBE_ARRAY_LOD_ABSTRACT(_CookieCubeTextures, s_linear_clamp_sampler, coord, index, 0).rgb;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Reflection probe / Sky sampling function
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#define SINGLE_PASS_CONTEXT_SAMPLE_REFLECTION_PROBES 0
|
|
#define SINGLE_PASS_CONTEXT_SAMPLE_SKY 1
|
|
|
|
// Note: index is whatever the lighting architecture want, it can contain information like in which texture to sample (in case we have a compressed BC6H texture and an uncompressed for real time reflection ?)
|
|
// EnvIndex can also be use to fetch in another array of struct (to atlas information etc...).
|
|
float4 SampleEnv(LightLoopContext lightLoopContext, int index, float3 texCoord, float lod)
|
|
{
|
|
// 31 bit index, 1 bit cache type
|
|
uint cacheType = index & 1;
|
|
index = index >> 1;
|
|
|
|
// This code will be inlined as lightLoopContext is hardcoded in the light loop
|
|
if (lightLoopContext.sampleReflection == SINGLE_PASS_CONTEXT_SAMPLE_REFLECTION_PROBES)
|
|
{
|
|
if (cacheType == ENVCACHETYPE_TEXTURE2D)
|
|
return SAMPLE_TEXTURE2D_ARRAY_LOD(_Env2DTextures, s_trilinear_clamp_sampler, texCoord.xy, index, 0);
|
|
else if (cacheType == ENVCACHETYPE_CUBEMAP)
|
|
return SAMPLE_TEXTURECUBE_ARRAY_LOD_ABSTRACT(_EnvCubemapTextures, s_trilinear_clamp_sampler, texCoord, index, lod);
|
|
return float4(0, 0, 0, 0);
|
|
}
|
|
else // SINGLE_PASS_SAMPLE_SKY
|
|
{
|
|
return SampleSkyTexture(texCoord, lod);
|
|
}
|
|
}
|
|
|
|
float3 GetSampleEnvCoordinates(LightLoopContext lightLoopContext, int index, float3 texCoord, float lod, out float outWeight)
|
|
{
|
|
// 31 bit index, 1 bit cache type
|
|
uint cacheType = index & 1;
|
|
index = index >> 1;
|
|
|
|
// This code will be inlined as lightLoopContext is hardcoded in the light loop
|
|
if (lightLoopContext.sampleReflection == SINGLE_PASS_CONTEXT_SAMPLE_REFLECTION_PROBES)
|
|
{
|
|
if (cacheType == ENVCACHETYPE_TEXTURE2D)
|
|
{
|
|
float2 positionNCD = ComputeNormalizedDeviceCoordinates(_Env2DCapturePositionWS[index] + texCoord, _Env2DCaptureVP[index]);
|
|
outWeight = any(positionNCD.xy > 1) || any(positionNCD.xy < 0) ? 0 : 1;
|
|
return float3(positionNCD, 1);
|
|
}
|
|
else if (cacheType == ENVCACHETYPE_CUBEMAP)
|
|
{
|
|
outWeight = 1;
|
|
return texCoord;
|
|
}
|
|
outWeight = 0;
|
|
return float4(0, 0, 0, 0);
|
|
}
|
|
else // SINGLE_PASS_SAMPLE_SKY
|
|
{
|
|
outWeight = 1;
|
|
return texCoord;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Single Pass and Tile Pass
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#ifdef LIGHTLOOP_TILE_PASS
|
|
|
|
// Calculate the offset in global light index light for current light category
|
|
int GetTileOffset(PositionInputs posInput, uint lightCategory)
|
|
{
|
|
uint2 tileIndex = posInput.tileCoord;
|
|
return (tileIndex.y + lightCategory * _NumTileFtplY) * _NumTileFtplX + tileIndex.x;
|
|
}
|
|
|
|
void GetCountAndStartTile(PositionInputs posInput, uint lightCategory, out uint start, out uint lightCount)
|
|
{
|
|
const int tileOffset = GetTileOffset(posInput, lightCategory);
|
|
|
|
// The first entry inside a tile is the number of light for lightCategory (thus the +0)
|
|
lightCount = g_vLightListGlobal[DWORD_PER_TILE * tileOffset + 0] & 0xffff;
|
|
start = tileOffset;
|
|
}
|
|
|
|
#ifdef USE_FPTL_LIGHTLIST
|
|
|
|
uint GetTileSize()
|
|
{
|
|
return TILE_SIZE_FPTL;
|
|
}
|
|
|
|
void GetCountAndStart(PositionInputs posInput, uint lightCategory, out uint start, out uint lightCount)
|
|
{
|
|
GetCountAndStartTile(posInput, lightCategory, start, lightCount);
|
|
}
|
|
|
|
uint FetchIndex(uint tileOffset, uint lightIndex)
|
|
{
|
|
const uint lightIndexPlusOne = lightIndex + 1; // Add +1 as first slot is reserved to store number of light
|
|
// Light index are store on 16bit
|
|
return (g_vLightListGlobal[DWORD_PER_TILE * tileOffset + (lightIndexPlusOne >> 1)] >> ((lightIndexPlusOne & 1) * DWORD_PER_TILE)) & 0xffff;
|
|
}
|
|
|
|
#elif defined(USE_CLUSTERED_LIGHTLIST)
|
|
|
|
#include "ClusteredUtils.hlsl"
|
|
|
|
uint GetTileSize()
|
|
{
|
|
return TILE_SIZE_CLUSTERED;
|
|
}
|
|
|
|
float GetLightClusterMinLinearDepth(uint2 tileIndex, uint clusterIndex)
|
|
{
|
|
float logBase = g_fClustBase;
|
|
if (g_isLogBaseBufferEnabled)
|
|
{
|
|
logBase = g_logBaseBuffer[tileIndex.y * _NumTileClusteredX + tileIndex.x];
|
|
}
|
|
|
|
return ClusterIdxToZFlex(clusterIndex, logBase, g_isLogBaseBufferEnabled != 0);
|
|
}
|
|
|
|
uint GetLightClusterIndex(uint2 tileIndex, float linearDepth)
|
|
{
|
|
float logBase = g_fClustBase;
|
|
if (g_isLogBaseBufferEnabled)
|
|
{
|
|
logBase = g_logBaseBuffer[tileIndex.y * _NumTileClusteredX + tileIndex.x];
|
|
}
|
|
|
|
return SnapToClusterIdxFlex(linearDepth, logBase, g_isLogBaseBufferEnabled != 0);
|
|
}
|
|
|
|
void GetCountAndStartCluster(uint2 tileIndex, uint clusterIndex, uint lightCategory, out uint start, out uint lightCount)
|
|
{
|
|
int nrClusters = (1 << g_iLog2NumClusters);
|
|
const int idx = ((lightCategory * nrClusters + clusterIndex) * _NumTileClusteredY + tileIndex.y) * _NumTileClusteredX + tileIndex.x;
|
|
uint dataPair = g_vLayeredOffsetsBuffer[idx];
|
|
start = dataPair & 0x7ffffff;
|
|
lightCount = (dataPair >> 27) & 31;
|
|
}
|
|
|
|
void GetCountAndStartCluster(PositionInputs posInput, uint lightCategory, out uint start, out uint lightCount)
|
|
{
|
|
uint2 tileIndex = posInput.tileCoord;
|
|
uint clusterIndex = GetLightClusterIndex(tileIndex, posInput.linearDepth);
|
|
|
|
GetCountAndStartCluster(tileIndex, clusterIndex, lightCategory, start, lightCount);
|
|
}
|
|
|
|
void GetCountAndStart(PositionInputs posInput, uint lightCategory, out uint start, out uint lightCount)
|
|
{
|
|
GetCountAndStartCluster(posInput, lightCategory, start, lightCount);
|
|
}
|
|
|
|
uint FetchIndex(uint tileOffset, uint lightIndex)
|
|
{
|
|
return g_vLightListGlobal[tileOffset + lightIndex];
|
|
}
|
|
|
|
#endif // USE_FPTL_LIGHTLIST
|
|
|
|
#else
|
|
|
|
uint GetTileSize()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
#endif // LIGHTLOOP_TILE_PASS
|
|
|
|
LightData FetchLight(uint start, uint i)
|
|
{
|
|
#ifdef LIGHTLOOP_TILE_PASS
|
|
int j = FetchIndex(start, i);
|
|
#else
|
|
int j = start + i;
|
|
#endif
|
|
return _LightDatas[j];
|
|
}
|