浏览代码
Merge branch 'master' into lowendmobile
Merge branch 'master' into lowendmobile
# Conflicts: # Assets/LowEndMobilePipeline/TestScenes/Materials.meta # Assets/ScriptableRenderPipeline/Editor/MaterialUpgrader.cs # Assets/TestScenes/HDTest/GraphicTest/LayeredTessellation/Material.meta # Assets/TestScenes/HDTest/LayeredLitTest/Mesh/Materials.meta/vr_sandbox
Felipe Lira
8 年前
当前提交
557acdfd
共有 470 个文件被更改,包括 4056 次插入 和 4092 次删除
-
2Assets/ScriptableRenderPipeline.meta
-
6Assets/ScriptableRenderPipeline/AdditionalLightData.cs
-
29Assets/ScriptableRenderPipeline/Editor/MaterialUpgrader.cs
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline.meta
-
28Assets/ScriptableRenderPipeline/HDRenderPipeline/Debug/HDRenderPipelineDebug.cs
-
1Assets/ScriptableRenderPipeline/HDRenderPipeline/Debug/HDRenderPipelineDebug.cs.hlsl
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/Debug/Resources/DebugDisplayShadowMap.shader
-
18Assets/ScriptableRenderPipeline/HDRenderPipeline/Debug/Resources/DebugViewMaterialGBuffer.shader
-
409Assets/ScriptableRenderPipeline/HDRenderPipeline/Debug/Resources/DebugViewTiles.shader
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/Editor.meta
-
172Assets/ScriptableRenderPipeline/HDRenderPipeline/Editor/HDRenderPipelineInspector.cs
-
92Assets/ScriptableRenderPipeline/HDRenderPipeline/Editor/HDRenderPipelineMenuItems.cs
-
6Assets/ScriptableRenderPipeline/HDRenderPipeline/Editor/UpgradeStandardShaderMaterials.cs
-
160Assets/ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.asset
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.asset.meta
-
535Assets/ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.cs
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.cs.meta
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting.meta
-
9Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/LightLoop.cs
-
23Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/Lighting.hlsl
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/Resources.meta
-
47Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/Resources/Deferred.shader
-
25Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TileLightLoopProducer.cs
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass.meta
-
16Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/lightlistbuild-bigtile.compute
-
50Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/lightlistbuild-clustered.compute
-
925Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/lightlistbuild.compute
-
4Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/scrbound.compute
-
185Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/shadeopaque.compute
-
1001Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePass.cs
-
14Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePass.cs.hlsl
-
62Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePass.hlsl
-
700Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePassLoop.hlsl
-
8Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePassProducer.asset
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePassProducer.asset.meta
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePassResources.asset
-
1Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePassResources.cs
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/Material.meta
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Builtin/BuiltinData.hlsl
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/LayeredLit.meta
-
296Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/LayeredLit/Editor/LayeredLitUI.cs
-
79Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/LayeredLit/LayeredLit.shader
-
118Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/LayeredLit/LayeredLitTessellation.shader
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit.meta
-
558Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Editor/BaseLitUI.cs
-
206Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Editor/LitUI.cs
-
17Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Editor/StandardSpecularToHDLitMaterialUpgrader.cs
-
17Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Editor/StandardToHDLitMaterialUpgrader.cs
-
8Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.cs
-
8Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.cs.hlsl
-
238Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.hlsl
-
62Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.shader
-
466Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitData.hlsl
-
153Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitDataInternal.hlsl
-
69Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitProperties.hlsl
-
13Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitTessellation.hlsl
-
69Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitTessellation.shader
-
4Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LtcData.DisneyDiffuse.cs
-
8Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LtcData.GGX.cs
-
81Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Resources/CombineSubsurfaceScattering.shader
-
6Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Resources/PreIntegratedFGD.shader
-
1Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/ShaderPass/LitDepthPass.hlsl
-
1Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/ShaderPass/LitDistortionPass.hlsl
-
1Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/ShaderPass/LitVelocityPass.hlsl
-
18Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Material.hlsl
-
34Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/MaterialUtilities.hlsl
-
278Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Unlit/Editor/BaseUnlitUI.cs
-
58Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Unlit/Editor/UnlitUI.cs
-
18Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Unlit/Unlit.shader
-
6Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Unlit/UnlitProperties.hlsl
-
68Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/Editor/PostProcessingSRPEditor.cs
-
4Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/Resources/EyeAdaptation.shader
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/Resources/EyeHistogram.compute
-
32Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/Resources/FinalPass.shader
-
6Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/Resources/LutGen.shader
-
157Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/PostProcessingSRP.cs
-
19Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/PostProcessingSRP.Settings.cs
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass.meta
-
22Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/FragInputs.hlsl
-
15Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/ShaderPassDebugViewMaterial.hlsl
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/ShaderPassDepthOnly.hlsl
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/ShaderPassDistortion.hlsl
-
5Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/ShaderPassForward.hlsl
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/ShaderPassForwardUnlit.hlsl
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/ShaderPassGBuffer.hlsl
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/ShaderPassLightTransport.hlsl
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/ShaderPassVelocity.hlsl
-
34Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/VaryingMesh.hlsl
-
104Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderVariables.hlsl
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/Shadow.meta
-
135Assets/ScriptableRenderPipeline/HDRenderPipeline/Shadow/Shadow.hlsl
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky.meta
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/HDRISky/Editor/HDRISkyEditor.cs
-
6Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/HDRISky/HDRISkyRenderer.cs
-
8Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/HDRISky/Resources/SkyHDRI.shader
-
31Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/ProceduralSky/ProceduralSkyRenderer.cs
-
18Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/ProceduralSky/Resources/AtmosphericScattering.hlsl
-
11Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/ProceduralSky/Resources/SkyProcedural.shader
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/ProceduralSky/ProceduralSkySettings.cs
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/Resources.meta
|
|||
Shader "Hidden/HDRenderPipeline/DebugViewTiles" |
|||
{ |
|||
SubShader |
|||
{ |
|||
|
|||
Pass |
|||
{ |
|||
ZWrite Off |
|||
Blend SrcAlpha OneMinusSrcAlpha |
|||
|
|||
HLSLPROGRAM |
|||
#pragma target 4.5 |
|||
#pragma only_renderers d3d11 ps4 metal // TEMP: until we go further in dev |
|||
|
|||
#pragma vertex Vert |
|||
#pragma fragment Frag |
|||
|
|||
#define LIGHTLOOP_TILE_PASS |
|||
#define LIGHTLOOP_TILE_ALL |
|||
|
|||
#pragma multi_compile USE_FPTL_LIGHTLIST USE_CLUSTERED_LIGHTLIST |
|||
|
|||
//------------------------------------------------------------------------------------- |
|||
// Include |
|||
//------------------------------------------------------------------------------------- |
|||
|
|||
#include "ShaderLibrary/Common.hlsl" |
|||
|
|||
// Note: We have fix as guidelines that we have only one deferred material (with control of GBuffer enabled). Mean a users that add a new |
|||
// deferred material must replace the old one here. If in the future we want to support multiple layout (cause a lot of consistency problem), |
|||
// the deferred shader will require to use multicompile. |
|||
#define UNITY_MATERIAL_LIT // Need to be define before including Material.hlsl |
|||
#include "HDRenderPipeline/ShaderConfig.cs.hlsl" |
|||
#include "HDRenderPipeline/ShaderVariables.hlsl" |
|||
#include "HDRenderPipeline/Lighting/Lighting.hlsl" // This include Material.hlsl |
|||
|
|||
//------------------------------------------------------------------------------------- |
|||
// variable declaration |
|||
//------------------------------------------------------------------------------------- |
|||
|
|||
TEXTURE2D_FLOAT(_CameraDepthTexture); |
|||
SAMPLER2D(sampler_CameraDepthTexture); |
|||
|
|||
uint _ViewTilesFlags; |
|||
float2 _MousePixelCoord; |
|||
|
|||
|
|||
float4 Vert(float3 positionOS : POSITION): SV_POSITION |
|||
{ |
|||
return TransformWorldToHClip(TransformObjectToWorld(positionOS)); |
|||
} |
|||
|
|||
float4 AlphaBlend(float4 c0, float4 c1) // c1 over c0 |
|||
{ |
|||
return float4(lerp(c0.rgb, c1.rgb, c1.a), c0.a + c1.a - c0.a * c1.a); |
|||
} |
|||
|
|||
float4 OverlayHeatMap(uint2 pixCoord, uint numLights) |
|||
{ |
|||
const float4 kRadarColors[12] = |
|||
{ |
|||
float4(0.0, 0.0, 0.0, 0.0), // black |
|||
float4(0.0, 0.0, 0.6, 0.5), // dark blue |
|||
float4(0.0, 0.0, 0.9, 0.5), // blue |
|||
float4(0.0, 0.6, 0.9, 0.5), // light blue |
|||
float4(0.0, 0.9, 0.9, 0.5), // cyan |
|||
float4(0.0, 0.9, 0.6, 0.5), // blueish green |
|||
float4(0.0, 0.9, 0.0, 0.5), // green |
|||
float4(0.6, 0.9, 0.0, 0.5), // yellowish green |
|||
float4(0.9, 0.9, 0.0, 0.5), // yellow |
|||
float4(0.9, 0.6, 0.0, 0.5), // orange |
|||
float4(0.9, 0.0, 0.0, 0.5), // red |
|||
float4(1.0, 0.0, 0.0, 0.9) // strong red |
|||
}; |
|||
|
|||
float maxNrLightsPerTile = 31; // TODO: setup a constant for that |
|||
|
|||
int colorIndex = numLights == 0 ? 0 : (1 + (int)floor(10 * (log2((float)numLights) / log2(maxNrLightsPerTile)))); |
|||
colorIndex = colorIndex < 0 ? 0 : colorIndex; |
|||
float4 col = colorIndex > 11 ? float4(1.0, 1.0, 1.0, 1.0) : kRadarColors[colorIndex]; |
|||
|
|||
int2 coord = pixCoord - int2(1, 1); |
|||
|
|||
float4 color = float4(PositivePow(col.xyz, 2.2), 0.3 * col.w); |
|||
if (numLights > 0) |
|||
{ |
|||
if (SampleDebugFontNumber(coord, numLights)) // Shadow |
|||
color = float4(0, 0, 0, 1); |
|||
if (SampleDebugFontNumber(coord + 1, numLights)) // Text |
|||
color = float4(1, 1, 1, 1); |
|||
} |
|||
return color; |
|||
} |
|||
|
|||
float4 Frag(float4 positionCS : SV_POSITION) : SV_Target |
|||
{ |
|||
// positionCS is SV_Position |
|||
PositionInputs posInput = GetPositionInput(positionCS.xy, _ScreenSize.zw); |
|||
float depth = LOAD_TEXTURE2D(_CameraDepthTexture, posInput.unPositionSS).x; |
|||
UpdatePositionInput(depth, _InvViewProjMatrix, _ViewProjMatrix, posInput); |
|||
|
|||
int2 pixelCoord = posInput.unPositionSS.xy; |
|||
int2 tileCoord = (float2)pixelCoord / TILE_SIZE; |
|||
int2 mouseTileCoord = _MousePixelCoord / TILE_SIZE; |
|||
int2 offsetInTile = pixelCoord - tileCoord * TILE_SIZE; |
|||
|
|||
int n = 0; |
|||
for (int category = 0; category < LIGHTCATEGORY_COUNT; category++) |
|||
{ |
|||
uint mask = 1u << category; |
|||
if (mask & _ViewTilesFlags) |
|||
{ |
|||
uint start; |
|||
uint count; |
|||
GetCountAndStart(posInput, category, start, count); |
|||
n += count; |
|||
} |
|||
} |
|||
|
|||
float4 result = float4(0.0, 0.0, 0.0, 0.0); |
|||
|
|||
// Tile overlap counter |
|||
if (n > 0) |
|||
{ |
|||
result = OverlayHeatMap(int2(posInput.unPositionSS.xy) & (TILE_SIZE - 1), n); |
|||
} |
|||
|
|||
// Highlight selected tile |
|||
if (all(mouseTileCoord == tileCoord)) |
|||
{ |
|||
bool border = any(offsetInTile == 0 || offsetInTile == TILE_SIZE - 1); |
|||
float4 result2 = float4(1.0, 1.0, 1.0, border ? 1.0 : 0.5); |
|||
result = AlphaBlend(result, result2); |
|||
} |
|||
|
|||
// Print light lists for selected tile at the bottom of the screen |
|||
int maxLights = 32; |
|||
if (tileCoord.y < LIGHTCATEGORY_COUNT && tileCoord.x < maxLights + 3) |
|||
{ |
|||
PositionInputs mousePosInput = GetPositionInput(_MousePixelCoord, _ScreenSize.zw); |
|||
float depthMouse = LOAD_TEXTURE2D(_CameraDepthTexture, mousePosInput.unPositionSS).x; |
|||
UpdatePositionInput(depthMouse, _InvViewProjMatrix, _ViewProjMatrix, mousePosInput); |
|||
|
|||
uint category = (LIGHTCATEGORY_COUNT - 1) - tileCoord.y; |
|||
uint start; |
|||
uint count; |
|||
GetCountAndStart(mousePosInput, category, start, count); |
|||
|
|||
float4 result2 = float4(.1,.1,.1,.9); |
|||
int2 fontCoord = int2(pixelCoord.x, offsetInTile.y); |
|||
int lightListIndex = tileCoord.x - 2; |
|||
|
|||
int n = -1; |
|||
if(tileCoord.x == 0) |
|||
{ |
|||
n = (int)count; |
|||
} |
|||
else if(lightListIndex >= 0 && lightListIndex < (int)count) |
|||
{ |
|||
n = FetchIndex(start, lightListIndex); |
|||
} |
|||
|
|||
if (n >= 0) |
|||
{ |
|||
if (SampleDebugFontNumber(offsetInTile, n)) |
|||
result2 = float4(0.0, 0.0, 0.0, 1.0); |
|||
if (SampleDebugFontNumber(offsetInTile + 1, n)) |
|||
result2 = float4(1.0, 1.0, 1.0, 1.0); |
|||
} |
|||
|
|||
result = AlphaBlend(result, result2); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
ENDHLSL |
|||
} |
|||
} |
|||
Fallback Off |
|||
} |
|||
Shader "Hidden/HDRenderPipeline/DebugViewTiles" |
|||
{ |
|||
SubShader |
|||
{ |
|||
|
|||
Pass |
|||
{ |
|||
ZWrite Off |
|||
Blend SrcAlpha OneMinusSrcAlpha |
|||
|
|||
HLSLPROGRAM |
|||
#pragma target 4.5 |
|||
#pragma only_renderers d3d11 ps4 metal // TEMP: until we go further in dev |
|||
|
|||
#pragma vertex Vert |
|||
#pragma fragment Frag |
|||
|
|||
#define LIGHTLOOP_TILE_PASS |
|||
#define LIGHTLOOP_TILE_ALL |
|||
|
|||
#pragma multi_compile USE_FPTL_LIGHTLIST USE_CLUSTERED_LIGHTLIST |
|||
#pragma multi_compile SHOW_LIGHT_CATEGORIES SHOW_FEATURE_VARIANTS |
|||
|
|||
//------------------------------------------------------------------------------------- |
|||
// Include |
|||
//------------------------------------------------------------------------------------- |
|||
|
|||
#include "../../../ShaderLibrary/Common.hlsl" |
|||
|
|||
// Note: We have fix as guidelines that we have only one deferred material (with control of GBuffer enabled). Mean a users that add a new |
|||
// deferred material must replace the old one here. If in the future we want to support multiple layout (cause a lot of consistency problem), |
|||
// the deferred shader will require to use multicompile. |
|||
#define UNITY_MATERIAL_LIT // Need to be define before including Material.hlsl |
|||
#include "../../ShaderConfig.cs.hlsl" |
|||
#include "../../ShaderVariables.hlsl" |
|||
#include "../../Lighting/Lighting.hlsl" // This include Material.hlsl |
|||
|
|||
//------------------------------------------------------------------------------------- |
|||
// variable declaration |
|||
//------------------------------------------------------------------------------------- |
|||
|
|||
uint _ViewTilesFlags; |
|||
uint _NumTiles; |
|||
float2 _MousePixelCoord; |
|||
|
|||
StructuredBuffer<uint> g_TileList; |
|||
Buffer<uint> g_DispatchIndirectBuffer; |
|||
|
|||
struct VSOut |
|||
{ |
|||
float4 Pos : SV_POSITION; |
|||
int Variant : TEXCOORD0; |
|||
}; |
|||
|
|||
#if SHOW_FEATURE_VARIANTS |
|||
VSOut Vert(uint vertexID : SV_VertexID) |
|||
{ |
|||
uint quadIndex = vertexID / 6; |
|||
uint quadVertex = vertexID - quadIndex * 6; |
|||
quadVertex = (0x312210 >> (quadVertex<<2)) & 3; //remap [0,5]->[0,3] |
|||
|
|||
uint2 tileSize = GetTileSize(); |
|||
|
|||
uint variant = 0; |
|||
while (quadIndex >= g_DispatchIndirectBuffer[variant * 3 + 0] && variant < NUM_FEATURE_VARIANTS) |
|||
{ |
|||
quadIndex -= g_DispatchIndirectBuffer[variant * 3 + 0]; |
|||
variant++; |
|||
} |
|||
|
|||
uint tileIndex = g_TileList[variant * _NumTiles + quadIndex]; |
|||
uint2 tileCoord = uint2(tileIndex & 0xFFFF, tileIndex >> 16); |
|||
uint2 pixelCoord = (tileCoord + uint2((quadVertex+1) & 1, (quadVertex >> 1) & 1)) * tileSize; |
|||
|
|||
float2 clipCoord = (pixelCoord / _ScreenParams.xy) * 2.0 - 1.0; |
|||
clipCoord.y *= -1; |
|||
|
|||
VSOut Out; |
|||
Out.Pos = float4(clipCoord, 0, 1.0); |
|||
Out.Variant = variant; |
|||
return Out; |
|||
} |
|||
#else |
|||
VSOut Vert(float3 positionOS : POSITION) |
|||
{ |
|||
VSOut Out; |
|||
Out.Pos = TransformWorldToHClip(TransformObjectToWorld(positionOS)); |
|||
Out.Variant = 0; |
|||
return Out; |
|||
} |
|||
#endif |
|||
|
|||
float4 AlphaBlend(float4 c0, float4 c1) // c1 over c0 |
|||
{ |
|||
return float4(lerp(c0.rgb, c1.rgb, c1.a), c0.a + c1.a - c0.a * c1.a); |
|||
} |
|||
|
|||
float4 OverlayHeatMap(uint2 pixCoord, uint n) |
|||
{ |
|||
const float4 kRadarColors[12] = |
|||
{ |
|||
float4(0.0, 0.0, 0.0, 0.0), // black |
|||
float4(0.0, 0.0, 0.6, 0.5), // dark blue |
|||
float4(0.0, 0.0, 0.9, 0.5), // blue |
|||
float4(0.0, 0.6, 0.9, 0.5), // light blue |
|||
float4(0.0, 0.9, 0.9, 0.5), // cyan |
|||
float4(0.0, 0.9, 0.6, 0.5), // blueish green |
|||
float4(0.0, 0.9, 0.0, 0.5), // green |
|||
float4(0.6, 0.9, 0.0, 0.5), // yellowish green |
|||
float4(0.9, 0.9, 0.0, 0.5), // yellow |
|||
float4(0.9, 0.6, 0.0, 0.5), // orange |
|||
float4(0.9, 0.0, 0.0, 0.5), // red |
|||
float4(1.0, 0.0, 0.0, 0.9) // strong red |
|||
}; |
|||
|
|||
float maxNrLightsPerTile = 31; // TODO: setup a constant for that |
|||
|
|||
int colorIndex = n == 0 ? 0 : (1 + (int)floor(10 * (log2((float)n) / log2(maxNrLightsPerTile)))); |
|||
colorIndex = colorIndex < 0 ? 0 : colorIndex; |
|||
float4 col = colorIndex > 11 ? float4(1.0, 1.0, 1.0, 1.0) : kRadarColors[colorIndex]; |
|||
|
|||
int2 coord = pixCoord - int2(1, 1); |
|||
|
|||
float4 color = float4(PositivePow(col.xyz, 2.2), 0.3 * col.w); |
|||
if (n >= 0) |
|||
{ |
|||
if (SampleDebugFontNumber(coord, n)) // Shadow |
|||
color = float4(0, 0, 0, 1); |
|||
if (SampleDebugFontNumber(coord + 1, n)) // Text |
|||
color = float4(1, 1, 1, 1); |
|||
} |
|||
return color; |
|||
} |
|||
|
|||
float4 Frag(float4 positionCS : SV_POSITION, int Variant : TEXCOORD0) : SV_Target |
|||
{ |
|||
// positionCS is SV_Position |
|||
PositionInputs posInput = GetPositionInput(positionCS.xy, _ScreenSize.zw, uint2(positionCS.xy) / GetTileSize()); |
|||
float depth = LOAD_TEXTURE2D(_MainDepthTexture, posInput.unPositionSS).x; |
|||
UpdatePositionInput(depth, _InvViewProjMatrix, _ViewProjMatrix, posInput); |
|||
|
|||
int2 pixelCoord = posInput.unPositionSS.xy; |
|||
int2 tileCoord = (float2)pixelCoord / TILE_SIZE; |
|||
int2 mouseTileCoord = _MousePixelCoord / TILE_SIZE; |
|||
int2 offsetInTile = pixelCoord - tileCoord * TILE_SIZE; |
|||
|
|||
int n = 0; |
|||
#ifdef SHOW_LIGHT_CATEGORIES |
|||
for (int category = 0; category < LIGHTCATEGORY_COUNT; category++) |
|||
{ |
|||
uint mask = 1u << category; |
|||
if (mask & _ViewTilesFlags) |
|||
{ |
|||
uint start; |
|||
uint count; |
|||
GetCountAndStart(posInput, category, start, count); |
|||
n += count; |
|||
} |
|||
} |
|||
if(n == 0) n = -1; |
|||
#else |
|||
n = Variant; |
|||
#endif |
|||
|
|||
float4 result = float4(0.0, 0.0, 0.0, 0.0); |
|||
|
|||
// Tile overlap counter |
|||
if (n >= 0) |
|||
{ |
|||
result = OverlayHeatMap(int2(posInput.unPositionSS.xy) & (TILE_SIZE - 1), n); |
|||
} |
|||
|
|||
#ifdef SHOW_LIGHT_CATEGORIES |
|||
// Highlight selected tile |
|||
if (all(mouseTileCoord == tileCoord)) |
|||
{ |
|||
bool border = any(offsetInTile == 0 || offsetInTile == TILE_SIZE - 1); |
|||
float4 result2 = float4(1.0, 1.0, 1.0, border ? 1.0 : 0.5); |
|||
result = AlphaBlend(result, result2); |
|||
} |
|||
|
|||
// Print light lists for selected tile at the bottom of the screen |
|||
int maxLights = 32; |
|||
if (tileCoord.y < LIGHTCATEGORY_COUNT && tileCoord.x < maxLights + 3) |
|||
{ |
|||
PositionInputs mousePosInput = GetPositionInput(_MousePixelCoord, _ScreenSize.zw, uint2(0,0)); |
|||
float depthMouse = LOAD_TEXTURE2D(_MainDepthTexture, mousePosInput.unPositionSS).x; |
|||
UpdatePositionInput(depthMouse, _InvViewProjMatrix, _ViewProjMatrix, mousePosInput); |
|||
|
|||
uint category = (LIGHTCATEGORY_COUNT - 1) - tileCoord.y; |
|||
uint start; |
|||
uint count; |
|||
GetCountAndStart(mousePosInput, category, start, count); |
|||
|
|||
float4 result2 = float4(.1,.1,.1,.9); |
|||
int2 fontCoord = int2(pixelCoord.x, offsetInTile.y); |
|||
int lightListIndex = tileCoord.x - 2; |
|||
|
|||
int n = -1; |
|||
if(tileCoord.x == 0) |
|||
{ |
|||
n = (int)count; |
|||
} |
|||
else if(lightListIndex >= 0 && lightListIndex < (int)count) |
|||
{ |
|||
n = FetchIndex(start, lightListIndex); |
|||
} |
|||
|
|||
if (n >= 0) |
|||
{ |
|||
if (SampleDebugFontNumber(offsetInTile, n)) |
|||
result2 = float4(0.0, 0.0, 0.0, 1.0); |
|||
if (SampleDebugFontNumber(offsetInTile + 1, n)) |
|||
result2 = float4(1.0, 1.0, 1.0, 1.0); |
|||
} |
|||
|
|||
result = AlphaBlend(result, result2); |
|||
} |
|||
#endif |
|||
|
|||
return result; |
|||
} |
|||
|
|||
ENDHLSL |
|||
} |
|||
} |
|||
Fallback Off |
|||
} |
|
|||
// The implementation is based on the demo on "fine pruned tiled lighting" published in GPU Pro 7. |
|||
// https://github.com/wolfgangfengel/GPU-Pro-7 |
|||
|
|||
#pragma kernel TileLightListGen LIGHTLISTGEN=TileLightListGen |
|||
#pragma kernel TileLightListGen_SrcBigTile LIGHTLISTGEN=TileLightListGen_SrcBigTile USE_TWO_PASS_TILED_LIGHTING |
|||
|
|||
#include "ShaderLibrary/common.hlsl" |
|||
#include "../ShaderBase.hlsl" |
|||
#include "../TilePass.cs.hlsl" |
|||
#include "../LightingConvexHullUtils.hlsl" |
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
#include "../SortingComputeUtils.hlsl" |
|||
#endif |
|||
|
|||
|
|||
#define FINE_PRUNING_ENABLED |
|||
#define PERFORM_SPHERICAL_INTERSECTION_TESTS |
|||
|
|||
|
|||
uniform int g_iNrVisibLights; |
|||
uniform uint2 g_viDimensions; |
|||
uniform float4x4 g_mInvScrProjection; |
|||
uniform float4x4 g_mScrProjection; |
|||
uniform int _EnvLightIndexShift; |
|||
|
|||
Texture2D g_depth_tex : register( t0 ); |
|||
StructuredBuffer<float3> g_vBoundsBuffer : register( t1 ); |
|||
StructuredBuffer<LightVolumeData> _LightVolumeData : register(t2); |
|||
StructuredBuffer<SFiniteLightBound> g_data : register( t3 ); |
|||
|
|||
#ifdef USE_TWO_PASS_TILED_LIGHTING |
|||
StructuredBuffer<uint> g_vBigTileLightList : register( t4 ); // don't support Buffer yet in unity |
|||
#endif |
|||
|
|||
#define NR_THREADS 64 |
|||
|
|||
// output buffer |
|||
RWStructuredBuffer<uint> g_vLightList : register( u0 ); // don't support RWBuffer yet in unity |
|||
|
|||
|
|||
#define MAX_NR_COARSE_ENTRIES 64 |
|||
#define MAX_NR_PRUNED_ENTRIES 24 |
|||
|
|||
groupshared unsigned int coarseList[MAX_NR_COARSE_ENTRIES]; |
|||
groupshared unsigned int prunedList[MAX_NR_COARSE_ENTRIES]; // temporarily support room for all 64 while in LDS |
|||
|
|||
groupshared uint ldsZMin; |
|||
groupshared uint ldsZMax; |
|||
groupshared uint lightOffs; |
|||
#ifdef FINE_PRUNING_ENABLED |
|||
groupshared uint ldsDoesLightIntersect[2]; |
|||
#endif |
|||
groupshared int ldsNrLightsFinal; |
|||
|
|||
groupshared int ldsCategoryListCount[LIGHTCATEGORY_COUNT]; // since LIGHTCATEGORY_COUNT is 3 |
|||
|
|||
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS |
|||
groupshared uint lightOffsSph; |
|||
#endif |
|||
|
|||
|
|||
//float GetLinearDepth(float3 vP) |
|||
//{ |
|||
// float4 v4Pres = mul(g_mInvScrProjection, float4(vP,1.0)); |
|||
// return v4Pres.z / v4Pres.w; |
|||
//} |
|||
|
|||
float GetLinearDepth(float zDptBufSpace) // 0 is near 1 is far |
|||
{ |
|||
float3 vP = float3(0.0f,0.0f,zDptBufSpace); |
|||
float4 v4Pres = mul(g_mInvScrProjection, float4(vP,1.0)); |
|||
return v4Pres.z / v4Pres.w; |
|||
} |
|||
|
|||
|
|||
float3 GetViewPosFromLinDepth(float2 v2ScrPos, float fLinDepth) |
|||
{ |
|||
float fSx = g_mScrProjection[0].x; |
|||
float fCx = g_mScrProjection[0].z; |
|||
float fSy = g_mScrProjection[1].y; |
|||
float fCy = g_mScrProjection[1].z; |
|||
|
|||
#if USE_LEFTHAND_CAMERASPACE |
|||
return fLinDepth*float3( ((v2ScrPos.x-fCx)/fSx), ((v2ScrPos.y-fCy)/fSy), 1.0 ); |
|||
#else |
|||
return fLinDepth*float3( -((v2ScrPos.x+fCx)/fSx), -((v2ScrPos.y+fCy)/fSy), 1.0 ); |
|||
#endif |
|||
} |
|||
|
|||
float GetOnePixDiagWorldDistAtDepthOne() |
|||
{ |
|||
float fSx = g_mScrProjection[0].x; |
|||
float fSy = g_mScrProjection[1].y; |
|||
|
|||
return length( float2(1.0/fSx,1.0/fSy) ); |
|||
} |
|||
|
|||
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS |
|||
int SphericalIntersectionTests(uint threadID, int iNrCoarseLights, float2 screenCoordinate); |
|||
#endif |
|||
|
|||
#ifdef FINE_PRUNING_ENABLED |
|||
void FinePruneLights(uint threadID, int iNrCoarseLights, uint2 viTilLL, float4 vLinDepths); |
|||
#endif |
|||
|
|||
|
|||
[numthreads(NR_THREADS, 1, 1)] |
|||
void LIGHTLISTGEN(uint threadID : SV_GroupIndex, uint3 u3GroupID : SV_GroupID) |
|||
{ |
|||
uint2 tileIDX = u3GroupID.xy; |
|||
uint t=threadID; |
|||
|
|||
if(t<MAX_NR_COARSE_ENTRIES) |
|||
prunedList[t]=0; |
|||
|
|||
uint iWidth = g_viDimensions.x; |
|||
uint iHeight = g_viDimensions.y; |
|||
uint nrTilesX = (iWidth+15)/16; |
|||
uint nrTilesY = (iHeight+15)/16; |
|||
|
|||
// build tile scr boundary |
|||
const uint uFltMax = 0x7f7fffff; // FLT_MAX as a uint |
|||
if(t==0) |
|||
{ |
|||
ldsZMin = uFltMax; |
|||
ldsZMax = 0; |
|||
lightOffs = 0; |
|||
} |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
|
|||
|
|||
uint2 viTilLL = 16*tileIDX; |
|||
|
|||
// establish min and max depth first |
|||
float dpt_mi=asfloat(uFltMax), dpt_ma=0.0; |
|||
|
|||
|
|||
float4 vLinDepths; |
|||
{ |
|||
// Fetch depths and calculate min/max |
|||
[unroll] |
|||
for(int i = 0; i < 4; i++) |
|||
{ |
|||
int idx = i * NR_THREADS + t; |
|||
uint2 uCrd = min( uint2(viTilLL.x+(idx&0xf), viTilLL.y+(idx>>4)), uint2(iWidth-1, iHeight-1) ); |
|||
const float fDepth = FetchDepth(g_depth_tex, uCrd); |
|||
vLinDepths[i] = GetLinearDepth(fDepth); |
|||
if(fDepth<VIEWPORT_SCALE_Z) // if not skydome |
|||
{ |
|||
dpt_mi = min(fDepth, dpt_mi); |
|||
dpt_ma = max(fDepth, dpt_ma); |
|||
} |
|||
} |
|||
|
|||
InterlockedMax(ldsZMax, asuint(dpt_ma)); |
|||
InterlockedMin(ldsZMin, asuint(dpt_mi)); |
|||
|
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
} |
|||
|
|||
|
|||
float3 vTileLL = float3(viTilLL.x/(float) iWidth, viTilLL.y/(float) iHeight, asfloat(ldsZMin)); |
|||
float3 vTileUR = float3((viTilLL.x+16)/(float) iWidth, (viTilLL.y+16)/(float) iHeight, asfloat(ldsZMax)); |
|||
vTileUR.xy = min(vTileUR.xy,float2(1.0,1.0)).xy; |
|||
|
|||
|
|||
// build coarse list using AABB |
|||
#ifdef USE_TWO_PASS_TILED_LIGHTING |
|||
int NrBigTilesX = (nrTilesX+3)>>2; |
|||
const int bigTileIdx = (tileIDX.y>>2)*NrBigTilesX + (tileIDX.x>>2); // map the idx to 64x64 tiles |
|||
int nrBigTileLights = g_vBigTileLightList[MAX_NR_BIGTILE_LIGHTS_PLUSONE*bigTileIdx+0]; |
|||
for(int l0=(int) t; l0<(int) nrBigTileLights; l0 += NR_THREADS) |
|||
{ |
|||
int l = g_vBigTileLightList[MAX_NR_BIGTILE_LIGHTS_PLUSONE*bigTileIdx+l0+1]; |
|||
#else |
|||
for(int l=(int) t; l<(int) g_iNrVisibLights; l += NR_THREADS) |
|||
{ |
|||
#endif |
|||
const float3 vMi = g_vBoundsBuffer[l]; |
|||
const float3 vMa = g_vBoundsBuffer[l+g_iNrVisibLights]; |
|||
|
|||
if( all(vMa>vTileLL) && all(vMi<vTileUR)) |
|||
{ |
|||
unsigned int uInc = 1; |
|||
unsigned int uIndex; |
|||
InterlockedAdd(lightOffs, uInc, uIndex); |
|||
if(uIndex<MAX_NR_COARSE_ENTRIES) coarseList[uIndex] = l; // add to light list |
|||
} |
|||
} |
|||
|
|||
#ifdef FINE_PRUNING_ENABLED |
|||
if(t<2) ldsDoesLightIntersect[t] = 0; |
|||
#endif |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
|
|||
int iNrCoarseLights = min(lightOffs,MAX_NR_COARSE_ENTRIES); |
|||
|
|||
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS |
|||
iNrCoarseLights = SphericalIntersectionTests( t, iNrCoarseLights, float2(min(viTilLL.xy+uint2(16/2,16/2), uint2(iWidth-1, iHeight-1))) ); |
|||
#endif |
|||
|
|||
#ifndef FINE_PRUNING_ENABLED |
|||
{ |
|||
if((int)t<iNrCoarseLights) prunedList[t] = coarseList[t]; |
|||
if(t==0) ldsNrLightsFinal=iNrCoarseLights; |
|||
} |
|||
#else |
|||
{ |
|||
// initializes ldsNrLightsFinal with the number of accepted lights. |
|||
// all accepted entries delivered in prunedList[]. |
|||
FinePruneLights(t, iNrCoarseLights, viTilLL, vLinDepths); |
|||
} |
|||
#endif |
|||
|
|||
// |
|||
if(t<LIGHTCATEGORY_COUNT) ldsCategoryListCount[t]=0; |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
|
|||
|
|||
int nrLightsCombinedList = min(ldsNrLightsFinal,MAX_NR_COARSE_ENTRIES); |
|||
for(int i=t; i<nrLightsCombinedList; i+=NR_THREADS) |
|||
{ |
|||
InterlockedAdd(ldsCategoryListCount[_LightVolumeData[prunedList[i]].lightCategory], 1); |
|||
} |
|||
|
|||
|
|||
// sort lights (gives a more efficient execution in both deferred and tiled forward lighting). |
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
SORTLIST(prunedList, nrLightsCombinedList, MAX_NR_COARSE_ENTRIES, t, NR_THREADS); |
|||
//MERGESORTLIST(prunedList, coarseList, nrLightsCombinedList, t, NR_THREADS); |
|||
#endif |
|||
|
|||
// write lights to global buffers |
|||
int localOffs=0; |
|||
int offs = tileIDX.y*nrTilesX + tileIDX.x; |
|||
|
|||
// All our cull data are in the same list, but at render time envLights are separated so we need to shit the index |
|||
// to make it work correctly |
|||
int shiftIndex[LIGHTCATEGORY_COUNT] = {0, 0, _EnvLightIndexShift}; // 3 for now, will throw an error if we change LIGHTCATEGORY_COUNT |
|||
|
|||
for(int category=0; category<LIGHTCATEGORY_COUNT; category++) |
|||
{ |
|||
int nrLightsFinal = ldsCategoryListCount[category]; |
|||
int nrLightsFinalClamped = nrLightsFinal<MAX_NR_PRUNED_ENTRIES ? nrLightsFinal : MAX_NR_PRUNED_ENTRIES; |
|||
|
|||
|
|||
const int nrDWords = ((nrLightsFinalClamped+1)+1)>>1; |
|||
for(int l=(int) t; l<(int) nrDWords; l += NR_THREADS) |
|||
{ |
|||
// We remap the prunedList index to the original LightData / EnvLightData indices |
|||
uint uLow = l==0 ? nrLightsFinalClamped : prunedList[2*l-1+localOffs] - shiftIndex[category]; |
|||
uint uHigh = prunedList[2 * l + 0 + localOffs] - shiftIndex[category]; |
|||
|
|||
g_vLightList[16*offs + l] = (uLow&0xffff) | (uHigh<<16); |
|||
} |
|||
|
|||
localOffs += nrLightsFinal; |
|||
offs += (nrTilesX*nrTilesY); |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS |
|||
int SphericalIntersectionTests(uint threadID, int iNrCoarseLights, float2 screenCoordinate) |
|||
{ |
|||
if(threadID==0) lightOffsSph = 0; |
|||
|
|||
// make a copy of coarseList in prunedList. |
|||
int l; |
|||
for(l=threadID; l<iNrCoarseLights; l+=NR_THREADS) |
|||
prunedList[l]=coarseList[l]; |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
|
|||
#if USE_LEFTHAND_CAMERASPACE |
|||
float3 V = GetViewPosFromLinDepth( screenCoordinate, 1.0); |
|||
#else |
|||
float3 V = GetViewPosFromLinDepth( screenCoordinate, -1.0); |
|||
#endif |
|||
|
|||
float onePixDiagDist = GetOnePixDiagWorldDistAtDepthOne(); |
|||
float halfTileSizeAtZDistOne = 8*onePixDiagDist; // scale by half a tile |
|||
|
|||
for(l=threadID; l<iNrCoarseLights; l+=NR_THREADS) |
|||
{ |
|||
SFiniteLightBound lightData = g_data[prunedList[l]]; |
|||
|
|||
if( DoesSphereOverlapTile(V, halfTileSizeAtZDistOne, lightData.center.xyz, lightData.radius) ) |
|||
{ |
|||
unsigned int uIndex; |
|||
InterlockedAdd(lightOffsSph, 1, uIndex); |
|||
coarseList[uIndex]=prunedList[l]; // read from the original copy of coarseList which is backed up in prunedList |
|||
} |
|||
} |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
|
|||
return lightOffsSph; |
|||
} |
|||
#endif |
|||
|
|||
|
|||
#ifdef FINE_PRUNING_ENABLED |
|||
// initializes ldsNrLightsFinal with the number of accepted lights. |
|||
// all accepted entries delivered in prunedList[]. |
|||
void FinePruneLights(uint threadID, int iNrCoarseLights, uint2 viTilLL, float4 vLinDepths) |
|||
{ |
|||
uint t = threadID; |
|||
uint iWidth = g_viDimensions.x; |
|||
uint iHeight = g_viDimensions.y; |
|||
|
|||
uint uLightsFlags[2] = {0,0}; |
|||
int l=0; |
|||
// need this outer loop even on xb1 and ps4 since direct lights and |
|||
// reflection lights are kept in separate regions. |
|||
while(l<iNrCoarseLights) |
|||
{ |
|||
// fetch light |
|||
int idxCoarse = l<iNrCoarseLights ? coarseList[l] : 0; |
|||
uint uLightVolume = l<iNrCoarseLights ? _LightVolumeData[idxCoarse].lightVolume : 0; |
|||
|
|||
// spot |
|||
while(l<iNrCoarseLights && uLightVolume==LIGHTVOLUMETYPE_CONE) |
|||
{ |
|||
LightVolumeData lightData = _LightVolumeData[idxCoarse]; |
|||
// TODO: Change by SebL |
|||
const bool bIsSpotDisc = true; // (lightData.flags&IS_CIRCULAR_SPOT_SHAPE) != 0; |
|||
|
|||
// serially check 4 pixels |
|||
uint uVal = 0; |
|||
for(int i=0; i<4; i++) |
|||
{ |
|||
int idx = t + i*NR_THREADS; |
|||
|
|||
uint2 uPixLoc = min(uint2(viTilLL.x+(idx&0xf), viTilLL.y+(idx>>4)), uint2(iWidth-1, iHeight-1)); |
|||
float3 vVPos = GetViewPosFromLinDepth(uPixLoc + float2(0.5,0.5), vLinDepths[i]); |
|||
|
|||
// check pixel |
|||
float3 fromLight = vVPos-lightData.lightPos.xyz; |
|||
float distSq = dot(fromLight,fromLight); |
|||
const float fSclProj = dot(fromLight, lightData.lightAxisZ.xyz); // spotDir = lightData.lightAxisZ.xyz |
|||
|
|||
float2 V = abs( float2( dot(fromLight, lightData.lightAxisX.xyz), dot(fromLight, lightData.lightAxisY.xyz) ) ); |
|||
|
|||
float fDist2D = bIsSpotDisc ? length(V) : max(V.x,V.y); |
|||
if( all( float2(lightData.radiusSq, fSclProj) > float2(distSq, fDist2D*lightData.cotan) ) ) uVal = 1; |
|||
} |
|||
|
|||
uLightsFlags[l<32 ? 0 : 1] |= (uVal<<(l&31)); |
|||
++l; idxCoarse = l<iNrCoarseLights ? coarseList[l] : 0; |
|||
uLightVolume = l<iNrCoarseLights ? _LightVolumeData[idxCoarse].lightVolume : 0; |
|||
} |
|||
|
|||
// sphere |
|||
while(l<iNrCoarseLights && uLightVolume==LIGHTVOLUMETYPE_SPHERE) |
|||
{ |
|||
LightVolumeData lightData = _LightVolumeData[idxCoarse]; |
|||
|
|||
// serially check 4 pixels |
|||
uint uVal = 0; |
|||
for(int i=0; i<4; i++) |
|||
{ |
|||
int idx = t + i*NR_THREADS; |
|||
|
|||
uint2 uPixLoc = min(uint2(viTilLL.x+(idx&0xf), viTilLL.y+(idx>>4)), uint2(iWidth-1, iHeight-1)); |
|||
float3 vVPos = GetViewPosFromLinDepth(uPixLoc + float2(0.5,0.5), vLinDepths[i]); |
|||
|
|||
// check pixel |
|||
float3 vLp = lightData.lightPos.xyz; |
|||
float3 toLight = vLp - vVPos; |
|||
float distSq = dot(toLight,toLight); |
|||
|
|||
if(lightData.radiusSq>distSq) uVal = 1; |
|||
} |
|||
|
|||
uLightsFlags[l<32 ? 0 : 1] |= (uVal<<(l&31)); |
|||
++l; idxCoarse = l<iNrCoarseLights ? coarseList[l] : 0; |
|||
uLightVolume = l<iNrCoarseLights ? _LightVolumeData[idxCoarse].lightVolume : 0; |
|||
} |
|||
|
|||
// Box |
|||
while(l<iNrCoarseLights && uLightVolume==LIGHTVOLUMETYPE_BOX) |
|||
{ |
|||
LightVolumeData lightData = _LightVolumeData[idxCoarse]; |
|||
|
|||
// serially check 4 pixels |
|||
uint uVal = 0; |
|||
for(int i=0; i<4; i++) |
|||
{ |
|||
int idx = t + i*NR_THREADS; |
|||
|
|||
uint2 uPixLoc = min(uint2(viTilLL.x+(idx&0xf), viTilLL.y+(idx>>4)), uint2(iWidth-1, iHeight-1)); |
|||
float3 vVPos = GetViewPosFromLinDepth(uPixLoc + float2(0.5,0.5), vLinDepths[i]); |
|||
|
|||
// check pixel |
|||
float3 toLight = lightData.lightPos.xyz - vVPos; |
|||
|
|||
float3 dist = float3( dot(toLight, lightData.lightAxisX), dot(toLight, lightData.lightAxisY), dot(toLight, lightData.lightAxisZ) ); |
|||
dist = (abs(dist) - lightData.boxInnerDist) * lightData.boxInvRange; // not as efficient as it could be |
|||
if( max(max(dist.x, dist.y), dist.z)<1 ) uVal = 1; // but allows us to not write out OuterDists |
|||
} |
|||
|
|||
uLightsFlags[l<32 ? 0 : 1] |= (uVal<<(l&31)); |
|||
++l; idxCoarse = l<iNrCoarseLights ? coarseList[l] : 0; |
|||
uLightVolume = l<iNrCoarseLights ? _LightVolumeData[idxCoarse].lightVolume : 0; |
|||
} |
|||
|
|||
// in case we have some corrupt data make sure we terminate |
|||
if(uLightVolume >=LIGHTVOLUMETYPE_COUNT) ++l; |
|||
} |
|||
|
|||
InterlockedOr(ldsDoesLightIntersect[0], uLightsFlags[0]); |
|||
InterlockedOr(ldsDoesLightIntersect[1], uLightsFlags[1]); |
|||
if(t==0) ldsNrLightsFinal = 0; |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
|
|||
if(t<(uint) iNrCoarseLights && (ldsDoesLightIntersect[t<32 ? 0 : 1]&(1<<(t&31)))!=0 ) |
|||
{ |
|||
unsigned int uInc = 1; |
|||
unsigned int uIndex; |
|||
InterlockedAdd(ldsNrLightsFinal, uInc, uIndex); |
|||
if(uIndex<MAX_NR_COARSE_ENTRIES) prunedList[uIndex] = coarseList[t]; // we allow up to 64 pruned lights while stored in LDS. |
|||
} |
|||
} |
|||
#endif |
|||
// The implementation is based on the demo on "fine pruned tiled lighting" published in GPU Pro 7. |
|||
// https://github.com/wolfgangfengel/GPU-Pro-7 |
|||
|
|||
#pragma kernel TileLightListGen LIGHTLISTGEN=TileLightListGen |
|||
#pragma kernel TileLightListGen_SrcBigTile LIGHTLISTGEN=TileLightListGen_SrcBigTile USE_TWO_PASS_TILED_LIGHTING |
|||
#pragma kernel TileLightListGen_FeatureFlags LIGHTLISTGEN=TileLightListGen_FeatureFlags USE_FEATURE_FLAGS |
|||
#pragma kernel TileLightListGen_SrcBigTile_FeatureFlags LIGHTLISTGEN=TileLightListGen_SrcBigTile_FeatureFlags USE_TWO_PASS_TILED_LIGHTING USE_FEATURE_FLAGS |
|||
|
|||
#pragma #pragma enable_d3d11_debug_symbols |
|||
|
|||
#include "../../../../ShaderLibrary/common.hlsl" |
|||
#include "../ShaderBase.hlsl" |
|||
#include "../TilePass.cs.hlsl" |
|||
#include "../LightingConvexHullUtils.hlsl" |
|||
#include "../FeatureFlags.hlsl" |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
#include "../SortingComputeUtils.hlsl" |
|||
#endif |
|||
|
|||
#define FINE_PRUNING_ENABLED |
|||
#define PERFORM_SPHERICAL_INTERSECTION_TESTS |
|||
|
|||
|
|||
uniform int g_iNrVisibLights; |
|||
uniform uint2 g_viDimensions; |
|||
uniform float4x4 g_mInvScrProjection; |
|||
uniform float4x4 g_mScrProjection; |
|||
uniform int _EnvLightIndexShift; |
|||
|
|||
|
|||
Texture2D g_depth_tex : register( t0 ); |
|||
StructuredBuffer<float3> g_vBoundsBuffer : register( t1 ); |
|||
StructuredBuffer<LightVolumeData> _LightVolumeData : register(t2); |
|||
StructuredBuffer<SFiniteLightBound> g_data : register( t3 ); |
|||
|
|||
#ifdef USE_TWO_PASS_TILED_LIGHTING |
|||
StructuredBuffer<uint> g_vBigTileLightList : register( t4 ); // don't support Buffer yet in unity |
|||
#endif |
|||
|
|||
#define NR_THREADS 64 |
|||
|
|||
// output buffer |
|||
RWStructuredBuffer<uint> g_vLightList : register( u0 ); // don't support RWBuffer yet in unity |
|||
|
|||
|
|||
#define MAX_NR_COARSE_ENTRIES 64 |
|||
#define MAX_NR_PRUNED_ENTRIES 24 |
|||
|
|||
groupshared unsigned int coarseList[MAX_NR_COARSE_ENTRIES]; |
|||
groupshared unsigned int prunedList[MAX_NR_COARSE_ENTRIES]; // temporarily support room for all 64 while in LDS |
|||
|
|||
groupshared uint ldsZMin; |
|||
groupshared uint ldsZMax; |
|||
groupshared uint lightOffs; |
|||
#ifdef FINE_PRUNING_ENABLED |
|||
groupshared uint ldsDoesLightIntersect[2]; |
|||
#endif |
|||
groupshared int ldsNrLightsFinal; |
|||
|
|||
groupshared int ldsCategoryListCount[LIGHTCATEGORY_COUNT]; // since LIGHTCATEGORY_COUNT is 3 |
|||
|
|||
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS |
|||
groupshared uint lightOffsSph; |
|||
#endif |
|||
|
|||
|
|||
uniform uint g_BaseFeatureFlags; |
|||
#ifdef USE_FEATURE_FLAGS |
|||
groupshared uint ldsFeatureFlags; |
|||
RWBuffer<uint> g_DispatchIndirectBuffer; |
|||
RWStructuredBuffer<uint> g_TileList; |
|||
#endif |
|||
|
|||
|
|||
//float GetLinearDepth(float3 vP) |
|||
//{ |
|||
// float4 v4Pres = mul(g_mInvScrProjection, float4(vP,1.0)); |
|||
// return v4Pres.z / v4Pres.w; |
|||
//} |
|||
|
|||
float GetLinearDepth(float zDptBufSpace) // 0 is near 1 is far |
|||
{ |
|||
float3 vP = float3(0.0f,0.0f,zDptBufSpace); |
|||
float4 v4Pres = mul(g_mInvScrProjection, float4(vP,1.0)); |
|||
return v4Pres.z / v4Pres.w; |
|||
} |
|||
|
|||
|
|||
float3 GetViewPosFromLinDepth(float2 v2ScrPos, float fLinDepth) |
|||
{ |
|||
float fSx = g_mScrProjection[0].x; |
|||
float fCx = g_mScrProjection[0].z; |
|||
float fSy = g_mScrProjection[1].y; |
|||
float fCy = g_mScrProjection[1].z; |
|||
|
|||
#if USE_LEFTHAND_CAMERASPACE |
|||
return fLinDepth*float3( ((v2ScrPos.x-fCx)/fSx), ((v2ScrPos.y-fCy)/fSy), 1.0 ); |
|||
#else |
|||
return fLinDepth*float3( -((v2ScrPos.x+fCx)/fSx), -((v2ScrPos.y+fCy)/fSy), 1.0 ); |
|||
#endif |
|||
} |
|||
|
|||
float GetOnePixDiagWorldDistAtDepthOne() |
|||
{ |
|||
float fSx = g_mScrProjection[0].x; |
|||
float fSy = g_mScrProjection[1].y; |
|||
|
|||
return length( float2(1.0/fSx,1.0/fSy) ); |
|||
} |
|||
|
|||
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS |
|||
int SphericalIntersectionTests(uint threadID, int iNrCoarseLights, float2 screenCoordinate); |
|||
#endif |
|||
|
|||
#ifdef FINE_PRUNING_ENABLED |
|||
void FinePruneLights(uint threadID, int iNrCoarseLights, uint2 viTilLL, float4 vLinDepths); |
|||
#endif |
|||
|
|||
|
|||
[numthreads(NR_THREADS, 1, 1)] |
|||
void LIGHTLISTGEN(uint threadID : SV_GroupIndex, uint3 u3GroupID : SV_GroupID) |
|||
{ |
|||
uint2 tileIDX = u3GroupID.xy; |
|||
uint t=threadID; |
|||
|
|||
if(t<MAX_NR_COARSE_ENTRIES) |
|||
prunedList[t]=0; |
|||
|
|||
uint iWidth = g_viDimensions.x; |
|||
uint iHeight = g_viDimensions.y; |
|||
uint nrTilesX = (iWidth+15)/16; |
|||
uint nrTilesY = (iHeight+15)/16; |
|||
uint nrTiles = nrTilesX * nrTilesY; // Precompute? |
|||
|
|||
// build tile scr boundary |
|||
const uint uFltMax = 0x7f7fffff; // FLT_MAX as a uint |
|||
if(t==0) |
|||
{ |
|||
ldsZMin = uFltMax; |
|||
ldsZMax = 0; |
|||
lightOffs = 0; |
|||
} |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
|
|||
|
|||
uint2 viTilLL = 16*tileIDX; |
|||
|
|||
// establish min and max depth first |
|||
float dpt_mi=asfloat(uFltMax), dpt_ma=0.0; |
|||
|
|||
|
|||
float4 vLinDepths; |
|||
{ |
|||
// Fetch depths and calculate min/max |
|||
[unroll] |
|||
for(int i = 0; i < 4; i++) |
|||
{ |
|||
int idx = i * NR_THREADS + t; |
|||
uint2 uCrd = min( uint2(viTilLL.x+(idx&0xf), viTilLL.y+(idx>>4)), uint2(iWidth-1, iHeight-1) ); |
|||
const float fDepth = FetchDepth(g_depth_tex, uCrd); |
|||
vLinDepths[i] = GetLinearDepth(fDepth); |
|||
if(fDepth<VIEWPORT_SCALE_Z) // if not skydome |
|||
{ |
|||
dpt_mi = min(fDepth, dpt_mi); |
|||
dpt_ma = max(fDepth, dpt_ma); |
|||
} |
|||
} |
|||
|
|||
InterlockedMax(ldsZMax, asuint(dpt_ma)); |
|||
InterlockedMin(ldsZMin, asuint(dpt_mi)); |
|||
|
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
} |
|||
|
|||
|
|||
float3 vTileLL = float3(viTilLL.x/(float) iWidth, viTilLL.y/(float) iHeight, asfloat(ldsZMin)); |
|||
float3 vTileUR = float3((viTilLL.x+16)/(float) iWidth, (viTilLL.y+16)/(float) iHeight, asfloat(ldsZMax)); |
|||
vTileUR.xy = min(vTileUR.xy,float2(1.0,1.0)).xy; |
|||
|
|||
|
|||
// build coarse list using AABB |
|||
#ifdef USE_TWO_PASS_TILED_LIGHTING |
|||
int NrBigTilesX = (nrTilesX+3)>>2; |
|||
const int bigTileIdx = (tileIDX.y>>2)*NrBigTilesX + (tileIDX.x>>2); // map the idx to 64x64 tiles |
|||
int nrBigTileLights = g_vBigTileLightList[MAX_NR_BIGTILE_LIGHTS_PLUSONE*bigTileIdx+0]; |
|||
for(int l0=(int) t; l0<(int) nrBigTileLights; l0 += NR_THREADS) |
|||
{ |
|||
int l = g_vBigTileLightList[MAX_NR_BIGTILE_LIGHTS_PLUSONE*bigTileIdx+l0+1]; |
|||
#else |
|||
for(int l=(int) t; l<(int) g_iNrVisibLights; l += NR_THREADS) |
|||
{ |
|||
#endif |
|||
const float3 vMi = g_vBoundsBuffer[l]; |
|||
const float3 vMa = g_vBoundsBuffer[l+g_iNrVisibLights]; |
|||
|
|||
if( all(vMa>vTileLL) && all(vMi<vTileUR)) |
|||
{ |
|||
unsigned int uInc = 1; |
|||
unsigned int uIndex; |
|||
InterlockedAdd(lightOffs, uInc, uIndex); |
|||
if(uIndex<MAX_NR_COARSE_ENTRIES) coarseList[uIndex] = l; // add to light list |
|||
} |
|||
} |
|||
|
|||
#ifdef FINE_PRUNING_ENABLED |
|||
if(t<2) ldsDoesLightIntersect[t] = 0; |
|||
#endif |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
|
|||
int iNrCoarseLights = min(lightOffs,MAX_NR_COARSE_ENTRIES); |
|||
|
|||
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS |
|||
iNrCoarseLights = SphericalIntersectionTests( t, iNrCoarseLights, float2(min(viTilLL.xy+uint2(16/2,16/2), uint2(iWidth-1, iHeight-1))) ); |
|||
#endif |
|||
|
|||
#ifndef FINE_PRUNING_ENABLED |
|||
{ |
|||
if((int)t<iNrCoarseLights) prunedList[t] = coarseList[t]; |
|||
if(t==0) ldsNrLightsFinal=iNrCoarseLights; |
|||
} |
|||
#else |
|||
{ |
|||
// initializes ldsNrLightsFinal with the number of accepted lights. |
|||
// all accepted entries delivered in prunedList[]. |
|||
FinePruneLights(t, iNrCoarseLights, viTilLL, vLinDepths); |
|||
} |
|||
#endif |
|||
|
|||
// |
|||
if(t<LIGHTCATEGORY_COUNT) ldsCategoryListCount[t]=0; |
|||
#ifdef USE_FEATURE_FLAGS |
|||
if(t==0) ldsFeatureFlags=0; |
|||
#endif |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
|
|||
|
|||
int nrLightsCombinedList = min(ldsNrLightsFinal,MAX_NR_COARSE_ENTRIES); |
|||
for(int i=t; i<nrLightsCombinedList; i+=NR_THREADS) |
|||
{ |
|||
InterlockedAdd(ldsCategoryListCount[_LightVolumeData[prunedList[i]].lightCategory], 1); |
|||
#ifdef USE_FEATURE_FLAGS |
|||
InterlockedOr(ldsFeatureFlags, _LightVolumeData[prunedList[i]].featureFlags); |
|||
#endif |
|||
} |
|||
|
|||
// sort lights (gives a more efficient execution in both deferred and tiled forward lighting). |
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
SORTLIST(prunedList, nrLightsCombinedList, MAX_NR_COARSE_ENTRIES, t, NR_THREADS); |
|||
//MERGESORTLIST(prunedList, coarseList, nrLightsCombinedList, t, NR_THREADS); |
|||
#endif |
|||
|
|||
#ifdef USE_FEATURE_FLAGS |
|||
if(t == 0) |
|||
{ |
|||
uint featureFlags = g_BaseFeatureFlags | ldsFeatureFlags; |
|||
if(ldsZMax < ldsZMin) // is background pixel |
|||
{ |
|||
featureFlags &= ~(FEATURE_FLAG_PUNCTUAL_LIGHT | FEATURE_FLAG_AREA_LIGHT | FEATURE_FLAG_DIRECTIONAL_LIGHT | FEATURE_FLAG_ENV_LIGHT); // list of features that are not enabled on background |
|||
} |
|||
|
|||
uint variant = FeatureFlagsToTileVariant(featureFlags); |
|||
uint offset; |
|||
InterlockedAdd(g_DispatchIndirectBuffer[variant * 3 + 0], 1, offset); |
|||
g_TileList[variant*nrTiles + offset] = (tileIDX.y << 16) + tileIDX.x; |
|||
} |
|||
#endif |
|||
|
|||
// write lights to global buffers |
|||
int localOffs=0; |
|||
int offs = tileIDX.y*nrTilesX + tileIDX.x; |
|||
|
|||
// All our cull data are in the same list, but at render time envLights are separated so we need to shit the index |
|||
// to make it work correctly |
|||
int shiftIndex[LIGHTCATEGORY_COUNT] = {0, 0, _EnvLightIndexShift}; // 3 for now, will throw an error if we change LIGHTCATEGORY_COUNT |
|||
|
|||
for(int category=0; category<LIGHTCATEGORY_COUNT; category++) |
|||
{ |
|||
int nrLightsFinal = ldsCategoryListCount[category]; |
|||
int nrLightsFinalClamped = nrLightsFinal<MAX_NR_PRUNED_ENTRIES ? nrLightsFinal : MAX_NR_PRUNED_ENTRIES; |
|||
|
|||
const int nrDWords = ((nrLightsFinalClamped+1)+1)>>1; |
|||
for(int l=(int) t; l<(int) nrDWords; l += NR_THREADS) |
|||
{ |
|||
// We remap the prunedList index to the original LightData / EnvLightData indices |
|||
uint uLow = l==0 ? nrLightsFinalClamped : prunedList[2 * l - 1 + localOffs] - shiftIndex[category]; |
|||
uint uHigh = prunedList[2 * l + 0 + localOffs] - shiftIndex[category]; |
|||
|
|||
g_vLightList[16*offs + l] = (uLow&0xffff) | (uHigh<<16); |
|||
} |
|||
|
|||
localOffs += nrLightsFinal; |
|||
offs += (nrTilesX*nrTilesY); |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS |
|||
int SphericalIntersectionTests(uint threadID, int iNrCoarseLights, float2 screenCoordinate) |
|||
{ |
|||
if(threadID==0) lightOffsSph = 0; |
|||
|
|||
// make a copy of coarseList in prunedList. |
|||
int l; |
|||
for(l=threadID; l<iNrCoarseLights; l+=NR_THREADS) |
|||
prunedList[l]=coarseList[l]; |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
|
|||
#if USE_LEFTHAND_CAMERASPACE |
|||
float3 V = GetViewPosFromLinDepth( screenCoordinate, 1.0); |
|||
#else |
|||
float3 V = GetViewPosFromLinDepth( screenCoordinate, -1.0); |
|||
#endif |
|||
|
|||
float onePixDiagDist = GetOnePixDiagWorldDistAtDepthOne(); |
|||
float halfTileSizeAtZDistOne = 8*onePixDiagDist; // scale by half a tile |
|||
|
|||
for(l=threadID; l<iNrCoarseLights; l+=NR_THREADS) |
|||
{ |
|||
SFiniteLightBound lightData = g_data[prunedList[l]]; |
|||
|
|||
if( DoesSphereOverlapTile(V, halfTileSizeAtZDistOne, lightData.center.xyz, lightData.radius) ) |
|||
{ |
|||
unsigned int uIndex; |
|||
InterlockedAdd(lightOffsSph, 1, uIndex); |
|||
coarseList[uIndex]=prunedList[l]; // read from the original copy of coarseList which is backed up in prunedList |
|||
} |
|||
} |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
|
|||
return lightOffsSph; |
|||
} |
|||
#endif |
|||
|
|||
|
|||
#ifdef FINE_PRUNING_ENABLED |
|||
// initializes ldsNrLightsFinal with the number of accepted lights. |
|||
// all accepted entries delivered in prunedList[]. |
|||
void FinePruneLights(uint threadID, int iNrCoarseLights, uint2 viTilLL, float4 vLinDepths) |
|||
{ |
|||
uint t = threadID; |
|||
uint iWidth = g_viDimensions.x; |
|||
uint iHeight = g_viDimensions.y; |
|||
|
|||
uint uLightsFlags[2] = {0,0}; |
|||
int l=0; |
|||
// need this outer loop even on xb1 and ps4 since direct lights and |
|||
// reflection lights are kept in separate regions. |
|||
while(l<iNrCoarseLights) |
|||
{ |
|||
// fetch light |
|||
int idxCoarse = l<iNrCoarseLights ? coarseList[l] : 0; |
|||
uint uLightVolume = l<iNrCoarseLights ? _LightVolumeData[idxCoarse].lightVolume : 0; |
|||
|
|||
// spot |
|||
while(l<iNrCoarseLights && uLightVolume==LIGHTVOLUMETYPE_CONE) |
|||
{ |
|||
LightVolumeData lightData = _LightVolumeData[idxCoarse]; |
|||
// TODO: Change by SebL |
|||
const bool bIsSpotDisc = true; // (lightData.flags&IS_CIRCULAR_SPOT_SHAPE) != 0; |
|||
|
|||
// serially check 4 pixels |
|||
uint uVal = 0; |
|||
for(int i=0; i<4; i++) |
|||
{ |
|||
int idx = t + i*NR_THREADS; |
|||
|
|||
uint2 uPixLoc = min(uint2(viTilLL.x+(idx&0xf), viTilLL.y+(idx>>4)), uint2(iWidth-1, iHeight-1)); |
|||
float3 vVPos = GetViewPosFromLinDepth(uPixLoc + float2(0.5,0.5), vLinDepths[i]); |
|||
|
|||
// check pixel |
|||
float3 fromLight = vVPos-lightData.lightPos.xyz; |
|||
float distSq = dot(fromLight,fromLight); |
|||
const float fSclProj = dot(fromLight, lightData.lightAxisZ.xyz); // spotDir = lightData.lightAxisZ.xyz |
|||
|
|||
float2 V = abs( float2( dot(fromLight, lightData.lightAxisX.xyz), dot(fromLight, lightData.lightAxisY.xyz) ) ); |
|||
|
|||
float fDist2D = bIsSpotDisc ? length(V) : max(V.x,V.y); |
|||
if( all( float2(lightData.radiusSq, fSclProj) > float2(distSq, fDist2D*lightData.cotan) ) ) uVal = 1; |
|||
} |
|||
|
|||
uLightsFlags[l<32 ? 0 : 1] |= (uVal<<(l&31)); |
|||
++l; idxCoarse = l<iNrCoarseLights ? coarseList[l] : 0; |
|||
uLightVolume = l<iNrCoarseLights ? _LightVolumeData[idxCoarse].lightVolume : 0; |
|||
} |
|||
|
|||
// sphere |
|||
while(l<iNrCoarseLights && uLightVolume==LIGHTVOLUMETYPE_SPHERE) |
|||
{ |
|||
LightVolumeData lightData = _LightVolumeData[idxCoarse]; |
|||
|
|||
// serially check 4 pixels |
|||
uint uVal = 0; |
|||
for(int i=0; i<4; i++) |
|||
{ |
|||
int idx = t + i*NR_THREADS; |
|||
|
|||
uint2 uPixLoc = min(uint2(viTilLL.x+(idx&0xf), viTilLL.y+(idx>>4)), uint2(iWidth-1, iHeight-1)); |
|||
float3 vVPos = GetViewPosFromLinDepth(uPixLoc + float2(0.5,0.5), vLinDepths[i]); |
|||
|
|||
// check pixel |
|||
float3 vLp = lightData.lightPos.xyz; |
|||
float3 toLight = vLp - vVPos; |
|||
float distSq = dot(toLight,toLight); |
|||
|
|||
if(lightData.radiusSq>distSq) uVal = 1; |
|||
} |
|||
|
|||
uLightsFlags[l<32 ? 0 : 1] |= (uVal<<(l&31)); |
|||
++l; idxCoarse = l<iNrCoarseLights ? coarseList[l] : 0; |
|||
uLightVolume = l<iNrCoarseLights ? _LightVolumeData[idxCoarse].lightVolume : 0; |
|||
} |
|||
|
|||
// Box |
|||
while(l<iNrCoarseLights && uLightVolume==LIGHTVOLUMETYPE_BOX) |
|||
{ |
|||
LightVolumeData lightData = _LightVolumeData[idxCoarse]; |
|||
|
|||
// serially check 4 pixels |
|||
uint uVal = 0; |
|||
for(int i=0; i<4; i++) |
|||
{ |
|||
int idx = t + i*NR_THREADS; |
|||
|
|||
uint2 uPixLoc = min(uint2(viTilLL.x+(idx&0xf), viTilLL.y+(idx>>4)), uint2(iWidth-1, iHeight-1)); |
|||
float3 vVPos = GetViewPosFromLinDepth(uPixLoc + float2(0.5,0.5), vLinDepths[i]); |
|||
|
|||
// check pixel |
|||
float3 toLight = lightData.lightPos.xyz - vVPos; |
|||
|
|||
float3 dist = float3( dot(toLight, lightData.lightAxisX), dot(toLight, lightData.lightAxisY), dot(toLight, lightData.lightAxisZ) ); |
|||
dist = (abs(dist) - lightData.boxInnerDist) * lightData.boxInvRange; // not as efficient as it could be |
|||
if( max(max(dist.x, dist.y), dist.z)<1 ) uVal = 1; // but allows us to not write out OuterDists |
|||
} |
|||
|
|||
uLightsFlags[l<32 ? 0 : 1] |= (uVal<<(l&31)); |
|||
++l; idxCoarse = l<iNrCoarseLights ? coarseList[l] : 0; |
|||
uLightVolume = l<iNrCoarseLights ? _LightVolumeData[idxCoarse].lightVolume : 0; |
|||
} |
|||
|
|||
// in case we have some corrupt data make sure we terminate |
|||
if(uLightVolume >=LIGHTVOLUMETYPE_COUNT) ++l; |
|||
} |
|||
|
|||
InterlockedOr(ldsDoesLightIntersect[0], uLightsFlags[0]); |
|||
InterlockedOr(ldsDoesLightIntersect[1], uLightsFlags[1]); |
|||
if(t==0) ldsNrLightsFinal = 0; |
|||
|
|||
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL) |
|||
GroupMemoryBarrierWithGroupSync(); |
|||
#endif |
|||
|
|||
if(t<(uint) iNrCoarseLights && (ldsDoesLightIntersect[t<32 ? 0 : 1]&(1<<(t&31)))!=0 ) |
|||
{ |
|||
unsigned int uInc = 1; |
|||
unsigned int uIndex; |
|||
InterlockedAdd(ldsNrLightsFinal, uInc, uIndex); |
|||
if(uIndex<MAX_NR_COARSE_ENTRIES) prunedList[uIndex] = coarseList[t]; // we allow up to 64 pruned lights while stored in LDS. |
|||
} |
|||
} |
|||
#endif |
|
|||
#pragma kernel ShadeOpaque_Fptl SHADE_OPAQUE_ENTRY=ShadeOpaque_Fptl USE_FPTL_LIGHTLIST |
|||
#pragma kernel ShadeOpaque_Fptl_DebugLighting SHADE_OPAQUE_ENTRY=ShadeOpaque_Fptl_DebugLighting USE_FPTL_LIGHTLIST LIGHTING_DEBUG |
|||
#pragma kernel ShadeOpaque_Clustered SHADE_OPAQUE_ENTRY=ShadeOpaque_Clustered USE_CLUSTERED_LIGHTLIST |
|||
#pragma kernel ShadeOpaque_Clustered_DebugLighting SHADE_OPAQUE_ENTRY=ShadeOpaque_Clustered_DebugLighting USE_CLUSTERED_LIGHTLIST LIGHTING_DEBUG |
|||
|
|||
// Split lighting is required for the SSS pass. |
|||
// Not currently possible since we need to access the stencil buffer from the compute shader. |
|||
// #pragma multi_compile _ OUTPUT_SPLIT_LIGHTING |
|||
|
|||
#define LIGHTLOOP_TILE_PASS 1 |
|||
#define LIGHTLOOP_TILE_DIRECT 1 |
|||
#define LIGHTLOOP_TILE_INDIRECT 1 |
|||
#define LIGHTLOOP_TILE_ALL 1 |
|||
#define USE_FPTL_LIGHTLIST 1 |
|||
|
|||
//------------------------------------------------------------------------------------- |
|||
// Include |
|||
//------------------------------------------------------------------------------------- |
|||
|
|||
#include "ShaderLibrary/Common.hlsl" |
|||
#include "HDRenderPipeline/Debug/HDRenderPipelineDebug.cs.hlsl" |
|||
#include "HDRenderPipeline/Debug/DebugLighting.hlsl" |
|||
|
|||
// Note: We have fix as guidelines that we have only one deferred material (with control of GBuffer enabled). Mean a users that add a new |
|||
// deferred material must replace the old one here. If in the future we want to support multiple layout (cause a lot of consistency problem), |
|||
// the deferred shader will require to use multicompile. |
|||
#define UNITY_MATERIAL_LIT // Need to be define before including Material.hlsl |
|||
#include "HDRenderPipeline/ShaderConfig.cs.hlsl" |
|||
#include "HDRenderPipeline/ShaderVariables.hlsl" |
|||
#include "HDRenderPipeline/Lighting/Lighting.hlsl" // This include Material.hlsl |
|||
|
|||
//------------------------------------------------------------------------------------- |
|||
// variable declaration |
|||
//------------------------------------------------------------------------------------- |
|||
|
|||
DECLARE_GBUFFER_TEXTURE(_GBufferTexture); |
|||
|
|||
TEXTURE2D_FLOAT(_CameraDepthTexture); |
|||
SAMPLER2D(sampler_CameraDepthTexture); |
|||
|
|||
#ifdef OUTPUT_SPLIT_LIGHTING |
|||
RWTexture2D<float4> specularLightingUAV; |
|||
RWTexture2D<float3> diffuseLightingUAV; |
|||
#else |
|||
RWTexture2D<float4> combinedLightingUAV; |
|||
#endif |
|||
|
|||
[numthreads(TILE_SIZE, TILE_SIZE, 1)] |
|||
void SHADE_OPAQUE_ENTRY(uint2 dispatchThreadId : SV_DispatchThreadID, uint2 groupId : SV_GroupID) |
|||
{ |
|||
// input.positionCS is SV_Position |
|||
uint2 pixelCoord = dispatchThreadId; |
|||
PositionInputs posInput = GetPositionInput(pixelCoord.xy, _ScreenSize.zw); |
|||
float depth = LOAD_TEXTURE2D(_CameraDepthTexture, posInput.unPositionSS).x; |
|||
UpdatePositionInput(depth, _InvViewProjMatrix, _ViewProjMatrix, posInput); |
|||
float3 V = GetWorldSpaceNormalizeViewDir(posInput.positionWS); |
|||
|
|||
FETCH_GBUFFER(gbuffer, _GBufferTexture, posInput.unPositionSS); |
|||
BSDFData bsdfData; |
|||
float3 bakeDiffuseLighting; |
|||
DECODE_FROM_GBUFFER(gbuffer, bsdfData, bakeDiffuseLighting); |
|||
|
|||
PreLightData preLightData = GetPreLightData(V, posInput, bsdfData); |
|||
|
|||
float3 diffuseLighting; |
|||
float3 specularLighting; |
|||
LightLoop(V, posInput, preLightData, bsdfData, bakeDiffuseLighting, diffuseLighting, specularLighting); |
|||
|
|||
#ifdef OUTPUT_SPLIT_LIGHTING |
|||
specularLightingUAV[pixelCoord] = float4(specularLighting, 1.0); |
|||
diffuseLightingUAV[pixelCoord] = diffuseLighting; |
|||
#else |
|||
combinedLightingUAV[pixelCoord] = float4(diffuseLighting + specularLighting, 1.0); |
|||
#endif |
|||
} |
|||
|
|||
#pragma kernel ShadeOpaque_Direct_Fptl SHADE_OPAQUE_ENTRY=ShadeOpaque_Direct_Fptl USE_FPTL_LIGHTLIST |
|||
#pragma kernel ShadeOpaque_Direct_Fptl_DebugLighting SHADE_OPAQUE_ENTRY=ShadeOpaque_Direct_Fptl_DebugLighting USE_FPTL_LIGHTLIST LIGHTING_DEBUG |
|||
#pragma kernel ShadeOpaque_Direct_Clustered SHADE_OPAQUE_ENTRY=ShadeOpaque_Direct_Clustered USE_CLUSTERED_LIGHTLIST |
|||
#pragma kernel ShadeOpaque_Direct_Clustered_DebugLighting SHADE_OPAQUE_ENTRY=ShadeOpaque_Direct_Clustered_DebugLighting USE_CLUSTERED_LIGHTLIST LIGHTING_DEBUG |
|||
|
|||
#pragma kernel ShadeOpaque_Indirect_Fptl_Variant0 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Fptl_Variant0 USE_FPTL_LIGHTLIST USE_INDIRECT VARIANT=0 |
|||
#pragma kernel ShadeOpaque_Indirect_Fptl_Variant1 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Fptl_Variant1 USE_FPTL_LIGHTLIST USE_INDIRECT VARIANT=1 |
|||
#pragma kernel ShadeOpaque_Indirect_Fptl_Variant2 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Fptl_Variant2 USE_FPTL_LIGHTLIST USE_INDIRECT VARIANT=2 |
|||
#pragma kernel ShadeOpaque_Indirect_Fptl_Variant3 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Fptl_Variant3 USE_FPTL_LIGHTLIST USE_INDIRECT VARIANT=3 |
|||
#pragma kernel ShadeOpaque_Indirect_Fptl_Variant4 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Fptl_Variant4 USE_FPTL_LIGHTLIST USE_INDIRECT VARIANT=4 |
|||
#pragma kernel ShadeOpaque_Indirect_Fptl_Variant5 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Fptl_Variant5 USE_FPTL_LIGHTLIST USE_INDIRECT VARIANT=5 |
|||
#pragma kernel ShadeOpaque_Indirect_Fptl_Variant6 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Fptl_Variant6 USE_FPTL_LIGHTLIST USE_INDIRECT VARIANT=6 |
|||
#pragma kernel ShadeOpaque_Indirect_Fptl_Variant7 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Fptl_Variant7 USE_FPTL_LIGHTLIST USE_INDIRECT VARIANT=7 |
|||
|
|||
#pragma kernel ShadeOpaque_Indirect_Clustered_Variant0 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Clustered_Variant0 USE_CLUSTERED_LIGHTLIST USE_INDIRECT VARIANT=0 |
|||
#pragma kernel ShadeOpaque_Indirect_Clustered_Variant1 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Clustered_Variant1 USE_CLUSTERED_LIGHTLIST USE_INDIRECT VARIANT=1 |
|||
#pragma kernel ShadeOpaque_Indirect_Clustered_Variant2 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Clustered_Variant2 USE_CLUSTERED_LIGHTLIST USE_INDIRECT VARIANT=2 |
|||
#pragma kernel ShadeOpaque_Indirect_Clustered_Variant3 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Clustered_Variant3 USE_CLUSTERED_LIGHTLIST USE_INDIRECT VARIANT=3 |
|||
#pragma kernel ShadeOpaque_Indirect_Clustered_Variant4 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Clustered_Variant4 USE_CLUSTERED_LIGHTLIST USE_INDIRECT VARIANT=4 |
|||
#pragma kernel ShadeOpaque_Indirect_Clustered_Variant5 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Clustered_Variant5 USE_CLUSTERED_LIGHTLIST USE_INDIRECT VARIANT=5 |
|||
#pragma kernel ShadeOpaque_Indirect_Clustered_Variant6 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Clustered_Variant6 USE_CLUSTERED_LIGHTLIST USE_INDIRECT VARIANT=6 |
|||
#pragma kernel ShadeOpaque_Indirect_Clustered_Variant7 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Clustered_Variant7 USE_CLUSTERED_LIGHTLIST USE_INDIRECT VARIANT=7 |
|||
|
|||
#pragma #pragma enable_d3d11_debug_symbols |
|||
|
|||
// Split lighting is required for the SSS pass. |
|||
// Not currently possible since we need to access the stencil buffer from the compute shader. |
|||
// #pragma multi_compile _ OUTPUT_SPLIT_LIGHTING |
|||
|
|||
#define LIGHTLOOP_TILE_PASS 1 |
|||
#define LIGHTLOOP_TILE_DIRECT 1 |
|||
#define LIGHTLOOP_TILE_INDIRECT 1 |
|||
#define LIGHTLOOP_TILE_ALL 1 |
|||
|
|||
//------------------------------------------------------------------------------------- |
|||
// Include |
|||
//------------------------------------------------------------------------------------- |
|||
|
|||
#include "../../../../ShaderLibrary/Common.hlsl" |
|||
#include "../../../Debug/HDRenderPipelineDebug.cs.hlsl" |
|||
#include "../../../Debug/DebugLighting.hlsl" |
|||
|
|||
// Note: We have fix as guidelines that we have only one deferred material (with control of GBuffer enabled). Mean a users that add a new |
|||
// deferred material must replace the old one here. If in the future we want to support multiple layout (cause a lot of consistency problem), |
|||
// the deferred shader will require to use multicompile. |
|||
#define UNITY_MATERIAL_LIT // Need to be define before including Material.hlsl |
|||
#include "../../../ShaderConfig.cs.hlsl" |
|||
#include "../../../ShaderVariables.hlsl" |
|||
#include "../../../Lighting/Lighting.hlsl" // This include Material.hlsl |
|||
#include "../../../Lighting/TilePass/FeatureFlags.hlsl" |
|||
//------------------------------------------------------------------------------------- |
|||
// variable declaration |
|||
//------------------------------------------------------------------------------------- |
|||
|
|||
DECLARE_GBUFFER_TEXTURE(_GBufferTexture); |
|||
|
|||
#ifdef OUTPUT_SPLIT_LIGHTING |
|||
RWTexture2D<float4> specularLightingUAV; |
|||
RWTexture2D<float3> diffuseLightingUAV; |
|||
#else |
|||
RWTexture2D<float4> combinedLightingUAV; |
|||
#endif |
|||
|
|||
#if USE_INDIRECT |
|||
uint g_TileListOffset; |
|||
StructuredBuffer<uint> g_TileList; |
|||
// Indirect |
|||
[numthreads(16, 16, 1)] |
|||
void SHADE_OPAQUE_ENTRY(uint2 groupThreadId : SV_GroupThreadID, uint groupId : SV_GroupID) |
|||
{ |
|||
uint tileIndex = g_TileList[g_TileListOffset + groupId]; |
|||
uint2 tileCoord = uint2(tileIndex & 0xFFFF, tileIndex >> 16); |
|||
uint2 pixelCoord = tileCoord * GetTileSize() + groupThreadId; |
|||
|
|||
PositionInputs posInput = GetPositionInput(pixelCoord.xy, _ScreenSize.zw, tileCoord); |
|||
uint featureFlags = TileVariantToFeatureFlags(VARIANT); |
|||
#else |
|||
// Direct |
|||
[numthreads(16, 16, 1)] |
|||
void SHADE_OPAQUE_ENTRY(uint2 dispatchThreadId : SV_DispatchThreadID, uint2 groupId : SV_GroupID) |
|||
{ |
|||
uint2 pixelCoord = dispatchThreadId; |
|||
PositionInputs posInput = GetPositionInput(pixelCoord.xy, _ScreenSize.zw, groupId); |
|||
uint featureFlags = 0xFFFFFFFF; |
|||
#endif |
|||
|
|||
float depth = LOAD_TEXTURE2D(_MainDepthTexture, posInput.unPositionSS).x; |
|||
UpdatePositionInput(depth, _InvViewProjMatrix, _ViewProjMatrix, posInput); |
|||
float3 V = GetWorldSpaceNormalizeViewDir(posInput.positionWS); |
|||
|
|||
FETCH_GBUFFER(gbuffer, _GBufferTexture, posInput.unPositionSS); |
|||
BSDFData bsdfData; |
|||
float3 bakeDiffuseLighting; |
|||
DECODE_FROM_GBUFFER(gbuffer, bsdfData, bakeDiffuseLighting); |
|||
|
|||
PreLightData preLightData = GetPreLightData(V, posInput, bsdfData); |
|||
|
|||
float3 diffuseLighting; |
|||
float3 specularLighting; |
|||
LightLoop(V, posInput, preLightData, bsdfData, bakeDiffuseLighting, featureFlags, diffuseLighting, specularLighting); |
|||
|
|||
#ifdef OUTPUT_SPLIT_LIGHTING |
|||
specularLightingUAV[pixelCoord] = float4(specularLighting, 1.0); |
|||
diffuseLightingUAV[pixelCoord] = diffuseLighting; |
|||
#else |
|||
combinedLightingUAV[pixelCoord] = float4(diffuseLighting + specularLighting, 1.0); |
|||
#endif |
|||
} |
|||
|
1001
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePass.cs
文件差异内容过多而无法显示
查看文件
文件差异内容过多而无法显示
查看文件
|
|||
//----------------------------------------------------------------------------- |
|||
// LightLoop |
|||
// ---------------------------------------------------------------------------- |
|||
|
|||
void ApplyDebug(inout float3 diffuseLighting, inout float3 specularLighting) |
|||
{ |
|||
#ifdef LIGHTING_DEBUG |
|||
int lightDebugMode = (int)_DebugLightModeAndAlbedo.x; |
|||
|
|||
if (lightDebugMode == LIGHTINGDEBUGMODE_DIFFUSE_LIGHTING) |
|||
{ |
|||
specularLighting = float3(0.0, 0.0, 0.0); |
|||
} |
|||
else if (lightDebugMode == LIGHTINGDEBUGMODE_SPECULAR_LIGHTING) |
|||
{ |
|||
diffuseLighting = float3(0.0, 0.0, 0.0); |
|||
} |
|||
#endif |
|||
} |
|||
|
|||
#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.unPositionSS / TILE_SIZE; |
|||
return (tileIndex.y + lightCategory * _NumTileY) * _NumTileX + 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; |
|||
} |
|||
|
|||
uint FetchIndexTile(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; |
|||
} |
|||
|
|||
|
|||
#ifdef USE_FPTL_LIGHTLIST |
|||
|
|||
void GetCountAndStart(PositionInputs posInput, uint lightCategory, out uint start, out uint lightCount) |
|||
{ |
|||
GetCountAndStartTile(posInput, lightCategory, start, lightCount); |
|||
} |
|||
|
|||
uint FetchIndex(uint tileOffset, uint lightIndex) |
|||
{ |
|||
return FetchIndexTile(tileOffset, lightIndex); |
|||
} |
|||
|
|||
#elif defined(USE_CLUSTERED_LIGHTLIST) |
|||
|
|||
#include "ClusteredUtils.hlsl" |
|||
|
|||
void GetCountAndStartCluster(PositionInputs posInput, uint lightCategory, out uint start, out uint lightCount) |
|||
{ |
|||
uint2 tileIndex = posInput.unPositionSS / TILE_SIZE; |
|||
|
|||
float logBase = g_fClustBase; |
|||
if (g_isLogBaseBufferEnabled) |
|||
{ |
|||
logBase = g_logBaseBuffer[tileIndex.y * _NumTileX + tileIndex.x]; |
|||
} |
|||
|
|||
int clustIdx = SnapToClusterIdxFlex(posInput.depthVS, logBase, g_isLogBaseBufferEnabled != 0); |
|||
|
|||
int nrClusters = (1 << g_iLog2NumClusters); |
|||
const int idx = ((lightCategory * nrClusters + clustIdx) * _NumTileY + tileIndex.y) * _NumTileX + tileIndex.x; |
|||
uint dataPair = g_vLayeredOffsetsBuffer[idx]; |
|||
start = dataPair & 0x7ffffff; |
|||
lightCount = (dataPair >> 27) & 31; |
|||
} |
|||
|
|||
uint FetchIndexCluster(uint tileOffset, uint lightIndex) |
|||
{ |
|||
return g_vLightListGlobal[tileOffset + lightIndex]; |
|||
} |
|||
|
|||
void GetCountAndStart(PositionInputs posInput, uint lightCategory, out uint start, out uint lightCount) |
|||
{ |
|||
if (_UseTileLightList) |
|||
GetCountAndStartTile(posInput, lightCategory, start, lightCount); |
|||
else |
|||
GetCountAndStartCluster(posInput, lightCategory, start, lightCount); |
|||
} |
|||
|
|||
uint FetchIndex(uint tileOffset, uint lightIndex) |
|||
{ |
|||
if (_UseTileLightList) |
|||
return FetchIndexTile(tileOffset, lightIndex); |
|||
else |
|||
return FetchIndexCluster(tileOffset, lightIndex); |
|||
} |
|||
|
|||
#endif |
|||
|
|||
// bakeDiffuseLighting is part of the prototype so a user is able to implement a "base pass" with GI and multipass direct light (aka old unity rendering path) |
|||
void LightLoop( float3 V, PositionInputs posInput, PreLightData prelightData, BSDFData bsdfData, float3 bakeDiffuseLighting, |
|||
out float3 diffuseLighting, |
|||
out float3 specularLighting) |
|||
{ |
|||
LightLoopContext context; |
|||
ZERO_INITIALIZE(LightLoopContext, context); |
|||
|
|||
diffuseLighting = float3(0.0, 0.0, 0.0); |
|||
specularLighting = float3(0.0, 0.0, 0.0); |
|||
|
|||
uint i = 0; // Declare once to avoid the D3D11 compiler warning. |
|||
|
|||
#ifdef PROCESS_DIRECTIONAL_LIGHT |
|||
for (i = 0; i < _DirectionalLightCount; ++i) |
|||
{ |
|||
float3 localDiffuseLighting, localSpecularLighting; |
|||
|
|||
EvaluateBSDF_Directional( context, V, posInput, prelightData, _DirectionalLightDatas[i], bsdfData, |
|||
localDiffuseLighting, localSpecularLighting); |
|||
|
|||
diffuseLighting += localDiffuseLighting; |
|||
specularLighting += localSpecularLighting; |
|||
} |
|||
#endif |
|||
|
|||
#ifdef PROCESS_PUNCTUAL_LIGHT |
|||
// TODO: Convert the for loop below to a while on each type as we know we are sorted! |
|||
uint punctualLightStart; |
|||
uint punctualLightCount; |
|||
GetCountAndStart(posInput, LIGHTCATEGORY_PUNCTUAL, punctualLightStart, punctualLightCount); |
|||
for (i = 0; i < punctualLightCount; ++i) |
|||
{ |
|||
float3 localDiffuseLighting, localSpecularLighting; |
|||
|
|||
EvaluateBSDF_Punctual( context, V, posInput, prelightData, _LightDatas[FetchIndex(punctualLightStart, i)], bsdfData, |
|||
localDiffuseLighting, localSpecularLighting); |
|||
|
|||
diffuseLighting += localDiffuseLighting; |
|||
specularLighting += localSpecularLighting; |
|||
} |
|||
#endif |
|||
|
|||
#ifdef PROCESS_AREA_LIGHT |
|||
// TODO: Convert the for loop below to a while on each type as we know we are sorted! |
|||
uint areaLightStart; |
|||
uint areaLightCount; |
|||
GetCountAndStart(posInput, LIGHTCATEGORY_AREA, areaLightStart, areaLightCount); |
|||
for (i = 0; i < areaLightCount; ++i) |
|||
{ |
|||
float3 localDiffuseLighting, localSpecularLighting; |
|||
|
|||
uint areaIndex = FetchIndex(areaLightStart, i); |
|||
|
|||
if(_LightDatas[areaIndex].lightType == GPULIGHTTYPE_LINE) |
|||
{ |
|||
EvaluateBSDF_Line( context, V, posInput, prelightData, _LightDatas[areaIndex], bsdfData, |
|||
localDiffuseLighting, localSpecularLighting); |
|||
} |
|||
else |
|||
{ |
|||
EvaluateBSDF_Area( context, V, posInput, prelightData, _LightDatas[areaIndex], bsdfData, |
|||
localDiffuseLighting, localSpecularLighting); |
|||
} |
|||
|
|||
|
|||
diffuseLighting += localDiffuseLighting; |
|||
specularLighting += localSpecularLighting; |
|||
} |
|||
#endif |
|||
|
|||
#ifdef PROCESS_ENV_LIGHT |
|||
|
|||
float3 iblDiffuseLighting = float3(0.0, 0.0, 0.0); |
|||
float3 iblSpecularLighting = float3(0.0, 0.0, 0.0); |
|||
|
|||
// Only apply sky IBL if the sky texture is available. |
|||
if (_EnvLightSkyEnabled) |
|||
{ |
|||
float3 localDiffuseLighting, localSpecularLighting; |
|||
float2 weight; |
|||
// The sky is a single cubemap texture separate from the reflection probe texture array (different resolution and compression) |
|||
context.sampleReflection = SINGLE_PASS_CONTEXT_SAMPLE_SKY; |
|||
EnvLightData envLightSky = InitSkyEnvLightData(0); // The sky data are generated on the fly so the compiler can optimize the code |
|||
EvaluateBSDF_Env(context, V, posInput, prelightData, envLightSky, bsdfData, localDiffuseLighting, localSpecularLighting, weight); |
|||
iblDiffuseLighting = lerp(iblDiffuseLighting, localDiffuseLighting, weight.x); // Should be remove by the compiler if it is smart as all is constant 0 |
|||
iblSpecularLighting = lerp(iblSpecularLighting, localSpecularLighting, weight.y); |
|||
} |
|||
|
|||
uint envLightStart; |
|||
uint envLightCount; |
|||
GetCountAndStart(posInput, LIGHTCATEGORY_ENV, envLightStart, envLightCount); |
|||
|
|||
for (i = 0; i < envLightCount; ++i) |
|||
{ |
|||
float3 localDiffuseLighting, localSpecularLighting; |
|||
float2 weight; |
|||
context.sampleReflection = SINGLE_PASS_CONTEXT_SAMPLE_REFLECTION_PROBES; |
|||
EvaluateBSDF_Env(context, V, posInput, prelightData, _EnvLightDatas[FetchIndex(envLightStart, i)], bsdfData, localDiffuseLighting, localSpecularLighting, weight); |
|||
iblDiffuseLighting = lerp(iblDiffuseLighting, localDiffuseLighting, weight.x); // Should be remove by the compiler if it is smart as all is constant 0 |
|||
iblSpecularLighting = lerp(iblSpecularLighting, localSpecularLighting, weight.y); |
|||
} |
|||
|
|||
diffuseLighting += iblDiffuseLighting; |
|||
specularLighting += iblSpecularLighting; |
|||
#endif |
|||
|
|||
// TODO: currently apply GI at the same time as reflection |
|||
#ifdef PROCESS_ENV_LIGHT |
|||
// Add indirect diffuse + emissive (if any) |
|||
diffuseLighting += bakeDiffuseLighting; |
|||
#endif |
|||
|
|||
ApplyDebug(diffuseLighting, specularLighting); |
|||
} |
|||
|
|||
#else // LIGHTLOOP_SINGLE_PASS |
|||
|
|||
// bakeDiffuseLighting is part of the prototype so a user is able to implement a "base pass" with GI and multipass direct light (aka old unity rendering path) |
|||
void LightLoop( float3 V, PositionInputs posInput, PreLightData prelightData, BSDFData bsdfData, float3 bakeDiffuseLighting, |
|||
out float3 diffuseLighting, |
|||
out float3 specularLighting) |
|||
{ |
|||
LightLoopContext context; |
|||
ZERO_INITIALIZE(LightLoopContext, context); |
|||
|
|||
diffuseLighting = float3(0.0, 0.0, 0.0); |
|||
specularLighting = float3(0.0, 0.0, 0.0); |
|||
|
|||
uint i = 0; // Declare once to avoid the D3D11 compiler warning. |
|||
|
|||
for (i = 0; i < _DirectionalLightCount; ++i) |
|||
{ |
|||
float3 localDiffuseLighting, localSpecularLighting; |
|||
|
|||
EvaluateBSDF_Directional( context, V, posInput, prelightData, _DirectionalLightDatas[i], bsdfData, |
|||
localDiffuseLighting, localSpecularLighting); |
|||
|
|||
diffuseLighting += localDiffuseLighting; |
|||
specularLighting += localSpecularLighting; |
|||
} |
|||
|
|||
for (i = 0; i < _PunctualLightCount; ++i) |
|||
{ |
|||
float3 localDiffuseLighting, localSpecularLighting; |
|||
|
|||
EvaluateBSDF_Punctual( context, V, posInput, prelightData, _LightDatas[i], bsdfData, |
|||
localDiffuseLighting, localSpecularLighting); |
|||
|
|||
diffuseLighting += localDiffuseLighting; |
|||
specularLighting += localSpecularLighting; |
|||
} |
|||
|
|||
// Area are store with punctual, just offset the index |
|||
for (i = _PunctualLightCount; i < _AreaLightCount + _PunctualLightCount; ++i) |
|||
{ |
|||
float3 localDiffuseLighting, localSpecularLighting; |
|||
|
|||
if (_LightDatas[i].lightType == GPULIGHTTYPE_LINE) |
|||
{ |
|||
EvaluateBSDF_Line( context, V, posInput, prelightData, _LightDatas[i], bsdfData, |
|||
localDiffuseLighting, localSpecularLighting); |
|||
} |
|||
else |
|||
{ |
|||
EvaluateBSDF_Area( context, V, posInput, prelightData, _LightDatas[i], bsdfData, |
|||
localDiffuseLighting, localSpecularLighting); |
|||
} |
|||
|
|||
diffuseLighting += localDiffuseLighting; |
|||
specularLighting += localSpecularLighting; |
|||
} |
|||
|
|||
// TODO: Check the reflection hierarchy, for the current system (matching legacy unity) we must sort from bigger solid angle to lower (lower override bigger). So begging by sky |
|||
// TODO: Change the way it is done by reversing the order, from smaller solid angle to bigger, so we can early out when the weight is 1. |
|||
float3 iblDiffuseLighting = float3(0.0, 0.0, 0.0); |
|||
float3 iblSpecularLighting = float3(0.0, 0.0, 0.0); |
|||
|
|||
// Only apply sky IBL if the sky texture is available. |
|||
if (_EnvLightSkyEnabled) |
|||
{ |
|||
float3 localDiffuseLighting, localSpecularLighting; |
|||
float2 weight; |
|||
// The sky is a single cubemap texture separate from the reflection probe texture array (different resolution and compression) |
|||
context.sampleReflection = SINGLE_PASS_CONTEXT_SAMPLE_SKY; |
|||
EnvLightData envLightSky = InitSkyEnvLightData(0); // The sky data are generated on the fly so the compiler can optimize the code |
|||
EvaluateBSDF_Env(context, V, posInput, prelightData, envLightSky, bsdfData, localDiffuseLighting, localSpecularLighting, weight); |
|||
iblDiffuseLighting = lerp(iblDiffuseLighting, localDiffuseLighting, weight.x); // Should be remove by the compiler if it is smart as all is constant 0 |
|||
iblSpecularLighting = lerp(iblSpecularLighting, localSpecularLighting, weight.y); |
|||
} |
|||
|
|||
for (i = 0; i < _EnvLightCount; ++i) |
|||
{ |
|||
float3 localDiffuseLighting, localSpecularLighting; |
|||
float2 weight; |
|||
context.sampleReflection = SINGLE_PASS_CONTEXT_SAMPLE_REFLECTION_PROBES; |
|||
EvaluateBSDF_Env(context, V, posInput, prelightData, _EnvLightDatas[i], bsdfData, localDiffuseLighting, localSpecularLighting, weight); |
|||
iblDiffuseLighting = lerp(iblDiffuseLighting, localDiffuseLighting, weight.x); // Should be remove by the compiler if it is smart as all is constant 0 |
|||
iblSpecularLighting = lerp(iblSpecularLighting, localSpecularLighting, weight.y); |
|||
} |
|||
|
|||
diffuseLighting += iblDiffuseLighting; |
|||
specularLighting += iblSpecularLighting; |
|||
|
|||
// Add indirect diffuse + emissive (if any) |
|||
diffuseLighting += bakeDiffuseLighting; |
|||
|
|||
ApplyDebug(diffuseLighting, specularLighting); |
|||
} |
|||
|
|||
#endif |
|||
//----------------------------------------------------------------------------- |
|||
// LightLoop |
|||
// ---------------------------------------------------------------------------- |
|||
|
|||
void ApplyDebug(LightLoopContext lightLoopContext, float3 positionWS, inout float3 diffuseLighting, inout float3 specularLighting) |
|||
{ |
|||
#ifdef LIGHTING_DEBUG |
|||
int lightDebugMode = (int)_DebugLightModeAndAlbedo.x; |
|||
|
|||
if (lightDebugMode == LIGHTINGDEBUGMODE_DIFFUSE_LIGHTING) |
|||
{ |
|||
specularLighting = float3(0.0, 0.0, 0.0); |
|||
} |
|||
else if (lightDebugMode == LIGHTINGDEBUGMODE_SPECULAR_LIGHTING) |
|||
{ |
|||
diffuseLighting = float3(0.0, 0.0, 0.0); |
|||
} |
|||
else if (lightDebugMode == LIGHTINGDEBUGMODE_VISUALIZE_CASCADE) |
|||
{ |
|||
specularLighting = float3(0.0, 0.0, 0.0); |
|||
|
|||
const float3 s_CascadeColors[] = { |
|||
float3(1.0, 0.0, 0.0), |
|||
float3(0.0, 1.0, 0.0), |
|||
float3(0.0, 0.0, 1.0), |
|||
float3(1.0, 1.0, 0.0) |
|||
}; |
|||
|
|||
#ifdef SHADOWS_USE_SHADOWCTXT |
|||
float shadow = GetDirectionalShadowAttenuation(lightLoopContext.shadowContext, positionWS, 0, float3(0.0, 0.0, 0.0), float2(0.0, 0.0)); |
|||
#else |
|||
float shadow = GetDirectionalShadowAttenuation(lightLoopContext, positionWS, 0, float3(0.0, 0.0, 0.0), float2(0.0, 0.0)); |
|||
#endif |
|||
|
|||
int shadowSplitIndex = GetSplitSphereIndexForDirshadows(positionWS, _DirShadowSplitSpheres); |
|||
if (shadowSplitIndex == -1) |
|||
diffuseLighting = float3(0.0, 0.0, 0.0); |
|||
else |
|||
{ |
|||
diffuseLighting = s_CascadeColors[shadowSplitIndex] * shadow; |
|||
} |
|||
|
|||
} |
|||
#endif |
|||
} |
|||
|
|||
#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.unTileCoord; |
|||
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; |
|||
} |
|||
|
|||
uint FetchIndexTile(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; |
|||
} |
|||
|
|||
#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) |
|||
{ |
|||
return FetchIndexTile(tileOffset, lightIndex); |
|||
} |
|||
|
|||
#elif defined(USE_CLUSTERED_LIGHTLIST) |
|||
|
|||
#include "ClusteredUtils.hlsl" |
|||
|
|||
uint GetTileSize() |
|||
{ |
|||
return TILE_SIZE_CLUSTERED; |
|||
} |
|||
|
|||
void GetCountAndStartCluster(PositionInputs posInput, uint lightCategory, out uint start, out uint lightCount) |
|||
{ |
|||
uint2 tileIndex = posInput.unTileCoord; |
|||
|
|||
float logBase = g_fClustBase; |
|||
if (g_isLogBaseBufferEnabled) |
|||
{ |
|||
logBase = g_logBaseBuffer[tileIndex.y * _NumTileClusteredX + tileIndex.x]; |
|||
} |
|||
|
|||
int clustIdx = SnapToClusterIdxFlex(posInput.depthVS, logBase, g_isLogBaseBufferEnabled != 0); |
|||
|
|||
int nrClusters = (1 << g_iLog2NumClusters); |
|||
const int idx = ((lightCategory * nrClusters + clustIdx) * _NumTileClusteredY + tileIndex.y) * _NumTileClusteredX + tileIndex.x; |
|||
uint dataPair = g_vLayeredOffsetsBuffer[idx]; |
|||
start = dataPair & 0x7ffffff; |
|||
lightCount = (dataPair >> 27) & 31; |
|||
} |
|||
|
|||
uint FetchIndexCluster(uint tileOffset, uint lightIndex) |
|||
{ |
|||
return g_vLightListGlobal[tileOffset + lightIndex]; |
|||
} |
|||
|
|||
void GetCountAndStart(PositionInputs posInput, uint lightCategory, out uint start, out uint lightCount) |
|||
{ |
|||
if (_UseTileLightList) |
|||
GetCountAndStartTile(posInput, lightCategory, start, lightCount); |
|||
else |
|||
GetCountAndStartCluster(posInput, lightCategory, start, lightCount); |
|||
} |
|||
|
|||
uint FetchIndex(uint tileOffset, uint lightIndex) |
|||
{ |
|||
if (_UseTileLightList) |
|||
return FetchIndexTile(tileOffset, lightIndex); |
|||
else |
|||
return FetchIndexCluster(tileOffset, lightIndex); |
|||
} |
|||
|
|||
#endif |
|||
|
|||
// bakeDiffuseLighting is part of the prototype so a user is able to implement a "base pass" with GI and multipass direct light (aka old unity rendering path) |
|||
void LightLoop( float3 V, PositionInputs posInput, PreLightData prelightData, BSDFData bsdfData, float3 bakeDiffuseLighting, uint featureFlags, |
|||
out float3 diffuseLighting, |
|||
out float3 specularLighting) |
|||
{ |
|||
LightLoopContext context; |
|||
#ifndef SHADOWS_USE_SHADOWCTXT |
|||
ZERO_INITIALIZE(LightLoopContext, context); |
|||
#else |
|||
context.sampleShadow = 0; |
|||
context.sampleReflection = 0; |
|||
context.shadowContext = InitShadowContext(); |
|||
#endif |
|||
|
|||
diffuseLighting = float3(0.0, 0.0, 0.0); |
|||
specularLighting = float3(0.0, 0.0, 0.0); |
|||
|
|||
uint i = 0; // Declare once to avoid the D3D11 compiler warning. |
|||
|
|||
#ifdef PROCESS_DIRECTIONAL_LIGHT |
|||
if(featureFlags & FEATURE_FLAG_DIRECTIONAL_LIGHT) |
|||
{ |
|||
for(i = 0; i < _DirectionalLightCount; ++i) |
|||
{ |
|||
float3 localDiffuseLighting, localSpecularLighting; |
|||
|
|||
EvaluateBSDF_Directional(context, V, posInput, prelightData, _DirectionalLightDatas[i], bsdfData, |
|||
localDiffuseLighting, localSpecularLighting); |
|||
|
|||
diffuseLighting += localDiffuseLighting; |
|||
specularLighting += localSpecularLighting; |
|||
} |
|||
} |
|||
#endif |
|||
|
|||
#ifdef PROCESS_PUNCTUAL_LIGHT |
|||
if(featureFlags & FEATURE_FLAG_PUNCTUAL_LIGHT) |
|||
{ |
|||
// TODO: Convert the for loop below to a while on each type as we know we are sorted! |
|||
uint punctualLightStart; |
|||
uint punctualLightCount; |
|||
GetCountAndStart(posInput, LIGHTCATEGORY_PUNCTUAL, punctualLightStart, punctualLightCount); |
|||
|
|||
for(i = 0; i < punctualLightCount; ++i) |
|||
{ |
|||
float3 localDiffuseLighting, localSpecularLighting; |
|||
|
|||
EvaluateBSDF_Punctual(context, V, posInput, prelightData, _LightDatas[FetchIndex(punctualLightStart, i)], bsdfData, |
|||
localDiffuseLighting, localSpecularLighting); |
|||
|
|||
diffuseLighting += localDiffuseLighting; |
|||
specularLighting += localSpecularLighting; |
|||
} |
|||
} |
|||
#endif |
|||
|
|||
#ifdef PROCESS_AREA_LIGHT |
|||
if(featureFlags & FEATURE_FLAG_AREA_LIGHT) |
|||
{ |
|||
// TODO: Convert the for loop below to a while on each type as we know we are sorted! |
|||
uint areaLightStart; |
|||
uint areaLightCount; |
|||
GetCountAndStart(posInput, LIGHTCATEGORY_AREA, areaLightStart, areaLightCount); |
|||
for(i = 0; i < areaLightCount; ++i) |
|||
{ |
|||
float3 localDiffuseLighting, localSpecularLighting; |
|||
|
|||
uint areaIndex = FetchIndex(areaLightStart, i); |
|||
|
|||
if(_LightDatas[areaIndex].lightType == GPULIGHTTYPE_LINE) |
|||
{ |
|||
EvaluateBSDF_Line(context, V, posInput, prelightData, _LightDatas[areaIndex], bsdfData, |
|||
localDiffuseLighting, localSpecularLighting); |
|||
} |
|||
else |
|||
{ |
|||
EvaluateBSDF_Area(context, V, posInput, prelightData, _LightDatas[areaIndex], bsdfData, |
|||
localDiffuseLighting, localSpecularLighting); |
|||
} |
|||
|
|||
|
|||
diffuseLighting += localDiffuseLighting; |
|||
specularLighting += localSpecularLighting; |
|||
} |
|||
} |
|||
#endif |
|||
|
|||
#ifdef PROCESS_ENV_LIGHT |
|||
float3 iblDiffuseLighting = float3(0.0, 0.0, 0.0); |
|||
float3 iblSpecularLighting = float3(0.0, 0.0, 0.0); |
|||
|
|||
// Only apply sky IBL if the sky texture is available. |
|||
if(featureFlags & FEATURE_FLAG_SKY_LIGHT) |
|||
{ |
|||
if(_EnvLightSkyEnabled) |
|||
{ |
|||
float3 localDiffuseLighting, localSpecularLighting; |
|||
float2 weight; |
|||
// The sky is a single cubemap texture separate from the reflection probe texture array (different resolution and compression) |
|||
context.sampleReflection = SINGLE_PASS_CONTEXT_SAMPLE_SKY; |
|||
EnvLightData envLightSky = InitSkyEnvLightData(0); // The sky data are generated on the fly so the compiler can optimize the code |
|||
EvaluateBSDF_Env(context, V, posInput, prelightData, envLightSky, bsdfData, localDiffuseLighting, localSpecularLighting, weight); |
|||
iblDiffuseLighting = lerp(iblDiffuseLighting, localDiffuseLighting, weight.x); // Should be remove by the compiler if it is smart as all is constant 0 |
|||
iblSpecularLighting = lerp(iblSpecularLighting, localSpecularLighting, weight.y); |
|||
} |
|||
} |
|||
|
|||
|
|||
if(featureFlags & FEATURE_FLAG_ENV_LIGHT) |
|||
{ |
|||
uint envLightStart; |
|||
uint envLightCount; |
|||
GetCountAndStart(posInput, LIGHTCATEGORY_ENV, envLightStart, envLightCount); |
|||
|
|||
for(i = 0; i < envLightCount; ++i) |
|||
{ |
|||
float3 localDiffuseLighting, localSpecularLighting; |
|||
float2 weight; |
|||
context.sampleReflection = SINGLE_PASS_CONTEXT_SAMPLE_REFLECTION_PROBES; |
|||
EvaluateBSDF_Env(context, V, posInput, prelightData, _EnvLightDatas[FetchIndex(envLightStart, i)], bsdfData, localDiffuseLighting, localSpecularLighting, weight); |
|||
iblDiffuseLighting = lerp(iblDiffuseLighting, localDiffuseLighting, weight.x); // Should be remove by the compiler if it is smart as all is constant 0 |
|||
iblSpecularLighting = lerp(iblSpecularLighting, localSpecularLighting, weight.y); |
|||
} |
|||
} |
|||
|
|||
|
|||
diffuseLighting += iblDiffuseLighting; |
|||
specularLighting += iblSpecularLighting; |
|||
#endif |
|||
|
|||
// TODO: currently apply GI at the same time as reflection |
|||
#ifdef PROCESS_ENV_LIGHT |
|||
// Add indirect diffuse + emissive (if any) |
|||
diffuseLighting += bakeDiffuseLighting; |
|||
#endif |
|||
|
|||
ApplyDebug(context, posInput.positionWS, diffuseLighting, specularLighting); |
|||
} |
|||
|
|||
#else // LIGHTLOOP_SINGLE_PASS |
|||
|
|||
uint GetTileSize() |
|||
{ |
|||
return 1; |
|||
} |
|||
|
|||
|
|||
// bakeDiffuseLighting is part of the prototype so a user is able to implement a "base pass" with GI and multipass direct light (aka old unity rendering path) |
|||
void LightLoop( float3 V, PositionInputs posInput, PreLightData prelightData, BSDFData bsdfData, float3 bakeDiffuseLighting, uint featureFlag, |
|||
out float3 diffuseLighting, |
|||
out float3 specularLighting) |
|||
{ |
|||
LightLoopContext context; |
|||
#ifndef SHADOWS_USE_SHADOWCTXT |
|||
ZERO_INITIALIZE(LightLoopContext, context); |
|||
#else |
|||
context.sampleShadow = 0; |
|||
context.sampleReflection = 0; |
|||
context.shadowContext = InitShadowContext(); |
|||
#endif |
|||
|
|||
diffuseLighting = float3(0.0, 0.0, 0.0); |
|||
specularLighting = float3(0.0, 0.0, 0.0); |
|||
|
|||
uint i = 0; // Declare once to avoid the D3D11 compiler warning. |
|||
|
|||
for (i = 0; i < _DirectionalLightCount; ++i) |
|||
{ |
|||
float3 localDiffuseLighting, localSpecularLighting; |
|||
|
|||
EvaluateBSDF_Directional( context, V, posInput, prelightData, _DirectionalLightDatas[i], bsdfData, |
|||
localDiffuseLighting, localSpecularLighting); |
|||
|
|||
diffuseLighting += localDiffuseLighting; |
|||
specularLighting += localSpecularLighting; |
|||
} |
|||
|
|||
for (i = 0; i < _PunctualLightCount; ++i) |
|||
{ |
|||
float3 localDiffuseLighting, localSpecularLighting; |
|||
|
|||
EvaluateBSDF_Punctual( context, V, posInput, prelightData, _LightDatas[i], bsdfData, |
|||
localDiffuseLighting, localSpecularLighting); |
|||
|
|||
diffuseLighting += localDiffuseLighting; |
|||
specularLighting += localSpecularLighting; |
|||
} |
|||
|
|||
// Area are store with punctual, just offset the index |
|||
for (i = _PunctualLightCount; i < _AreaLightCount + _PunctualLightCount; ++i) |
|||
{ |
|||
float3 localDiffuseLighting, localSpecularLighting; |
|||
|
|||
if (_LightDatas[i].lightType == GPULIGHTTYPE_LINE) |
|||
{ |
|||
EvaluateBSDF_Line( context, V, posInput, prelightData, _LightDatas[i], bsdfData, |
|||
localDiffuseLighting, localSpecularLighting); |
|||
} |
|||
else |
|||
{ |
|||
EvaluateBSDF_Area( context, V, posInput, prelightData, _LightDatas[i], bsdfData, |
|||
localDiffuseLighting, localSpecularLighting); |
|||
} |
|||
|
|||
diffuseLighting += localDiffuseLighting; |
|||
specularLighting += localSpecularLighting; |
|||
} |
|||
|
|||
// TODO: Check the reflection hierarchy, for the current system (matching legacy unity) we must sort from bigger solid angle to lower (lower override bigger). So begging by sky |
|||
// TODO: Change the way it is done by reversing the order, from smaller solid angle to bigger, so we can early out when the weight is 1. |
|||
float3 iblDiffuseLighting = float3(0.0, 0.0, 0.0); |
|||
float3 iblSpecularLighting = float3(0.0, 0.0, 0.0); |
|||
|
|||
// Only apply sky IBL if the sky texture is available. |
|||
if (_EnvLightSkyEnabled) |
|||
{ |
|||
float3 localDiffuseLighting, localSpecularLighting; |
|||
float2 weight; |
|||
// The sky is a single cubemap texture separate from the reflection probe texture array (different resolution and compression) |
|||
context.sampleReflection = SINGLE_PASS_CONTEXT_SAMPLE_SKY; |
|||
EnvLightData envLightSky = InitSkyEnvLightData(0); // The sky data are generated on the fly so the compiler can optimize the code |
|||
EvaluateBSDF_Env(context, V, posInput, prelightData, envLightSky, bsdfData, localDiffuseLighting, localSpecularLighting, weight); |
|||
iblDiffuseLighting = lerp(iblDiffuseLighting, localDiffuseLighting, weight.x); // Should be remove by the compiler if it is smart as all is constant 0 |
|||
iblSpecularLighting = lerp(iblSpecularLighting, localSpecularLighting, weight.y); |
|||
} |
|||
|
|||
for (i = 0; i < _EnvLightCount; ++i) |
|||
{ |
|||
float3 localDiffuseLighting, localSpecularLighting; |
|||
float2 weight; |
|||
context.sampleReflection = SINGLE_PASS_CONTEXT_SAMPLE_REFLECTION_PROBES; |
|||
EvaluateBSDF_Env(context, V, posInput, prelightData, _EnvLightDatas[i], bsdfData, localDiffuseLighting, localSpecularLighting, weight); |
|||
iblDiffuseLighting = lerp(iblDiffuseLighting, localDiffuseLighting, weight.x); // Should be remove by the compiler if it is smart as all is constant 0 |
|||
iblSpecularLighting = lerp(iblSpecularLighting, localSpecularLighting, weight.y); |
|||
} |
|||
|
|||
diffuseLighting += iblDiffuseLighting; |
|||
specularLighting += iblSpecularLighting; |
|||
|
|||
// Add indirect diffuse + emissive (if any) |
|||
diffuseLighting += bakeDiffuseLighting; |
|||
|
|||
ApplyDebug(context, posInput.positionWS, diffuseLighting, specularLighting); |
|||
} |
|||
|
|||
#endif |
|
|||
// TODO: |
|||
// - How to support a Gather sampling with such abstraction ? |
|||
// - What's belong to shadow and what's belong to renderloop ? (shadowmap size depends on the usage of atlas or not) |
|||
// - Is PunctualShadowData fixed or customizable ? Who is the owner ? Should it be pass to GetPunctualShadowAttenuation ? Sure it should... |
|||
// - Could be return by GetShadowTextureCoordinate() and pass to GetPunctualShadowAttenuation(). But in this case, who control the atlas application ? |
|||
// TODO: |
|||
// Caution: formula doesn't work as we are texture atlas... |
|||
// if (max3(abs(NDC.x), abs(NDC.y), 1.0 - texCoordXYZ.z) <= 1.0) return 1.0; |
|||
#ifndef SHADOW_HLSL |
|||
#define SHADOW_HLSL |
|||
// |
|||
// Shadow master include header. |
|||
// |
|||
// There are four relevant files for shadows. |
|||
// First ShadowContext.hlsl must declare the specific ShadowContext struct and the loader that goes along with it. |
|||
// ShadowContext loading and resource setup from C# must be in sync. |
|||
// |
|||
// Second there are two headers for shadow algorithms, whose signatures must match any of the Get...Attenuation function prototypes. |
|||
// The first header contains engine defaults, whereas the second header is empty by default. All project specific custom shadow algorithms should go in there or leave empty. |
|||
// |
|||
// Last there's a dispatcher include. By default the Get...Attenuation functions are rerouted to their default implementations. This can be overridden for each |
|||
// shadow type in the dispatcher source. For each overridden shadow type a specific define must be defined to prevent falling back to the default functions. |
|||
// |
|||
|
|||
|
|||
//#define SHADOWS_USE_SHADOWCTXT |
|||
|
|||
#ifdef SHADOWS_USE_SHADOWCTXT |
|||
#define SHADOW_SUPPORTS_DYNAMIC_INDEXING 0 // only on >= sm 5.1 |
|||
|
|||
// TODO: Remove this once we've moved over to the new system. Also delete the undef at the bottom again. |
|||
#define ShadowData ShadowDataExp |
|||
|
|||
#include "ShadowBase.cs.hlsl" // ShadowData definition, auto generated (don't modify) |
|||
#include "ShadowTexFetch.hlsl" // Resource sampling definitions (don't modify) |
|||
|
|||
#define SHADOWCONTEXT_DECLARE( _Tex2DArraySlots, _TexCubeArraySlots, _SamplerCompSlots, _SamplerSlots ) \ |
|||
\ |
|||
struct ShadowContext \ |
|||
{ \ |
|||
StructuredBuffer<ShadowData> shadowDatas; \ |
|||
StructuredBuffer<int4> payloads; \ |
|||
Texture2DArray tex2DArray[_Tex2DArraySlots]; \ |
|||
TextureCubeArray texCubeArray[_TexCubeArraySlots]; \ |
|||
SamplerComparisonState compSamplers[_SamplerCompSlots]; \ |
|||
SamplerState samplers[_SamplerSlots]; \ |
|||
}; \ |
|||
\ |
|||
SHADOW_DEFINE_SAMPLING_FUNCS( _Tex2DArraySlots, _TexCubeArraySlots, _SamplerCompSlots, _SamplerSlots ) |
|||
|
|||
// Shadow context definition and initialization, i.e. resource binding (project header, must be kept in sync with C# runtime) |
|||
#include "ShadowContext.hlsl" |
|||
|
|||
// helper function to extract shadowmap data from the ShadowData struct |
|||
void unpackShadowmapId( uint shadowmapId, out uint texIdx, out uint sampIdx, out float slice ) |
|||
{ |
|||
texIdx = (shadowmapId >> 24) & 0xff; |
|||
sampIdx = (shadowmapId >> 16) & 0xff; |
|||
slice = (float)(shadowmapId & 0xffff); |
|||
} |
|||
void unpackShadowmapId( uint shadowmapId, out uint texIdx, out uint sampIdx ) |
|||
{ |
|||
texIdx = (shadowmapId >> 24) & 0xff; |
|||
sampIdx = (shadowmapId >> 16) & 0xff; |
|||
} |
|||
void unpackShadowmapId( uint shadowmapId, out float slice ) |
|||
{ |
|||
slice = (float)(shadowmapId & 0xffff); |
|||
} |
|||
|
|||
|
|||
|
|||
// shadow sampling prototypes |
|||
float GetPunctualShadowAttenuation( ShadowContext shadowContext, float3 positionWS, int shadowDataIndex, float3 L ); |
|||
float GetPunctualShadowAttenuation( ShadowContext shadowContext, float3 positionWS, int shadowDataIndex, float3 L, float2 unPositionSS ); |
|||
// shadow sampling prototypes with screenspace info |
|||
float GetDirectionalShadowAttenuation( ShadowContext shadowContext, float3 positionWS, int shadowDataIndex, float3 L ); |
|||
float GetDirectionalShadowAttenuation( ShadowContext shadowContext, float3 positionWS, int shadowDataIndex, float3 L, float2 unPositionSS ); |
|||
|
|||
|
|||
// wedge in the actual shadow sampling algorithms |
|||
#include "ShadowSampling.hlsl" // sampling patterns |
|||
#include "ShadowAlgorithms.hlsl" // engine default algorithms (don't modify) |
|||
#include "ShadowAlgorithmsCustom.hlsl" // project specific custom algorithms (project can modify this) |
|||
|
|||
|
|||
// default dispatchers for the individual shadow types (with and without screenspace support) |
|||
// point/spot light shadows |
|||
float GetPunctualShadowAttenuationDefault( ShadowContext shadowContext, float3 positionWS, int shadowDataIndex, float3 L ) |
|||
{ |
|||
return EvalShadow_PunctualDepth(shadowContext, positionWS, shadowDataIndex, L); |
|||
} |
|||
float GetPunctualShadowAttenuationDefault( ShadowContext shadowContext, float3 positionWS, int shadowDataIndex, float3 L, float2 unPositionSS ) |
|||
{ |
|||
return GetPunctualShadowAttenuationDefault( shadowContext, positionWS, shadowDataIndex, L ); |
|||
} |
|||
// directional light shadows |
|||
float GetDirectionalShadowAttenuationDefault( ShadowContext shadowContext, float3 positionWS, int shadowDataIndex, float3 L ) |
|||
{ |
|||
return EvalShadow_CascadedDepth( shadowContext, positionWS, shadowDataIndex, L ); |
|||
} |
|||
float GetDirectionalShadowAttenuationDefault( ShadowContext shadowContext, float3 positionWS, int shadowDataIndex, float3 L, float2 unPositionSS ) |
|||
{ |
|||
return GetDirectionalShadowAttenuationDefault( shadowContext, positionWS, shadowDataIndex, L ); |
|||
} |
|||
|
|||
// include project specific shadow dispatcher. If this file is not empty, it MUST define which default shadows it's overriding |
|||
#include "ShadowDispatch.hlsl" |
|||
|
|||
// if shadow dispatch is empty we'll fall back to default shadow sampling implementations |
|||
#ifndef SHADOW_DISPATCH_USE_CUSTOM_PUNCTUAL |
|||
float GetPunctualShadowAttenuation( ShadowContext shadowContext, float3 positionWS, int shadowDataIndex, float3 L ) |
|||
{ |
|||
return GetPunctualShadowAttenuationDefault( shadowContext, positionWS, shadowDataIndex, L ); |
|||
} |
|||
float GetPunctualShadowAttenuation( ShadowContext shadowContext, float3 positionWS, int shadowDataIndex, float3 L, float2 unPositionSS ) |
|||
{ |
|||
return GetPunctualShadowAttenuationDefault( shadowContext, positionWS, shadowDataIndex, L, unPositionSS ); |
|||
} |
|||
#endif |
|||
#ifndef SHADOW_DISPATCH_USE_CUSTOM_DIRECTIONAL |
|||
float GetDirectionalShadowAttenuation( ShadowContext shadowContext, float3 positionWS, int shadowDataIndex, float3 L ) |
|||
{ |
|||
return GetDirectionalShadowAttenuationDefault( shadowContext, positionWS, shadowDataIndex, L ); |
|||
} |
|||
float GetDirectionalShadowAttenuation( ShadowContext shadowContext, float3 positionWS, int shadowDataIndex, float3 L, float2 unPositionSS ) |
|||
{ |
|||
return GetDirectionalShadowAttenuationDefault( shadowContext, positionWS, shadowDataIndex, L, unPositionSS ); |
|||
} |
|||
#endif |
|||
#undef ShadowData // TODO: Remove this once we've moved over to the new system. Also delete the define at the top again. |
|||
|
|||
#endif // SHADOWS_USE_SHADOWCTXT |
|||
|
|||
#endif // SHADOW_HLSL |
部分文件因为文件数量过多而无法显示
撰写
预览
正在加载...
取消
保存
Reference in new issue