Antti Tapaninen
8 年前
当前提交
0574ef6b
共有 191 个文件被更改,包括 4604 次插入 和 3357 次删除
-
75Assets/ScriptableRenderPipeline/Editor/MaterialUpgrader.cs
-
4Assets/ScriptableRenderPipeline/HDRenderPipeline/Debug/Resources/DebugDisplayLatlong.shader
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/Debug/Resources/DebugDisplayShadowMap.shader
-
12Assets/ScriptableRenderPipeline/HDRenderPipeline/Debug/Resources/DebugViewMaterialGBuffer.shader
-
406Assets/ScriptableRenderPipeline/HDRenderPipeline/Debug/Resources/DebugViewTiles.shader
-
100Assets/ScriptableRenderPipeline/HDRenderPipeline/Editor/HDRenderPipelineInspector.cs
-
30Assets/ScriptableRenderPipeline/HDRenderPipeline/Editor/HDRenderPipelineMenuItems.cs
-
6Assets/ScriptableRenderPipeline/HDRenderPipeline/Editor/UpgradeStandardShaderMaterials.cs
-
81Assets/ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.asset
-
23Assets/ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.cs
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/LightLoop.cs
-
22Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/Lighting.hlsl
-
17Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/Resources/Deferred.shader
-
8Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TileLightLoopProducer.cs
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/lightlistbuild-bigtile.compute
-
9Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/lightlistbuild-clustered.compute
-
925Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/lightlistbuild.compute
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/scrbound.compute
-
183Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/shadeopaque.compute
-
1001Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePass.cs
-
12Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePass.cs.hlsl
-
74Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePass.hlsl
-
747Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePassLoop.hlsl
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePassResources.asset
-
1Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePassResources.cs
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Builtin/BuiltinData.hlsl
-
22Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/LayeredLit/LayeredLit.shader
-
24Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/LayeredLit/LayeredLitTessellation.shader
-
33Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Editor/LitUI.cs
-
17Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Editor/StandardSpecularToHDLitMaterialUpgrader.cs
-
17Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Editor/StandardToHDLitMaterialUpgrader.cs
-
33Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.hlsl
-
24Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.shader
-
12Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitData.hlsl
-
24Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitTessellation.shader
-
4Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LtcData.DisneyDiffuse.cs
-
8Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LtcData.GGX.cs
-
13Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Resources/CombineSubsurfaceScattering.shader
-
6Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Resources/PreIntegratedFGD.shader
-
18Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Material.hlsl
-
12Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Unlit/Unlit.shader
-
20Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/Editor/PostProcessingSRPEditor.cs
-
4Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/Resources/EyeAdaptation.shader
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/Resources/EyeHistogram.compute
-
6Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/Resources/FinalPass.shader
-
6Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/Resources/LutGen.shader
-
6Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/PostProcessingSRP.cs
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/PostProcessingSRP.Settings.cs
-
8Assets/ScriptableRenderPipeline/HDRenderPipeline/SceneSettings/Resources/DrawGaussianProfile.shader
-
6Assets/ScriptableRenderPipeline/HDRenderPipeline/SceneSettings/Resources/DrawTransmittanceGraph.shader
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/FragInputs.hlsl
-
3Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/ShaderPassForward.hlsl
-
2Assets/ScriptableRenderPipeline/HDRenderPipeline/Shadow/Shadow.cs
-
6Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/HDRISky/Resources/SkyHDRI.shader
-
6Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/ProceduralSky/Resources/SkyProcedural.shader
-
4Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/Resources/BuildProbabilityTables.compute
-
4Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/Resources/ComputeGgxIblSampleData.compute
-
4Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/Resources/GGXConvolve.shader
-
7Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/SkyManager.cs
-
41Assets/ScriptableRenderPipeline/ShaderLibrary/Common.hlsl
-
157Assets/ScriptableRenderPipeline/common/Camera/CameraSwitcher.cs
-
102Assets/ScriptableRenderPipeline/common/Camera/FreeCamera.cs
-
191Assets/ScriptableRenderPipeline/common/Debugging.cs
-
415Assets/ScriptableRenderPipeline/common/SkyboxHelper.cs
-
689Assets/ScriptableRenderPipeline/common/TextureCache.cs
-
21Assets/ScriptableRenderPipeline/fptl/TiledLightingUtils.hlsl
-
7Assets/ScriptableRenderPipeline/fptl/lightlistbuild-clustered.compute
-
2Assets/ScriptableRenderPipeline/fptl/lightlistbuild.compute
-
196Assets/TestScenes/HDTest/CascadedShadowsTest.unity
-
49Assets/TestScenes/HDTest/GlobalIlluminationTest.unity
-
3Assets/TestScenes/HDTest/GraphicTest/Tessellation/Material/Tessellation - Rock.mat
-
2Assets/TestScenes/HDTest/GraphicTest/Tessellation/Material/Tessellation - Wood.mat
-
42Assets/TestScenes/HDTest/HDRenderLoopTest.unity
-
40Assets/TestScenes/HDTest/LayeredLitTest.unity
-
40Assets/TestScenes/HDTest/LayeredLitTest/Textures/Detail_Checker.tga.meta
-
4Assets/TestScenes/HDTest/Rock/rcgRock012/Materials/rcgRock012Material.mat
-
2ProjectSettings/ProjectVersion.txt
-
2ProjectSettings/QualitySettings.asset
-
9Assets/LowEndMobilePipeline.meta
-
9Assets/Plugins.meta
-
35Assets/ScriptableRenderPipeline/HDRenderPipeline/Default SSS Profile.asset
-
9Assets/ScriptableRenderPipeline/HDRenderPipeline/Default SSS Profile.asset.meta
-
41Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/FeatureFlags.hlsl
-
9Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/FeatureFlags.hlsl.meta
-
11Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/cleardispatchindirect.compute
-
9Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/cleardispatchindirect.compute.meta
-
494Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/SubsurfaceScatteringProfile.cs
-
12Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/SubsurfaceScatteringProfile.cs.meta
-
9Assets/LowEndMobilePipeline/LowEndMobilePipelineAsset.asset.meta
-
145Assets/LowEndMobilePipeline/LowEndMobilePipelineAsset.cs
-
12Assets/LowEndMobilePipeline/LowEndMobilePipelineAsset.cs.meta
-
9Assets/LowEndMobilePipeline/TestScenes.meta
-
9Assets/LowEndMobilePipeline/Editor.meta
-
12Assets/LowEndMobilePipeline/LowEndMobilePipeline.cs.meta
-
1001Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineVikingVillage/LightingData.asset
-
8Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineVikingVillage/LightingData.asset.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 |
|||
//------------------------------------------------------------------------------------- |
|||
|
|||
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, 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; |
|||
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, 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); |
|||
} |
|||
|
|||
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[max(0,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 |
|||
|
|||
#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 "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); |
|||
|
|||
#ifdef OUTPUT_SPLIT_LIGHTING |
|||
RWTexture2D<float4> specularLightingUAV; |
|||
RWTexture2D<float3> diffuseLightingUAV; |
|||
#else |
|||
RWTexture2D<float4> combinedLightingUAV; |
|||
#endif |
|||
|
|||
[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, uint2(pixelCoord.xy) / GetTileSize()); |
|||
PositionInputs posInput = GetPositionInput(pixelCoord.xy, _ScreenSize.zw, groupId); |
|||
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, 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(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, _LightingSettings[0].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 * _LightingSettings[0].numTileFtplY) * _LightingSettings[0].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, |
|||
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 |
|||
for (i = 0; i < _LightingSettings[0].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. |
|||
#ifdef SKY_LIGHTING |
|||
{ |
|||
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); |
|||
} |
|||
#endif |
|||
|
|||
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 |
|||
|
|||
//----------------------------------------------------------------------------- |
|||
// 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; |
|||
} |
|||
|
|||
#ifdef USE_FPTL_LIGHTLIST |
|||
|
|||
uint GetTileSize() |
|||
{ |
|||
return TILE_SIZE_FPTL; |
|||
} |
|||
|
|||
void GetCountAndStart(PositionInputs posInput, uint lightCategory, out uint start, out uint lightCount) |
|||
{ |
|||
GetCountAndStartTile(posInput, lightCategory, start, lightCount); |
|||
} |
|||
|
|||
uint FetchIndex(uint tileOffset, uint lightIndex) |
|||
{ |
|||
const uint lightIndexPlusOne = lightIndex + 1; // Add +1 as first slot is reserved to store number of light |
|||
// Light index are store on 16bit |
|||
return (g_vLightListGlobal[DWORD_PER_TILE * tileOffset + (lightIndexPlusOne >> 1)] >> ((lightIndexPlusOne & 1) * DWORD_PER_TILE)) & 0xffff; |
|||
} |
|||
|
|||
#elif defined(USE_CLUSTERED_LIGHTLIST) |
|||
|
|||
#include "ClusteredUtils.hlsl" |
|||
|
|||
uint GetTileSize() |
|||
{ |
|||
return TILE_SIZE_CLUSTERED; |
|||
} |
|||
|
|||
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; |
|||
} |
|||
|
|||
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) |
|||
{ |
|||
uint offset = tileOffset + lightIndex; |
|||
const uint lightIndexPlusOne = lightIndex + 1; // Add +1 as first slot is reserved to store number of light |
|||
|
|||
if (_UseTileLightList) |
|||
offset = DWORD_PER_TILE * tileOffset + (lightIndexPlusOne >> 1); |
|||
|
|||
// Avoid generated HLSL bytecode to always access g_vLightListGlobal with |
|||
// two different offsets, fixes out of bounds issue |
|||
uint value = g_vLightListGlobal[offset]; |
|||
|
|||
// Light index are store on 16bit |
|||
return (_UseTileLightList ? ((value >> ((lightIndexPlusOne & 1) * DWORD_PER_TILE)) & 0xffff) : value); |
|||
} |
|||
|
|||
#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 |
|||
|
|||
|
|||
|
|||
// 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; |
|||
#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 < _LightingSettings[0].directionalLightCount; ++i) |
|||
{ |
|||
float3 localDiffuseLighting, localSpecularLighting; |
|||
|
|||
EvaluateBSDF_Directional( context, V, posInput, prelightData, _DirectionalLightDatas[i], bsdfData, |
|||
localDiffuseLighting, localSpecularLighting); |
|||
|
|||
diffuseLighting += localDiffuseLighting; |
|||
specularLighting += localSpecularLighting; |
|||
} |
|||
|
|||
|
|||
for (i = 0; i < _LightingSettings[0].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 = _LightingSettings[0].punctualLightCount; i < _LightingSettings[0].punctualLightCount + _LightingSettings[0].areaLightCount; ++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. |
|||
#ifdef SKY_LIGHTING |
|||
{ |
|||
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); |
|||
} |
|||
#endif |
|||
|
|||
for (i = 0; i < _LightingSettings[0].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 |
|||
|
|||
|
|||
// 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 |
|
|||
using UnityEngine; |
|||
|
|||
public class FreeCamera : MonoBehaviour |
|||
namespace UnityEngine.Experimental.Rendering |
|||
public float m_LookSpeedController = 120f; |
|||
public float m_LookSpeedMouse = 10.0f; |
|||
public float m_MoveSpeed = 50.0f; |
|||
public float m_Turbo = 10.0f; |
|||
public class FreeCamera : MonoBehaviour |
|||
{ |
|||
public float m_LookSpeedController = 120f; |
|||
public float m_LookSpeedMouse = 10.0f; |
|||
public float m_MoveSpeed = 50.0f; |
|||
public float m_Turbo = 10.0f; |
|||
private static string kMouseX = "Mouse X"; |
|||
private static string kMouseY = "Mouse Y"; |
|||
private static string kRightStickX = "Controller Right Stick X"; |
|||
private static string kRightStickY = "Controller Right Stick Y"; |
|||
private static string kVertical = "Vertical"; |
|||
private static string kHorizontal = "Horizontal"; |
|||
private string[] m_RequiredInputAxes = { kMouseX, kMouseY, kRightStickX, kRightStickY, kVertical, kHorizontal }; |
|||
private static string kMouseX = "Mouse X"; |
|||
private static string kMouseY = "Mouse Y"; |
|||
private static string kRightStickX = "Controller Right Stick X"; |
|||
private static string kRightStickY = "Controller Right Stick Y"; |
|||
private static string kVertical = "Vertical"; |
|||
private static string kHorizontal = "Horizontal"; |
|||
private string[] m_RequiredInputAxes = { kMouseX, kMouseY, kRightStickX, kRightStickY, kVertical, kHorizontal }; |
|||
|
|||
private bool m_Valid = true; |
|||
void OnEnable() |
|||
{ |
|||
m_Valid = Debugging.CheckRequiredInputAxisMapping(m_RequiredInputAxes); |
|||
} |
|||
private bool m_Valid = true; |
|||
void OnEnable() |
|||
{ |
|||
m_Valid = Debugging.CheckRequiredInputAxisMapping(m_RequiredInputAxes); |
|||
} |
|||
void Update() |
|||
{ |
|||
if(m_Valid) |
|||
void Update() |
|||
float inputRotateAxisX = 0.0f; |
|||
float inputRotateAxisY = 0.0f; |
|||
if (Input.GetMouseButton(1)) |
|||
if(m_Valid) |
|||
inputRotateAxisX = Input.GetAxis(kMouseX) * m_LookSpeedMouse; |
|||
inputRotateAxisY = Input.GetAxis(kMouseY) * m_LookSpeedMouse; |
|||
} |
|||
inputRotateAxisX += (Input.GetAxis(kRightStickX) * m_LookSpeedController * Time.deltaTime); |
|||
inputRotateAxisY += (Input.GetAxis(kRightStickY) * m_LookSpeedController * Time.deltaTime); |
|||
float inputRotateAxisX = 0.0f; |
|||
float inputRotateAxisY = 0.0f; |
|||
if (Input.GetMouseButton(1)) |
|||
{ |
|||
inputRotateAxisX = Input.GetAxis(kMouseX) * m_LookSpeedMouse; |
|||
inputRotateAxisY = Input.GetAxis(kMouseY) * m_LookSpeedMouse; |
|||
} |
|||
inputRotateAxisX += (Input.GetAxis(kRightStickX) * m_LookSpeedController * Time.deltaTime); |
|||
inputRotateAxisY += (Input.GetAxis(kRightStickY) * m_LookSpeedController * Time.deltaTime); |
|||
float inputVertical = Input.GetAxis(kVertical); |
|||
float inputHorizontal = Input.GetAxis(kHorizontal); |
|||
float inputVertical = Input.GetAxis(kVertical); |
|||
float inputHorizontal = Input.GetAxis(kHorizontal); |
|||
bool moved = inputRotateAxisX != 0.0f || inputRotateAxisY != 0.0f || inputVertical != 0.0f || inputHorizontal != 0.0f; |
|||
if (moved) |
|||
{ |
|||
float rotationX = transform.localEulerAngles.x; |
|||
float newRotationY = transform.localEulerAngles.y + inputRotateAxisX; |
|||
bool moved = inputRotateAxisX != 0.0f || inputRotateAxisY != 0.0f || inputVertical != 0.0f || inputHorizontal != 0.0f; |
|||
if (moved) |
|||
{ |
|||
float rotationX = transform.localEulerAngles.x; |
|||
float newRotationY = transform.localEulerAngles.y + inputRotateAxisX; |
|||
// Weird clamping code due to weird Euler angle mapping...
|
|||
float newRotationX = (rotationX - inputRotateAxisY); |
|||
if (rotationX <= 90.0f && newRotationX >= 0.0f) |
|||
newRotationX = Mathf.Clamp(newRotationX, 0.0f, 90.0f); |
|||
if (rotationX >= 270.0f) |
|||
newRotationX = Mathf.Clamp(newRotationX, 270.0f, 360.0f); |
|||
// Weird clamping code due to weird Euler angle mapping...
|
|||
float newRotationX = (rotationX - inputRotateAxisY); |
|||
if (rotationX <= 90.0f && newRotationX >= 0.0f) |
|||
newRotationX = Mathf.Clamp(newRotationX, 0.0f, 90.0f); |
|||
if (rotationX >= 270.0f) |
|||
newRotationX = Mathf.Clamp(newRotationX, 270.0f, 360.0f); |
|||
transform.localRotation = Quaternion.Euler(newRotationX, newRotationY, transform.localEulerAngles.z); |
|||
transform.localRotation = Quaternion.Euler(newRotationX, newRotationY, transform.localEulerAngles.z); |
|||
float moveSpeed = Time.deltaTime * m_MoveSpeed; |
|||
if (Input.GetMouseButton(1)) |
|||
moveSpeed *= Input.GetKey(KeyCode.LeftShift) ? m_Turbo : 1.0f; |
|||
else |
|||
moveSpeed *= Input.GetAxis("Fire1") > 0.0f ? m_Turbo : 1.0f; |
|||
transform.position += transform.forward * moveSpeed * inputVertical; |
|||
transform.position += transform.right * moveSpeed * inputHorizontal; |
|||
float moveSpeed = Time.deltaTime * m_MoveSpeed; |
|||
if (Input.GetMouseButton(1)) |
|||
moveSpeed *= Input.GetKey(KeyCode.LeftShift) ? m_Turbo : 1.0f; |
|||
else |
|||
moveSpeed *= Input.GetAxis("Fire1") > 0.0f ? m_Turbo : 1.0f; |
|||
transform.position += transform.forward * moveSpeed * inputVertical; |
|||
transform.position += transform.right * moveSpeed * inputHorizontal; |
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
m_EditorVersion: 2017.1.0a4 |
|||
m_EditorVersion: 2017.1.0a5 |
|
|||
fileFormatVersion: 2 |
|||
guid: 7a2706b41ea31e54d9e4ca93be22278a |
|||
folderAsset: yes |
|||
timeCreated: 1481548458 |
|||
licenseType: Pro |
|||
DefaultImporter: |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: b18282e7b9e41194a9ccbdd7f1e00f91 |
|||
folderAsset: yes |
|||
timeCreated: 1484737171 |
|||
licenseType: Pro |
|||
DefaultImporter: |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
%YAML 1.1 |
|||
%TAG !u! tag:unity3d.com,2011: |
|||
--- !u!114 &11400000 |
|||
MonoBehaviour: |
|||
m_ObjectHideFlags: 0 |
|||
m_PrefabParentObject: {fileID: 0} |
|||
m_PrefabInternal: {fileID: 0} |
|||
m_GameObject: {fileID: 0} |
|||
m_Enabled: 1 |
|||
m_EditorHideFlags: 0 |
|||
m_Script: {fileID: 11500000, guid: a6e7465350bf0d248b4799d98e18cd24, type: 3} |
|||
m_Name: Default SSS Profile |
|||
m_EditorClassIdentifier: |
|||
stdDev1: {r: 0.3, g: 0.3, b: 0.3, a: 0} |
|||
stdDev2: {r: 0.6, g: 0.6, b: 0.6, a: 0} |
|||
lerpWeight: 0.5 |
|||
enableTransmission: 0 |
|||
thicknessRemap: {x: 0, y: 1} |
|||
settingsIndex: 0 |
|||
m_FilterKernel: |
|||
- {x: 0.09090909, y: 0.09090909, z: 0.09090909, w: -0.7609476} |
|||
- {x: 0.09090909, y: 0.09090909, z: 0.09090909, w: -0.49358216} |
|||
- {x: 0.09090909, y: 0.09090909, z: 0.09090909, w: -0.33642715} |
|||
- {x: 0.09090909, y: 0.09090909, z: 0.09090909, w: -0.21256521} |
|||
- {x: 0.09090909, y: 0.09090909, z: 0.09090909, w: -0.10326859} |
|||
- {x: 0.09090909, y: 0.09090909, z: 0.09090909, w: -0.000000048879357} |
|||
- {x: 0.09090909, y: 0.09090909, z: 0.09090909, w: 0.10326859} |
|||
- {x: 0.09090909, y: 0.09090909, z: 0.09090909, w: 0.21256521} |
|||
- {x: 0.09090909, y: 0.09090909, z: 0.09090909, w: 0.33642715} |
|||
- {x: 0.09090909, y: 0.09090909, z: 0.09090909, w: 0.4935822} |
|||
- {x: 0.09090909, y: 0.09090909, z: 0.09090909, w: 0.7609475} |
|||
m_HalfRcpVariances: |
|||
- {x: 5.5555553, y: 5.5555553, z: 5.5555553} |
|||
- {x: 1.3888888, y: 1.3888888, z: 1.3888888} |
|||
m_HalfRcpWeightedVariances: {x: 2.4691355, y: 2.4691355, z: 2.4691355, w: 2.4691355} |
|
|||
fileFormatVersion: 2 |
|||
guid: 09521380d86baee43bf09b32473ea5f3 |
|||
timeCreated: 1490117690 |
|||
licenseType: Pro |
|||
NativeFormatImporter: |
|||
mainObjectFileID: 11400000 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
#ifndef __FEATURE_FLAGS_H__ |
|||
#define __FEATURE_FLAGS_H__ |
|||
|
|||
#include "TilePass.cs.hlsl" |
|||
|
|||
static const uint FeatureVariantFlags[NUM_FEATURE_VARIANTS] = |
|||
{ |
|||
/* 0 */ 0, |
|||
/* 1 */ FEATURE_FLAG_SKY_LIGHT | FEATURE_FLAG_DIRECTIONAL_LIGHT, |
|||
/* 2 */ FEATURE_FLAG_SKY_LIGHT | FEATURE_FLAG_DIRECTIONAL_LIGHT | FEATURE_FLAG_ENV_LIGHT, |
|||
/* 3 */ FEATURE_FLAG_SKY_LIGHT | FEATURE_FLAG_DIRECTIONAL_LIGHT | FEATURE_FLAG_PUNCTUAL_LIGHT, |
|||
/* 3 */ FEATURE_FLAG_SKY_LIGHT | FEATURE_FLAG_DIRECTIONAL_LIGHT | FEATURE_FLAG_PUNCTUAL_LIGHT | FEATURE_FLAG_ENV_LIGHT, |
|||
/* 5 */ FEATURE_FLAG_SKY_LIGHT | FEATURE_FLAG_DIRECTIONAL_LIGHT | FEATURE_FLAG_AREA_LIGHT, |
|||
/* 6 */ FEATURE_FLAG_SKY_LIGHT | FEATURE_FLAG_DIRECTIONAL_LIGHT | FEATURE_FLAG_AREA_LIGHT | FEATURE_FLAG_PUNCTUAL_LIGHT | FEATURE_FLAG_ENV_LIGHT, |
|||
/* 7 */ 0xFFFFFFFF, |
|||
}; |
|||
|
|||
/* |
|||
public static uint FEATURE_FLAG_PUNCTUAL_LIGHT = 1<<0; |
|||
public static uint FEATURE_FLAG_AREA_LIGHT = 1<<1; |
|||
public static uint FEATURE_FLAG_DIRECTIONAL_LIGHT = 1<<2; |
|||
public static uint FEATURE_FLAG_ENV_LIGHT = 1<<3; |
|||
public static uint FEATURE_FLAG_SKY_LIGHT = 1<<4; |
|||
*/ |
|||
|
|||
uint FeatureFlagsToTileVariant(uint featureFlags) |
|||
{ |
|||
for(int i = 0; i < NUM_FEATURE_VARIANTS; i++) |
|||
{ |
|||
if((featureFlags & FeatureVariantFlags[i]) == featureFlags) |
|||
return i; |
|||
} |
|||
return NUM_FEATURE_VARIANTS - 1; |
|||
} |
|||
|
|||
uint TileVariantToFeatureFlags(uint variant) |
|||
{ |
|||
return FeatureVariantFlags[variant]; |
|||
} |
|||
|
|||
#endif |
|
|||
fileFormatVersion: 2 |
|||
guid: 0ef495ee49d152b419e9fd62aa24523f |
|||
timeCreated: 1489679489 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
#pragma kernel ClearDispatchIndirect |
|||
|
|||
RWBuffer<uint> g_DispatchIndirectBuffer : register( u0 ); // Indirect arguments have to be in a _buffer_, not a structured buffer |
|||
|
|||
[numthreads(64, 1, 1)] |
|||
void ClearDispatchIndirect(uint dispatchThreadId : SV_DispatchThreadID) |
|||
{ |
|||
g_DispatchIndirectBuffer[dispatchThreadId * 3 + 0] = 0; // ThreadGroupCountX |
|||
g_DispatchIndirectBuffer[dispatchThreadId * 3 + 1] = 1; // ThreadGroupCountY |
|||
g_DispatchIndirectBuffer[dispatchThreadId * 3 + 2] = 1; // ThreadGroupCountZ |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: fc1f553acb80a6446a32d33e403d0656 |
|||
timeCreated: 1490196244 |
|||
licenseType: Pro |
|||
ComputeShaderImporter: |
|||
currentAPIMask: 8196 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
#if UNITY_EDITOR
|
|||
using UnityEditor; |
|||
#endif
|
|||
|
|||
namespace UnityEngine.Experimental.Rendering.HDPipeline |
|||
{ |
|||
[Serializable] |
|||
public class SubsurfaceScatteringProfile : ScriptableObject |
|||
{ |
|||
public const int numSamples = 11; // Must be an odd number
|
|||
|
|||
[SerializeField, ColorUsage(false, true, 0.05f, 2.0f, 1.0f, 1.0f)] |
|||
public Color stdDev1; |
|||
[SerializeField, ColorUsage(false, true, 0.05f, 2.0f, 1.0f, 1.0f)] |
|||
public Color stdDev2; |
|||
[SerializeField] |
|||
public float lerpWeight; |
|||
[SerializeField] |
|||
public bool enableTransmission; |
|||
[SerializeField] |
|||
public Vector2 thicknessRemap; |
|||
[SerializeField] [HideInInspector] |
|||
public int settingsIndex; |
|||
[SerializeField] [HideInInspector] |
|||
Vector4[] m_FilterKernel; |
|||
[SerializeField] [HideInInspector] |
|||
Vector3[] m_HalfRcpVariances; |
|||
[SerializeField] [HideInInspector] |
|||
Vector4 m_HalfRcpWeightedVariances; |
|||
|
|||
private static SubsurfaceScatteringProfile s_DefaultProfile = null; // Singleton
|
|||
|
|||
// --- Public Methods ---
|
|||
|
|||
public static SubsurfaceScatteringProfile defaultProfile |
|||
{ |
|||
get |
|||
{ |
|||
if (s_DefaultProfile == null) |
|||
{ |
|||
#if UNITY_EDITOR
|
|||
s_DefaultProfile = CreateInstance<SubsurfaceScatteringProfile>(); |
|||
AssetDatabase.CreateAsset(s_DefaultProfile, "Assets/ScriptableRenderPipeline/HDRenderPipeline/Default SSS Profile.asset"); |
|||
AssetDatabase.SaveAssets(); |
|||
#else
|
|||
throw new UnassignedReferenceException("SubsurfaceScatteringProfile.defaultProfile can not be null."); |
|||
#endif
|
|||
} |
|||
return s_DefaultProfile; |
|||
} |
|||
} |
|||
|
|||
public SubsurfaceScatteringProfile() |
|||
{ |
|||
stdDev1 = new Color(0.3f, 0.3f, 0.3f, 0.0f); |
|||
stdDev2 = new Color(0.6f, 0.6f, 0.6f, 0.0f); |
|||
lerpWeight = 0.5f; |
|||
enableTransmission = false; |
|||
thicknessRemap = new Vector2(0, 1); |
|||
settingsIndex = 0; |
|||
|
|||
UpdateKernelAndVarianceData(); |
|||
} |
|||
|
|||
public Vector4[] filterKernel |
|||
{ |
|||
// Set via UpdateKernelAndVarianceData().
|
|||
get { return m_FilterKernel; } |
|||
} |
|||
|
|||
public Vector3[] halfRcpVariances |
|||
{ |
|||
// Set via UpdateKernelAndVarianceData().
|
|||
get { return m_HalfRcpVariances; } |
|||
} |
|||
|
|||
public Vector4 halfRcpWeightedVariances |
|||
{ |
|||
// Set via UpdateKernelAndVarianceData().
|
|||
get { return m_HalfRcpWeightedVariances; } |
|||
} |
|||
|
|||
public void UpdateKernelAndVarianceData() |
|||
{ |
|||
if (m_FilterKernel == null || m_FilterKernel.Length != numSamples) |
|||
{ |
|||
m_FilterKernel = new Vector4[numSamples]; |
|||
} |
|||
|
|||
if (m_HalfRcpVariances == null) |
|||
{ |
|||
m_HalfRcpVariances = new Vector3[2]; |
|||
} |
|||
|
|||
// Our goal is to blur the image using a filter which is represented
|
|||
// as a product of a linear combination of two normalized 1D Gaussians
|
|||
// as suggested by Jimenez et al. in "Separable Subsurface Scattering".
|
|||
// A normalized (i.e. energy-preserving) 1D Gaussian with the mean of 0
|
|||
// is defined as follows: G1(x, v) = exp(-x * x / (2 * v)) / sqrt(2 * Pi * v),
|
|||
// where 'v' is variance and 'x' is the radial distance from the origin.
|
|||
// Using the weight 'w', our 1D and the resulting 2D filters are given as:
|
|||
// A1(v1, v2, w, x) = G1(x, v1) * (1 - w) + G1(r, v2) * w,
|
|||
// A2(v1, v2, w, x, y) = A1(v1, v2, w, x) * A1(v1, v2, w, y).
|
|||
// The resulting filter function is a non-Gaussian PDF.
|
|||
// It is separable by design, but generally not radially symmetric.
|
|||
|
|||
// Find the widest Gaussian across 3 color channels.
|
|||
float maxStdDev1 = Mathf.Max(stdDev1.r, stdDev1.g, stdDev1.b); |
|||
float maxStdDev2 = Mathf.Max(stdDev2.r, stdDev2.g, stdDev2.b); |
|||
|
|||
Vector3 weightSum = new Vector3(0, 0, 0); |
|||
|
|||
// Importance sample the linear combination of two Gaussians.
|
|||
for (uint i = 0; i < numSamples; i++) |
|||
{ |
|||
float u = (i + 0.5f) / numSamples; |
|||
float pos = GaussianCombinationCdfInverse(u, maxStdDev1, maxStdDev2, lerpWeight); |
|||
float pdf = GaussianCombination(pos, maxStdDev1, maxStdDev2, lerpWeight); |
|||
|
|||
Vector3 val; |
|||
val.x = GaussianCombination(pos, stdDev1.r, stdDev2.r, lerpWeight); |
|||
val.y = GaussianCombination(pos, stdDev1.g, stdDev2.g, lerpWeight); |
|||
val.z = GaussianCombination(pos, stdDev1.b, stdDev2.b, lerpWeight); |
|||
|
|||
// We do not divide by 'numSamples' since we will renormalize, anyway.
|
|||
m_FilterKernel[i].x = val.x * (1 / pdf); |
|||
m_FilterKernel[i].y = val.y * (1 / pdf); |
|||
m_FilterKernel[i].z = val.z * (1 / pdf); |
|||
m_FilterKernel[i].w = pos; |
|||
|
|||
weightSum.x += m_FilterKernel[i].x; |
|||
weightSum.y += m_FilterKernel[i].y; |
|||
weightSum.z += m_FilterKernel[i].z; |
|||
} |
|||
|
|||
// Renormalize the weights to conserve energy.
|
|||
for (uint i = 0; i < numSamples; i++) |
|||
{ |
|||
m_FilterKernel[i].x *= 1 / weightSum.x; |
|||
m_FilterKernel[i].y *= 1 / weightSum.y; |
|||
m_FilterKernel[i].z *= 1 / weightSum.z; |
|||
} |
|||
|
|||
// Store (1 / (2 * Variance)) per color channel per Gaussian.
|
|||
m_HalfRcpVariances[0].x = 0.5f / (stdDev1.r * stdDev1.r); |
|||
m_HalfRcpVariances[0].y = 0.5f / (stdDev1.g * stdDev1.g); |
|||
m_HalfRcpVariances[0].z = 0.5f / (stdDev1.b * stdDev1.b); |
|||
m_HalfRcpVariances[1].x = 0.5f / (stdDev2.r * stdDev2.r); |
|||
m_HalfRcpVariances[1].y = 0.5f / (stdDev2.g * stdDev2.g); |
|||
m_HalfRcpVariances[1].z = 0.5f / (stdDev2.b * stdDev2.b); |
|||
|
|||
Vector4 weightedStdDev; |
|||
weightedStdDev.x = Mathf.Lerp(stdDev1.r, stdDev2.r, lerpWeight); |
|||
weightedStdDev.y = Mathf.Lerp(stdDev1.g, stdDev2.g, lerpWeight); |
|||
weightedStdDev.z = Mathf.Lerp(stdDev1.b, stdDev2.b, lerpWeight); |
|||
weightedStdDev.w = Mathf.Lerp(maxStdDev1, maxStdDev2, lerpWeight); |
|||
|
|||
// Store (1 / (2 * WeightedVariance)) per color channel.
|
|||
m_HalfRcpWeightedVariances.x = 0.5f / (weightedStdDev.x * weightedStdDev.x); |
|||
m_HalfRcpWeightedVariances.y = 0.5f / (weightedStdDev.y * weightedStdDev.y); |
|||
m_HalfRcpWeightedVariances.z = 0.5f / (weightedStdDev.z * weightedStdDev.z); |
|||
m_HalfRcpWeightedVariances.w = 0.5f / (weightedStdDev.w * weightedStdDev.w); |
|||
} |
|||
|
|||
// --- Private Methods ---
|
|||
|
|||
static float Gaussian(float x, float stdDev) |
|||
{ |
|||
float variance = stdDev * stdDev; |
|||
return Mathf.Exp(-x * x / (2 * variance)) / Mathf.Sqrt(2 * Mathf.PI * variance); |
|||
} |
|||
|
|||
static float GaussianCombination(float x, float stdDev1, float stdDev2, float lerpWeight) |
|||
{ |
|||
return Mathf.Lerp(Gaussian(x, stdDev1), Gaussian(x, stdDev2), lerpWeight); |
|||
} |
|||
|
|||
static float RationalApproximation(float t) |
|||
{ |
|||
// Abramowitz and Stegun formula 26.2.23.
|
|||
// The absolute value of the error should be less than 4.5 e-4.
|
|||
float[] c = {2.515517f, 0.802853f, 0.010328f}; |
|||
float[] d = {1.432788f, 0.189269f, 0.001308f}; |
|||
return t - ((c[2] * t + c[1]) * t + c[0]) / (((d[2] * t + d[1]) * t + d[0]) * t + 1.0f); |
|||
} |
|||
|
|||
// Ref: https://www.johndcook.com/blog/csharp_phi_inverse/
|
|||
static float NormalCdfInverse(float p, float stdDev) |
|||
{ |
|||
float x; |
|||
|
|||
if (p < 0.5) |
|||
{ |
|||
// F^-1(p) = - G^-1(p)
|
|||
x = -RationalApproximation(Mathf.Sqrt(-2.0f * Mathf.Log(p))); |
|||
} |
|||
else |
|||
{ |
|||
// F^-1(p) = G^-1(1-p)
|
|||
x = RationalApproximation(Mathf.Sqrt(-2.0f * Mathf.Log(1.0f - p))); |
|||
} |
|||
|
|||
return x * stdDev; |
|||
} |
|||
|
|||
static float GaussianCombinationCdfInverse(float p, float stdDev1, float stdDev2, float lerpWeight) |
|||
{ |
|||
return Mathf.Lerp(NormalCdfInverse(p, stdDev1), NormalCdfInverse(p, stdDev2), lerpWeight); |
|||
} |
|||
} |
|||
|
|||
[Serializable] |
|||
public class SubsurfaceScatteringSettings |
|||
{ |
|||
public enum TexturingMode : int { PreScatter = 0, PostScatter = 1, PreAndPostScatter = 2, MaxValue = 2 }; |
|||
|
|||
public const int maxNumProfiles = 8; |
|||
|
|||
public int numProfiles; |
|||
public TexturingMode texturingMode; |
|||
public int transmissionFlags; |
|||
public SubsurfaceScatteringProfile[] profiles; |
|||
public float[] thicknessRemaps; |
|||
public Vector4[] halfRcpVariancesAndLerpWeights; |
|||
public Vector4[] halfRcpWeightedVariances; |
|||
public Vector4[] filterKernels; |
|||
|
|||
// --- Public Methods ---
|
|||
|
|||
public SubsurfaceScatteringSettings() |
|||
{ |
|||
numProfiles = 1; |
|||
texturingMode = TexturingMode.PreScatter; |
|||
profiles = null; |
|||
thicknessRemaps = null; |
|||
halfRcpVariancesAndLerpWeights = null; |
|||
halfRcpWeightedVariances = null; |
|||
filterKernels = null; |
|||
} |
|||
|
|||
public void OnValidate() |
|||
{ |
|||
if (profiles == null) |
|||
{ |
|||
// It will be called during the initialization of the HDRenderPipeline.
|
|||
CreateProfiles(); |
|||
} |
|||
|
|||
numProfiles = Math.Max(1, Math.Min(profiles.Length, maxNumProfiles)); |
|||
|
|||
if (profiles.Length != numProfiles) |
|||
{ |
|||
Array.Resize(ref profiles, numProfiles); |
|||
} |
|||
|
|||
for (int i = 0; i < numProfiles; i++) |
|||
{ |
|||
if (profiles[i] == null) |
|||
{ |
|||
// No invalid/empty assets allowed!
|
|||
profiles[i] = SubsurfaceScatteringProfile.defaultProfile; |
|||
} |
|||
|
|||
// Assign profile IDs.
|
|||
profiles[i].settingsIndex = i; |
|||
} |
|||
|
|||
texturingMode = (TexturingMode)Math.Max(0, Math.Min((int)texturingMode, (int)TexturingMode.MaxValue)); |
|||
|
|||
if (thicknessRemaps == null || thicknessRemaps.Length != (maxNumProfiles * 2)) |
|||
{ |
|||
thicknessRemaps = new float[maxNumProfiles * 2]; |
|||
} |
|||
|
|||
if (halfRcpVariancesAndLerpWeights == null || halfRcpVariancesAndLerpWeights.Length != (maxNumProfiles * 2)) |
|||
{ |
|||
halfRcpVariancesAndLerpWeights = new Vector4[maxNumProfiles * 2]; |
|||
} |
|||
|
|||
if (halfRcpWeightedVariances == null || halfRcpWeightedVariances.Length != maxNumProfiles) |
|||
{ |
|||
halfRcpWeightedVariances = new Vector4[maxNumProfiles]; |
|||
} |
|||
|
|||
if (filterKernels == null || filterKernels.Length != (maxNumProfiles * SubsurfaceScatteringProfile.numSamples)) |
|||
{ |
|||
filterKernels = new Vector4[maxNumProfiles * SubsurfaceScatteringProfile.numSamples]; |
|||
} |
|||
|
|||
transmissionFlags = 0; |
|||
Color c = new Color(); |
|||
|
|||
for (int i = 0; i < numProfiles; i++) |
|||
{ |
|||
transmissionFlags |= (profiles[i].enableTransmission ? 1 : 0) << i; |
|||
|
|||
c.r = Mathf.Clamp(profiles[i].stdDev1.r, 0.05f, 2.0f); |
|||
c.g = Mathf.Clamp(profiles[i].stdDev1.g, 0.05f, 2.0f); |
|||
c.b = Mathf.Clamp(profiles[i].stdDev1.b, 0.05f, 2.0f); |
|||
c.a = 0.0f; |
|||
|
|||
profiles[i].stdDev1 = c; |
|||
|
|||
c.r = Mathf.Clamp(profiles[i].stdDev2.r, 0.05f, 2.0f); |
|||
c.g = Mathf.Clamp(profiles[i].stdDev2.g, 0.05f, 2.0f); |
|||
c.b = Mathf.Clamp(profiles[i].stdDev2.b, 0.05f, 2.0f); |
|||
c.a = 0.0f; |
|||
|
|||
profiles[i].stdDev2 = c; |
|||
|
|||
profiles[i].lerpWeight = Mathf.Clamp01(profiles[i].lerpWeight); |
|||
|
|||
profiles[i].thicknessRemap.x = Mathf.Clamp(profiles[i].thicknessRemap.x, 0, profiles[i].thicknessRemap.y); |
|||
profiles[i].thicknessRemap.y = Mathf.Max(profiles[i].thicknessRemap.x, profiles[i].thicknessRemap.y); |
|||
|
|||
profiles[i].UpdateKernelAndVarianceData(); |
|||
} |
|||
|
|||
// Use the updated data to fill the cache.
|
|||
for (int i = 0; i < numProfiles; i++) |
|||
{ |
|||
thicknessRemaps[2 * i] = profiles[i].thicknessRemap.x; |
|||
thicknessRemaps[2 * i + 1] = profiles[i].thicknessRemap.y - profiles[i].thicknessRemap.x; |
|||
halfRcpVariancesAndLerpWeights[2 * i] = profiles[i].halfRcpVariances[0]; |
|||
halfRcpVariancesAndLerpWeights[2 * i].w = 1.0f - profiles[i].lerpWeight; |
|||
halfRcpVariancesAndLerpWeights[2 * i + 1] = profiles[i].halfRcpVariances[1]; |
|||
halfRcpVariancesAndLerpWeights[2 * i + 1].w = profiles[i].lerpWeight; |
|||
halfRcpWeightedVariances[i] = profiles[i].halfRcpWeightedVariances; |
|||
|
|||
for (int j = 0, n = SubsurfaceScatteringProfile.numSamples; j < n; j++) |
|||
{ |
|||
filterKernels[n * i + j] = profiles[i].filterKernel[j]; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// --- Private Methods ---
|
|||
|
|||
// Limitation of Unity - cannot create assets in the constructor.
|
|||
public void CreateProfiles() |
|||
{ |
|||
profiles = new SubsurfaceScatteringProfile[numProfiles]; |
|||
|
|||
for (int i = 0; i < numProfiles; i++) |
|||
{ |
|||
profiles[i] = SubsurfaceScatteringProfile.defaultProfile; |
|||
} |
|||
} |
|||
} |
|||
|
|||
#if UNITY_EDITOR
|
|||
public class SubsurfaceScatteringProfileFactory |
|||
{ |
|||
[MenuItem("Assets/Create/Subsurface Scattering Profile", priority = 666)] |
|||
static void MenuCreateSubsurfaceScatteringProfile() |
|||
{ |
|||
Texture2D icon = EditorGUIUtility.FindTexture("ScriptableObject Icon"); |
|||
ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, |
|||
ScriptableObject.CreateInstance<DoCreateSubsurfaceScatteringProfile>(), |
|||
"New SSS Profile.asset", icon, null); |
|||
} |
|||
|
|||
public static SubsurfaceScatteringProfile CreateSssProfileAtPath(string path) |
|||
{ |
|||
var profile = ScriptableObject.CreateInstance<SubsurfaceScatteringProfile>(); |
|||
profile.name = System.IO.Path.GetFileName(path); |
|||
AssetDatabase.CreateAsset(profile, path); |
|||
return profile; |
|||
} |
|||
} |
|||
|
|||
class DoCreateSubsurfaceScatteringProfile : UnityEditor.ProjectWindowCallback.EndNameEditAction |
|||
{ |
|||
public override void Action(int instanceId, string pathName, string resourceFile) |
|||
{ |
|||
var profiles = SubsurfaceScatteringProfileFactory.CreateSssProfileAtPath(pathName); |
|||
ProjectWindowUtil.ShowCreatedAsset(profiles); |
|||
} |
|||
} |
|||
|
|||
[CustomEditor(typeof(SubsurfaceScatteringProfile))] |
|||
public class SubsurfaceScatteringProfileEditor : Editor { |
|||
private class Styles |
|||
{ |
|||
public readonly GUIContent sssProfilePreview0 = new GUIContent("Profile preview"); |
|||
public readonly GUIContent sssProfilePreview1 = new GUIContent("Shows the fraction of light scattered from the source as radius increases to 1."); |
|||
public readonly GUIContent sssProfilePreview2 = new GUIContent("Note that the intensity of the region in the center may be clamped."); |
|||
public readonly GUIContent sssTransmittancePreview0 = new GUIContent("Transmittance preview"); |
|||
public readonly GUIContent sssTransmittancePreview1 = new GUIContent("Shows the fraction of light passing through the object as thickness increases to 1."); |
|||
public readonly GUIContent sssProfileStdDev1 = new GUIContent("Standard deviation #1", "Determines the shape of the 1st Gaussian filter. Increases the strength and the radius of the blur of the corresponding color channel."); |
|||
public readonly GUIContent sssProfileStdDev2 = new GUIContent("Standard deviation #2", "Determines the shape of the 2nd Gaussian filter. Increases the strength and the radius of the blur of the corresponding color channel."); |
|||
public readonly GUIContent sssProfileLerpWeight = new GUIContent("Filter interpolation", "Controls linear interpolation between the two Gaussian filters."); |
|||
public readonly GUIContent sssProfileTransmission = new GUIContent("Enable transmission", "Toggles simulation of light passing through thin objects. Depends on the thickness of the material."); |
|||
public readonly GUIContent sssProfileThicknessRemap = new GUIContent("Thickness remap", "Remaps the thickness parameter from [0, 1] to the desired range."); |
|||
|
|||
public readonly GUIStyle centeredMiniBoldLabel = new GUIStyle(GUI.skin.label); |
|||
|
|||
public Styles() |
|||
{ |
|||
centeredMiniBoldLabel.alignment = TextAnchor.MiddleCenter; |
|||
centeredMiniBoldLabel.fontSize = 10; |
|||
centeredMiniBoldLabel.fontStyle = FontStyle.Bold; |
|||
} |
|||
} |
|||
|
|||
private static Styles styles |
|||
{ |
|||
get |
|||
{ |
|||
if (s_Styles == null) |
|||
{ |
|||
s_Styles = new Styles(); |
|||
} |
|||
return s_Styles; |
|||
} |
|||
} |
|||
|
|||
private static Styles s_Styles = null; |
|||
|
|||
private RenderTexture m_ProfileImage, m_TransmittanceImage; |
|||
private Material m_ProfileMaterial, m_TransmittanceMaterial; |
|||
private SerializedProperty m_ProfileStdDev1, m_ProfileStdDev2, |
|||
m_ProfileLerpWeight, m_ProfileTransmission, |
|||
m_ProfileThicknessRemap; |
|||
|
|||
void OnEnable() |
|||
{ |
|||
m_ProfileStdDev1 = serializedObject.FindProperty("stdDev1"); |
|||
m_ProfileStdDev2 = serializedObject.FindProperty("stdDev2"); |
|||
m_ProfileLerpWeight = serializedObject.FindProperty("lerpWeight"); |
|||
m_ProfileTransmission = serializedObject.FindProperty("enableTransmission"); |
|||
m_ProfileThicknessRemap = serializedObject.FindProperty("thicknessRemap"); |
|||
|
|||
m_ProfileMaterial = Utilities.CreateEngineMaterial("Hidden/HDRenderPipeline/DrawGaussianProfile"); |
|||
m_TransmittanceMaterial = Utilities.CreateEngineMaterial("Hidden/HDRenderPipeline/DrawTransmittanceGraph"); |
|||
|
|||
m_ProfileImage = new RenderTexture(256, 256, 0, RenderTextureFormat.DefaultHDR); |
|||
m_TransmittanceImage = new RenderTexture( 16, 256, 0, RenderTextureFormat.DefaultHDR); |
|||
} |
|||
|
|||
public override void OnInspectorGUI() { |
|||
serializedObject.Update(); |
|||
|
|||
EditorGUI.BeginChangeCheck(); |
|||
{ |
|||
EditorGUILayout.PropertyField(m_ProfileStdDev1, styles.sssProfileStdDev1); |
|||
EditorGUILayout.PropertyField(m_ProfileStdDev2, styles.sssProfileStdDev2); |
|||
EditorGUILayout.PropertyField(m_ProfileLerpWeight, styles.sssProfileLerpWeight); |
|||
EditorGUILayout.PropertyField(m_ProfileTransmission, styles.sssProfileTransmission); |
|||
|
|||
Vector2 thicknessRemap = m_ProfileThicknessRemap.vector2Value; |
|||
EditorGUILayout.LabelField("Min thickness: ", thicknessRemap.x.ToString()); |
|||
EditorGUILayout.LabelField("Max thickness: ", thicknessRemap.y.ToString()); |
|||
EditorGUILayout.MinMaxSlider(styles.sssProfileThicknessRemap, ref thicknessRemap.x, ref thicknessRemap.y, 0, 10); |
|||
m_ProfileThicknessRemap.vector2Value = thicknessRemap; |
|||
|
|||
EditorGUILayout.Space(); |
|||
EditorGUILayout.LabelField(styles.sssProfilePreview0, styles.centeredMiniBoldLabel); |
|||
EditorGUILayout.LabelField(styles.sssProfilePreview1, EditorStyles.centeredGreyMiniLabel); |
|||
EditorGUILayout.LabelField(styles.sssProfilePreview2, EditorStyles.centeredGreyMiniLabel); |
|||
EditorGUILayout.Space(); |
|||
} |
|||
|
|||
// Draw the profile.
|
|||
m_ProfileMaterial.SetColor("_StdDev1", m_ProfileStdDev1.colorValue); |
|||
m_ProfileMaterial.SetColor("_StdDev2", m_ProfileStdDev2.colorValue); |
|||
m_ProfileMaterial.SetFloat("_LerpWeight", m_ProfileLerpWeight.floatValue); |
|||
EditorGUI.DrawPreviewTexture(GUILayoutUtility.GetRect(256, 256), m_ProfileImage, m_ProfileMaterial, ScaleMode.ScaleToFit, 1.0f); |
|||
|
|||
EditorGUILayout.Space(); |
|||
EditorGUILayout.LabelField(styles.sssTransmittancePreview0, styles.centeredMiniBoldLabel); |
|||
EditorGUILayout.LabelField(styles.sssTransmittancePreview1, EditorStyles.centeredGreyMiniLabel); |
|||
EditorGUILayout.Space(); |
|||
|
|||
// Draw the transmittance graph.
|
|||
m_TransmittanceMaterial.SetColor("_StdDev1", m_ProfileStdDev1.colorValue); |
|||
m_TransmittanceMaterial.SetColor("_StdDev2", m_ProfileStdDev2.colorValue); |
|||
m_TransmittanceMaterial.SetFloat("_LerpWeight", m_ProfileLerpWeight.floatValue); |
|||
m_TransmittanceMaterial.SetVector("_ThicknessRemap", m_ProfileThicknessRemap.vector2Value); |
|||
EditorGUI.DrawPreviewTexture(GUILayoutUtility.GetRect(16, 16), m_TransmittanceImage, m_TransmittanceMaterial, ScaleMode.ScaleToFit, 16.0f); |
|||
|
|||
serializedObject.ApplyModifiedProperties(); |
|||
|
|||
if (EditorGUI.EndChangeCheck()) |
|||
{ |
|||
// Validate each individual asset and update caches.
|
|||
HDRenderPipelineInstance hdPipeline = RenderPipelineManager.currentPipeline as HDRenderPipelineInstance; |
|||
hdPipeline.sssSettings.OnValidate(); |
|||
} |
|||
} |
|||
} |
|||
#endif
|
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: a6e7465350bf0d248b4799d98e18cd24 |
|||
timeCreated: 1490016484 |
|||
licenseType: Pro |
|||
MonoImporter: |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 877878ed40e8ad94095582ff91179016 |
|||
timeCreated: 1489068733 |
|||
licenseType: Pro |
|||
NativeFormatImporter: |
|||
mainObjectFileID: 11400000 |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
namespace UnityEngine.Experimental.Rendering.LowendMobile |
|||
{ |
|||
public enum ShadowCascades |
|||
{ |
|||
NO_CASCADES = 1, |
|||
TWO_CASCADES = 2, |
|||
FOUR_CASCADES = 4, |
|||
} |
|||
|
|||
public enum ShadowType |
|||
{ |
|||
NO_SHADOW = 0, |
|||
HARD_SHADOWS, |
|||
SOFT_SHADOWS, |
|||
} |
|||
|
|||
public enum ShadowResolution |
|||
{ |
|||
_512 = 512, |
|||
_1024 = 1024, |
|||
_2048 = 2048 |
|||
} |
|||
|
|||
public class LowEndMobilePipelineAsset : RenderPipelineAsset |
|||
{ |
|||
#region AssetAndPipelineCreation
|
|||
|
|||
#if UNITY_EDITOR
|
|||
[UnityEditor.MenuItem("RenderPipeline/LowEndMobilePipeline/Create Pipeline Asset")] |
|||
static void CreateLowEndPipeline() |
|||
{ |
|||
var instance = ScriptableObject.CreateInstance<LowEndMobilePipelineAsset>(); |
|||
UnityEditor.AssetDatabase.CreateAsset(instance, |
|||
"Assets/LowEndMobilePipeline/LowEndMobilePipelineAsset.asset"); |
|||
} |
|||
#endif
|
|||
|
|||
protected override IRenderPipeline InternalCreatePipeline() |
|||
{ |
|||
return new LowEndMobilePipeline(this); |
|||
} |
|||
|
|||
#endregion
|
|||
|
|||
#region PipelineAssetSettings
|
|||
|
|||
[SerializeField] private int m_MaxPixelLights = 1; |
|||
|
|||
[SerializeField] private bool m_SupportsVertexLight = true; |
|||
|
|||
[SerializeField] private bool m_EnableLightmaps = true; |
|||
|
|||
[SerializeField] private bool m_EnableAmbientProbe = true; |
|||
|
|||
[SerializeField] private ShadowType m_ShadowType = ShadowType.HARD_SHADOWS; |
|||
|
|||
[SerializeField] private ShadowResolution m_ShadowAtlasResolution = ShadowResolution._1024; |
|||
|
|||
[SerializeField] private float m_ShadowNearPlaneOffset = 2.0f; |
|||
|
|||
[SerializeField] private float m_ShadowDistance = 50.0f; |
|||
|
|||
[SerializeField] private float m_ShadowBias = 0.0005f; |
|||
|
|||
[SerializeField] private ShadowCascades m_ShadowCascades = ShadowCascades.NO_CASCADES; |
|||
|
|||
[SerializeField] private float m_Cascade2Split = 0.25f; |
|||
|
|||
[SerializeField] private Vector3 m_Cascade4Split = new Vector3(0.067f, 0.2f, 0.467f); |
|||
|
|||
public int MaxSupportedPixelLights |
|||
{ |
|||
get { return m_MaxPixelLights; } |
|||
private set { m_MaxPixelLights = value; } |
|||
} |
|||
|
|||
public bool SupportsVertexLight |
|||
{ |
|||
get { return m_SupportsVertexLight; } |
|||
private set { m_SupportsVertexLight = value; } |
|||
} |
|||
|
|||
public bool EnableLightmap |
|||
{ |
|||
get { return m_EnableLightmaps; } |
|||
private set { m_EnableLightmaps = value; } |
|||
} |
|||
|
|||
public bool EnableAmbientProbe |
|||
{ |
|||
get { return m_EnableAmbientProbe; } |
|||
private set { m_EnableAmbientProbe = value; } |
|||
} |
|||
|
|||
public ShadowType CurrShadowType |
|||
{ |
|||
get { return m_ShadowType; } |
|||
private set { m_ShadowType = value; } |
|||
} |
|||
|
|||
public int ShadowAtlasResolution |
|||
{ |
|||
get { return (int) m_ShadowAtlasResolution; } |
|||
private set { m_ShadowAtlasResolution = (ShadowResolution) value; } |
|||
} |
|||
|
|||
public float ShadowNearOffset |
|||
{ |
|||
get { return m_ShadowNearPlaneOffset; } |
|||
private set { m_ShadowNearPlaneOffset = value; } |
|||
} |
|||
|
|||
public float ShadowDistance |
|||
{ |
|||
get { return m_ShadowDistance; } |
|||
private set { m_ShadowDistance = value; } |
|||
} |
|||
|
|||
public float ShadowBias |
|||
{ |
|||
get { return m_ShadowBias; } |
|||
private set { m_ShadowBias = value; } |
|||
} |
|||
|
|||
public int CascadeCount |
|||
{ |
|||
get { return (int) m_ShadowCascades; } |
|||
private set { m_ShadowCascades = (ShadowCascades) value; } |
|||
} |
|||
|
|||
public float Cascade2Split |
|||
{ |
|||
get { return m_Cascade2Split; } |
|||
private set { m_Cascade2Split = value; } |
|||
} |
|||
|
|||
public Vector3 Cascade4Split |
|||
{ |
|||
get { return m_Cascade4Split; } |
|||
private set { m_Cascade4Split = value; } |
|||
} |
|||
|
|||
#endregion
|
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: bf2edee5c58d82540a51f03df9d42094 |
|||
timeCreated: 1488808083 |
|||
licenseType: Pro |
|||
MonoImporter: |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 2c0fa72aa713a664b9be2de857697293 |
|||
folderAsset: yes |
|||
timeCreated: 1488808638 |
|||
licenseType: Pro |
|||
DefaultImporter: |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: 316ed34724625cb47b31136769381b57 |
|||
folderAsset: yes |
|||
timeCreated: 1484576996 |
|||
licenseType: Pro |
|||
DefaultImporter: |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
fileFormatVersion: 2 |
|||
guid: ae13646e45aa3634da32df7c7da1c380 |
|||
timeCreated: 1481548757 |
|||
licenseType: Pro |
|||
MonoImporter: |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
1001
Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineVikingVillage/LightingData.asset
文件差异内容过多而无法显示
查看文件
文件差异内容过多而无法显示
查看文件
|
|||
fileFormatVersion: 2 |
|||
guid: 8964f843d8f1330418cbd7ae5166468f |
|||
timeCreated: 1485353234 |
|||
licenseType: Pro |
|||
NativeFormatImporter: |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
部分文件因为文件数量过多而无法显示
撰写
预览
正在加载...
取消
保存
Reference in new issue