浏览代码

Merge branch 'master' into shadows

/main
uygar 7 年前
当前提交
cefe8b15
共有 246 个文件被更改,包括 3990 次插入2650 次删除
  1. 6
      Assets/ScriptableRenderPipeline/AdditionalLightData.cs
  2. 25
      Assets/ScriptableRenderPipeline/Editor/MaterialUpgrader.cs
  3. 12
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Debug/HDRenderPipelineDebug.cs
  4. 1
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Debug/HDRenderPipelineDebug.cs.hlsl
  5. 2
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Debug/Resources/DebugDisplayShadowMap.shader
  6. 18
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Debug/Resources/DebugViewMaterialGBuffer.shader
  7. 409
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Debug/Resources/DebugViewTiles.shader
  8. 66
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Editor/HDRenderPipelineInspector.cs
  9. 32
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Editor/HDRenderPipelineMenuItems.cs
  10. 6
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Editor/SceneSettingsManagementWindow.cs
  11. 6
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Editor/UpgradeStandardShaderMaterials.cs
  12. 148
      Assets/ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.asset
  13. 2
      Assets/ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.asset.meta
  14. 430
      Assets/ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.cs
  15. 4
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/LightLoop.cs
  16. 22
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/Lighting.hlsl
  17. 27
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/Resources/Deferred.shader
  18. 25
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TileLightLoopProducer.cs
  19. 16
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/lightlistbuild-bigtile.compute
  20. 50
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/lightlistbuild-clustered.compute
  21. 925
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/lightlistbuild.compute
  22. 4
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/scrbound.compute
  23. 185
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/shadeopaque.compute
  24. 584
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePass.cs
  25. 14
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePass.cs.hlsl
  26. 47
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePass.hlsl
  27. 716
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePassLoop.hlsl
  28. 8
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePassProducer.asset
  29. 2
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePassResources.asset
  30. 1
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePassResources.cs
  31. 2
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Builtin/BuiltinData.hlsl
  32. 18
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/LayeredLit/Editor/LayeredLitUI.cs
  33. 44
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/LayeredLit/LayeredLit.shader
  34. 87
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/LayeredLit/LayeredLitTessellation.shader
  35. 10
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Editor/BaseLitUI.cs
  36. 51
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Editor/LitUI.cs
  37. 17
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Editor/StandardSpecularToHDLitMaterialUpgrader.cs
  38. 17
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Editor/StandardToHDLitMaterialUpgrader.cs
  39. 2
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.cs
  40. 2
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.cs.hlsl
  41. 94
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.hlsl
  42. 29
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.shader
  43. 462
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitData.hlsl
  44. 148
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitDataInternal.hlsl
  45. 4
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitProperties.hlsl
  46. 13
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitTessellation.hlsl
  47. 38
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitTessellation.shader
  48. 4
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LtcData.DisneyDiffuse.cs
  49. 8
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LtcData.GGX.cs
  50. 76
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Resources/CombineSubsurfaceScattering.shader
  51. 6
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Resources/PreIntegratedFGD.shader
  52. 1
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/ShaderPass/LitDepthPass.hlsl
  53. 1
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/ShaderPass/LitDistortionPass.hlsl
  54. 1
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/ShaderPass/LitVelocityPass.hlsl
  55. 18
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Material.hlsl
  56. 34
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/MaterialUtilities.hlsl
  57. 8
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Unlit/Editor/BaseUnlitUI.cs
  58. 12
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Unlit/Unlit.shader
  59. 20
      Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/Editor/PostProcessingSRPEditor.cs
  60. 4
      Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/Resources/EyeAdaptation.shader
  61. 2
      Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/Resources/EyeHistogram.compute
  62. 6
      Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/Resources/FinalPass.shader
  63. 6
      Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/Resources/LutGen.shader
  64. 6
      Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/PostProcessingSRP.cs
  65. 2
      Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/PostProcessingSRP.Settings.cs
  66. 10
      Assets/ScriptableRenderPipeline/HDRenderPipeline/SceneSettings/Resources/DrawGaussianProfile.shader
  67. 22
      Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/FragInputs.hlsl
  68. 15
      Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/ShaderPassDebugViewMaterial.hlsl
  69. 2
      Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/ShaderPassDepthOnly.hlsl
  70. 2
      Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/ShaderPassDistortion.hlsl
  71. 5
      Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/ShaderPassForward.hlsl
  72. 2
      Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/ShaderPassForwardUnlit.hlsl
  73. 2
      Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/ShaderPassGBuffer.hlsl
  74. 2
      Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/ShaderPassLightTransport.hlsl
  75. 2
      Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/ShaderPassVelocity.hlsl
  76. 34
      Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/VaryingMesh.hlsl
  77. 104
      Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderVariables.hlsl
  78. 4
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Shadow/Shadow.cs
  79. 12
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Shadow/ShadowAlgorithms.hlsl
  80. 5
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Shadow/ShadowAlgorithmsCustom.hlsl
  81. 2
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Shadow/ShadowBase.cs.hlsl
  82. 6
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Shadow/ShadowDispatch.hlsl
  83. 8
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/HDRISky/Resources/SkyHDRI.shader
  84. 5
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/ProceduralSky/ProceduralSkyRenderer.cs
  85. 18
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/ProceduralSky/Resources/AtmosphericScattering.hlsl
  86. 11
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/ProceduralSky/Resources/SkyProcedural.shader
  87. 4
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/Resources/BuildProbabilityTables.compute
  88. 4
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/Resources/ComputeGgxIblSampleData.compute
  89. 4
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/Resources/GGXConvolve.shader
  90. 2
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/SkyManager.cs
  91. 15
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Utilities.cs
  92. 118
      Assets/ScriptableRenderPipeline/ShaderLibrary/Common.hlsl
  93. 8
      Assets/ScriptableRenderPipeline/ShaderLibrary/CommonLighting.hlsl
  94. 29
      Assets/ScriptableRenderPipeline/ShaderLibrary/CommonMaterial.hlsl
  95. 17
      Assets/ScriptableRenderPipeline/ShaderLibrary/PerPixelDisplacement.hlsl
  96. 7
      Assets/ScriptableRenderPipeline/common/ShaderBase.h
  97. 415
      Assets/ScriptableRenderPipeline/common/SkyboxHelper.cs
  98. 667
      Assets/ScriptableRenderPipeline/common/TextureCache.cs
  99. 27
      Assets/ScriptableRenderPipeline/fptl/ClusteredUtils.h
  100. 4
      Assets/ScriptableRenderPipeline/fptl/FPTLRenderPipeline.asset

6
Assets/ScriptableRenderPipeline/AdditionalLightData.cs


[Range(0.0F, 1.0F)]
public float shadowDimmer = 1.0f;
[Range(0.0F, 1.0F)]
public float lightDimmer = 1.0f;
// Not used for directional lights.
public float fadeDistance = 10000.0f;
public float shadowFadeDistance = 10000.0f;
public bool affectDiffuse = true;
public bool affectSpecular = true;

25
Assets/ScriptableRenderPipeline/Editor/MaterialUpgrader.cs


{
public class MaterialUpgrader
{
public delegate void MaterialFinalizer(Material mat);
MaterialFinalizer m_Finalizer;
class KeywordFloatRename
{
public string keyword;
public string property;
public float setVal, unsetVal;
}
List<KeywordFloatRename> m_KeywordFloatRename = new List<KeywordFloatRename>();
[Flags]
public enum UpgradeFlags

material.shader = Shader.Find(m_NewShader);
material.CopyPropertiesFromMaterial(newMaterial);
UnityEngine.Object.DestroyImmediate(newMaterial);
if(m_Finalizer != null)
m_Finalizer(material);
}
// Overridable function to implement custom material upgrading functionality

foreach (var t in m_ColorRename)
dstMaterial.SetColor(t.Value, srcMaterial.GetColor(t.Key));
foreach (var t in m_KeywordFloatRename)
dstMaterial.SetFloat(t.property, srcMaterial.IsKeywordEnabled(t.keyword) ? t.setVal : t.unsetVal);
public void RenameShader(string oldName, string newName)
public void RenameShader(string oldName, string newName, MaterialFinalizer finalizer)
m_Finalizer = finalizer;
}
public void RenameTexture(string oldName, string newName)

public void RenameColor(string oldName, string newName)
{
m_ColorRename[oldName] = newName;
}
public void RenameKeywordToFloat(string oldName, string newName, float setVal, float unsetVal)
{
m_KeywordFloatRename.Add(new KeywordFloatRename { keyword = oldName, property = newName, setVal = setVal, unsetVal = unsetVal });
}
static bool IsMaterialPath(string path)

12
Assets/ScriptableRenderPipeline/HDRenderPipeline/Debug/HDRenderPipelineDebug.cs


public bool displayOpaqueObjects = true;
public bool displayTransparentObjects = true;
public bool enableDistortion = true;
public bool enableSSS = true;
public enum ShadowDebugMode
public enum ShadowMapDebugMode
{
None,
VisualizeAtlas,

{
None,
DiffuseLighting,
SpecularLighting
SpecularLighting,
VisualizeCascade
}
[Serializable]

public ShadowDebugMode shadowDebugMode = ShadowDebugMode.None;
public ShadowMapDebugMode shadowDebugMode = ShadowMapDebugMode.None;
public uint shadowMapIndex = 0;
public LightingDebugMode lightingDebugMode = LightingDebugMode.None;

public bool displaySkyReflection = false;
public float skyReflectionMipmap = 0.0f;
skyReflectionMipmap = Mathf.Clamp(skyReflectionMipmap, 0.0f, 1.0f);
}
}
}

1
Assets/ScriptableRenderPipeline/HDRenderPipeline/Debug/HDRenderPipelineDebug.cs.hlsl


#define LIGHTINGDEBUGMODE_NONE (0)
#define LIGHTINGDEBUGMODE_DIFFUSE_LIGHTING (1)
#define LIGHTINGDEBUGMODE_SPECULAR_LIGHTING (2)
#define LIGHTINGDEBUGMODE_VISUALIZE_CASCADE (3)
#endif

2
Assets/ScriptableRenderPipeline/HDRenderPipeline/Debug/Resources/DebugDisplayShadowMap.shader


#pragma vertex Vert
#pragma fragment Frag
#include "ShaderLibrary/Common.hlsl"
#include "../../../ShaderLibrary/Common.hlsl"
TEXTURE2D_FLOAT(g_tShadowBuffer);

18
Assets/ScriptableRenderPipeline/HDRenderPipeline/Debug/Resources/DebugViewMaterialGBuffer.shader


#pragma vertex Vert
#pragma fragment Frag
#include "ShaderLibrary/Common.hlsl"
#include "ShaderLibrary/Color.hlsl"
#include "../../../ShaderLibrary/Common.hlsl"
#include "../../../ShaderLibrary/Color.hlsl"
#include "HDRenderPipeline/ShaderConfig.cs.hlsl"
#include "HDRenderPipeline/ShaderVariables.hlsl"
#include "HDRenderPipeline/Debug/DebugViewMaterial.cs.hlsl"
#include "HDRenderPipeline/Material/Material.hlsl"
#include "../../ShaderConfig.cs.hlsl"
#include "../../ShaderVariables.hlsl"
#include "../../Debug/DebugViewMaterial.cs.hlsl"
#include "../../Material/Material.hlsl"
TEXTURE2D_FLOAT(_CameraDepthTexture);
SAMPLER2D(sampler_CameraDepthTexture);
int _DebugViewMaterial;
struct Attributes

float4 Frag(Varyings input) : SV_Target
{
// input.positionCS is SV_Position
PositionInputs posInput = GetPositionInput(input.positionCS.xy, _ScreenSize.zw);
float depth = LOAD_TEXTURE2D(_CameraDepthTexture, posInput.unPositionSS).x;
PositionInputs posInput = GetPositionInput(input.positionCS.xy, _ScreenSize.zw, uint2(0, 0));
float depth = LOAD_TEXTURE2D(_MainDepthTexture, posInput.unPositionSS).x;
UpdatePositionInput(depth, _InvViewProjMatrix, _ViewProjMatrix, posInput);
FETCH_GBUFFER(gbuffer, _GBufferTexture, posInput.unPositionSS);

409
Assets/ScriptableRenderPipeline/HDRenderPipeline/Debug/Resources/DebugViewTiles.shader


Shader "Hidden/HDRenderPipeline/DebugViewTiles"
{
SubShader
{
Pass
{
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
HLSLPROGRAM
#pragma target 4.5
#pragma only_renderers d3d11 ps4 metal // TEMP: until we go further in dev
#pragma vertex Vert
#pragma fragment Frag
#define LIGHTLOOP_TILE_PASS
#define LIGHTLOOP_TILE_ALL
#pragma multi_compile USE_FPTL_LIGHTLIST USE_CLUSTERED_LIGHTLIST
//-------------------------------------------------------------------------------------
// Include
//-------------------------------------------------------------------------------------
#include "ShaderLibrary/Common.hlsl"
// Note: We have fix as guidelines that we have only one deferred material (with control of GBuffer enabled). Mean a users that add a new
// deferred material must replace the old one here. If in the future we want to support multiple layout (cause a lot of consistency problem),
// the deferred shader will require to use multicompile.
#define UNITY_MATERIAL_LIT // Need to be define before including Material.hlsl
#include "HDRenderPipeline/ShaderConfig.cs.hlsl"
#include "HDRenderPipeline/ShaderVariables.hlsl"
#include "HDRenderPipeline/Lighting/Lighting.hlsl" // This include Material.hlsl
//-------------------------------------------------------------------------------------
// variable declaration
//-------------------------------------------------------------------------------------
TEXTURE2D_FLOAT(_CameraDepthTexture);
SAMPLER2D(sampler_CameraDepthTexture);
uint _ViewTilesFlags;
float2 _MousePixelCoord;
float4 Vert(float3 positionOS : POSITION): SV_POSITION
{
return TransformWorldToHClip(TransformObjectToWorld(positionOS));
}
float4 AlphaBlend(float4 c0, float4 c1) // c1 over c0
{
return float4(lerp(c0.rgb, c1.rgb, c1.a), c0.a + c1.a - c0.a * c1.a);
}
float4 OverlayHeatMap(uint2 pixCoord, uint numLights)
{
const float4 kRadarColors[12] =
{
float4(0.0, 0.0, 0.0, 0.0), // black
float4(0.0, 0.0, 0.6, 0.5), // dark blue
float4(0.0, 0.0, 0.9, 0.5), // blue
float4(0.0, 0.6, 0.9, 0.5), // light blue
float4(0.0, 0.9, 0.9, 0.5), // cyan
float4(0.0, 0.9, 0.6, 0.5), // blueish green
float4(0.0, 0.9, 0.0, 0.5), // green
float4(0.6, 0.9, 0.0, 0.5), // yellowish green
float4(0.9, 0.9, 0.0, 0.5), // yellow
float4(0.9, 0.6, 0.0, 0.5), // orange
float4(0.9, 0.0, 0.0, 0.5), // red
float4(1.0, 0.0, 0.0, 0.9) // strong red
};
float maxNrLightsPerTile = 31; // TODO: setup a constant for that
int colorIndex = numLights == 0 ? 0 : (1 + (int)floor(10 * (log2((float)numLights) / log2(maxNrLightsPerTile))));
colorIndex = colorIndex < 0 ? 0 : colorIndex;
float4 col = colorIndex > 11 ? float4(1.0, 1.0, 1.0, 1.0) : kRadarColors[colorIndex];
int2 coord = pixCoord - int2(1, 1);
float4 color = float4(PositivePow(col.xyz, 2.2), 0.3 * col.w);
if (numLights > 0)
{
if (SampleDebugFontNumber(coord, numLights)) // Shadow
color = float4(0, 0, 0, 1);
if (SampleDebugFontNumber(coord + 1, numLights)) // Text
color = float4(1, 1, 1, 1);
}
return color;
}
float4 Frag(float4 positionCS : SV_POSITION) : SV_Target
{
// positionCS is SV_Position
PositionInputs posInput = GetPositionInput(positionCS.xy, _ScreenSize.zw);
float depth = LOAD_TEXTURE2D(_CameraDepthTexture, posInput.unPositionSS).x;
UpdatePositionInput(depth, _InvViewProjMatrix, _ViewProjMatrix, posInput);
int2 pixelCoord = posInput.unPositionSS.xy;
int2 tileCoord = (float2)pixelCoord / TILE_SIZE;
int2 mouseTileCoord = _MousePixelCoord / TILE_SIZE;
int2 offsetInTile = pixelCoord - tileCoord * TILE_SIZE;
int n = 0;
for (int category = 0; category < LIGHTCATEGORY_COUNT; category++)
{
uint mask = 1u << category;
if (mask & _ViewTilesFlags)
{
uint start;
uint count;
GetCountAndStart(posInput, category, start, count);
n += count;
}
}
float4 result = float4(0.0, 0.0, 0.0, 0.0);
// Tile overlap counter
if (n > 0)
{
result = OverlayHeatMap(int2(posInput.unPositionSS.xy) & (TILE_SIZE - 1), n);
}
// Highlight selected tile
if (all(mouseTileCoord == tileCoord))
{
bool border = any(offsetInTile == 0 || offsetInTile == TILE_SIZE - 1);
float4 result2 = float4(1.0, 1.0, 1.0, border ? 1.0 : 0.5);
result = AlphaBlend(result, result2);
}
// Print light lists for selected tile at the bottom of the screen
int maxLights = 32;
if (tileCoord.y < LIGHTCATEGORY_COUNT && tileCoord.x < maxLights + 3)
{
PositionInputs mousePosInput = GetPositionInput(_MousePixelCoord, _ScreenSize.zw);
float depthMouse = LOAD_TEXTURE2D(_CameraDepthTexture, mousePosInput.unPositionSS).x;
UpdatePositionInput(depthMouse, _InvViewProjMatrix, _ViewProjMatrix, mousePosInput);
uint category = (LIGHTCATEGORY_COUNT - 1) - tileCoord.y;
uint start;
uint count;
GetCountAndStart(mousePosInput, category, start, count);
float4 result2 = float4(.1,.1,.1,.9);
int2 fontCoord = int2(pixelCoord.x, offsetInTile.y);
int lightListIndex = tileCoord.x - 2;
int n = -1;
if(tileCoord.x == 0)
{
n = (int)count;
}
else if(lightListIndex >= 0 && lightListIndex < (int)count)
{
n = FetchIndex(start, lightListIndex);
}
if (n >= 0)
{
if (SampleDebugFontNumber(offsetInTile, n))
result2 = float4(0.0, 0.0, 0.0, 1.0);
if (SampleDebugFontNumber(offsetInTile + 1, n))
result2 = float4(1.0, 1.0, 1.0, 1.0);
}
result = AlphaBlend(result, result2);
}
return result;
}
ENDHLSL
}
}
Fallback Off
}
Shader "Hidden/HDRenderPipeline/DebugViewTiles"
{
SubShader
{
Pass
{
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
HLSLPROGRAM
#pragma target 4.5
#pragma only_renderers d3d11 ps4 metal // TEMP: until we go further in dev
#pragma vertex Vert
#pragma fragment Frag
#define LIGHTLOOP_TILE_PASS
#define LIGHTLOOP_TILE_ALL
#pragma multi_compile USE_FPTL_LIGHTLIST USE_CLUSTERED_LIGHTLIST
#pragma multi_compile SHOW_LIGHT_CATEGORIES SHOW_FEATURE_VARIANTS
//-------------------------------------------------------------------------------------
// Include
//-------------------------------------------------------------------------------------
#include "../../../ShaderLibrary/Common.hlsl"
// Note: We have fix as guidelines that we have only one deferred material (with control of GBuffer enabled). Mean a users that add a new
// deferred material must replace the old one here. If in the future we want to support multiple layout (cause a lot of consistency problem),
// the deferred shader will require to use multicompile.
#define UNITY_MATERIAL_LIT // Need to be define before including Material.hlsl
#include "../../ShaderConfig.cs.hlsl"
#include "../../ShaderVariables.hlsl"
#include "../../Lighting/Lighting.hlsl" // This include Material.hlsl
//-------------------------------------------------------------------------------------
// variable declaration
//-------------------------------------------------------------------------------------
uint _ViewTilesFlags;
uint _NumTiles;
float2 _MousePixelCoord;
StructuredBuffer<uint> g_TileList;
Buffer<uint> g_DispatchIndirectBuffer;
struct VSOut
{
float4 Pos : SV_POSITION;
int Variant : TEXCOORD0;
};
#if SHOW_FEATURE_VARIANTS
VSOut Vert(uint vertexID : SV_VertexID)
{
uint quadIndex = vertexID / 6;
uint quadVertex = vertexID - quadIndex * 6;
quadVertex = (0x312210 >> (quadVertex<<2)) & 3; //remap [0,5]->[0,3]
uint2 tileSize = GetTileSize();
uint variant = 0;
while (quadIndex >= g_DispatchIndirectBuffer[variant * 3 + 0] && variant < NUM_FEATURE_VARIANTS)
{
quadIndex -= g_DispatchIndirectBuffer[variant * 3 + 0];
variant++;
}
uint tileIndex = g_TileList[variant * _NumTiles + quadIndex];
uint2 tileCoord = uint2(tileIndex & 0xFFFF, tileIndex >> 16);
uint2 pixelCoord = (tileCoord + uint2((quadVertex+1) & 1, (quadVertex >> 1) & 1)) * tileSize;
float2 clipCoord = (pixelCoord / _ScreenParams.xy) * 2.0 - 1.0;
clipCoord.y *= -1;
VSOut Out;
Out.Pos = float4(clipCoord, 0, 1.0);
Out.Variant = variant;
return Out;
}
#else
VSOut Vert(float3 positionOS : POSITION)
{
VSOut Out;
Out.Pos = TransformWorldToHClip(TransformObjectToWorld(positionOS));
Out.Variant = 0;
return Out;
}
#endif
float4 AlphaBlend(float4 c0, float4 c1) // c1 over c0
{
return float4(lerp(c0.rgb, c1.rgb, c1.a), c0.a + c1.a - c0.a * c1.a);
}
float4 OverlayHeatMap(uint2 pixCoord, uint n)
{
const float4 kRadarColors[12] =
{
float4(0.0, 0.0, 0.0, 0.0), // black
float4(0.0, 0.0, 0.6, 0.5), // dark blue
float4(0.0, 0.0, 0.9, 0.5), // blue
float4(0.0, 0.6, 0.9, 0.5), // light blue
float4(0.0, 0.9, 0.9, 0.5), // cyan
float4(0.0, 0.9, 0.6, 0.5), // blueish green
float4(0.0, 0.9, 0.0, 0.5), // green
float4(0.6, 0.9, 0.0, 0.5), // yellowish green
float4(0.9, 0.9, 0.0, 0.5), // yellow
float4(0.9, 0.6, 0.0, 0.5), // orange
float4(0.9, 0.0, 0.0, 0.5), // red
float4(1.0, 0.0, 0.0, 0.9) // strong red
};
float maxNrLightsPerTile = 31; // TODO: setup a constant for that
int colorIndex = n == 0 ? 0 : (1 + (int)floor(10 * (log2((float)n) / log2(maxNrLightsPerTile))));
colorIndex = colorIndex < 0 ? 0 : colorIndex;
float4 col = colorIndex > 11 ? float4(1.0, 1.0, 1.0, 1.0) : kRadarColors[colorIndex];
int2 coord = pixCoord - int2(1, 1);
float4 color = float4(PositivePow(col.xyz, 2.2), 0.3 * col.w);
if (n >= 0)
{
if (SampleDebugFontNumber(coord, n)) // Shadow
color = float4(0, 0, 0, 1);
if (SampleDebugFontNumber(coord + 1, n)) // Text
color = float4(1, 1, 1, 1);
}
return color;
}
float4 Frag(float4 positionCS : SV_POSITION, int Variant : TEXCOORD0) : SV_Target
{
// positionCS is SV_Position
PositionInputs posInput = GetPositionInput(positionCS.xy, _ScreenSize.zw, uint2(positionCS.xy) / GetTileSize());
float depth = LOAD_TEXTURE2D(_MainDepthTexture, posInput.unPositionSS).x;
UpdatePositionInput(depth, _InvViewProjMatrix, _ViewProjMatrix, posInput);
int2 pixelCoord = posInput.unPositionSS.xy;
int2 tileCoord = (float2)pixelCoord / TILE_SIZE;
int2 mouseTileCoord = _MousePixelCoord / TILE_SIZE;
int2 offsetInTile = pixelCoord - tileCoord * TILE_SIZE;
int n = 0;
#ifdef SHOW_LIGHT_CATEGORIES
for (int category = 0; category < LIGHTCATEGORY_COUNT; category++)
{
uint mask = 1u << category;
if (mask & _ViewTilesFlags)
{
uint start;
uint count;
GetCountAndStart(posInput, category, start, count);
n += count;
}
}
if(n == 0) n = -1;
#else
n = Variant;
#endif
float4 result = float4(0.0, 0.0, 0.0, 0.0);
// Tile overlap counter
if (n >= 0)
{
result = OverlayHeatMap(int2(posInput.unPositionSS.xy) & (TILE_SIZE - 1), n);
}
#ifdef SHOW_LIGHT_CATEGORIES
// Highlight selected tile
if (all(mouseTileCoord == tileCoord))
{
bool border = any(offsetInTile == 0 || offsetInTile == TILE_SIZE - 1);
float4 result2 = float4(1.0, 1.0, 1.0, border ? 1.0 : 0.5);
result = AlphaBlend(result, result2);
}
// Print light lists for selected tile at the bottom of the screen
int maxLights = 32;
if (tileCoord.y < LIGHTCATEGORY_COUNT && tileCoord.x < maxLights + 3)
{
PositionInputs mousePosInput = GetPositionInput(_MousePixelCoord, _ScreenSize.zw, uint2(0,0));
float depthMouse = LOAD_TEXTURE2D(_MainDepthTexture, mousePosInput.unPositionSS).x;
UpdatePositionInput(depthMouse, _InvViewProjMatrix, _ViewProjMatrix, mousePosInput);
uint category = (LIGHTCATEGORY_COUNT - 1) - tileCoord.y;
uint start;
uint count;
GetCountAndStart(mousePosInput, category, start, count);
float4 result2 = float4(.1,.1,.1,.9);
int2 fontCoord = int2(pixelCoord.x, offsetInTile.y);
int lightListIndex = tileCoord.x - 2;
int n = -1;
if(tileCoord.x == 0)
{
n = (int)count;
}
else if(lightListIndex >= 0 && lightListIndex < (int)count)
{
n = FetchIndex(start, lightListIndex);
}
if (n >= 0)
{
if (SampleDebugFontNumber(offsetInTile, n))
result2 = float4(0.0, 0.0, 0.0, 1.0);
if (SampleDebugFontNumber(offsetInTile + 1, n))
result2 = float4(1.0, 1.0, 1.0, 1.0);
}
result = AlphaBlend(result, result2);
}
#endif
return result;
}
ENDHLSL
}
}
Fallback Off
}

66
Assets/ScriptableRenderPipeline/HDRenderPipeline/Editor/HDRenderPipelineInspector.cs


public readonly GUIContent shadowsAtlasWidth = new GUIContent("Atlas width");
public readonly GUIContent shadowsAtlasHeight = new GUIContent("Atlas height");
// Subsurface Scattering Settings
public readonly GUIContent[] sssProfiles = new GUIContent[SubsurfaceScatteringSettings.maxNumProfiles] { new GUIContent("Profile #0"), new GUIContent("Profile #1"), new GUIContent("Profile #2"), new GUIContent("Profile #3"), new GUIContent("Profile #4"), new GUIContent("Profile #5"), new GUIContent("Profile #6"), new GUIContent("Profile #7") };
public readonly GUIContent sssNumProfiles = new GUIContent("Number of profiles");
public readonly GUIContent sssTexturingMode = new GUIContent("Texturing mode", "Specifies when the diffuse texture should be applied.");
public readonly GUIContent[] sssTexturingModeOptions = new GUIContent[3] { new GUIContent("Pre-scatter", "Before the blurring pass. Effectively results in the diffuse texture getting blurred together with the lighting."), new GUIContent("Post-scatter", "After the blurring pass. Effectively preserves the sharpness of the diffuse texture."), new GUIContent("Pre- and post-scatter", "Both before and after the blurring pass.") };
// Tile pass Settings
public readonly GUIContent tileLightLoopSettings = new GUIContent("Tile Light Loop Settings");
public readonly string[] tileLightLoopDebugTileFlagStrings = new string[] { "Punctual Light", "Area Light", "Env Light"};

public readonly GUIContent disableTileAndCluster = new GUIContent("Disable Tile/clustered", "Toggle");
public readonly GUIContent disableDeferredShadingInCompute = new GUIContent("Disable deferred shading in compute", "Toggle");
public readonly GUIContent enableTileAndCluster = new GUIContent("Enable Tile/clustered", "Toggle");
public readonly GUIContent enableComputeLightEvaluation = new GUIContent("Enable Compute Light Evaluation", "Toggle");
// Sky Settings
public readonly GUIContent skyParams = new GUIContent("Sky Settings");

public readonly GUIContent displayOpaqueObjects = new GUIContent("Display Opaque Objects", "Toggle opaque objects rendering on and off.");
public readonly GUIContent displayTransparentObjects = new GUIContent("Display Transparent Objects", "Toggle transparent objects rendering on and off.");
public readonly GUIContent enableDistortion = new GUIContent("Enable Distortion");
public readonly GUIContent enableSSS = new GUIContent("Enable Subsurface Scattering");
public readonly GUIContent shadowDebugVisualizationMode = new GUIContent("Shadow Debug Mode");
public readonly GUIContent shadowDebugVisualizationMode = new GUIContent("Shadow Maps Debug Mode");
public readonly GUIContent lightingDisplaySkyReflection = new GUIContent("Display Sky Reflection");
public readonly GUIContent lightingDisplaySkyReflectionMipmap = new GUIContent("Reflection Mipmap");
}
private static Styles s_Styles = null;

SerializedProperty m_ShowRenderingDebug = null;
SerializedProperty m_DebugOverlayRatio = null;
// Rendering Debug
// Material Debug
SerializedProperty m_MaterialDebugMode = null;
// Rendering Debug

SerializedProperty m_EnableSSS = null;
// Lighting debug
SerializedProperty m_DebugShadowEnabled = null;

SerializedProperty m_LightingDebugOverrideSmoothness = null;
SerializedProperty m_LightingDebugOverrideSmoothnessValue = null;
SerializedProperty m_LightingDebugAlbedo = null;
SerializedProperty m_LightingDebugDisplaySkyReflection = null;
SerializedProperty m_LightingDebugDisplaySkyReflectionMipmap = null;
// Subsurface Scattering Settings
SerializedProperty m_TexturingMode = null;
SerializedProperty m_Profiles = null;
SerializedProperty m_NumProfiles = null;
private void InitializeProperties()
{
// Global debug

m_DisplayOpaqueObjects = FindProperty(x => x.globalDebugSettings.renderingDebugSettings.displayOpaqueObjects);
m_DisplayTransparentObjects = FindProperty(x => x.globalDebugSettings.renderingDebugSettings.displayTransparentObjects);
m_EnableDistortion = FindProperty(x => x.globalDebugSettings.renderingDebugSettings.enableDistortion);
m_EnableSSS = FindProperty(x => x.globalDebugSettings.renderingDebugSettings.enableSSS);
// Lighting debug
m_DebugShadowEnabled = FindProperty(x => x.globalDebugSettings.lightingDebugSettings.enableShadows);

m_LightingDebugOverrideSmoothness = FindProperty(x => x.globalDebugSettings.lightingDebugSettings.overrideSmoothness);
m_LightingDebugOverrideSmoothnessValue = FindProperty(x => x.globalDebugSettings.lightingDebugSettings.overrideSmoothnessValue);
m_LightingDebugAlbedo = FindProperty(x => x.globalDebugSettings.lightingDebugSettings.debugLightingAlbedo);
m_LightingDebugDisplaySkyReflection = FindProperty(x => x.globalDebugSettings.lightingDebugSettings.displaySkyReflection);
m_LightingDebugDisplaySkyReflectionMipmap = FindProperty(x => x.globalDebugSettings.lightingDebugSettings.skyReflectionMipmap);
// Subsurface Scattering Settings
m_TexturingMode = FindProperty(x => x.sssSettings.texturingMode);
m_Profiles = FindProperty(x => x.sssSettings.profiles);
m_NumProfiles = m_Profiles.FindPropertyRelative("Array.size");
}
SerializedProperty FindProperty<TValue>(Expression<Func<HDRenderPipeline, TValue>> expr)

EditorGUILayout.PropertyField(m_DisplayOpaqueObjects, styles.displayOpaqueObjects);
EditorGUILayout.PropertyField(m_DisplayTransparentObjects, styles.displayTransparentObjects);
EditorGUILayout.PropertyField(m_EnableDistortion, styles.enableDistortion);
EditorGUILayout.PropertyField(m_EnableSSS, styles.enableSSS);
EditorGUI.indentLevel--;
}

EditorGUILayout.LabelField(styles.sssSettings);
EditorGUI.BeginChangeCheck();
EditorGUI.indentLevel++;
pipe.localSssParameters = (SubsurfaceScatteringParameters) EditorGUILayout.ObjectField(new GUIContent("Subsurface Scattering Parameters"), pipe.localSssParameters, typeof(SubsurfaceScatteringParameters), false);
EditorGUI.indentLevel--;
EditorGUI.BeginChangeCheck();
if (EditorGUI.EndChangeCheck())
EditorGUILayout.PropertyField(m_NumProfiles, styles.sssNumProfiles);
m_TexturingMode.intValue = EditorGUILayout.Popup(styles.sssTexturingMode, m_TexturingMode.intValue, styles.sssTexturingModeOptions, (GUILayoutOption[])null);
for (int i = 0, n = Math.Min(m_Profiles.arraySize, SubsurfaceScatteringSettings.maxNumProfiles); i < n; i++)
HackSetDirty(pipe); // Repaint
SerializedProperty profile = m_Profiles.GetArrayElementAtIndex(i);
EditorGUILayout.PropertyField(profile, styles.sssProfiles[i]);
EditorGUI.indentLevel--;
}
private void LightingDebugSettingsUI(HDRenderPipeline renderContext, HDRenderPipelineInstance renderpipelineInstance)

EditorGUILayout.PropertyField(m_ShadowDebugMode, styles.shadowDebugVisualizationMode);
if (!m_ShadowDebugMode.hasMultipleDifferentValues)
{
if ((ShadowDebugMode)m_ShadowDebugMode.intValue == ShadowDebugMode.VisualizeShadowMap)
if ((ShadowMapDebugMode)m_ShadowDebugMode.intValue == ShadowMapDebugMode.VisualizeShadowMap)
{
EditorGUILayout.IntSlider(m_ShadowDebugShadowMapIndex, 0, renderpipelineInstance.GetCurrentShadowCount() - 1, styles.shadowDebugVisualizeShadowIndex);
}

{
if ((LightingDebugMode)m_LightingDebugMode.intValue != LightingDebugMode.None)
{
{
{
{
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(m_LightingDebugOverrideSmoothnessValue, styles.lightingDebugOverrideSmoothnessValue);
EditorGUI.indentLevel--;

}
EditorGUILayout.PropertyField(m_LightingDebugDisplaySkyReflection, styles.lightingDisplaySkyReflection);
if (!m_LightingDebugDisplaySkyReflection.hasMultipleDifferentValues && m_LightingDebugDisplaySkyReflection.boolValue == true)
{
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(m_LightingDebugDisplaySkyReflectionMipmap, styles.lightingDisplaySkyReflectionMipmap);
EditorGUI.indentLevel--;
}
EditorGUI.indentLevel--;
if (EditorGUI.EndChangeCheck())

tilePass.debugViewTilesFlags = EditorGUILayout.MaskField("DebugView Tiles", tilePass.debugViewTilesFlags, styles.tileLightLoopDebugTileFlagStrings);
tilePass.enableSplitLightEvaluation = EditorGUILayout.Toggle(styles.splitLightEvaluation, tilePass.enableSplitLightEvaluation);
tilePass.disableTileAndCluster = EditorGUILayout.Toggle(styles.disableTileAndCluster, tilePass.disableTileAndCluster);
tilePass.disableDeferredShadingInCompute = EditorGUILayout.Toggle(styles.disableDeferredShadingInCompute, tilePass.disableDeferredShadingInCompute);
tilePass.enableTileAndCluster = EditorGUILayout.Toggle(styles.enableTileAndCluster, tilePass.enableTileAndCluster);
tilePass.enableComputeLightEvaluation = EditorGUILayout.Toggle(styles.enableComputeLightEvaluation, tilePass.enableComputeLightEvaluation);
if (EditorGUI.EndChangeCheck())
{

32
Assets/ScriptableRenderPipeline/HDRenderPipeline/Editor/HDRenderPipelineMenuItems.cs


LayeredLitGUI.SynchronizeAllLayers(mat);
EditorUtility.SetDirty(mat);
}
}
}
static void RemoveMaterialKeywords(Material material)
{

finally
{
EditorUtility.ClearProgressBar();
}
}
[MenuItem("HDRenderPipeline/Debug/Remove tessellation materials (not reversible)")]
static void RemoveTessellationMaterials()
{
Object[] materials = Resources.FindObjectsOfTypeAll<Material>();
Shader litShader = Shader.Find("HDRenderPipeline/Lit");
Shader layeredLitShader = Shader.Find("HDRenderPipeline/LayeredLit");
foreach (Object obj in materials)
{
Material mat = obj as Material;
if (mat.shader.name == "HDRenderPipeline/LitTessellation")
{
mat.shader = litShader;
// We remove all keyword already present
RemoveMaterialKeywords(mat);
LitGUI.SetupMaterialKeywordsAndPass(mat);
EditorUtility.SetDirty(mat);
}
else if (mat.shader.name == "HDRenderPipeline/LayeredLitTessellation")
{
mat.shader = layeredLitShader;
// We remove all keyword already present
RemoveMaterialKeywords(mat);
LayeredLitGUI.SetupMaterialKeywordsAndPass(mat);
EditorUtility.SetDirty(mat);
}
}
}
}

6
Assets/ScriptableRenderPipeline/HDRenderPipeline/Editor/SceneSettingsManagementWindow.cs


void OnGUI()
{
// Keep it there temporarily until it's back to an "engine" setting in the HDRenderPipeline asset.
SubsurfaceScatteringSettings.overrideSettings = (SubsurfaceScatteringParameters)EditorGUILayout.ObjectField(new GUIContent("SSS Settings"), SubsurfaceScatteringSettings.overrideSettings, typeof(SubsurfaceScatteringParameters), false);
EditorGUILayout.Space();
if (GUILayout.Button("Create new Common Settings"))

if (GUILayout.Button("Create new Procedural sky params"))
{
CreateAsset<ProceduralSkySettings>("NewProceduralSkyParameters");
}
if (GUILayout.Button("Create new SSS params"))
{
CreateAsset<SubsurfaceScatteringParameters>("NewSssParameters");
}
EditorGUILayout.Space();

6
Assets/ScriptableRenderPipeline/HDRenderPipeline/Editor/UpgradeStandardShaderMaterials.cs


namespace UnityEditor.Experimental.Rendering.HDPipeline
{
public class UpgradeStandardShaderMaterials
public class UpgradeStandardShaderMaterials
upgraders.Add(new StandardToHDLitMaterialUpgrader());
upgraders.Add(new StandardSpecularToHDLitMaterialUpgrader());
upgraders.Add(new StandardToHDLitMaterialUpgrader("Standard", "HDRenderPipeline/Lit", LitGUI.SetupMaterialKeywordsAndPass));
upgraders.Add(new StandardSpecularToHDLitMaterialUpgrader("Standard (Specular setup)", "HDRenderPipeline/Lit", LitGUI.SetupMaterialKeywordsAndPass));
return upgraders;
}

148
Assets/ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.asset


type: 2}
globalDebugSettings:
debugOverlayRatio: 0.33
displayMaterialDebug: 0
displayRenderingDebug: 0
displayMaterialDebug: 1
displayRenderingDebug: 1
displayLightingDebug: 0
materialDebugSettings:
debugViewMaterial: 0

overrideSmoothness: 0
overrideSmoothnessValue: 0.5
debugLightingAlbedo: {r: 0.5, g: 0.5, b: 0.5, a: 1}
displaySkyReflection: 0
skyReflectionMipmap: 0
enableSSS: 1
sssSettings:
numProfiles: 1
texturingMode: 0
transmissionFlags: 0
profiles:
- {fileID: 11400000, guid: 09521380d86baee43bf09b32473ea5f3, type: 2}
thicknessRemaps:
- 0
- 1
- 0
- 1
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
halfRcpVariancesAndLerpWeights:
- {x: 5.5555553, y: 5.5555553, z: 5.5555553, w: 0.5}
- {x: 1.3888888, y: 1.3888888, z: 1.3888888, w: 0.5}
- {x: 5.5555553, y: 5.5555553, z: 5.5555553, w: 0.5}
- {x: 1.3888888, y: 1.3888888, z: 1.3888888, w: 0.5}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
halfRcpWeightedVariances:
- {x: 2.4691355, y: 2.4691355, z: 2.4691355, w: 2.4691355}
- {x: 2.4691355, y: 2.4691355, z: 2.4691355, w: 2.4691355}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
filterKernels:
- {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}
- {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}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
- {x: 0, y: 0, z: 0, w: 0}
maxShadowDistance: 400
maxShadowDistance: 1000
localSssParameters: {fileID: 0}
m_TextureSettings:
spotCookieSize: 128
pointCookieSize: 512

2
Assets/ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.asset.meta


fileFormatVersion: 2
guid: e185fecca3c73cd47a09f1092663ef32
timeCreated: 1486997164
timeCreated: 1487689448
licenseType: Pro
NativeFormatImporter:
mainObjectFileID: 11400000

430
Assets/ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.cs


// Those that are not will be refatored later.
// Debugging
public GlobalDebugSettings globalDebugSettings = new GlobalDebugSettings();
public GlobalDebugSettings globalDebugSettings = new GlobalDebugSettings();
public RenderingSettings renderingSettings = new RenderingSettings();
[SerializeField] ShadowSettings m_ShadowSettings = ShadowSettings.Default;
public SubsurfaceScatteringParameters localSssParameters;
[SerializeField] TextureSettings m_TextureSettings = TextureSettings.Default;
public RenderingSettings renderingSettings = new RenderingSettings();
public SubsurfaceScatteringSettings sssSettings = new SubsurfaceScatteringSettings();
[SerializeField]
ShadowSettings m_ShadowSettings = ShadowSettings.Default;
[SerializeField]
TextureSettings m_TextureSettings = TextureSettings.Default;
public ShadowSettings shadowSettings { get { return m_ShadowSettings; } }
public TextureSettings textureSettings { get { return m_TextureSettings; } set { m_TextureSettings = value; } }

return m_SkySettings;
}
}
public SubsurfaceScatteringParameters sssParameters
{
get
{
if (SubsurfaceScatteringSettings.overrideSettings != null)
{
return SubsurfaceScatteringSettings.overrideSettings;
}
if (localSssParameters == null)
{
localSssParameters = CreateInstance<SubsurfaceScatteringParameters>();
}
return localSssParameters;
}
}
public void ApplyDebugSettings()
{
m_ShadowSettings.enabled = globalDebugSettings.lightingDebugSettings.enableShadows;

public void OnValidate()
{
globalDebugSettings.OnValidate();
sssSettings.OnValidate();
}
}

public struct HDCamera
{
public Camera camera;
public Vector4 screenSize;
public Camera camera;
public Vector4 screenSize;
public Vector4 invProjectionParam;
}
public class GBufferManager
{
public const int MaxGbuffer = 8;
public void SetBufferDescription(int index, string stringId, RenderTextureFormat inFormat, RenderTextureReadWrite inSRGBWrite)
{
IDs[index] = Shader.PropertyToID(stringId);
RTIDs[index] = new RenderTargetIdentifier(IDs[index]);
formats[index] = inFormat;
sRGBWrites[index] = inSRGBWrite;
public class GBufferManager
public void InitGBuffers(int width, int height, CommandBuffer cmd)
public const int MaxGbuffer = 8;
public void SetBufferDescription(int index, string stringId, RenderTextureFormat inFormat, RenderTextureReadWrite inSRGBWrite)
for (int index = 0; index < gbufferCount; index++)
IDs[index] = Shader.PropertyToID(stringId);
RTIDs[index] = new RenderTargetIdentifier(IDs[index]);
formats[index] = inFormat;
sRGBWrites[index] = inSRGBWrite;
/* RTs[index] = */
cmd.GetTemporaryRT(IDs[index], width, height, 0, FilterMode.Point, formats[index], sRGBWrites[index]);
}
public void InitGBuffers(int width, int height, CommandBuffer cmd)
public RenderTargetIdentifier[] GetGBuffers()
{
var colorMRTs = new RenderTargetIdentifier[gbufferCount];
for (int index = 0; index < gbufferCount; index++)
for (int index = 0; index < gbufferCount; index++)
{
/* RTs[index] = */
cmd.GetTemporaryRT(IDs[index], width, height, 0, FilterMode.Point, formats[index], sRGBWrites[index]);
}
colorMRTs[index] = RTIDs[index];
public RenderTargetIdentifier[] GetGBuffers()
{
var colorMRTs = new RenderTargetIdentifier[gbufferCount];
for (int index = 0; index < gbufferCount; index++)
{
colorMRTs[index] = RTIDs[index];
}
return colorMRTs;
}
return colorMRTs;
}
/*
public void BindBuffers(Material mat)
/*
public void BindBuffers(Material mat)
{
for (int index = 0; index < gbufferCount; index++)
for (int index = 0; index < gbufferCount; index++)
{
mat.SetTexture(IDs[index], RTs[index]);
}
mat.SetTexture(IDs[index], RTs[index]);
*/
}
*/
public int gbufferCount { get; set; }
int[] IDs = new int[MaxGbuffer];
RenderTargetIdentifier[] RTIDs = new RenderTargetIdentifier[MaxGbuffer];
RenderTextureFormat[] formats = new RenderTextureFormat[MaxGbuffer];
RenderTextureReadWrite[] sRGBWrites = new RenderTextureReadWrite[MaxGbuffer];
}
public int gbufferCount { get; set; }
int[] IDs = new int[MaxGbuffer];
RenderTargetIdentifier[] RTIDs = new RenderTargetIdentifier[MaxGbuffer];
RenderTextureFormat[] formats = new RenderTextureFormat[MaxGbuffer];
RenderTextureReadWrite[] sRGBWrites = new RenderTextureReadWrite[MaxGbuffer];
}
{
{
private readonly HDRenderPipeline m_Owner;
// TODO: Find a way to automatically create/iterate through deferred material

readonly GBufferManager m_gbufferManager = new GBufferManager();
// Various set of material use in render loop
readonly Material m_DebugViewMaterialGBuffer;
readonly Material m_DebugDisplayShadowMap;
private Material m_DebugDisplayShadowMap;
private Material m_DebugViewMaterialGBuffer;
private Material m_DebugDisplayLatlong;
readonly int m_CameraDepthStencilBuffer;
readonly int m_CameraDepthStencilBufferCopy; // This is temporary, we will need to provide the correct opaque depth buffer to transparent without needing a copy
readonly int m_CameraStencilBuffer;
readonly int m_VelocityBuffer;
readonly int m_DistortionBuffer;

readonly RenderTargetIdentifier m_CameraSubsurfaceBufferRT;
readonly RenderTargetIdentifier m_CameraFilteringBufferRT;
readonly RenderTargetIdentifier m_CameraDepthStencilBufferRT;
readonly RenderTargetIdentifier m_CameraDepthStencilBufferCopyRT;
// 'm_CameraStencilBufferRT' is a temporary copy of the stencil buffer and should be removed
// once we are able to read from the depth buffer and perform the stencil test simultaneously.
readonly RenderTargetIdentifier m_CameraStencilBufferRT;
private RenderTexture m_CameraDepthStencilBuffer = null;
private RenderTexture m_CameraDepthStencilBufferCopy = null;
private RenderTargetIdentifier m_CameraDepthStencilBufferRT;
private RenderTargetIdentifier m_CameraDepthStencilBufferCopyRT;
// Detect when windows size is changing
int m_CurrentWidth;

get { return m_Owner.globalDebugSettings; }
}
public SubsurfaceScatteringSettings sssSettings
{
get { return m_Owner.sssSettings; }
}
public HDRenderPipelineInstance(HDRenderPipeline owner)
{
m_Owner = owner;

m_CameraFilteringBuffer = Shader.PropertyToID("_CameraFilteringBuffer");
m_CameraDepthStencilBuffer = Shader.PropertyToID("_CameraDepthTexture");
m_CameraDepthStencilBufferCopy = Shader.PropertyToID("_CameraDepthTextureCopy");
m_CameraStencilBuffer = Shader.PropertyToID("_CameraStencilTexture");
m_CameraDepthStencilBufferRT = new RenderTargetIdentifier(m_CameraDepthStencilBuffer);
m_CameraDepthStencilBufferCopyRT = new RenderTargetIdentifier(m_CameraDepthStencilBufferCopy);
m_CameraStencilBufferRT = new RenderTargetIdentifier(m_CameraStencilBuffer);
m_DebugViewMaterialGBuffer = Utilities.CreateEngineMaterial("Hidden/HDRenderPipeline/DebugViewMaterialGBuffer");
m_FilterSubsurfaceScattering.DisableKeyword("FILTER_HORIZONTAL");
m_FilterSubsurfaceScattering.DisableKeyword("FILTER_HORIZONTAL_AND_COMBINE");
m_FilterSubsurfaceScattering.EnableKeyword("FILTER_HORIZONTAL");
m_FilterAndCombineSubsurfaceScattering.EnableKeyword("FILTER_HORIZONTAL_AND_COMBINE");
m_DebugDisplayShadowMap = Utilities.CreateEngineMaterial("Hidden/HDRenderPipeline/DebugDisplayShadowMap");
InitializeDebugMaterials();
m_ShadowPass = new ShadowRenderPass(owner.shadowSettings);

m_SkyManager.skySettings = owner.skySettingsToUse;
}
void InitializeDebugMaterials()
{
m_DebugDisplayShadowMap = Utilities.CreateEngineMaterial("Hidden/HDRenderPipeline/DebugDisplayShadowMap");
m_DebugViewMaterialGBuffer = Utilities.CreateEngineMaterial("Hidden/HDRenderPipeline/DebugViewMaterialGBuffer");
m_DebugDisplayLatlong = Utilities.CreateEngineMaterial("Hidden/HDRenderPipeline/DebugDisplayLatlong");
}
public override void Dispose()
{
base.Dispose();

};
#endif
void CreateDepthBuffer(Camera camera)
{
if (m_CameraDepthStencilBuffer != null)
{
m_CameraDepthStencilBuffer.Release();
}
m_CameraDepthStencilBuffer = new RenderTexture(camera.pixelWidth, camera.pixelHeight, 24, RenderTextureFormat.Depth);
m_CameraDepthStencilBuffer.filterMode = FilterMode.Point;
m_CameraDepthStencilBuffer.Create();
m_CameraDepthStencilBufferRT = new RenderTargetIdentifier(m_CameraDepthStencilBuffer);
if (NeedDepthBufferCopy())
{
if (m_CameraDepthStencilBufferCopy != null)
{
m_CameraDepthStencilBufferCopy.Release();
}
m_CameraDepthStencilBufferCopy = new RenderTexture(camera.pixelWidth, camera.pixelHeight, 24, RenderTextureFormat.Depth);
m_CameraDepthStencilBufferCopy.filterMode = FilterMode.Point;
m_CameraDepthStencilBufferCopy.Create();
m_CameraDepthStencilBufferCopyRT = new RenderTargetIdentifier(m_CameraDepthStencilBufferCopy);
}
}
void Resize(Camera camera)
{
// TODO: Detect if renderdoc just load and force a resize in this case, as often renderdoc require to realloc resource.

if (m_LightLoop == null)
return;
if (camera.pixelWidth != m_CurrentWidth || camera.pixelHeight != m_CurrentHeight || m_LightLoop.NeedResize())
bool resolutionChanged = camera.pixelWidth != m_CurrentWidth || camera.pixelHeight != m_CurrentHeight;
if (resolutionChanged || m_CameraDepthStencilBuffer == null)
{
CreateDepthBuffer(camera);
}
if (resolutionChanged || m_LightLoop.NeedResize())
{
if (m_CurrentWidth > 0 && m_CurrentHeight > 0)
{

m_LightLoop.AllocResolutionDependentBuffers(camera.pixelWidth, camera.pixelHeight);
}
// update recorded window resolution
m_CurrentWidth = camera.pixelWidth;
m_CurrentHeight = camera.pixelHeight;
}
// update recorded window resolution
m_CurrentWidth = camera.pixelWidth;
m_CurrentHeight = camera.pixelHeight;
public void PushGlobalParams(HDCamera hdCamera, ScriptableRenderContext renderContext, SubsurfaceScatteringParameters sssParameters)
public void PushGlobalParams(HDCamera hdCamera, ScriptableRenderContext renderContext, SubsurfaceScatteringSettings sssParameters)
var cmd = new CommandBuffer {name = "Push Global Parameters"};
cmd.SetGlobalVector("_ScreenSize", hdCamera.screenSize);
cmd.SetGlobalMatrix("_ViewProjMatrix", hdCamera.viewProjectionMatrix);
cmd.SetGlobalMatrix("_InvViewProjMatrix", hdCamera.invViewProjectionMatrix);
cmd.SetGlobalMatrix("_InvProjMatrix", hdCamera.invProjectionMatrix);
cmd.SetGlobalVector("_InvProjParam", hdCamera.invProjectionParam);
// TODO: cmd.SetGlobalInt() does not exist, so we are forced to use Shader.SetGlobalInt() instead.
if (m_SkyManager.IsSkyValid())
{
m_SkyManager.SetGlobalSkyTexture();

// Broadcast SSS parameters to all shaders.
Shader.SetGlobalInt("_TransmissionFlags", sssParameters.transmissionFlags);
Shader.SetGlobalFloatArray("_ThicknessScales", sssParameters.thicknessScales);
Shader.SetGlobalVectorArray("_HalfRcpVariancesAndLerpWeights", sssParameters.halfRcpVariancesAndLerpWeights);
cmd.SetGlobalFloatArray("_ThicknessRemaps", sssParameters.thicknessRemaps);
cmd.SetGlobalVectorArray("_HalfRcpVariancesAndLerpWeights", sssParameters.halfRcpVariancesAndLerpWeights);
if (sssParameters.enableSSS)
switch (sssParameters.texturingMode)
{
case SubsurfaceScatteringSettings.TexturingMode.PreScatter:
cmd.EnableShaderKeyword("SSS_PRE_SCATTER_TEXTURING");
cmd.DisableShaderKeyword("SSS_POST_SCATTER_TEXTURING");
break;
case SubsurfaceScatteringSettings.TexturingMode.PostScatter:
cmd.DisableShaderKeyword("SSS_PRE_SCATTER_TEXTURING");
cmd.EnableShaderKeyword("SSS_POST_SCATTER_TEXTURING");
break;
case SubsurfaceScatteringSettings.TexturingMode.PreAndPostScatter:
cmd.DisableShaderKeyword("SSS_PRE_SCATTER_TEXTURING");
cmd.DisableShaderKeyword("SSS_POST_SCATTER_TEXTURING");
break;
}
if (globalDebugSettings.renderingDebugSettings.enableSSS)
Shader.EnableKeyword("_SUBSURFACE_SCATTERING");
cmd.EnableShaderKeyword("_SUBSURFACE_SCATTERING");
Shader.DisableKeyword("_SUBSURFACE_SCATTERING");
cmd.DisableShaderKeyword("_SUBSURFACE_SCATTERING");
var cmd = new CommandBuffer {name = "Push Global Parameters"};
renderContext.ExecuteCommandBuffer(cmd);
cmd.Dispose();
}
cmd.SetGlobalVector("_ScreenSize", hdCamera.screenSize);
cmd.SetGlobalMatrix("_ViewProjMatrix", hdCamera.viewProjectionMatrix);
cmd.SetGlobalMatrix("_InvViewProjMatrix", hdCamera.invViewProjectionMatrix);
bool NeedDepthBufferCopy()
{
// For now we consider only PS4 to be able to read from a bound depth buffer. Need to test/implement for other platforms.
return SystemInfo.graphicsDeviceType != GraphicsDeviceType.PlayStation4;
}
Texture GetDepthTexture()
{
if (NeedDepthBufferCopy())
return m_CameraDepthStencilBufferCopy;
else
return m_CameraDepthStencilBuffer;
}
private void CopyDepthBufferIfNeeded(ScriptableRenderContext renderContext)
{
var cmd = new CommandBuffer();
if (NeedDepthBufferCopy())
{
using (new Utilities.ProfilingSample("Copy depth-stencil buffer", renderContext))
{
cmd.CopyTexture(m_CameraDepthStencilBufferRT, m_CameraDepthStencilBufferCopyRT);
}
}
cmd.SetGlobalTexture("_MainDepthTexture", GetDepthTexture());
if (m_LightLoop != null)
m_LightLoop.PushGlobalParams(hdCamera.camera, renderContext);
}
public override void Render(ScriptableRenderContext renderContext, Camera[] cameras)

RenderForwardOnlyOpaqueDepthPrepass(cullResults, camera, renderContext);
RenderGBuffer(cullResults, camera, renderContext);
// 'm_CameraStencilBufferRT' is a temporary copy of the stencil buffer and should be removed
// once we are able to read from the depth buffer and perform the stencil test simultaneously.
using (new Utilities.ProfilingSample("Copy depth-stencil buffer", renderContext))
// If full forward rendering, we did not do any rendering yet, so don't need to copy the buffer.
// If Deferred then the depth buffer is full (regular GBuffer + ForwardOnly depth prepass are done so we can copy it safely.
if(!m_Owner.renderingSettings.useForwardRenderingOnly)
var cmd = new CommandBuffer();
cmd.CopyTexture(m_CameraDepthStencilBufferRT, m_CameraStencilBufferRT);
renderContext.ExecuteCommandBuffer(cmd);
cmd.Dispose();
CopyDepthBufferIfNeeded(renderContext);
}
if (globalDebugSettings.materialDebugSettings.debugViewMaterial != 0)

else
{
using (new Utilities.ProfilingSample("Shadow Pass", renderContext))
{
m_ShadowPass.Render(renderContext, cullResults, out m_ShadowsResult);
}
using (new Utilities.ProfilingSample("Shadow Pass", renderContext))
{
m_ShadowPass.Render(renderContext, cullResults, out m_ShadowsResult);
}
renderContext.SetupCameraProperties(camera); // Need to recall SetupCameraProperties after m_ShadowPass.Render
renderContext.SetupCameraProperties(camera); // Need to recall SetupCameraProperties after m_ShadowPass.Render
if (m_LightLoop != null)
{
using (new Utilities.ProfilingSample("Build Light list", renderContext))
if (m_LightLoop != null)
m_LightLoop.PrepareLightsForGPU(m_Owner.shadowSettings, cullResults, camera, ref m_ShadowsResult);
m_LightLoop.RenderShadows(renderContext, cullResults);
renderContext.SetupCameraProperties(camera); // Need to recall SetupCameraProperties after m_ShadowPass.Render
m_LightLoop.BuildGPULightLists(camera, renderContext, m_CameraDepthStencilBufferRT); // TODO: Use async compute here to run light culling during shadow
using (new Utilities.ProfilingSample("Build Light list", renderContext))
{
m_LightLoop.PrepareLightsForGPU(m_Owner.shadowSettings, cullResults, camera, ref m_ShadowsResult);
m_LightLoop.RenderShadows(renderContext, cullResults);
renderContext.SetupCameraProperties(camera); // Need to recall SetupCameraProperties after m_ShadowPass.Render
m_LightLoop.BuildGPULightLists(camera, renderContext, m_CameraDepthStencilBufferRT); // TODO: Use async compute here to run light culling during shadow
}
}
PushGlobalParams(hdCamera, renderContext, m_Owner.sssParameters);
PushGlobalParams(hdCamera, renderContext, m_Owner.sssSettings);
// Caution: We require sun light here as some sky use the sun light to render, mean UpdateSkyEnvironment
// must be call after BuildGPULightLists.
// TODO: Try to arrange code so we can trigger this call earlier and use async compute here to run sky convolution during other passes (once we move convolution shader to compute).
UpdateSkyEnvironment(hdCamera, renderContext);
// Caution: We require sun light here as some sky use the sun light to render, mean UpdateSkyEnvironment
// must be call after BuildGPULightLists.
// TODO: Try to arrange code so we can trigger this call earlier and use async compute here to run sky convolution during other passes (once we move convolution shader to compute).
UpdateSkyEnvironment(hdCamera, renderContext);
RenderDeferredLighting(hdCamera, renderContext, m_Owner.sssParameters.enableSSS);
RenderDeferredLighting(hdCamera, renderContext, m_Owner.globalDebugSettings.renderingDebugSettings.enableSSS);
// We compute subsurface scattering here. Therefore, no objects rendered afterwards will exhibit SSS.
// Currently, there is no efficient way to switch between SRT and MRT for the forward pass;
// therefore, forward-rendered objects do not output split lighting required for the SSS pass.
CombineSubsurfaceScattering(hdCamera, renderContext, m_Owner.sssParameters);
// We compute subsurface scattering here. Therefore, no objects rendered afterwards will exhibit SSS.
// Currently, there is no efficient way to switch between SRT and MRT for the forward pass;
// therefore, forward-rendered objects do not output split lighting required for the SSS pass.
CombineSubsurfaceScattering(hdCamera, renderContext, m_Owner.sssSettings);
// For opaque forward we have split rendering in two categories
// Material that are always forward and material that can be deferred or forward depends on render pipeline options (like switch to rendering forward only mode)
// Material that are always forward are unlit and complex (Like Hair) and don't require sorting, so it is ok to split them.
RenderForward(cullResults, camera, renderContext, true); // Render deferred or forward opaque
RenderForwardOnlyOpaque(cullResults, camera, renderContext);
// For opaque forward we have split rendering in two categories
// Material that are always forward and material that can be deferred or forward depends on render pipeline options (like switch to rendering forward only mode)
// Material that are always forward are unlit and complex (Like Hair) and don't require sorting, so it is ok to split them.
RenderForward(cullResults, camera, renderContext, true); // Render deferred or forward opaque
RenderForwardOnlyOpaque(cullResults, camera, renderContext);
// 'm_CameraDepthStencilBufferCopyRT' is a temporary copy of the depth textureand should be removed
// once we are able to read from the depth buffer during transparent pass.
using (new Utilities.ProfilingSample("Copy depth-stencil buffer after all opaque", renderContext))
{
var cmd = new CommandBuffer();
cmd.CopyTexture(m_CameraDepthStencilBufferRT, m_CameraDepthStencilBufferCopyRT);
renderContext.ExecuteCommandBuffer(cmd);
cmd.Dispose();
}
// If full forward rendering, we did just rendered everything, so we can copy the depth buffer
// If Deferred nothing needs copying anymore.
if(m_Owner.renderingSettings.useForwardRenderingOnly)
{
CopyDepthBufferIfNeeded(renderContext);
}
RenderSky(hdCamera, renderContext);
RenderSky(hdCamera, renderContext);
// Render all type of transparent forward (unlit, lit, complex (hair...)) to keep the sorting between transparent objects.
RenderForward(cullResults, camera, renderContext, false);
// Render all type of transparent forward (unlit, lit, complex (hair...)) to keep the sorting between transparent objects.
RenderForward(cullResults, camera, renderContext, false);
RenderVelocity(cullResults, camera, renderContext); // Note we may have to render velocity earlier if we do temporalAO, temporal volumetric etc... Mean we will not take into account forward opaque in case of deferred rendering ?
// Planar and real time cubemap doesn't need post process and render in FP16
if (camera.cameraType == CameraType.Reflection)
{
// Simple blit
var cmd = new CommandBuffer { name = "Blit to final RT" };
cmd.Blit(m_CameraColorBufferRT, BuiltinRenderTextureType.CameraTarget);
renderContext.ExecuteCommandBuffer(cmd);
cmd.Dispose();
}
else
{
RenderVelocity(cullResults, camera, renderContext); // Note we may have to render velocity earlier if we do temporalAO, temporal volumetric etc... Mean we will not take into account forward opaque in case of deferred rendering ?
// TODO: Check with VFX team.
// Rendering distortion here have off course lot of artifact.
// But resolving at each objects that write in distortion is not possible (need to sort transparent, render those that do not distort, then resolve, then etc...)
// Instead we chose to apply distortion at the end after we cumulate distortion vector and desired blurriness. This
RenderDistortion(cullResults, camera, renderContext);
// TODO: Check with VFX team.
// Rendering distortion here have off course lot of artifact.
// But resolving at each objects that write in distortion is not possible (need to sort transparent, render those that do not distort, then resolve, then etc...)
// Instead we chose to apply distortion at the end after we cumulate distortion vector and desired blurriness. This
RenderDistortion(cullResults, camera, renderContext);
FinalPass(camera, renderContext);
FinalPass(camera, renderContext);
}
}
RenderDebugOverlay(camera, renderContext);

if (enableSSS)
{
// Output split lighting for materials tagged with the SSS stencil bit.
m_LightLoop.RenderDeferredLighting(hdCamera, renderContext, globalDebugSettings.lightingDebugSettings, colorRTs, m_CameraStencilBufferRT, true, enableSSS);
m_LightLoop.RenderDeferredLighting(hdCamera, renderContext, globalDebugSettings.lightingDebugSettings, colorRTs, m_CameraDepthStencilBufferRT, new RenderTargetIdentifier(GetDepthTexture()), true, enableSSS);
m_LightLoop.RenderDeferredLighting(hdCamera, renderContext, globalDebugSettings.lightingDebugSettings, colorRTs, m_CameraStencilBufferRT, false, enableSSS);
m_LightLoop.RenderDeferredLighting(hdCamera, renderContext, globalDebugSettings.lightingDebugSettings, colorRTs, m_CameraDepthStencilBufferRT, new RenderTargetIdentifier(GetDepthTexture()), false, enableSSS);
void CombineSubsurfaceScattering(HDCamera hdCamera, ScriptableRenderContext context, SubsurfaceScatteringParameters sssParameters)
void CombineSubsurfaceScattering(HDCamera hdCamera, ScriptableRenderContext context, SubsurfaceScatteringSettings sssParameters)
if (!sssParameters.enableSSS) return;
if (!globalDebugSettings.renderingDebugSettings.enableSSS) return;
m_FilterSubsurfaceScattering.SetMatrix("_InvProjMatrix", hdCamera.invProjectionMatrix);
m_CameraFilteringBufferRT, m_CameraStencilBufferRT);
m_CameraFilteringBufferRT, m_CameraDepthStencilBufferRT);
m_FilterAndCombineSubsurfaceScattering.SetMatrix("_InvProjMatrix", hdCamera.invProjectionMatrix);
m_CameraColorBufferRT, m_CameraStencilBufferRT);
m_CameraColorBufferRT, m_CameraDepthStencilBufferRT);
context.ExecuteCommandBuffer(cmd);
cmd.Dispose();

// All of this is temporary, sub-optimal and quickly hacked together but is necessary
// for artists to do lighting work until the fully-featured framework is ready
var localPostProcess = camera.GetComponent<PostProcessing>();
var localPostProcess = camera.GetComponent<PostProcessingSRP>();
bool localActive = localPostProcess != null && localPostProcess.enabled;

void RenderDebugOverlay(Camera camera, ScriptableRenderContext renderContext)
{
// We don't want any overlay for these kind of rendering
if (camera.cameraType == CameraType.Reflection || camera.cameraType == CameraType.Preview)
return;
CommandBuffer debugCB = new CommandBuffer();
debugCB.name = "Debug Overlay";

MaterialPropertyBlock propertyBlock = new MaterialPropertyBlock();
LightingDebugSettings shadowDebug = globalDebugSettings.lightingDebugSettings;
LightingDebugSettings lightingDebug = globalDebugSettings.lightingDebugSettings;
if (shadowDebug.shadowDebugMode != ShadowDebugMode.None)
if (lightingDebug.shadowDebugMode != ShadowMapDebugMode.None)
if (shadowDebug.shadowDebugMode == ShadowDebugMode.VisualizeShadowMap)
if (lightingDebug.shadowDebugMode == ShadowMapDebugMode.VisualizeShadowMap)
uint visualizeShadowIndex = Math.Min(shadowDebug.shadowMapIndex, (uint)(GetCurrentShadowCount() - 1));
uint visualizeShadowIndex = Math.Min(lightingDebug.shadowMapIndex, (uint)(GetCurrentShadowCount() - 1));
ShadowLight shadowLight = m_ShadowsResult.shadowLights[visualizeShadowIndex];
for (int slice = 0; slice < shadowLight.shadowSliceCount; ++slice)
{

NextOverlayCoord(ref x, ref y, overlaySize, camera.pixelWidth);
}
}
else if (shadowDebug.shadowDebugMode == ShadowDebugMode.VisualizeAtlas)
else if (lightingDebug.shadowDebugMode == ShadowMapDebugMode.VisualizeAtlas)
{
propertyBlock.SetVector("_TextureScaleBias", new Vector4(1.0f, 1.0f, 0.0f, 0.0f));

}
}
if(lightingDebug.displaySkyReflection)
{
Texture skyReflection = m_SkyManager.skyReflection;
propertyBlock.SetTexture("_InputCubemap", skyReflection);
propertyBlock.SetFloat("_Mipmap", lightingDebug.skyReflectionMipmap);
debugCB.SetViewport(new Rect(x, y, overlaySize, overlaySize));
debugCB.DrawProcedural(Matrix4x4.identity, m_DebugDisplayLatlong, 0, MeshTopology.Triangles, 3, 1, propertyBlock);
NextOverlayCoord(ref x, ref y, overlaySize, camera.pixelWidth);
}
renderContext.ExecuteCommandBuffer(debugCB);
}

cmd.GetTemporaryRT(m_CameraColorBuffer, w, h, 0, FilterMode.Point, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear, 1, true); // Enable UAV
cmd.GetTemporaryRT(m_CameraSubsurfaceBuffer, w, h, 0, FilterMode.Point, RenderTextureFormat.RGB111110Float, RenderTextureReadWrite.Linear, 1, true); // Enable UAV
cmd.GetTemporaryRT(m_CameraFilteringBuffer, w, h, 0, FilterMode.Point, RenderTextureFormat.RGB111110Float, RenderTextureReadWrite.Linear, 1, true); // Enable UAV
cmd.GetTemporaryRT(m_CameraDepthStencilBuffer, w, h, 24, FilterMode.Point, RenderTextureFormat.Depth);
cmd.GetTemporaryRT(m_CameraDepthStencilBufferCopy, w, h, 24, FilterMode.Point, RenderTextureFormat.Depth);
cmd.GetTemporaryRT(m_CameraStencilBuffer, w, h, 24, FilterMode.Point, RenderTextureFormat.Depth);
if (!m_Owner.renderingSettings.ShouldUseForwardRenderingOnly())
{

4
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/LightLoop.cs


// TODO: this should not be part of the interface but for now make something working
public virtual void BuildGPULightLists(Camera camera, ScriptableRenderContext loop, RenderTargetIdentifier cameraDepthBufferRT) { }
public virtual void PushGlobalParams(Camera camera, ScriptableRenderContext loop) {}
RenderTargetIdentifier[] colorBuffers, RenderTargetIdentifier stencilBuffer,
RenderTargetIdentifier[] colorBuffers, RenderTargetIdentifier depthStencilBuffer, RenderTargetIdentifier depthStencilTexture,
bool outputSplitLightingForSSS, bool enableSSS) {}
public virtual void RenderForward(Camera camera, ScriptableRenderContext renderContext, bool renderOpaque) {}

22
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/Lighting.hlsl


#ifndef UNITY_LIGHTING_INCLUDED
#define UNITY_LIGHTING_INCLUDED
#include "ShaderLibrary/CommonLighting.hlsl"
#include "ShaderLibrary/CommonShadow.hlsl"
#include "ShaderLibrary/Sampling.hlsl"
#include "ShaderLibrary/AreaLighting.hlsl"
#include "ShaderLibrary/ImageBasedLighting.hlsl"
#include "../../ShaderLibrary/CommonLighting.hlsl"
#include "../../ShaderLibrary/CommonShadow.hlsl"
#include "../../ShaderLibrary/Sampling.hlsl"
#include "../../ShaderLibrary/AreaLighting.hlsl"
#include "../../ShaderLibrary/ImageBasedLighting.hlsl"
// The light loop (or lighting architecture) is in charge to:
// - Define light list

#define HAS_LIGHTLOOP // Allow to not define LightLoop related function in Material.hlsl
#include "HDRenderPipeline/Lighting/LightDefinition.cs.hlsl"
#include "HDRenderPipeline/Lighting/LightUtilities.hlsl"
#include "../Lighting/LightDefinition.cs.hlsl"
#include "../Lighting/LightUtilities.hlsl"
#include "HDRenderPipeline/Shadow/Shadow.hlsl"
#include "../Shadow/Shadow.hlsl"
#include "HDRenderPipeline/Lighting/TilePass/TilePass.hlsl"
#include "../Lighting/TilePass/TilePass.hlsl"
#include "HDRenderPipeline/Material/Material.hlsl"
#include "../Material/Material.hlsl"
#include "HDRenderPipeline/Lighting/TilePass/TilePassLoop.hlsl"
#include "../Lighting/TilePass/TilePassLoop.hlsl"
#endif

27
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/Resources/Deferred.shader


HLSLPROGRAM
#pragma target 4.5
#pragma only_renderers d3d11 ps4 metal // TEMP: until we go further in dev
// #pragma enable_d3d11_debug_symbols
#pragma vertex Vert
#pragma fragment Frag

// Split lighting is utilized during the SSS pass.
#pragma multi_compile _ OUTPUT_SPLIT_LIGHTING
// #ifdef OUTPUT_SPLIT_LIGHTING
#pragma shader_feature _ SSS_PRE_SCATTER_TEXTURING SSS_POST_SCATTER_TEXTURING
// #endif
#pragma multi_compile _ LIGHTING_DEBUG
//-------------------------------------------------------------------------------------

#include "ShaderLibrary/Common.hlsl"
#include "HDRenderPipeline/Debug/HDRenderPipelineDebug.cs.hlsl"
#include "HDRenderPipeline/Debug/DebugLighting.hlsl"
#include "../../../ShaderLibrary/Common.hlsl"
#include "../../Debug/HDRenderPipelineDebug.cs.hlsl"
#include "../../Debug/DebugLighting.hlsl"
#include "HDRenderPipeline/ShaderConfig.cs.hlsl"
#include "HDRenderPipeline/ShaderVariables.hlsl"
#include "HDRenderPipeline/Lighting/Lighting.hlsl" // This include Material.hlsl
#include "../../ShaderConfig.cs.hlsl"
#include "../../ShaderVariables.hlsl"
#include "../../Lighting/Lighting.hlsl" // This include Material.hlsl
//-------------------------------------------------------------------------------------
// variable declaration

TEXTURE2D_FLOAT(_CameraDepthTexture);
SAMPLER2D(sampler_CameraDepthTexture);
struct Attributes
{

Outputs Frag(Varyings input)
{
// input.positionCS is SV_Position
PositionInputs posInput = GetPositionInput(input.positionCS.xy, _ScreenSize.zw);
float depth = LOAD_TEXTURE2D(_CameraDepthTexture, posInput.unPositionSS).x;
PositionInputs posInput = GetPositionInput(input.positionCS.xy, _ScreenSize.zw, uint2(input.positionCS.xy) / GetTileSize());
float depth = LOAD_TEXTURE2D(_MainDepthTexture, posInput.unPositionSS).x;
UpdatePositionInput(depth, _InvViewProjMatrix, _ViewProjMatrix, posInput);
float3 V = GetWorldSpaceNormalizeViewDir(posInput.positionWS);

PreLightData preLightData = GetPreLightData(V, posInput, bsdfData);
uint featureFlags = 0xFFFFFFFF;
LightLoop(V, posInput, preLightData, bsdfData, bakeDiffuseLighting, diffuseLighting, specularLighting);
LightLoop(V, posInput, preLightData, bsdfData, bakeDiffuseLighting, featureFlags, diffuseLighting, specularLighting);
Outputs outputs;
#ifdef OUTPUT_SPLIT_LIGHTING

25
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TileLightLoopProducer.cs


[Serializable]
public class TileSettings
{
public bool enableDrawLightBoundsDebug;
public bool disableTileAndCluster; // For debug / test
public bool disableDeferredShadingInCompute;
public bool enableTileAndCluster; // For debug / test
public bool enableComputeFeatureVariants;
public int debugViewTilesFlags;
public bool disableFptlWhenClustered; // still useful on opaques. Should be false by default to force tile on opaque.
public bool enableFptlForOpaqueWhenClustered; // still useful on opaques. Should be true by default to force tile on opaque.
[Range(0.0f, 1.0f)]
public float diffuseGlobalDimmer = 1.0f;
[Range(0.0f, 1.0f)]
public float specularGlobalDimmer = 1.0f;
public enum TileDebug : int { None = 0, Punctual = 1, Area = 2, AreaAndPunctual = 3, Environment = 4, EnvironmentAndPunctual = 5, EnvironmentAndArea = 6, EnvironmentAndAreaAndPunctual = 7, FeatureVariants = 8 };
public TileDebug tileDebugByCategory;
enableDrawLightBoundsDebug = false,
disableTileAndCluster = false,
disableDeferredShadingInCompute = true,
enableTileAndCluster = true,
enableComputeFeatureVariants = false,
debugViewTilesFlags = 0,
tileDebugByCategory = TileDebug.None,
disableFptlWhenClustered = false,
enableFptlForOpaqueWhenClustered = true,
enableBigTilePrepass = true,
};
}

16
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/lightlistbuild-bigtile.compute


#pragma kernel BigTileLightListGen
#include "ShaderLibrary/common.hlsl"
#include "../../../../ShaderLibrary/common.hlsl"
#if !defined(SHADER_API_XBOXONE)
#endif
#define EXACT_EDGE_TESTS
#define PERFORM_SPHERICAL_INTERSECTION_TESTS

}
}
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL)
#if /*!defined(SHADER_API_XBOXONE) && */!defined(SHADER_API_PSSL)
GroupMemoryBarrierWithGroupSync();
#endif

if(t==0) lightOffs = 0;
GroupMemoryBarrierWithGroupSync();
int i;
int i;
for(i=t; i<iNrCoarseLights; i+=NR_THREADS) if((int)lightsListLDS[i]<g_iNrVisibLights) InterlockedAdd(lightOffs, 1);
GroupMemoryBarrierWithGroupSync();
iNrCoarseLights = lightOffs;

int i=iSwizzle + (2*(iSection&0x2)); // offset by 4 at section 2
vP0 = GetTileVertex(uint2(viTilLL.x, viTilUR.y), uint2(viTilUR.x, viTilLL.y), i, fTileFarPlane);
vE0 = iSection == 0 ? vP0 : (((iSwizzle & 0x2) == 0 ? 1.0f : (-1.0f)) * ((int)(iSwizzle & 0x1) == (iSwizzle >> 1) ? float3(1, 0, 0) : float3(0, 1, 0)));
vE0 = iSection == 0 ? vP0 : (((iSwizzle & 0x2) == 0 ? 1.0f : (-1.0f)) * ((int)(iSwizzle & 0x1) == (iSwizzle >> 1) ? float3(1, 0, 0) : float3(0, 1, 0)));
}
void CullByExactEdgeTests(uint threadID, int iNrCoarseLights, uint2 viTilLL, uint2 viTilUR)

{
const uint idxCoarse = lightsListLDS[l];
bool canEnter = idxCoarse<(uint)g_iNrVisibLights;
bool canEnter = idxCoarse<(uint) g_iNrVisibLights;
[branch]if(canEnter)
[branch]if(canEnter)
const float3 boxZ = -lgtDat.boxAxisZ.xyz; // flip axis (so it points away from the light direction for a spot-light)
const float3 boxZ = -lgtDat.boxAxisZ.xyz; // flip axis (so it points away from the light direction for a spot-light)
const float3 center = lgtDat.center.xyz;
const float2 scaleXY = lgtDat.scaleXY;

50
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/lightlistbuild-clustered.compute


#pragma kernel TileLightListGen_DepthRT_MSAA_SrcBigTile LIGHTLISTGEN=TileLightListGen_DepthRT_MSAA_SrcBigTile ENABLE_DEPTH_TEXTURE_BACKPLANE MSAA_ENABLED USE_TWO_PASS_TILED_LIGHTING
#pragma kernel ClearAtomic
#include "ShaderLibrary/common.hlsl"
#include "../../../../ShaderLibrary/common.hlsl"
//#define EXACT_EDGE_TESTS
#define PERFORM_SPHERICAL_INTERSECTION_TESTS

#else
g_depth_tex.GetDimensions(iWidth, iHeight);
#endif
uint nrTilesX = (iWidth+15)/16;
uint nrTilesY = (iHeight+15)/16;
const uint log2TileSize = firstbithigh(TILE_SIZE_CLUSTERED);
uint nrTilesX = (iWidth+(TILE_SIZE_CLUSTERED-1))>>log2TileSize;
uint nrTilesY = (iHeight+(TILE_SIZE_CLUSTERED-1))>>log2TileSize;
uint2 viTilLL = 16*tileIDX;
uint2 viTilUR = min( viTilLL+uint2(16,16), uint2(iWidth, iHeight) ); // not width and height minus 1 since viTilUR represents the end of the tile corner.
uint2 viTilLL = TILE_SIZE_CLUSTERED*tileIDX;
uint2 viTilUR = min( viTilLL+uint2(TILE_SIZE_CLUSTERED,TILE_SIZE_CLUSTERED), uint2(iWidth, iHeight) ); // not width and height minus 1 since viTilUR represents the end of the tile corner.
if(t==0)
{

// establish min and max depth first
dpt_ma=0.0;
for(int idx=t; idx<256; idx+=NR_THREADS)
for(int idx=t; idx<(TILE_SIZE_CLUSTERED*TILE_SIZE_CLUSTERED); idx+=NR_THREADS)
uint2 uPixCrd = min( uint2(viTilLL.x+(idx&0xf), viTilLL.y+(idx>>4)), uint2(iWidth-1, iHeight-1) );
uint2 uPixCrd = min( uint2(viTilLL.x+(idx&(TILE_SIZE_CLUSTERED-1)), viTilLL.y+(idx>>log2TileSize)), uint2(iWidth-1, iHeight-1) );
#ifdef MSAA_ENABLED
for(uint i=0; i<iNumSamplesMSAA; i++)
{

dpt_ma = asfloat(ldsZMax);
#endif
float3 vTileLL = float3(viTilLL.x/(float) iWidth, viTilLL.y/(float) iHeight, 0.0);
float3 vTileUR = float3(viTilUR.x/(float) iWidth, viTilUR.y/(float) iHeight, 1.0);
float2 vTileLL = float2(viTilLL.x/(float) iWidth, viTilLL.y/(float) iHeight);
float2 vTileUR = float2(viTilUR.x/(float) iWidth, viTilUR.y/(float) iHeight);
int NrBigTilesX = (nrTilesX+3)>>2;
const int bigTileIdx = (tileIDX.y>>2)*NrBigTilesX + (tileIDX.x>>2); // map the idx to 64x64 tiles
const uint log2BigTileToClustTileRatio = firstbithigh(64) - log2TileSize;
int NrBigTilesX = (nrTilesX+((1<<log2BigTileToClustTileRatio)-1))>>log2BigTileToClustTileRatio;
const int bigTileIdx = (tileIDX.y>>log2BigTileToClustTileRatio)*NrBigTilesX + (tileIDX.x>>log2BigTileToClustTileRatio); // 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)
{

{
#endif
const float3 vMi = g_vBoundsBuffer[l];
const float3 vMa = g_vBoundsBuffer[l+g_iNrVisibLights];
const float2 vMi = g_vBoundsBuffer[l].xy;
const float2 vMa = g_vBoundsBuffer[l+g_iNrVisibLights].xy;
if( all(vMa.xy>vTileLL.xy) && all(vMi.xy<vTileUR.xy))
if( all(vMa>vTileLL) && all(vMi<vTileUR))
{
unsigned int uInc = 1;
unsigned int uIndex;

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))) );
iNrCoarseLights = SphericalIntersectionTests( t, iNrCoarseLights, float2(min(viTilLL.xy+uint2(TILE_SIZE_CLUSTERED/2,TILE_SIZE_CLUSTERED/2), uint2(iWidth-1, iHeight-1))) );
#endif
#ifdef ENABLE_DEPTH_TEXTURE_BACKPLANE

InterlockedAdd(g_LayeredSingleIdxBuffer[0], (uint) iSpaceAvail, start); // alloc list memory
}
// 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
// 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
int categoryListCount[LIGHTCATEGORY_COUNT]={0,0,0}; // direct light count and reflection lights
uint offs = start;

{
if(offs<(start+iSpaceAvail) && i<nrClusters && CheckIntersection(l, i, viTilLL.xy, viTilUR.xy, suggestedBase) )
{
uint lightCategory = _LightVolumeData[coarseList[l]].lightCategory;
++categoryListCount[lightCategory];
uint lightCategory = _LightVolumeData[coarseList[l]].lightCategory;
++categoryListCount[lightCategory];
g_vLayeredLightList[offs++] = coarseList[l] - shiftIndex[lightCategory]; // reflection lights will be last since we sorted
}
}

#endif
float onePixDiagDist = GetOnePixDiagWorldDistAtDepthOne();
float halfTileSizeAtZDistOne = 8*onePixDiagDist; // scale by half a tile
float halfTileSizeAtZDistOne = (TILE_SIZE_CLUSTERED/2)*onePixDiagDist; // scale by half a tile
for(int l=threadID; l<iNrCoarseLights; l+=NR_THREADS)
{

GroupMemoryBarrierWithGroupSync();
#endif
const int idxCoarse = coarseList[l];
[branch]if (_LightVolumeData[idxCoarse].lightVolume != LIGHTVOLUMETYPE_SPHERE) // don't bother doing edge tests for sphere lights since these have camera aligned bboxes.
[branch]if (_LightVolumeData[idxCoarse].lightVolume != LIGHTVOLUMETYPE_SPHERE) // don't bother doing edge tests for sphere lights since these have camera aligned bboxes.
{
SFiniteLightBound lgtDat = g_data[idxCoarse];

925
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/lightlistbuild.compute


// The implementation is based on the demo on "fine pruned tiled lighting" published in GPU Pro 7.
// https://github.com/wolfgangfengel/GPU-Pro-7
#pragma kernel TileLightListGen LIGHTLISTGEN=TileLightListGen
#pragma kernel TileLightListGen_SrcBigTile LIGHTLISTGEN=TileLightListGen_SrcBigTile USE_TWO_PASS_TILED_LIGHTING
#include "ShaderLibrary/common.hlsl"
#include "../ShaderBase.hlsl"
#include "../TilePass.cs.hlsl"
#include "../LightingConvexHullUtils.hlsl"
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL)
#include "../SortingComputeUtils.hlsl"
#endif
#define FINE_PRUNING_ENABLED
#define PERFORM_SPHERICAL_INTERSECTION_TESTS
uniform int g_iNrVisibLights;
uniform uint2 g_viDimensions;
uniform float4x4 g_mInvScrProjection;
uniform float4x4 g_mScrProjection;
uniform int _EnvLightIndexShift;
Texture2D g_depth_tex : register( t0 );
StructuredBuffer<float3> g_vBoundsBuffer : register( t1 );
StructuredBuffer<LightVolumeData> _LightVolumeData : register(t2);
StructuredBuffer<SFiniteLightBound> g_data : register( t3 );
#ifdef USE_TWO_PASS_TILED_LIGHTING
StructuredBuffer<uint> g_vBigTileLightList : register( t4 ); // don't support Buffer yet in unity
#endif
#define NR_THREADS 64
// output buffer
RWStructuredBuffer<uint> g_vLightList : register( u0 ); // don't support RWBuffer yet in unity
#define MAX_NR_COARSE_ENTRIES 64
#define MAX_NR_PRUNED_ENTRIES 24
groupshared unsigned int coarseList[MAX_NR_COARSE_ENTRIES];
groupshared unsigned int prunedList[MAX_NR_COARSE_ENTRIES]; // temporarily support room for all 64 while in LDS
groupshared uint ldsZMin;
groupshared uint ldsZMax;
groupshared uint lightOffs;
#ifdef FINE_PRUNING_ENABLED
groupshared uint ldsDoesLightIntersect[2];
#endif
groupshared int ldsNrLightsFinal;
groupshared int ldsCategoryListCount[LIGHTCATEGORY_COUNT]; // since LIGHTCATEGORY_COUNT is 3
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS
groupshared uint lightOffsSph;
#endif
//float GetLinearDepth(float3 vP)
//{
// float4 v4Pres = mul(g_mInvScrProjection, float4(vP,1.0));
// return v4Pres.z / v4Pres.w;
//}
float GetLinearDepth(float zDptBufSpace) // 0 is near 1 is far
{
float3 vP = float3(0.0f,0.0f,zDptBufSpace);
float4 v4Pres = mul(g_mInvScrProjection, float4(vP,1.0));
return v4Pres.z / v4Pres.w;
}
float3 GetViewPosFromLinDepth(float2 v2ScrPos, float fLinDepth)
{
float fSx = g_mScrProjection[0].x;
float fCx = g_mScrProjection[0].z;
float fSy = g_mScrProjection[1].y;
float fCy = g_mScrProjection[1].z;
#if USE_LEFTHAND_CAMERASPACE
return fLinDepth*float3( ((v2ScrPos.x-fCx)/fSx), ((v2ScrPos.y-fCy)/fSy), 1.0 );
#else
return fLinDepth*float3( -((v2ScrPos.x+fCx)/fSx), -((v2ScrPos.y+fCy)/fSy), 1.0 );
#endif
}
float GetOnePixDiagWorldDistAtDepthOne()
{
float fSx = g_mScrProjection[0].x;
float fSy = g_mScrProjection[1].y;
return length( float2(1.0/fSx,1.0/fSy) );
}
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS
int SphericalIntersectionTests(uint threadID, int iNrCoarseLights, float2 screenCoordinate);
#endif
#ifdef FINE_PRUNING_ENABLED
void FinePruneLights(uint threadID, int iNrCoarseLights, uint2 viTilLL, float4 vLinDepths);
#endif
[numthreads(NR_THREADS, 1, 1)]
void LIGHTLISTGEN(uint threadID : SV_GroupIndex, uint3 u3GroupID : SV_GroupID)
{
uint2 tileIDX = u3GroupID.xy;
uint t=threadID;
if(t<MAX_NR_COARSE_ENTRIES)
prunedList[t]=0;
uint iWidth = g_viDimensions.x;
uint iHeight = g_viDimensions.y;
uint nrTilesX = (iWidth+15)/16;
uint nrTilesY = (iHeight+15)/16;
// build tile scr boundary
const uint uFltMax = 0x7f7fffff; // FLT_MAX as a uint
if(t==0)
{
ldsZMin = uFltMax;
ldsZMax = 0;
lightOffs = 0;
}
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL)
GroupMemoryBarrierWithGroupSync();
#endif
uint2 viTilLL = 16*tileIDX;
// establish min and max depth first
float dpt_mi=asfloat(uFltMax), dpt_ma=0.0;
float4 vLinDepths;
{
// Fetch depths and calculate min/max
[unroll]
for(int i = 0; i < 4; i++)
{
int idx = i * NR_THREADS + t;
uint2 uCrd = min( uint2(viTilLL.x+(idx&0xf), viTilLL.y+(idx>>4)), uint2(iWidth-1, iHeight-1) );
const float fDepth = FetchDepth(g_depth_tex, uCrd);
vLinDepths[i] = GetLinearDepth(fDepth);
if(fDepth<VIEWPORT_SCALE_Z) // if not skydome
{
dpt_mi = min(fDepth, dpt_mi);
dpt_ma = max(fDepth, dpt_ma);
}
}
InterlockedMax(ldsZMax, asuint(dpt_ma));
InterlockedMin(ldsZMin, asuint(dpt_mi));
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL)
GroupMemoryBarrierWithGroupSync();
#endif
}
float3 vTileLL = float3(viTilLL.x/(float) iWidth, viTilLL.y/(float) iHeight, asfloat(ldsZMin));
float3 vTileUR = float3((viTilLL.x+16)/(float) iWidth, (viTilLL.y+16)/(float) iHeight, asfloat(ldsZMax));
vTileUR.xy = min(vTileUR.xy,float2(1.0,1.0)).xy;
// build coarse list using AABB
#ifdef USE_TWO_PASS_TILED_LIGHTING
int NrBigTilesX = (nrTilesX+3)>>2;
const int bigTileIdx = (tileIDX.y>>2)*NrBigTilesX + (tileIDX.x>>2); // map the idx to 64x64 tiles
int nrBigTileLights = g_vBigTileLightList[MAX_NR_BIGTILE_LIGHTS_PLUSONE*bigTileIdx+0];
for(int l0=(int) t; l0<(int) nrBigTileLights; l0 += NR_THREADS)
{
int l = g_vBigTileLightList[MAX_NR_BIGTILE_LIGHTS_PLUSONE*bigTileIdx+l0+1];
#else
for(int l=(int) t; l<(int) g_iNrVisibLights; l += NR_THREADS)
{
#endif
const float3 vMi = g_vBoundsBuffer[l];
const float3 vMa = g_vBoundsBuffer[l+g_iNrVisibLights];
if( all(vMa>vTileLL) && all(vMi<vTileUR))
{
unsigned int uInc = 1;
unsigned int uIndex;
InterlockedAdd(lightOffs, uInc, uIndex);
if(uIndex<MAX_NR_COARSE_ENTRIES) coarseList[uIndex] = l; // add to light list
}
}
#ifdef FINE_PRUNING_ENABLED
if(t<2) ldsDoesLightIntersect[t] = 0;
#endif
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL)
GroupMemoryBarrierWithGroupSync();
#endif
int iNrCoarseLights = min(lightOffs,MAX_NR_COARSE_ENTRIES);
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS
iNrCoarseLights = SphericalIntersectionTests( t, iNrCoarseLights, float2(min(viTilLL.xy+uint2(16/2,16/2), uint2(iWidth-1, iHeight-1))) );
#endif
#ifndef FINE_PRUNING_ENABLED
{
if((int)t<iNrCoarseLights) prunedList[t] = coarseList[t];
if(t==0) ldsNrLightsFinal=iNrCoarseLights;
}
#else
{
// initializes ldsNrLightsFinal with the number of accepted lights.
// all accepted entries delivered in prunedList[].
FinePruneLights(t, iNrCoarseLights, viTilLL, vLinDepths);
}
#endif
//
if(t<LIGHTCATEGORY_COUNT) ldsCategoryListCount[t]=0;
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL)
GroupMemoryBarrierWithGroupSync();
#endif
int nrLightsCombinedList = min(ldsNrLightsFinal,MAX_NR_COARSE_ENTRIES);
for(int i=t; i<nrLightsCombinedList; i+=NR_THREADS)
{
InterlockedAdd(ldsCategoryListCount[_LightVolumeData[prunedList[i]].lightCategory], 1);
}
// sort lights (gives a more efficient execution in both deferred and tiled forward lighting).
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL)
SORTLIST(prunedList, nrLightsCombinedList, MAX_NR_COARSE_ENTRIES, t, NR_THREADS);
//MERGESORTLIST(prunedList, coarseList, nrLightsCombinedList, t, NR_THREADS);
#endif
// write lights to global buffers
int localOffs=0;
int offs = tileIDX.y*nrTilesX + tileIDX.x;
// All our cull data are in the same list, but at render time envLights are separated so we need to shit the index
// to make it work correctly
int shiftIndex[LIGHTCATEGORY_COUNT] = {0, 0, _EnvLightIndexShift}; // 3 for now, will throw an error if we change LIGHTCATEGORY_COUNT
for(int category=0; category<LIGHTCATEGORY_COUNT; category++)
{
int nrLightsFinal = ldsCategoryListCount[category];
int nrLightsFinalClamped = nrLightsFinal<MAX_NR_PRUNED_ENTRIES ? nrLightsFinal : MAX_NR_PRUNED_ENTRIES;
const int nrDWords = ((nrLightsFinalClamped+1)+1)>>1;
for(int l=(int) t; l<(int) nrDWords; l += NR_THREADS)
{
// We remap the prunedList index to the original LightData / EnvLightData indices
uint uLow = l==0 ? nrLightsFinalClamped : prunedList[2*l-1+localOffs] - shiftIndex[category];
uint uHigh = prunedList[2 * l + 0 + localOffs] - shiftIndex[category];
g_vLightList[16*offs + l] = (uLow&0xffff) | (uHigh<<16);
}
localOffs += nrLightsFinal;
offs += (nrTilesX*nrTilesY);
}
}
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS
int SphericalIntersectionTests(uint threadID, int iNrCoarseLights, float2 screenCoordinate)
{
if(threadID==0) lightOffsSph = 0;
// make a copy of coarseList in prunedList.
int l;
for(l=threadID; l<iNrCoarseLights; l+=NR_THREADS)
prunedList[l]=coarseList[l];
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL)
GroupMemoryBarrierWithGroupSync();
#endif
#if USE_LEFTHAND_CAMERASPACE
float3 V = GetViewPosFromLinDepth( screenCoordinate, 1.0);
#else
float3 V = GetViewPosFromLinDepth( screenCoordinate, -1.0);
#endif
float onePixDiagDist = GetOnePixDiagWorldDistAtDepthOne();
float halfTileSizeAtZDistOne = 8*onePixDiagDist; // scale by half a tile
for(l=threadID; l<iNrCoarseLights; l+=NR_THREADS)
{
SFiniteLightBound lightData = g_data[prunedList[l]];
if( DoesSphereOverlapTile(V, halfTileSizeAtZDistOne, lightData.center.xyz, lightData.radius) )
{
unsigned int uIndex;
InterlockedAdd(lightOffsSph, 1, uIndex);
coarseList[uIndex]=prunedList[l]; // read from the original copy of coarseList which is backed up in prunedList
}
}
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL)
GroupMemoryBarrierWithGroupSync();
#endif
return lightOffsSph;
}
#endif
#ifdef FINE_PRUNING_ENABLED
// initializes ldsNrLightsFinal with the number of accepted lights.
// all accepted entries delivered in prunedList[].
void FinePruneLights(uint threadID, int iNrCoarseLights, uint2 viTilLL, float4 vLinDepths)
{
uint t = threadID;
uint iWidth = g_viDimensions.x;
uint iHeight = g_viDimensions.y;
uint uLightsFlags[2] = {0,0};
int l=0;
// need this outer loop even on xb1 and ps4 since direct lights and
// reflection lights are kept in separate regions.
while(l<iNrCoarseLights)
{
// fetch light
int idxCoarse = l<iNrCoarseLights ? coarseList[l] : 0;
uint uLightVolume = l<iNrCoarseLights ? _LightVolumeData[idxCoarse].lightVolume : 0;
// spot
while(l<iNrCoarseLights && uLightVolume==LIGHTVOLUMETYPE_CONE)
{
LightVolumeData lightData = _LightVolumeData[idxCoarse];
// TODO: Change by SebL
const bool bIsSpotDisc = true; // (lightData.flags&IS_CIRCULAR_SPOT_SHAPE) != 0;
// serially check 4 pixels
uint uVal = 0;
for(int i=0; i<4; i++)
{
int idx = t + i*NR_THREADS;
uint2 uPixLoc = min(uint2(viTilLL.x+(idx&0xf), viTilLL.y+(idx>>4)), uint2(iWidth-1, iHeight-1));
float3 vVPos = GetViewPosFromLinDepth(uPixLoc + float2(0.5,0.5), vLinDepths[i]);
// check pixel
float3 fromLight = vVPos-lightData.lightPos.xyz;
float distSq = dot(fromLight,fromLight);
const float fSclProj = dot(fromLight, lightData.lightAxisZ.xyz); // spotDir = lightData.lightAxisZ.xyz
float2 V = abs( float2( dot(fromLight, lightData.lightAxisX.xyz), dot(fromLight, lightData.lightAxisY.xyz) ) );
float fDist2D = bIsSpotDisc ? length(V) : max(V.x,V.y);
if( all( float2(lightData.radiusSq, fSclProj) > float2(distSq, fDist2D*lightData.cotan) ) ) uVal = 1;
}
uLightsFlags[l<32 ? 0 : 1] |= (uVal<<(l&31));
++l; idxCoarse = l<iNrCoarseLights ? coarseList[l] : 0;
uLightVolume = l<iNrCoarseLights ? _LightVolumeData[idxCoarse].lightVolume : 0;
}
// sphere
while(l<iNrCoarseLights && uLightVolume==LIGHTVOLUMETYPE_SPHERE)
{
LightVolumeData lightData = _LightVolumeData[idxCoarse];
// serially check 4 pixels
uint uVal = 0;
for(int i=0; i<4; i++)
{
int idx = t + i*NR_THREADS;
uint2 uPixLoc = min(uint2(viTilLL.x+(idx&0xf), viTilLL.y+(idx>>4)), uint2(iWidth-1, iHeight-1));
float3 vVPos = GetViewPosFromLinDepth(uPixLoc + float2(0.5,0.5), vLinDepths[i]);
// check pixel
float3 vLp = lightData.lightPos.xyz;
float3 toLight = vLp - vVPos;
float distSq = dot(toLight,toLight);
if(lightData.radiusSq>distSq) uVal = 1;
}
uLightsFlags[l<32 ? 0 : 1] |= (uVal<<(l&31));
++l; idxCoarse = l<iNrCoarseLights ? coarseList[l] : 0;
uLightVolume = l<iNrCoarseLights ? _LightVolumeData[idxCoarse].lightVolume : 0;
}
// Box
while(l<iNrCoarseLights && uLightVolume==LIGHTVOLUMETYPE_BOX)
{
LightVolumeData lightData = _LightVolumeData[idxCoarse];
// serially check 4 pixels
uint uVal = 0;
for(int i=0; i<4; i++)
{
int idx = t + i*NR_THREADS;
uint2 uPixLoc = min(uint2(viTilLL.x+(idx&0xf), viTilLL.y+(idx>>4)), uint2(iWidth-1, iHeight-1));
float3 vVPos = GetViewPosFromLinDepth(uPixLoc + float2(0.5,0.5), vLinDepths[i]);
// check pixel
float3 toLight = lightData.lightPos.xyz - vVPos;
float3 dist = float3( dot(toLight, lightData.lightAxisX), dot(toLight, lightData.lightAxisY), dot(toLight, lightData.lightAxisZ) );
dist = (abs(dist) - lightData.boxInnerDist) * lightData.boxInvRange; // not as efficient as it could be
if( max(max(dist.x, dist.y), dist.z)<1 ) uVal = 1; // but allows us to not write out OuterDists
}
uLightsFlags[l<32 ? 0 : 1] |= (uVal<<(l&31));
++l; idxCoarse = l<iNrCoarseLights ? coarseList[l] : 0;
uLightVolume = l<iNrCoarseLights ? _LightVolumeData[idxCoarse].lightVolume : 0;
}
// in case we have some corrupt data make sure we terminate
if(uLightVolume >=LIGHTVOLUMETYPE_COUNT) ++l;
}
InterlockedOr(ldsDoesLightIntersect[0], uLightsFlags[0]);
InterlockedOr(ldsDoesLightIntersect[1], uLightsFlags[1]);
if(t==0) ldsNrLightsFinal = 0;
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL)
GroupMemoryBarrierWithGroupSync();
#endif
if(t<(uint) iNrCoarseLights && (ldsDoesLightIntersect[t<32 ? 0 : 1]&(1<<(t&31)))!=0 )
{
unsigned int uInc = 1;
unsigned int uIndex;
InterlockedAdd(ldsNrLightsFinal, uInc, uIndex);
if(uIndex<MAX_NR_COARSE_ENTRIES) prunedList[uIndex] = coarseList[t]; // we allow up to 64 pruned lights while stored in LDS.
}
}
#endif
// The implementation is based on the demo on "fine pruned tiled lighting" published in GPU Pro 7.
// https://github.com/wolfgangfengel/GPU-Pro-7
#pragma kernel TileLightListGen LIGHTLISTGEN=TileLightListGen
#pragma kernel TileLightListGen_SrcBigTile LIGHTLISTGEN=TileLightListGen_SrcBigTile USE_TWO_PASS_TILED_LIGHTING
#pragma kernel TileLightListGen_FeatureFlags LIGHTLISTGEN=TileLightListGen_FeatureFlags USE_FEATURE_FLAGS
#pragma kernel TileLightListGen_SrcBigTile_FeatureFlags LIGHTLISTGEN=TileLightListGen_SrcBigTile_FeatureFlags USE_TWO_PASS_TILED_LIGHTING USE_FEATURE_FLAGS
#pragma #pragma enable_d3d11_debug_symbols
#include "../../../../ShaderLibrary/common.hlsl"
#include "../ShaderBase.hlsl"
#include "../TilePass.cs.hlsl"
#include "../LightingConvexHullUtils.hlsl"
#include "../FeatureFlags.hlsl"
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL)
#include "../SortingComputeUtils.hlsl"
#endif
#define FINE_PRUNING_ENABLED
#define PERFORM_SPHERICAL_INTERSECTION_TESTS
uniform int g_iNrVisibLights;
uniform uint2 g_viDimensions;
uniform float4x4 g_mInvScrProjection;
uniform float4x4 g_mScrProjection;
uniform int _EnvLightIndexShift;
Texture2D g_depth_tex : register( t0 );
StructuredBuffer<float3> g_vBoundsBuffer : register( t1 );
StructuredBuffer<LightVolumeData> _LightVolumeData : register(t2);
StructuredBuffer<SFiniteLightBound> g_data : register( t3 );
#ifdef USE_TWO_PASS_TILED_LIGHTING
StructuredBuffer<uint> g_vBigTileLightList : register( t4 ); // don't support Buffer yet in unity
#endif
#define NR_THREADS 64
// output buffer
RWStructuredBuffer<uint> g_vLightList : register( u0 ); // don't support RWBuffer yet in unity
#define MAX_NR_COARSE_ENTRIES 64
#define MAX_NR_PRUNED_ENTRIES 24
groupshared unsigned int coarseList[MAX_NR_COARSE_ENTRIES];
groupshared unsigned int prunedList[MAX_NR_COARSE_ENTRIES]; // temporarily support room for all 64 while in LDS
groupshared uint ldsZMin;
groupshared uint ldsZMax;
groupshared uint lightOffs;
#ifdef FINE_PRUNING_ENABLED
groupshared uint ldsDoesLightIntersect[2];
#endif
groupshared int ldsNrLightsFinal;
groupshared int ldsCategoryListCount[LIGHTCATEGORY_COUNT]; // since LIGHTCATEGORY_COUNT is 3
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS
groupshared uint lightOffsSph;
#endif
uniform uint g_BaseFeatureFlags;
#ifdef USE_FEATURE_FLAGS
groupshared uint ldsFeatureFlags;
RWBuffer<uint> g_DispatchIndirectBuffer;
RWStructuredBuffer<uint> g_TileList;
#endif
//float GetLinearDepth(float3 vP)
//{
// float4 v4Pres = mul(g_mInvScrProjection, float4(vP,1.0));
// return v4Pres.z / v4Pres.w;
//}
float GetLinearDepth(float zDptBufSpace) // 0 is near 1 is far
{
float3 vP = float3(0.0f,0.0f,zDptBufSpace);
float4 v4Pres = mul(g_mInvScrProjection, float4(vP,1.0));
return v4Pres.z / v4Pres.w;
}
float3 GetViewPosFromLinDepth(float2 v2ScrPos, float fLinDepth)
{
float fSx = g_mScrProjection[0].x;
float fCx = g_mScrProjection[0].z;
float fSy = g_mScrProjection[1].y;
float fCy = g_mScrProjection[1].z;
#if USE_LEFTHAND_CAMERASPACE
return fLinDepth*float3( ((v2ScrPos.x-fCx)/fSx), ((v2ScrPos.y-fCy)/fSy), 1.0 );
#else
return fLinDepth*float3( -((v2ScrPos.x+fCx)/fSx), -((v2ScrPos.y+fCy)/fSy), 1.0 );
#endif
}
float GetOnePixDiagWorldDistAtDepthOne()
{
float fSx = g_mScrProjection[0].x;
float fSy = g_mScrProjection[1].y;
return length( float2(1.0/fSx,1.0/fSy) );
}
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS
int SphericalIntersectionTests(uint threadID, int iNrCoarseLights, float2 screenCoordinate);
#endif
#ifdef FINE_PRUNING_ENABLED
void FinePruneLights(uint threadID, int iNrCoarseLights, uint2 viTilLL, float4 vLinDepths);
#endif
[numthreads(NR_THREADS, 1, 1)]
void LIGHTLISTGEN(uint threadID : SV_GroupIndex, uint3 u3GroupID : SV_GroupID)
{
uint2 tileIDX = u3GroupID.xy;
uint t=threadID;
if(t<MAX_NR_COARSE_ENTRIES)
prunedList[t]=0;
uint iWidth = g_viDimensions.x;
uint iHeight = g_viDimensions.y;
uint nrTilesX = (iWidth+15)/16;
uint nrTilesY = (iHeight+15)/16;
uint nrTiles = nrTilesX * nrTilesY; // Precompute?
// build tile scr boundary
const uint uFltMax = 0x7f7fffff; // FLT_MAX as a uint
if(t==0)
{
ldsZMin = uFltMax;
ldsZMax = 0;
lightOffs = 0;
}
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL)
GroupMemoryBarrierWithGroupSync();
#endif
uint2 viTilLL = 16*tileIDX;
// establish min and max depth first
float dpt_mi=asfloat(uFltMax), dpt_ma=0.0;
float4 vLinDepths;
{
// Fetch depths and calculate min/max
[unroll]
for(int i = 0; i < 4; i++)
{
int idx = i * NR_THREADS + t;
uint2 uCrd = min( uint2(viTilLL.x+(idx&0xf), viTilLL.y+(idx>>4)), uint2(iWidth-1, iHeight-1) );
const float fDepth = FetchDepth(g_depth_tex, uCrd);
vLinDepths[i] = GetLinearDepth(fDepth);
if(fDepth<VIEWPORT_SCALE_Z) // if not skydome
{
dpt_mi = min(fDepth, dpt_mi);
dpt_ma = max(fDepth, dpt_ma);
}
}
InterlockedMax(ldsZMax, asuint(dpt_ma));
InterlockedMin(ldsZMin, asuint(dpt_mi));
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL)
GroupMemoryBarrierWithGroupSync();
#endif
}
float3 vTileLL = float3(viTilLL.x/(float) iWidth, viTilLL.y/(float) iHeight, asfloat(ldsZMin));
float3 vTileUR = float3((viTilLL.x+16)/(float) iWidth, (viTilLL.y+16)/(float) iHeight, asfloat(ldsZMax));
vTileUR.xy = min(vTileUR.xy,float2(1.0,1.0)).xy;
// build coarse list using AABB
#ifdef USE_TWO_PASS_TILED_LIGHTING
int NrBigTilesX = (nrTilesX+3)>>2;
const int bigTileIdx = (tileIDX.y>>2)*NrBigTilesX + (tileIDX.x>>2); // map the idx to 64x64 tiles
int nrBigTileLights = g_vBigTileLightList[MAX_NR_BIGTILE_LIGHTS_PLUSONE*bigTileIdx+0];
for(int l0=(int) t; l0<(int) nrBigTileLights; l0 += NR_THREADS)
{
int l = g_vBigTileLightList[MAX_NR_BIGTILE_LIGHTS_PLUSONE*bigTileIdx+l0+1];
#else
for(int l=(int) t; l<(int) g_iNrVisibLights; l += NR_THREADS)
{
#endif
const float3 vMi = g_vBoundsBuffer[l];
const float3 vMa = g_vBoundsBuffer[l+g_iNrVisibLights];
if( all(vMa>vTileLL) && all(vMi<vTileUR))
{
unsigned int uInc = 1;
unsigned int uIndex;
InterlockedAdd(lightOffs, uInc, uIndex);
if(uIndex<MAX_NR_COARSE_ENTRIES) coarseList[uIndex] = l; // add to light list
}
}
#ifdef FINE_PRUNING_ENABLED
if(t<2) ldsDoesLightIntersect[t] = 0;
#endif
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL)
GroupMemoryBarrierWithGroupSync();
#endif
int iNrCoarseLights = min(lightOffs,MAX_NR_COARSE_ENTRIES);
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS
iNrCoarseLights = SphericalIntersectionTests( t, iNrCoarseLights, float2(min(viTilLL.xy+uint2(16/2,16/2), uint2(iWidth-1, iHeight-1))) );
#endif
#ifndef FINE_PRUNING_ENABLED
{
if((int)t<iNrCoarseLights) prunedList[t] = coarseList[t];
if(t==0) ldsNrLightsFinal=iNrCoarseLights;
}
#else
{
// initializes ldsNrLightsFinal with the number of accepted lights.
// all accepted entries delivered in prunedList[].
FinePruneLights(t, iNrCoarseLights, viTilLL, vLinDepths);
}
#endif
//
if(t<LIGHTCATEGORY_COUNT) ldsCategoryListCount[t]=0;
#ifdef USE_FEATURE_FLAGS
if(t==0) ldsFeatureFlags=0;
#endif
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL)
GroupMemoryBarrierWithGroupSync();
#endif
int nrLightsCombinedList = min(ldsNrLightsFinal,MAX_NR_COARSE_ENTRIES);
for(int i=t; i<nrLightsCombinedList; i+=NR_THREADS)
{
InterlockedAdd(ldsCategoryListCount[_LightVolumeData[prunedList[i]].lightCategory], 1);
#ifdef USE_FEATURE_FLAGS
InterlockedOr(ldsFeatureFlags, _LightVolumeData[prunedList[i]].featureFlags);
#endif
}
// sort lights (gives a more efficient execution in both deferred and tiled forward lighting).
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL)
SORTLIST(prunedList, nrLightsCombinedList, MAX_NR_COARSE_ENTRIES, t, NR_THREADS);
//MERGESORTLIST(prunedList, coarseList, nrLightsCombinedList, t, NR_THREADS);
#endif
#ifdef USE_FEATURE_FLAGS
if(t == 0)
{
uint featureFlags = g_BaseFeatureFlags | ldsFeatureFlags;
if(ldsZMax < ldsZMin) // is background pixel
{
featureFlags &= ~(FEATURE_FLAG_PUNCTUAL_LIGHT | FEATURE_FLAG_AREA_LIGHT | FEATURE_FLAG_DIRECTIONAL_LIGHT | FEATURE_FLAG_ENV_LIGHT); // list of features that are not enabled on background
}
uint variant = FeatureFlagsToTileVariant(featureFlags);
uint offset;
InterlockedAdd(g_DispatchIndirectBuffer[variant * 3 + 0], 1, offset);
g_TileList[variant*nrTiles + offset] = (tileIDX.y << 16) + tileIDX.x;
}
#endif
// write lights to global buffers
int localOffs=0;
int offs = tileIDX.y*nrTilesX + tileIDX.x;
// All our cull data are in the same list, but at render time envLights are separated so we need to shit the index
// to make it work correctly
int shiftIndex[LIGHTCATEGORY_COUNT] = {0, 0, _EnvLightIndexShift}; // 3 for now, will throw an error if we change LIGHTCATEGORY_COUNT
for(int category=0; category<LIGHTCATEGORY_COUNT; category++)
{
int nrLightsFinal = ldsCategoryListCount[category];
int nrLightsFinalClamped = nrLightsFinal<MAX_NR_PRUNED_ENTRIES ? nrLightsFinal : MAX_NR_PRUNED_ENTRIES;
const int nrDWords = ((nrLightsFinalClamped+1)+1)>>1;
for(int l=(int) t; l<(int) nrDWords; l += NR_THREADS)
{
// We remap the prunedList index to the original LightData / EnvLightData indices
uint uLow = l==0 ? nrLightsFinalClamped : prunedList[2 * l - 1 + localOffs] - shiftIndex[category];
uint uHigh = prunedList[2 * l + 0 + localOffs] - shiftIndex[category];
g_vLightList[16*offs + l] = (uLow&0xffff) | (uHigh<<16);
}
localOffs += nrLightsFinal;
offs += (nrTilesX*nrTilesY);
}
}
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS
int SphericalIntersectionTests(uint threadID, int iNrCoarseLights, float2 screenCoordinate)
{
if(threadID==0) lightOffsSph = 0;
// make a copy of coarseList in prunedList.
int l;
for(l=threadID; l<iNrCoarseLights; l+=NR_THREADS)
prunedList[l]=coarseList[l];
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL)
GroupMemoryBarrierWithGroupSync();
#endif
#if USE_LEFTHAND_CAMERASPACE
float3 V = GetViewPosFromLinDepth( screenCoordinate, 1.0);
#else
float3 V = GetViewPosFromLinDepth( screenCoordinate, -1.0);
#endif
float onePixDiagDist = GetOnePixDiagWorldDistAtDepthOne();
float halfTileSizeAtZDistOne = 8*onePixDiagDist; // scale by half a tile
for(l=threadID; l<iNrCoarseLights; l+=NR_THREADS)
{
SFiniteLightBound lightData = g_data[prunedList[l]];
if( DoesSphereOverlapTile(V, halfTileSizeAtZDistOne, lightData.center.xyz, lightData.radius) )
{
unsigned int uIndex;
InterlockedAdd(lightOffsSph, 1, uIndex);
coarseList[uIndex]=prunedList[l]; // read from the original copy of coarseList which is backed up in prunedList
}
}
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL)
GroupMemoryBarrierWithGroupSync();
#endif
return lightOffsSph;
}
#endif
#ifdef FINE_PRUNING_ENABLED
// initializes ldsNrLightsFinal with the number of accepted lights.
// all accepted entries delivered in prunedList[].
void FinePruneLights(uint threadID, int iNrCoarseLights, uint2 viTilLL, float4 vLinDepths)
{
uint t = threadID;
uint iWidth = g_viDimensions.x;
uint iHeight = g_viDimensions.y;
uint uLightsFlags[2] = {0,0};
int l=0;
// need this outer loop even on xb1 and ps4 since direct lights and
// reflection lights are kept in separate regions.
while(l<iNrCoarseLights)
{
// fetch light
int idxCoarse = l<iNrCoarseLights ? coarseList[l] : 0;
uint uLightVolume = l<iNrCoarseLights ? _LightVolumeData[idxCoarse].lightVolume : 0;
// spot
while(l<iNrCoarseLights && uLightVolume==LIGHTVOLUMETYPE_CONE)
{
LightVolumeData lightData = _LightVolumeData[idxCoarse];
// TODO: Change by SebL
const bool bIsSpotDisc = true; // (lightData.flags&IS_CIRCULAR_SPOT_SHAPE) != 0;
// serially check 4 pixels
uint uVal = 0;
for(int i=0; i<4; i++)
{
int idx = t + i*NR_THREADS;
uint2 uPixLoc = min(uint2(viTilLL.x+(idx&0xf), viTilLL.y+(idx>>4)), uint2(iWidth-1, iHeight-1));
float3 vVPos = GetViewPosFromLinDepth(uPixLoc + float2(0.5,0.5), vLinDepths[i]);
// check pixel
float3 fromLight = vVPos-lightData.lightPos.xyz;
float distSq = dot(fromLight,fromLight);
const float fSclProj = dot(fromLight, lightData.lightAxisZ.xyz); // spotDir = lightData.lightAxisZ.xyz
float2 V = abs( float2( dot(fromLight, lightData.lightAxisX.xyz), dot(fromLight, lightData.lightAxisY.xyz) ) );
float fDist2D = bIsSpotDisc ? length(V) : max(V.x,V.y);
if( all( float2(lightData.radiusSq, fSclProj) > float2(distSq, fDist2D*lightData.cotan) ) ) uVal = 1;
}
uLightsFlags[l<32 ? 0 : 1] |= (uVal<<(l&31));
++l; idxCoarse = l<iNrCoarseLights ? coarseList[l] : 0;
uLightVolume = l<iNrCoarseLights ? _LightVolumeData[idxCoarse].lightVolume : 0;
}
// sphere
while(l<iNrCoarseLights && uLightVolume==LIGHTVOLUMETYPE_SPHERE)
{
LightVolumeData lightData = _LightVolumeData[idxCoarse];
// serially check 4 pixels
uint uVal = 0;
for(int i=0; i<4; i++)
{
int idx = t + i*NR_THREADS;
uint2 uPixLoc = min(uint2(viTilLL.x+(idx&0xf), viTilLL.y+(idx>>4)), uint2(iWidth-1, iHeight-1));
float3 vVPos = GetViewPosFromLinDepth(uPixLoc + float2(0.5,0.5), vLinDepths[i]);
// check pixel
float3 vLp = lightData.lightPos.xyz;
float3 toLight = vLp - vVPos;
float distSq = dot(toLight,toLight);
if(lightData.radiusSq>distSq) uVal = 1;
}
uLightsFlags[l<32 ? 0 : 1] |= (uVal<<(l&31));
++l; idxCoarse = l<iNrCoarseLights ? coarseList[l] : 0;
uLightVolume = l<iNrCoarseLights ? _LightVolumeData[idxCoarse].lightVolume : 0;
}
// Box
while(l<iNrCoarseLights && uLightVolume==LIGHTVOLUMETYPE_BOX)
{
LightVolumeData lightData = _LightVolumeData[idxCoarse];
// serially check 4 pixels
uint uVal = 0;
for(int i=0; i<4; i++)
{
int idx = t + i*NR_THREADS;
uint2 uPixLoc = min(uint2(viTilLL.x+(idx&0xf), viTilLL.y+(idx>>4)), uint2(iWidth-1, iHeight-1));
float3 vVPos = GetViewPosFromLinDepth(uPixLoc + float2(0.5,0.5), vLinDepths[i]);
// check pixel
float3 toLight = lightData.lightPos.xyz - vVPos;
float3 dist = float3( dot(toLight, lightData.lightAxisX), dot(toLight, lightData.lightAxisY), dot(toLight, lightData.lightAxisZ) );
dist = (abs(dist) - lightData.boxInnerDist) * lightData.boxInvRange; // not as efficient as it could be
if( max(max(dist.x, dist.y), dist.z)<1 ) uVal = 1; // but allows us to not write out OuterDists
}
uLightsFlags[l<32 ? 0 : 1] |= (uVal<<(l&31));
++l; idxCoarse = l<iNrCoarseLights ? coarseList[l] : 0;
uLightVolume = l<iNrCoarseLights ? _LightVolumeData[idxCoarse].lightVolume : 0;
}
// in case we have some corrupt data make sure we terminate
if(uLightVolume >=LIGHTVOLUMETYPE_COUNT) ++l;
}
InterlockedOr(ldsDoesLightIntersect[0], uLightsFlags[0]);
InterlockedOr(ldsDoesLightIntersect[1], uLightsFlags[1]);
if(t==0) ldsNrLightsFinal = 0;
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL)
GroupMemoryBarrierWithGroupSync();
#endif
if(t<(uint) iNrCoarseLights && (ldsDoesLightIntersect[t<32 ? 0 : 1]&(1<<(t&31)))!=0 )
{
unsigned int uInc = 1;
unsigned int uIndex;
InterlockedAdd(ldsNrLightsFinal, uInc, uIndex);
if(uIndex<MAX_NR_COARSE_ENTRIES) prunedList[uIndex] = coarseList[t]; // we allow up to 64 pruned lights while stored in LDS.
}
}
#endif

4
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/scrbound.compute


#pragma kernel ScreenBoundsAABB
#include "ShaderLibrary/common.hlsl"
#include "../../../../ShaderLibrary/common.hlsl"
#include "../TilePass.cs.hlsl"
uniform int g_iNrVisibLights;

#define NR_THREADS 64

185
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/Resources/shadeopaque.compute


#pragma kernel ShadeOpaque_Fptl SHADE_OPAQUE_ENTRY=ShadeOpaque_Fptl USE_FPTL_LIGHTLIST
#pragma kernel ShadeOpaque_Fptl_DebugLighting SHADE_OPAQUE_ENTRY=ShadeOpaque_Fptl_DebugLighting USE_FPTL_LIGHTLIST LIGHTING_DEBUG
#pragma kernel ShadeOpaque_Clustered SHADE_OPAQUE_ENTRY=ShadeOpaque_Clustered USE_CLUSTERED_LIGHTLIST
#pragma kernel ShadeOpaque_Clustered_DebugLighting SHADE_OPAQUE_ENTRY=ShadeOpaque_Clustered_DebugLighting USE_CLUSTERED_LIGHTLIST LIGHTING_DEBUG
// Split lighting is required for the SSS pass.
// Not currently possible since we need to access the stencil buffer from the compute shader.
// #pragma multi_compile _ OUTPUT_SPLIT_LIGHTING
#define LIGHTLOOP_TILE_PASS 1
#define LIGHTLOOP_TILE_DIRECT 1
#define LIGHTLOOP_TILE_INDIRECT 1
#define LIGHTLOOP_TILE_ALL 1
#define USE_FPTL_LIGHTLIST 1
//-------------------------------------------------------------------------------------
// Include
//-------------------------------------------------------------------------------------
#include "ShaderLibrary/Common.hlsl"
#include "HDRenderPipeline/Debug/HDRenderPipelineDebug.cs.hlsl"
#include "HDRenderPipeline/Debug/DebugLighting.hlsl"
// Note: We have fix as guidelines that we have only one deferred material (with control of GBuffer enabled). Mean a users that add a new
// deferred material must replace the old one here. If in the future we want to support multiple layout (cause a lot of consistency problem),
// the deferred shader will require to use multicompile.
#define UNITY_MATERIAL_LIT // Need to be define before including Material.hlsl
#include "HDRenderPipeline/ShaderConfig.cs.hlsl"
#include "HDRenderPipeline/ShaderVariables.hlsl"
#include "HDRenderPipeline/Lighting/Lighting.hlsl" // This include Material.hlsl
//-------------------------------------------------------------------------------------
// variable declaration
//-------------------------------------------------------------------------------------
DECLARE_GBUFFER_TEXTURE(_GBufferTexture);
TEXTURE2D_FLOAT(_CameraDepthTexture);
SAMPLER2D(sampler_CameraDepthTexture);
#ifdef OUTPUT_SPLIT_LIGHTING
RWTexture2D<float4> specularLightingUAV;
RWTexture2D<float3> diffuseLightingUAV;
#else
RWTexture2D<float4> combinedLightingUAV;
#endif
[numthreads(TILE_SIZE, TILE_SIZE, 1)]
void SHADE_OPAQUE_ENTRY(uint2 dispatchThreadId : SV_DispatchThreadID, uint2 groupId : SV_GroupID)
{
// input.positionCS is SV_Position
uint2 pixelCoord = dispatchThreadId;
PositionInputs posInput = GetPositionInput(pixelCoord.xy, _ScreenSize.zw);
float depth = LOAD_TEXTURE2D(_CameraDepthTexture, posInput.unPositionSS).x;
UpdatePositionInput(depth, _InvViewProjMatrix, _ViewProjMatrix, posInput);
float3 V = GetWorldSpaceNormalizeViewDir(posInput.positionWS);
FETCH_GBUFFER(gbuffer, _GBufferTexture, posInput.unPositionSS);
BSDFData bsdfData;
float3 bakeDiffuseLighting;
DECODE_FROM_GBUFFER(gbuffer, bsdfData, bakeDiffuseLighting);
PreLightData preLightData = GetPreLightData(V, posInput, bsdfData);
float3 diffuseLighting;
float3 specularLighting;
LightLoop(V, posInput, preLightData, bsdfData, bakeDiffuseLighting, diffuseLighting, specularLighting);
#ifdef OUTPUT_SPLIT_LIGHTING
specularLightingUAV[pixelCoord] = float4(specularLighting, 1.0);
diffuseLightingUAV[pixelCoord] = diffuseLighting;
#else
combinedLightingUAV[pixelCoord] = float4(diffuseLighting + specularLighting, 1.0);
#endif
}
#pragma kernel ShadeOpaque_Direct_Fptl SHADE_OPAQUE_ENTRY=ShadeOpaque_Direct_Fptl USE_FPTL_LIGHTLIST
#pragma kernel ShadeOpaque_Direct_Fptl_DebugLighting SHADE_OPAQUE_ENTRY=ShadeOpaque_Direct_Fptl_DebugLighting USE_FPTL_LIGHTLIST LIGHTING_DEBUG
#pragma kernel ShadeOpaque_Direct_Clustered SHADE_OPAQUE_ENTRY=ShadeOpaque_Direct_Clustered USE_CLUSTERED_LIGHTLIST
#pragma kernel ShadeOpaque_Direct_Clustered_DebugLighting SHADE_OPAQUE_ENTRY=ShadeOpaque_Direct_Clustered_DebugLighting USE_CLUSTERED_LIGHTLIST LIGHTING_DEBUG
#pragma kernel ShadeOpaque_Indirect_Fptl_Variant0 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Fptl_Variant0 USE_FPTL_LIGHTLIST USE_INDIRECT VARIANT=0
#pragma kernel ShadeOpaque_Indirect_Fptl_Variant1 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Fptl_Variant1 USE_FPTL_LIGHTLIST USE_INDIRECT VARIANT=1
#pragma kernel ShadeOpaque_Indirect_Fptl_Variant2 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Fptl_Variant2 USE_FPTL_LIGHTLIST USE_INDIRECT VARIANT=2
#pragma kernel ShadeOpaque_Indirect_Fptl_Variant3 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Fptl_Variant3 USE_FPTL_LIGHTLIST USE_INDIRECT VARIANT=3
#pragma kernel ShadeOpaque_Indirect_Fptl_Variant4 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Fptl_Variant4 USE_FPTL_LIGHTLIST USE_INDIRECT VARIANT=4
#pragma kernel ShadeOpaque_Indirect_Fptl_Variant5 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Fptl_Variant5 USE_FPTL_LIGHTLIST USE_INDIRECT VARIANT=5
#pragma kernel ShadeOpaque_Indirect_Fptl_Variant6 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Fptl_Variant6 USE_FPTL_LIGHTLIST USE_INDIRECT VARIANT=6
#pragma kernel ShadeOpaque_Indirect_Fptl_Variant7 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Fptl_Variant7 USE_FPTL_LIGHTLIST USE_INDIRECT VARIANT=7
#pragma kernel ShadeOpaque_Indirect_Clustered_Variant0 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Clustered_Variant0 USE_CLUSTERED_LIGHTLIST USE_INDIRECT VARIANT=0
#pragma kernel ShadeOpaque_Indirect_Clustered_Variant1 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Clustered_Variant1 USE_CLUSTERED_LIGHTLIST USE_INDIRECT VARIANT=1
#pragma kernel ShadeOpaque_Indirect_Clustered_Variant2 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Clustered_Variant2 USE_CLUSTERED_LIGHTLIST USE_INDIRECT VARIANT=2
#pragma kernel ShadeOpaque_Indirect_Clustered_Variant3 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Clustered_Variant3 USE_CLUSTERED_LIGHTLIST USE_INDIRECT VARIANT=3
#pragma kernel ShadeOpaque_Indirect_Clustered_Variant4 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Clustered_Variant4 USE_CLUSTERED_LIGHTLIST USE_INDIRECT VARIANT=4
#pragma kernel ShadeOpaque_Indirect_Clustered_Variant5 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Clustered_Variant5 USE_CLUSTERED_LIGHTLIST USE_INDIRECT VARIANT=5
#pragma kernel ShadeOpaque_Indirect_Clustered_Variant6 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Clustered_Variant6 USE_CLUSTERED_LIGHTLIST USE_INDIRECT VARIANT=6
#pragma kernel ShadeOpaque_Indirect_Clustered_Variant7 SHADE_OPAQUE_ENTRY=ShadeOpaque_Indirect_Clustered_Variant7 USE_CLUSTERED_LIGHTLIST USE_INDIRECT VARIANT=7
#pragma #pragma enable_d3d11_debug_symbols
// Split lighting is required for the SSS pass.
// Not currently possible since we need to access the stencil buffer from the compute shader.
// #pragma multi_compile _ OUTPUT_SPLIT_LIGHTING
#define LIGHTLOOP_TILE_PASS 1
#define LIGHTLOOP_TILE_DIRECT 1
#define LIGHTLOOP_TILE_INDIRECT 1
#define LIGHTLOOP_TILE_ALL 1
//-------------------------------------------------------------------------------------
// Include
//-------------------------------------------------------------------------------------
#include "../../../../ShaderLibrary/Common.hlsl"
#include "../../../Debug/HDRenderPipelineDebug.cs.hlsl"
#include "../../../Debug/DebugLighting.hlsl"
// Note: We have fix as guidelines that we have only one deferred material (with control of GBuffer enabled). Mean a users that add a new
// deferred material must replace the old one here. If in the future we want to support multiple layout (cause a lot of consistency problem),
// the deferred shader will require to use multicompile.
#define UNITY_MATERIAL_LIT // Need to be define before including Material.hlsl
#include "../../../ShaderConfig.cs.hlsl"
#include "../../../ShaderVariables.hlsl"
#include "../../../Lighting/Lighting.hlsl" // This include Material.hlsl
#include "../../../Lighting/TilePass/FeatureFlags.hlsl"
//-------------------------------------------------------------------------------------
// variable declaration
//-------------------------------------------------------------------------------------
DECLARE_GBUFFER_TEXTURE(_GBufferTexture);
#ifdef OUTPUT_SPLIT_LIGHTING
RWTexture2D<float4> specularLightingUAV;
RWTexture2D<float3> diffuseLightingUAV;
#else
RWTexture2D<float4> combinedLightingUAV;
#endif
#if USE_INDIRECT
uint g_TileListOffset;
StructuredBuffer<uint> g_TileList;
// Indirect
[numthreads(16, 16, 1)]
void SHADE_OPAQUE_ENTRY(uint2 groupThreadId : SV_GroupThreadID, uint groupId : SV_GroupID)
{
uint tileIndex = g_TileList[g_TileListOffset + groupId];
uint2 tileCoord = uint2(tileIndex & 0xFFFF, tileIndex >> 16);
uint2 pixelCoord = tileCoord * GetTileSize() + groupThreadId;
PositionInputs posInput = GetPositionInput(pixelCoord.xy, _ScreenSize.zw, tileCoord);
uint featureFlags = TileVariantToFeatureFlags(VARIANT);
#else
// Direct
[numthreads(16, 16, 1)]
void SHADE_OPAQUE_ENTRY(uint2 dispatchThreadId : SV_DispatchThreadID, uint2 groupId : SV_GroupID)
{
uint2 pixelCoord = dispatchThreadId;
PositionInputs posInput = GetPositionInput(pixelCoord.xy, _ScreenSize.zw, groupId);
uint featureFlags = 0xFFFFFFFF;
#endif
float depth = LOAD_TEXTURE2D(_MainDepthTexture, posInput.unPositionSS).x;
UpdatePositionInput(depth, _InvViewProjMatrix, _ViewProjMatrix, posInput);
float3 V = GetWorldSpaceNormalizeViewDir(posInput.positionWS);
FETCH_GBUFFER(gbuffer, _GBufferTexture, posInput.unPositionSS);
BSDFData bsdfData;
float3 bakeDiffuseLighting;
DECODE_FROM_GBUFFER(gbuffer, bsdfData, bakeDiffuseLighting);
PreLightData preLightData = GetPreLightData(V, posInput, bsdfData);
float3 diffuseLighting;
float3 specularLighting;
LightLoop(V, posInput, preLightData, bsdfData, bakeDiffuseLighting, featureFlags, diffuseLighting, specularLighting);
#ifdef OUTPUT_SPLIT_LIGHTING
specularLightingUAV[pixelCoord] = float4(specularLighting, 1.0);
diffuseLightingUAV[pixelCoord] = diffuseLighting;
#else
combinedLightingUAV[pixelCoord] = float4(diffuseLighting + specularLighting, 1.0);
#endif
}

584
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePass.cs


#define SHADOWS_ENABLED
#define SHADOWS_ENABLED
#define SHADOWS_FIXSHADOWIDX
using UnityEngine.Rendering;
using System.Collections.Generic;

// enable unity's original left-hand shader camera space (right-hand internally in unity).
public static int USE_LEFTHAND_CAMERASPACE = 1;
public static int TILE_SIZE_FPTL = 16;
public static int TILE_SIZE_CLUSTERED = 32;
// feature flags
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;
// feature variants
public static int NUM_FEATURE_VARIANTS = 8;
}
[GenerateHLSL]

public float cotan;
public Vector3 boxInnerDist;
public float unused;
public uint featureFlags;
public Vector3 boxInvRange;
public float unused2;

private ComputeShader buildPerTileLightListShader { get { return m_PassResources.buildPerTileLightListShader; } }
private ComputeShader buildPerBigTileLightListShader { get { return m_PassResources.buildPerBigTileLightListShader; } }
private ComputeShader buildPerVoxelLightListShader { get { return m_PassResources.buildPerVoxelLightListShader; } }
private ComputeShader clearDispatchIndirectShader { get { return m_PassResources.clearDispatchIndirectShader; } }
private ComputeShader shadeOpaqueShader { get { return m_PassResources.shadeOpaqueShader; } }
static int s_GenAABBKernel;

static int s_shadeOpaqueClusteredKernel;
static int s_shadeOpaqueFptlKernel;
static int s_shadeOpaqueClusteredDebugLightingKernel;
static int s_shadeOpaqueFptlDebugLightingKernel;
static int s_ClearDispatchIndirectKernel;
static int s_shadeOpaqueDirectClusteredKernel;
static int s_shadeOpaqueDirectFptlKernel;
static int s_shadeOpaqueDirectClusteredDebugLightingKernel;
static int s_shadeOpaqueDirectFptlDebugLightingKernel;
static int[] s_shadeOpaqueIndirectClusteredKernels = new int[LightDefinitions.NUM_FEATURE_VARIANTS];
static int[] s_shadeOpaqueIndirectFptlKernels = new int[LightDefinitions.NUM_FEATURE_VARIANTS];
static ComputeBuffer s_TileList = null;
static ComputeBuffer s_DispatchIndirectBuffer = null;
static ComputeBuffer s_BigTileLightList = null; // used for pre-pass coarse culling on 64x64 tiles
static int s_GenListPerBigTileKernel;

{
bool isEnabledMSAA = false;
Debug.Assert(!isEnabledMSAA || m_PassSettings.enableClustered);
bool disableFptl = (m_PassSettings.disableFptlWhenClustered && m_PassSettings.enableClustered) || isEnabledMSAA;
bool disableFptl = (!m_PassSettings.enableFptlForOpaqueWhenClustered && m_PassSettings.enableClustered) || isEnabledMSAA;
return !disableFptl;
}
}

Material m_SingleDeferredMaterialSRT = null;
Material m_SingleDeferredMaterialMRT = null;
const int k_TileSize = 16;
#if (SHADOWS_ENABLED)
// shadow related stuff
FrameId m_FrameId;

#endif
int GetNumTileX(Camera camera)
int GetNumTileFtplX(Camera camera)
{
return (camera.pixelWidth + (LightDefinitions.TILE_SIZE_FPTL - 1)) / LightDefinitions.TILE_SIZE_FPTL;
}
int GetNumTileFtplY(Camera camera)
return (camera.pixelWidth + (k_TileSize - 1)) / k_TileSize;
return (camera.pixelHeight + (LightDefinitions.TILE_SIZE_FPTL - 1)) / LightDefinitions.TILE_SIZE_FPTL;
int GetNumTileY(Camera camera)
int GetNumTileClusteredX(Camera camera)
return (camera.pixelHeight + (k_TileSize - 1)) / k_TileSize;
return (camera.pixelWidth + (LightDefinitions.TILE_SIZE_CLUSTERED - 1)) / LightDefinitions.TILE_SIZE_CLUSTERED;
}
int GetNumTileClusteredY(Camera camera)
{
return (camera.pixelHeight + (LightDefinitions.TILE_SIZE_CLUSTERED - 1)) / LightDefinitions.TILE_SIZE_CLUSTERED;
}
bool GetFeatureVariantsEnabled()
{
return m_PassSettings.enableComputeLightEvaluation && m_PassSettings.enableComputeFeatureVariants;
}
TileLightLoopProducer.TileSettings m_PassSettings;

m_CubeCookieTexArray = new TextureCacheCubemap();
m_CubeCookieTexArray.AllocTextureArray(4, textureSettings.pointCookieSize, TextureFormat.RGBA32, true);
m_CubeReflTexArray = new TextureCacheCubemap();
m_CubeReflTexArray.AllocTextureArray(32, textureSettings.reflectionCubemapSize, TextureFormat.BC6H, true);
m_CubeReflTexArray.AllocTextureArray(32, textureSettings.reflectionCubemapSize, TextureCache.GetPreferredCompressedTextureFormat, true);
s_GenListPerTileKernel = buildPerTileLightListShader.FindKernel(m_PassSettings.enableBigTilePrepass ? "TileLightListGen_SrcBigTile" : "TileLightListGen");
bool enableFeatureVariants = GetFeatureVariantsEnabled();
if (enableFeatureVariants)
{
s_GenListPerTileKernel = buildPerTileLightListShader.FindKernel(m_PassSettings.enableBigTilePrepass ? "TileLightListGen_SrcBigTile_FeatureFlags" : "TileLightListGen_FeatureFlags");
}
else
{
s_GenListPerTileKernel = buildPerTileLightListShader.FindKernel(m_PassSettings.enableBigTilePrepass ? "TileLightListGen_SrcBigTile" : "TileLightListGen");
}
buildScreenAABBShader.SetBuffer(s_GenAABBKernel, "g_data", s_ConvexBoundsBuffer);
buildPerTileLightListShader.SetBuffer(s_GenListPerTileKernel, "g_vBoundsBuffer", s_AABBBoundsBuffer);
buildPerTileLightListShader.SetBuffer(s_GenListPerTileKernel, "_LightVolumeData", s_LightVolumeDataBuffer);
buildPerTileLightListShader.SetBuffer(s_GenListPerTileKernel, "g_data", s_ConvexBoundsBuffer);
s_DispatchIndirectBuffer = new ComputeBuffer(LightDefinitions.NUM_FEATURE_VARIANTS * 3, sizeof(uint), ComputeBufferType.IndirectArguments);
if (m_PassSettings.enableClustered)
{

buildPerVoxelLightListShader.SetBuffer(s_GenListPerVoxelKernel, "g_vBoundsBuffer", s_AABBBoundsBuffer);
buildPerVoxelLightListShader.SetBuffer(s_GenListPerVoxelKernel, "_LightVolumeData", s_LightVolumeDataBuffer);
buildPerVoxelLightListShader.SetBuffer(s_GenListPerVoxelKernel, "g_data", s_ConvexBoundsBuffer);
s_GlobalLightListAtomic = new ComputeBuffer(1, sizeof(uint));
}

buildPerBigTileLightListShader.SetBuffer(s_GenListPerBigTileKernel, "g_vBoundsBuffer", s_AABBBoundsBuffer);
buildPerBigTileLightListShader.SetBuffer(s_GenListPerBigTileKernel, "_LightVolumeData", s_LightVolumeDataBuffer);
buildPerBigTileLightListShader.SetBuffer(s_GenListPerBigTileKernel, "g_data", s_ConvexBoundsBuffer);
s_shadeOpaqueClusteredKernel = shadeOpaqueShader.FindKernel("ShadeOpaque_Clustered");
s_shadeOpaqueFptlKernel = shadeOpaqueShader.FindKernel("ShadeOpaque_Fptl");
s_shadeOpaqueClusteredDebugLightingKernel = shadeOpaqueShader.FindKernel("ShadeOpaque_Clustered_DebugLighting");
s_shadeOpaqueFptlDebugLightingKernel = shadeOpaqueShader.FindKernel("ShadeOpaque_Fptl_DebugLighting");
s_ClearDispatchIndirectKernel = clearDispatchIndirectShader.FindKernel("ClearDispatchIndirect");
s_shadeOpaqueDirectClusteredKernel = shadeOpaqueShader.FindKernel("ShadeOpaque_Direct_Clustered");
s_shadeOpaqueDirectFptlKernel = shadeOpaqueShader.FindKernel("ShadeOpaque_Direct_Fptl");
s_shadeOpaqueDirectClusteredDebugLightingKernel = shadeOpaqueShader.FindKernel("ShadeOpaque_Direct_Clustered_DebugLighting");
s_shadeOpaqueDirectFptlDebugLightingKernel = shadeOpaqueShader.FindKernel("ShadeOpaque_Direct_Fptl_DebugLighting");
for (int variant = 0; variant < LightDefinitions.NUM_FEATURE_VARIANTS; variant++)
{
s_shadeOpaqueIndirectClusteredKernels[variant] = shadeOpaqueShader.FindKernel("ShadeOpaque_Indirect_Clustered_Variant" + variant);
s_shadeOpaqueIndirectFptlKernels[variant] = shadeOpaqueShader.FindKernel("ShadeOpaque_Indirect_Fptl_Variant" + variant);
}
s_TileList = null;
string[] tileKeywords = {"LIGHTLOOP_TILE_DIRECT", "LIGHTLOOP_TILE_INDIRECT", "LIGHTLOOP_TILE_ALL"};

Utilities.SafeRelease(s_AABBBoundsBuffer);
Utilities.SafeRelease(s_ConvexBoundsBuffer);
Utilities.SafeRelease(s_LightVolumeDataBuffer);
Utilities.SafeRelease(s_DispatchIndirectBuffer);
// enableClustered
Utilities.SafeRelease(s_GlobalLightListAtomic);

public override bool NeedResize()
{
return s_LightList == null ||
return s_LightList == null || s_TileList == null ||
(s_BigTileLightList == null && m_PassSettings.enableBigTilePrepass) ||
(s_PerVoxelLightLists == null && m_PassSettings.enableClustered);
}

Utilities.SafeRelease(s_LightList);
Utilities.SafeRelease(s_TileList);
// enableClustered
Utilities.SafeRelease(s_PerVoxelLightLists);

public override void AllocResolutionDependentBuffers(int width, int height)
{
var nrTilesX = (width + k_TileSize - 1) / k_TileSize;
var nrTilesY = (height + k_TileSize - 1) / k_TileSize;
var nrTilesX = (width + LightDefinitions.TILE_SIZE_FPTL - 1) / LightDefinitions.TILE_SIZE_FPTL;
var nrTilesY = (height + LightDefinitions.TILE_SIZE_FPTL - 1) / LightDefinitions.TILE_SIZE_FPTL;
s_TileList = new ComputeBuffer((int)LightDefinitions.NUM_FEATURE_VARIANTS * nrTiles, sizeof(uint));
s_PerVoxelOffset = new ComputeBuffer((int)LightCategory.Count * (1 << k_Log2NumClusters) * nrTiles, sizeof(uint));
s_PerVoxelLightLists = new ComputeBuffer(NumLightIndicesPerClusteredTile() * nrTiles, sizeof(uint));
var nrClustersX = (width + LightDefinitions.TILE_SIZE_CLUSTERED - 1) / LightDefinitions.TILE_SIZE_CLUSTERED;
var nrClustersY = (height + LightDefinitions.TILE_SIZE_CLUSTERED - 1) / LightDefinitions.TILE_SIZE_CLUSTERED;
var nrClusterTiles = nrClustersX * nrClustersY;
s_PerVoxelOffset = new ComputeBuffer((int)LightCategory.Count * (1 << k_Log2NumClusters) * nrClusterTiles, sizeof(uint));
s_PerVoxelLightLists = new ComputeBuffer(NumLightIndicesPerClusteredTile() * nrClusterTiles, sizeof(uint));
s_PerTileLogBaseTweak = new ComputeBuffer(nrTiles, sizeof(float));
s_PerTileLogBaseTweak = new ComputeBuffer(nrClusterTiles, sizeof(float));
}
}

return shadowOutput.GetShadowSliceCountLightIndex(lightIndex);
}
public void GetDirectionalLightData(ShadowSettings shadowSettings, GPULightType gpuLightType, VisibleLight light, AdditionalLightData additionalData, int lightIndex, ref ShadowOutput shadowOutput, ref int directionalShadowcount)
public bool GetDirectionalLightData(ShadowSettings shadowSettings, GPULightType gpuLightType, VisibleLight light, AdditionalLightData additionalData, int lightIndex, ref ShadowOutput shadowOutput, ref int directionalShadowcount)
float diffuseDimmer = m_PassSettings.diffuseGlobalDimmer * additionalData.lightDimmer;
float specularDimmer = m_PassSettings.specularGlobalDimmer * additionalData.lightDimmer;
if (diffuseDimmer <= 0.0f && specularDimmer <= 0.0f)
return false;
// Light direction for directional is opposite to the forward direction
directionalLightData.forward = light.light.transform.forward;
directionalLightData.up = light.light.transform.up;

directionalLightData.diffuseScale = additionalData.affectDiffuse ? 1.0f : 0.0f;
directionalLightData.specularScale = additionalData.affectSpecular ? 1.0f : 0.0f;
directionalLightData.diffuseScale = additionalData.affectDiffuse ? diffuseDimmer : 0.0f;
directionalLightData.specularScale = additionalData.affectSpecular ? specularDimmer : 0.0f;
directionalLightData.invScaleX = 1.0f / light.light.transform.localScale.x;
directionalLightData.invScaleY = 1.0f / light.light.transform.localScale.y;
directionalLightData.cosAngle = 0.0f;

}
m_lightList.directionalLights.Add(directionalLightData);
return true;
public void GetLightData(ShadowSettings shadowSettings, GPULightType gpuLightType, VisibleLight light, AdditionalLightData additionalData, int lightIndex, ref ShadowOutput shadowOutput, ref int shadowCount)
float ComputeLinearDistanceFade(float distanceToCamera, float fadeDistance)
{
// Fade with distance calculation is just a linear fade from 90% of fade distance to fade distance. 90% arbitrarly chosen but should work well enough.
float distanceFadeNear = 0.9f * fadeDistance;
return 1.0f - Mathf.Clamp01((distanceToCamera - distanceFadeNear) / (fadeDistance - distanceFadeNear));
}
public bool GetLightData(ShadowSettings shadowSettings, Camera camera, GPULightType gpuLightType, VisibleLight light, AdditionalLightData additionalData, int lightIndex, ref ShadowOutput shadowOutput, ref int shadowCount)
{
var lightData = new LightData();

lightData.angleOffset = 2.0f;
}
lightData.diffuseScale = additionalData.affectDiffuse ? 1.0f : 0.0f;
lightData.specularScale = additionalData.affectSpecular ? 1.0f : 0.0f;
lightData.shadowDimmer = additionalData.shadowDimmer;
float distanceToCamera = (lightData.positionWS - camera.transform.position).magnitude;
float distanceFade = ComputeLinearDistanceFade(distanceToCamera, additionalData.fadeDistance);
float lightScale = additionalData.lightDimmer * distanceFade;
lightData.diffuseScale = additionalData.affectDiffuse ? lightScale * m_PassSettings.diffuseGlobalDimmer : 0.0f;
lightData.specularScale = additionalData.affectSpecular ? lightScale * m_PassSettings.specularGlobalDimmer : 0.0f;
if (lightData.diffuseScale <= 0.0f && lightData.specularScale <= 0.0f)
return false;
lightData.IESIndex = -1;
lightData.cookieIndex = -1;

}
}
float shadowDistanceFade = ComputeLinearDistanceFade(distanceToCamera, additionalData.shadowFadeDistance);
lightData.shadowDimmer = additionalData.shadowDimmer * shadowDistanceFade;
bool hasShadows = light.light.shadows != LightShadows.None && shadowOutput.GetShadowSliceCountLightIndex(lightIndex) != 0;
// In case lightData.shadowDimmer == 0.0 we need to avoid rendering the shadow map... see how it can be done with the culling (and more specifically, how can we do that BEFORE sending for shadows)
bool hasShadows = lightData.shadowDimmer > 0.0f && light.light.shadows != LightShadows.None && shadowOutput.GetShadowSliceCountLightIndex(lightIndex) != 0;
bool hasNotReachMaxLimit = shadowCount + (lightData.lightType == GPULightType.Point ? 6 : 1) <= k_MaxShadowOnScreen;
// TODO: Read the comment about shadow limit/management at the beginning of this loop

}
m_lightList.lights.Add(lightData);
return true;
}
// TODO: we should be able to do this calculation only with LightData without VisibleLight light, but for now pass both

// Fill bounds
var bound = new SFiniteLightBound();
var ligthVolumeData = new LightVolumeData();
var lightVolumeData = new LightVolumeData();
ligthVolumeData.lightCategory = (uint)lightCategory;
ligthVolumeData.lightVolume = (uint)lightVolumeType;
lightVolumeData.lightCategory = (uint)lightCategory;
lightVolumeData.lightVolume = (uint)lightVolumeType;
if (gpuLightType == GPULightType.Spot)
{

bound.radius = altDist > (0.5f * range) ? altDist : (0.5f * range); // will always pick fAltDist
bound.scaleXY = squeeze ? new Vector2(0.01f, 0.01f) : new Vector2(1.0f, 1.0f);
ligthVolumeData.lightAxisX = vx;
ligthVolumeData.lightAxisY = vy;
ligthVolumeData.lightAxisZ = vz;
ligthVolumeData.lightPos = worldToView.MultiplyPoint(lightPos);
ligthVolumeData.radiusSq = range * range;
ligthVolumeData.cotan = cota;
lightVolumeData.lightAxisX = vx;
lightVolumeData.lightAxisY = vy;
lightVolumeData.lightAxisZ = vz;
lightVolumeData.lightPos = worldToView.MultiplyPoint(lightPos);
lightVolumeData.radiusSq = range * range;
lightVolumeData.cotan = cota;
lightVolumeData.featureFlags = LightDefinitions.FEATURE_FLAG_PUNCTUAL_LIGHT;
}
else if (gpuLightType == GPULightType.Point)
{

Vector3 vz = lightToView.GetColumn(2);
// fill up ldata
ligthVolumeData.lightAxisX = vx;
ligthVolumeData.lightAxisY = vy;
ligthVolumeData.lightAxisZ = vz;
ligthVolumeData.lightPos = bound.center;
ligthVolumeData.radiusSq = range * range;
lightVolumeData.lightAxisX = vx;
lightVolumeData.lightAxisY = vy;
lightVolumeData.lightAxisZ = vz;
lightVolumeData.lightPos = bound.center;
lightVolumeData.radiusSq = range * range;
lightVolumeData.featureFlags = LightDefinitions.FEATURE_FLAG_PUNCTUAL_LIGHT;
}
else if (gpuLightType == GPULightType.Rectangle)
{

bound.scaleXY.Set(1.0f, 1.0f);
bound.radius = dimensions.magnitude;
ligthVolumeData.lightPos = centerVS;
ligthVolumeData.lightAxisX = xAxisVS;
ligthVolumeData.lightAxisY = yAxisVS;
ligthVolumeData.lightAxisZ = zAxisVS;
ligthVolumeData.boxInnerDist = dimensions;
ligthVolumeData.boxInvRange.Set(1e5f, 1e5f, 1e5f);
lightVolumeData.lightPos = centerVS;
lightVolumeData.lightAxisX = xAxisVS;
lightVolumeData.lightAxisY = yAxisVS;
lightVolumeData.lightAxisZ = zAxisVS;
lightVolumeData.boxInnerDist = dimensions;
lightVolumeData.boxInvRange.Set(1e5f, 1e5f, 1e5f);
lightVolumeData.featureFlags = LightDefinitions.FEATURE_FLAG_AREA_LIGHT;
}
else if (gpuLightType == GPULightType.Line)
{

bound.scaleXY.Set(1.0f, 1.0f);
bound.radius = dimensions.magnitude;
ligthVolumeData.lightPos = centerVS;
ligthVolumeData.lightAxisX = xAxisVS;
ligthVolumeData.lightAxisY = yAxisVS;
ligthVolumeData.lightAxisZ = zAxisVS;
ligthVolumeData.boxInnerDist = new Vector3(lightData.size.x * 0.5f, 0.01f, 0.01f);
ligthVolumeData.boxInvRange.Set(1.0f / radius, 1.0f / radius, 1.0f / radius);
lightVolumeData.lightPos = centerVS;
lightVolumeData.lightAxisX = xAxisVS;
lightVolumeData.lightAxisY = yAxisVS;
lightVolumeData.lightAxisZ = zAxisVS;
lightVolumeData.boxInnerDist = new Vector3(lightData.size.x * 0.5f, 0.01f, 0.01f);
lightVolumeData.boxInvRange.Set(1.0f / radius, 1.0f / radius, 1.0f / radius);
lightVolumeData.featureFlags = LightDefinitions.FEATURE_FLAG_AREA_LIGHT;
}
else
{

m_lightList.lightVolumes.Add(ligthVolumeData);
m_lightList.lightVolumes.Add(lightVolumeData);
}
public void GetEnvLightData(VisibleReflectionProbe probe)

public void GetEnvLightVolumeDataAndBound(VisibleReflectionProbe probe, LightVolumeType lightVolumeType, Matrix4x4 worldToView)
{
var bound = new SFiniteLightBound();
var ligthVolumeData = new LightVolumeData();
var lightVolumeData = new LightVolumeData();
var bnds = probe.bounds;
var boxOffset = probe.center; // reflection volume offset relative to cube map capture point

bound.radius = combinedExtent.magnitude;
ligthVolumeData.lightCategory = (uint)LightCategory.Env;
ligthVolumeData.lightVolume = (uint)lightVolumeType;
lightVolumeData.lightCategory = (uint)LightCategory.Env;
lightVolumeData.lightVolume = (uint)lightVolumeType;
lightVolumeData.featureFlags = LightDefinitions.FEATURE_FLAG_ENV_LIGHT;
ligthVolumeData.lightPos = Cw;
ligthVolumeData.lightAxisX = vx;
ligthVolumeData.lightAxisY = vy;
ligthVolumeData.lightAxisZ = vz;
lightVolumeData.lightPos = Cw;
lightVolumeData.lightAxisX = vx;
lightVolumeData.lightAxisY = vy;
lightVolumeData.lightAxisZ = vz;
ligthVolumeData.boxInnerDist = e;
ligthVolumeData.boxInvRange.Set(1.0f / delta.x, 1.0f / delta.y, 1.0f / delta.z);
lightVolumeData.boxInnerDist = e;
lightVolumeData.boxInvRange.Set(1.0f / delta.x, 1.0f / delta.y, 1.0f / delta.z);
m_lightList.lightVolumes.Add(ligthVolumeData);
m_lightList.lightVolumes.Add(lightVolumeData);
}
public override void PrepareLightsForGPU(ShadowSettings shadowSettings, CullResults cullResults, Camera camera, ref ShadowOutput shadowOutput)

}
}
#endif
float oldSpecularGlobalDimmer = m_PassSettings.specularGlobalDimmer;
// Change some parameters in case of "special" rendering (can be preview, reflection, etc.
if(camera.cameraType == CameraType.Reflection)
{
m_PassSettings.specularGlobalDimmer = 0.0f;
}
// 1. Count the number of lights and sort all light by category, type and volume
int directionalLightcount = 0;

lightCategory = LightCategory.Punctual;
gpuLightType = GPULightType.Point;
lightVolumeType = LightVolumeType.Sphere;
++punctualLightcount;
break;
case LightType.Spot:

gpuLightType = GPULightType.Spot;
lightVolumeType = LightVolumeType.Cone;
++punctualLightcount;
break;
case LightType.Directional:

gpuLightType = GPULightType.Directional;
// No need to add volume, always visible
lightVolumeType = LightVolumeType.Count; // Count is none
++directionalLightcount;
break;
default:

lightCategory = LightCategory.Area;
gpuLightType = GPULightType.Rectangle;
lightVolumeType = LightVolumeType.Box;
++areaLightCount;
break;
case LightArchetype.Line:

gpuLightType = GPULightType.Line;
lightVolumeType = LightVolumeType.Box;
++areaLightCount;
break;
default:

// Directional rendering side, it is separated as it is always visible so no volume to handle here
if (gpuLightType == GPULightType.Directional)
{
GetDirectionalLightData(shadowSettings, gpuLightType, light, additionalData, lightIndex, ref shadowOutput, ref directionalShadowcount);
if (GetDirectionalLightData(shadowSettings, gpuLightType, light, additionalData, lightIndex, ref shadowOutput, ref directionalShadowcount))
directionalLightcount++;
#if (SHADOWS_ENABLED && SHADOWS_FIXSHADOWIDX)
// fix up shadow information

}
// Spot, point, rect, line light - Rendering side
GetLightData(shadowSettings, gpuLightType, light, additionalData, lightIndex, ref shadowOutput, ref shadowCount);
// Then culling side. Must be call in this order as we pass the created Light data to the function
GetLightVolumeDataAndBound(lightCategory, gpuLightType, lightVolumeType, light, m_lightList.lights[m_lightList.lights.Count - 1], worldToView);
if(GetLightData(shadowSettings, camera, gpuLightType, light, additionalData, lightIndex, ref shadowOutput, ref shadowCount))
{
if (lightCategory == LightCategory.Punctual)
punctualLightcount++;
else if (lightCategory == LightCategory.Area)
areaLightCount++;
else
Debug.Assert(false); // Should not be anything else here.
// Then culling side. Must be call in this order as we pass the created Light data to the function
GetLightVolumeDataAndBound(lightCategory, gpuLightType, lightVolumeType, light, m_lightList.lights[m_lightList.lights.Count - 1], worldToView);
}
#if (SHADOWS_ENABLED && SHADOWS_FIXSHADOWIDX)
// fix up shadow information

m_lightCount = m_lightList.lights.Count + m_lightList.envLights.Count;
Debug.Assert(m_lightList.bounds.Count == m_lightCount);
Debug.Assert(m_lightList.lightVolumes.Count == m_lightCount);
// Restore values after "special rendering"
m_PassSettings.specularGlobalDimmer = oldSpecularGlobalDimmer;
UpdateDataBuffers();
}
void VoxelLightListGeneration(CommandBuffer cmd, Camera camera, Matrix4x4 projscr, Matrix4x4 invProjscr, RenderTargetIdentifier cameraDepthBufferRT)

cmd.SetComputeBufferParam(buildPerVoxelLightListShader, s_GenListPerVoxelKernel, "g_logBaseBuffer", s_PerTileLogBaseTweak);
}
var numTilesX = GetNumTileX(camera);
var numTilesY = GetNumTileY(camera);
cmd.SetComputeBufferParam(buildPerVoxelLightListShader, s_GenListPerVoxelKernel, "g_vBoundsBuffer", s_AABBBoundsBuffer);
cmd.SetComputeBufferParam(buildPerVoxelLightListShader, s_GenListPerVoxelKernel, "_LightVolumeData", s_LightVolumeDataBuffer);
cmd.SetComputeBufferParam(buildPerVoxelLightListShader, s_GenListPerVoxelKernel, "g_data", s_ConvexBoundsBuffer);
var numTilesX = GetNumTileClusteredX(camera);
var numTilesY = GetNumTileClusteredY(camera);
cmd.DispatchCompute(buildPerVoxelLightListShader, s_GenListPerVoxelKernel, numTilesX, numTilesY, 1);
}

var h = camera.pixelHeight;
var numTilesX = GetNumTileX(camera);
var numTilesY = GetNumTileY(camera);
var numBigTilesX = (w + 63) / 64;
var numBigTilesY = (h + 63) / 64;

var invProjh = projh.inverse;
cmd.SetComputeIntParam(buildScreenAABBShader, "g_iNrVisibLights", m_lightCount);
cmd.SetComputeBufferParam(buildScreenAABBShader, s_GenAABBKernel, "g_data", s_ConvexBoundsBuffer);
Utilities.SetMatrixCS(cmd, buildScreenAABBShader, "g_mProjection", projh);
Utilities.SetMatrixCS(cmd, buildScreenAABBShader, "g_mInvProjection", invProjh);
cmd.SetComputeBufferParam(buildScreenAABBShader, s_GenAABBKernel, "g_vBoundsBuffer", s_AABBBoundsBuffer);

cmd.SetComputeFloatParam(buildPerBigTileLightListShader, "g_fNearPlane", camera.nearClipPlane);
cmd.SetComputeFloatParam(buildPerBigTileLightListShader, "g_fFarPlane", camera.farClipPlane);
cmd.SetComputeBufferParam(buildPerBigTileLightListShader, s_GenListPerBigTileKernel, "g_vLightList", s_BigTileLightList);
cmd.SetComputeBufferParam(buildPerBigTileLightListShader, s_GenListPerBigTileKernel, "g_vBoundsBuffer", s_AABBBoundsBuffer);
cmd.SetComputeBufferParam(buildPerBigTileLightListShader, s_GenListPerBigTileKernel, "_LightVolumeData", s_LightVolumeDataBuffer);
cmd.SetComputeBufferParam(buildPerBigTileLightListShader, s_GenListPerBigTileKernel, "g_data", s_ConvexBoundsBuffer);
bool enableFeatureVariants = GetFeatureVariantsEnabled();
if (enableFeatureVariants)
{
cmd.SetComputeBufferParam(clearDispatchIndirectShader, s_ClearDispatchIndirectKernel, "g_DispatchIndirectBuffer", s_DispatchIndirectBuffer);
cmd.DispatchCompute(clearDispatchIndirectShader, s_ClearDispatchIndirectKernel, 1, 1, 1);
}
cmd.SetComputeBufferParam(buildPerTileLightListShader, s_GenListPerTileKernel, "g_vBoundsBuffer", s_AABBBoundsBuffer);
cmd.SetComputeBufferParam(buildPerTileLightListShader, s_GenListPerTileKernel, "_LightVolumeData", s_LightVolumeDataBuffer);
cmd.SetComputeBufferParam(buildPerTileLightListShader, s_GenListPerTileKernel, "g_data", s_ConvexBoundsBuffer);
Utilities.SetMatrixCS(cmd, buildPerTileLightListShader, "g_mScrProjection", projscr);
Utilities.SetMatrixCS(cmd, buildPerTileLightListShader, "g_mInvScrProjection", invProjscr);
cmd.SetComputeTextureParam(buildPerTileLightListShader, s_GenListPerTileKernel, "g_depth_tex", cameraDepthBufferRT);

if(enableFeatureVariants)
{
uint baseFeatureFlags = 0;
if(m_lightList.directionalLights.Count > 0)
{
baseFeatureFlags |= LightDefinitions.FEATURE_FLAG_DIRECTIONAL_LIGHT;
}
if(Shader.GetGlobalInt("_EnvLightSkyEnabled") != 0)
{
baseFeatureFlags |= LightDefinitions.FEATURE_FLAG_SKY_LIGHT;
}
cmd.SetComputeBufferParam(buildPerTileLightListShader, s_GenListPerTileKernel, "g_DispatchIndirectBuffer", s_DispatchIndirectBuffer);
cmd.SetComputeBufferParam(buildPerTileLightListShader, s_GenListPerTileKernel, "g_TileList", s_TileList);
cmd.SetComputeIntParam(buildPerTileLightListShader, "g_BaseFeatureFlags", (int)baseFeatureFlags);
}
var numTilesX = GetNumTileFtplX(camera);
var numTilesY = GetNumTileFtplY(camera);
cmd.DispatchCompute(buildPerTileLightListShader, s_GenListPerTileKernel, numTilesX, numTilesY, 1);
}

if (activeComputeShader)
activeCommandBuffer.SetComputeTextureParam(activeComputeShader, activeComputeKernel, name, value);
else
Shader.SetGlobalTexture(name, value);
activeCommandBuffer.SetGlobalTexture(name, value);
}

activeCommandBuffer.SetComputeBufferParam(activeComputeShader, activeComputeKernel, name, buffer);
else
Shader.SetGlobalBuffer(name, buffer);
activeCommandBuffer.SetGlobalBuffer(name, buffer);
}
private void SetGlobalInt(string name, int value)

if (activeComputeShader)
activeCommandBuffer.SetComputeFloatParam(activeComputeShader, name, value);
else
Shader.SetGlobalFloat(name, value);
activeCommandBuffer.SetGlobalFloat(name, value);
}
private void SetGlobalVector(string name, Vector4 value)

else
Shader.SetGlobalVector(name, value);
activeCommandBuffer.SetGlobalVector(name, value);
}
private void SetGlobalVectorArray(string name, Vector4[] values)

}
else
{
Shader.SetGlobalVectorArray(name, values);
activeCommandBuffer.SetGlobalVectorArray(name, values);
private void UpdateDataBuffers()
{
s_DirectionalLightDatas.SetData(m_lightList.directionalLights.ToArray());
s_LightDatas.SetData(m_lightList.lights.ToArray());
s_EnvLightDatas.SetData(m_lightList.envLights.ToArray());
s_shadowDatas.SetData(m_lightList.shadows.ToArray());
// These two buffers have been set in Rebuild()
s_ConvexBoundsBuffer.SetData(m_lightList.bounds.ToArray());
s_LightVolumeDataBuffer.SetData(m_lightList.lightVolumes.ToArray());
}
SetGlobalPropertyRedirect(computeShader, kernelIndex, cmd);
SetGlobalBuffer("g_vLightListGlobal", !usingFptl ? s_PerVoxelLightLists : s_LightList); // opaques list (unless MSAA possibly)
SetGlobalTexture("_CookieTextures", m_CookieTexArray.GetTexCache());
SetGlobalTexture("_CookieCubeTextures", m_CubeCookieTexArray.GetTexCache());

SetGlobalBuffer("_ShadowDatas", s_shadowDatas);
SetGlobalVectorArray("_DirShadowSplitSpheres", m_lightList.directionalShadowSplitSphereSqr);
SetGlobalInt("_NumTileX", GetNumTileX(camera));
SetGlobalInt("_NumTileY", GetNumTileY(camera));
SetGlobalInt("_NumTileFtplX", GetNumTileFtplX(camera));
SetGlobalInt("_NumTileFtplY", GetNumTileFtplY(camera));
SetGlobalInt("_NumTileClusteredX", GetNumTileClusteredX(camera));
SetGlobalInt("_NumTileClusteredY", GetNumTileClusteredY(camera));
if (m_PassSettings.enableBigTilePrepass)
SetGlobalBuffer("g_vBigTileLightList", s_BigTileLightList);

}
}
public override void PushGlobalParams(Camera camera, ScriptableRenderContext loop)
private void PushGlobalParams(Camera camera, ScriptableRenderContext loop, ComputeShader computeShader, int kernelIndex)
s_DirectionalLightDatas.SetData(m_lightList.directionalLights.ToArray());
s_LightDatas.SetData(m_lightList.lights.ToArray());
s_EnvLightDatas.SetData(m_lightList.envLights.ToArray());
s_shadowDatas.SetData(m_lightList.shadows.ToArray());
// These two buffers have been set in Rebuild()
s_ConvexBoundsBuffer.SetData(m_lightList.bounds.ToArray());
s_LightVolumeDataBuffer.SetData(m_lightList.lightVolumes.ToArray());
BindGlobalParams(cmd, null, 0, camera, loop);
SetGlobalPropertyRedirect(computeShader, kernelIndex, cmd);
BindGlobalParams(cmd, computeShader, kernelIndex, camera, loop);
SetGlobalPropertyRedirect(null, 0, null);
loop.ExecuteCommandBuffer(cmd);

public override void RenderDeferredLighting(HDCamera hdCamera, ScriptableRenderContext renderContext,
LightingDebugSettings lightDebugSettings,
RenderTargetIdentifier[] colorBuffers, RenderTargetIdentifier stencilBuffer,
RenderTargetIdentifier[] colorBuffers, RenderTargetIdentifier depthStencilBuffer, RenderTargetIdentifier depthStencilTexture,
bool outputSplitLightingForSSS, bool enableSSS)
{
var bUseClusteredForDeferred = !usingFptl;

}
#endif
using (new Utilities.ProfilingSample(m_PassSettings.disableTileAndCluster ? "SinglePass - Deferred Lighting Pass" : "TilePass - Deferred Lighting Pass", renderContext))
using (new Utilities.ProfilingSample(m_PassSettings.enableTileAndCluster ? "TilePass - Deferred Lighting Pass" : "SinglePass - Deferred Lighting Pass", renderContext))
SetGlobalBuffer("g_vLightListGlobal", bUseClusteredForDeferred ? s_PerVoxelLightLists : s_LightList); // opaques list (unless MSAA possibly)
if (lightDebugSettings.lightingDebugMode == LightingDebugMode.None)
SetGlobalPropertyRedirect(shadeOpaqueShader, usingFptl ? s_shadeOpaqueFptlKernel : s_shadeOpaqueClusteredKernel, cmd);
else
SetGlobalPropertyRedirect(shadeOpaqueShader, usingFptl ? s_shadeOpaqueFptlDebugLightingKernel : s_shadeOpaqueClusteredDebugLightingKernel, cmd);
// In case of bUseClusteredForDeferred disable toggle option since we're using m_perVoxelLightLists as opposed to lightList
if (bUseClusteredForDeferred)
{
SetGlobalFloat("_UseTileLightList", 0);
}
var camera = hdCamera.camera;
if (m_PassSettings.disableTileAndCluster)
if (!m_PassSettings.enableTileAndCluster)
PushGlobalParams(camera, renderContext, null, 0);
Utilities.DrawFullScreen(cmd, m_SingleDeferredMaterialMRT, hdCamera, colorBuffers, stencilBuffer);
Utilities.DrawFullScreen(cmd, m_SingleDeferredMaterialMRT, hdCamera, colorBuffers, depthStencilBuffer);
Utilities.DrawFullScreen(cmd, m_SingleDeferredMaterialSRT, hdCamera, colorBuffers[0], stencilBuffer);
Utilities.DrawFullScreen(cmd, m_SingleDeferredMaterialSRT, hdCamera, colorBuffers[0], depthStencilBuffer);
if (!m_PassSettings.disableDeferredShadingInCompute)
int w = camera.pixelWidth;
int h = camera.pixelHeight;
int numTilesX = (w + 15) / 16;
int numTilesY = (h + 15) / 16;
int numTiles = numTilesX * numTilesY;
if (m_PassSettings.enableComputeLightEvaluation)
// Compute shader evaluation
int kernel = bUseClusteredForDeferred ? s_shadeOpaqueClusteredKernel : s_shadeOpaqueFptlKernel;
bool enableFeatureVariants = GetFeatureVariantsEnabled() && lightDebugSettings.lightingDebugMode == LightingDebugMode.None;
var camera = hdCamera.camera;
int numVariants = 1;
if (enableFeatureVariants)
numVariants = LightDefinitions.NUM_FEATURE_VARIANTS;
int w = camera.pixelWidth;
int h = camera.pixelHeight;
int numTilesX = GetNumTileX(camera);
int numTilesY = GetNumTileY(camera);
for (int variant = 0; variant < numVariants; variant++)
{
int kernel;
// Pass global parameters to compute shader
// TODO: get rid of this by making global parameters visible to compute shaders
BindGlobalParams(cmd, shadeOpaqueShader, kernel, camera, renderContext);
if(enableFeatureVariants)
{
kernel = usingFptl ? s_shadeOpaqueIndirectFptlKernels[variant] : s_shadeOpaqueIndirectClusteredKernels[variant];
}
else
{
if (lightDebugSettings.lightingDebugMode == LightingDebugMode.None)
kernel = usingFptl ? s_shadeOpaqueDirectFptlKernel : s_shadeOpaqueDirectClusteredKernel;
else
kernel = usingFptl ? s_shadeOpaqueDirectFptlDebugLightingKernel : s_shadeOpaqueDirectClusteredDebugLightingKernel;
}
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "_CameraDepthTexture", Shader.PropertyToID("_CameraDepthTexture"));
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "_GBufferTexture0", Shader.PropertyToID("_GBufferTexture0"));
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "_GBufferTexture1", Shader.PropertyToID("_GBufferTexture1"));
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "_GBufferTexture2", Shader.PropertyToID("_GBufferTexture2"));
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "_GBufferTexture3", Shader.PropertyToID("_GBufferTexture3"));
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "_GBufferTexture4", Shader.PropertyToID("_GBufferTexture4"));
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "g_tShadowBuffer", Shader.PropertyToID("g_tShadowBuffer"));
// Pass global parameters to compute shader
// TODO: get rid of this by making global parameters visible to compute shaders
PushGlobalParams(camera, renderContext, shadeOpaqueShader, kernel);
cmd.SetComputeBufferParam(shadeOpaqueShader, kernel, "g_vLightListGlobal", bUseClusteredForDeferred ? s_PerVoxelLightLists : s_LightList);
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "_PreIntegratedFGD", Shader.GetGlobalTexture("_PreIntegratedFGD"));
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "_LtcGGXMatrix", Shader.GetGlobalTexture("_LtcGGXMatrix"));
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "_LtcDisneyDiffuseMatrix", Shader.GetGlobalTexture("_LtcDisneyDiffuseMatrix"));
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "_LtcMultiGGXFresnelDisneyDiffuse", Shader.GetGlobalTexture("_LtcMultiGGXFresnelDisneyDiffuse"));
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "_MainDepthTexture", depthStencilTexture);
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "_GBufferTexture0", Shader.PropertyToID("_GBufferTexture0"));
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "_GBufferTexture1", Shader.PropertyToID("_GBufferTexture1"));
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "_GBufferTexture2", Shader.PropertyToID("_GBufferTexture2"));
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "_GBufferTexture3", Shader.PropertyToID("_GBufferTexture3"));
//cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "_GBufferTexture4", Shader.PropertyToID("_GBufferTexture4"));
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "g_tShadowBuffer", Shader.PropertyToID("g_tShadowBuffer"));
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "_LtcData", Shader.GetGlobalTexture(Shader.PropertyToID("_LtcData")));
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "_PreIntegratedFGD", Shader.GetGlobalTexture("_PreIntegratedFGD"));
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "_LtcGGXMatrix", Shader.GetGlobalTexture("_LtcGGXMatrix"));
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "_LtcDisneyDiffuseMatrix", Shader.GetGlobalTexture("_LtcDisneyDiffuseMatrix"));
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "_LtcMultiGGXFresnelDisneyDiffuse", Shader.GetGlobalTexture("_LtcMultiGGXFresnelDisneyDiffuse"));
Matrix4x4 viewToWorld = camera.cameraToWorldMatrix;
Matrix4x4 worldToView = camera.worldToCameraMatrix;
Matrix4x4 viewProjection = hdCamera.viewProjectionMatrix;
Matrix4x4 invViewProjection = hdCamera.invViewProjectionMatrix;
Utilities.SetMatrixCS(cmd, shadeOpaqueShader, "_InvViewProjMatrix", Shader.GetGlobalMatrix("_InvViewProjMatrix"));
Utilities.SetMatrixCS(cmd, shadeOpaqueShader, "_ViewProjMatrix", Shader.GetGlobalMatrix("_ViewProjMatrix"));
Utilities.SetMatrixCS(cmd, shadeOpaqueShader, "g_mInvScrProjection", Shader.GetGlobalMatrix("g_mInvScrProjection"));
cmd.SetComputeVectorParam(shadeOpaqueShader, "_ScreenSize", Shader.GetGlobalVector("_ScreenSize"));
cmd.SetComputeIntParam(shadeOpaqueShader, "_UseTileLightList", Shader.GetGlobalInt("_UseTileLightList"));
Utilities.SetMatrixCS(cmd, shadeOpaqueShader, "unity_MatrixV", worldToView);
Utilities.SetMatrixCS(cmd, shadeOpaqueShader, "unity_MatrixInvV", viewToWorld);
Utilities.SetMatrixCS(cmd, shadeOpaqueShader, "unity_MatrixVP", viewProjection);
Utilities.SetMatrixCS(cmd, shadeOpaqueShader, "_InvViewProjMatrix", invViewProjection);
Utilities.SetMatrixCS(cmd, shadeOpaqueShader, "_ViewProjMatrix", viewProjection);
Utilities.SetMatrixCS(cmd, shadeOpaqueShader, "g_mInvScrProjection", Shader.GetGlobalMatrix("g_mInvScrProjection"));
cmd.SetComputeVectorParam(shadeOpaqueShader, "_ScreenSize", Shader.GetGlobalVector("_ScreenSize"));
cmd.SetComputeIntParam(shadeOpaqueShader, "_UseTileLightList", Shader.GetGlobalInt("_UseTileLightList"));
cmd.SetComputeVectorParam(shadeOpaqueShader, "_Time", Shader.GetGlobalVector("_Time"));
cmd.SetComputeVectorParam(shadeOpaqueShader, "_SinTime", Shader.GetGlobalVector("_SinTime"));
cmd.SetComputeVectorParam(shadeOpaqueShader, "_CosTime", Shader.GetGlobalVector("_CosTime"));
cmd.SetComputeVectorParam(shadeOpaqueShader, "unity_DeltaTime", Shader.GetGlobalVector("unity_DeltaTime"));
cmd.SetComputeVectorParam(shadeOpaqueShader, "_WorldSpaceCameraPos", Shader.GetGlobalVector("_WorldSpaceCameraPos"));
cmd.SetComputeVectorParam(shadeOpaqueShader, "_ProjectionParams", Shader.GetGlobalVector("_ProjectionParams"));
cmd.SetComputeVectorParam(shadeOpaqueShader, "_ScreenParams", Shader.GetGlobalVector("_ScreenParams"));
cmd.SetComputeVectorParam(shadeOpaqueShader, "_ZBufferParams", Shader.GetGlobalVector("_ZBufferParams"));
cmd.SetComputeVectorParam(shadeOpaqueShader, "unity_OrthoParams", Shader.GetGlobalVector("unity_OrthoParams"));
cmd.SetComputeIntParam(shadeOpaqueShader, "_EnvLightSkyEnabled", Shader.GetGlobalInt("_EnvLightSkyEnabled"));
cmd.SetComputeVectorParam(shadeOpaqueShader, "_Time", Shader.GetGlobalVector("_Time"));
cmd.SetComputeVectorParam(shadeOpaqueShader, "_SinTime", Shader.GetGlobalVector("_SinTime"));
cmd.SetComputeVectorParam(shadeOpaqueShader, "_CosTime", Shader.GetGlobalVector("_CosTime"));
cmd.SetComputeVectorParam(shadeOpaqueShader, "unity_DeltaTime", Shader.GetGlobalVector("unity_DeltaTime"));
cmd.SetComputeVectorParam(shadeOpaqueShader, "_WorldSpaceCameraPos", Shader.GetGlobalVector("_WorldSpaceCameraPos"));
cmd.SetComputeVectorParam(shadeOpaqueShader, "_ProjectionParams", Shader.GetGlobalVector("_ProjectionParams"));
cmd.SetComputeVectorParam(shadeOpaqueShader, "_ScreenParams", Shader.GetGlobalVector("_ScreenParams"));
cmd.SetComputeVectorParam(shadeOpaqueShader, "_ZBufferParams", Shader.GetGlobalVector("_ZBufferParams"));
cmd.SetComputeVectorParam(shadeOpaqueShader, "unity_OrthoParams", Shader.GetGlobalVector("unity_OrthoParams"));
cmd.SetComputeIntParam(shadeOpaqueShader, "_EnvLightSkyEnabled", Shader.GetGlobalInt("_EnvLightSkyEnabled"));
Texture skyTexture = Shader.GetGlobalTexture("_SkyTexture");
Texture IESArrayTexture = Shader.GetGlobalTexture("_IESArray");
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "_IESArray", IESArrayTexture ? IESArrayTexture : m_DefaultTexture2DArray);
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "_SkyTexture", skyTexture ? skyTexture : m_DefaultTexture2DArray);
Texture skyTexture = Shader.GetGlobalTexture("_SkyTexture");
Texture IESArrayTexture = Shader.GetGlobalTexture("_IESArray");
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "_IESArray", IESArrayTexture ? IESArrayTexture : m_DefaultTexture2DArray);
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "_SkyTexture", skyTexture ? skyTexture : m_DefaultTexture2DArray);
// Since we need the stencil test, the compute path does not currently support SSS.
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "combinedLightingUAV", colorBuffers[0]);
cmd.DispatchCompute(shadeOpaqueShader, kernel, numTilesX, numTilesY, 1);
// Since we need the stencil test, the compute path does not currently support SSS.
cmd.SetComputeTextureParam(shadeOpaqueShader, kernel, "combinedLightingUAV", colorBuffers[0]);
// always do deferred lighting in blocks of 16x16 (not same as tiled light size)
if (enableFeatureVariants)
{
cmd.SetComputeIntParam(shadeOpaqueShader, "g_TileListOffset", variant * numTiles);
cmd.SetComputeBufferParam(shadeOpaqueShader, kernel, "g_TileList", s_TileList);
cmd.DispatchCompute(shadeOpaqueShader, kernel, s_DispatchIndirectBuffer, (uint)variant * 3 * sizeof(uint));
}
else
{
cmd.DispatchCompute(shadeOpaqueShader, kernel, numTilesX, numTilesY, 1);
}
}
PushGlobalParams(camera, renderContext, null, 0);
Utilities.DrawFullScreen(cmd, m_DeferredDirectMaterialMRT, hdCamera, colorBuffers, stencilBuffer);
Utilities.DrawFullScreen(cmd, m_DeferredDirectMaterialMRT, hdCamera, colorBuffers, depthStencilBuffer);
Utilities.DrawFullScreen(cmd, m_DeferredIndirectMaterialMRT, hdCamera, colorBuffers, stencilBuffer);
Utilities.DrawFullScreen(cmd, m_DeferredIndirectMaterialMRT, hdCamera, colorBuffers, depthStencilBuffer);
Utilities.DrawFullScreen(cmd, m_DeferredDirectMaterialSRT, hdCamera, colorBuffers[0], stencilBuffer);
Utilities.DrawFullScreen(cmd, m_DeferredDirectMaterialSRT, hdCamera, colorBuffers[0], depthStencilBuffer);
Utilities.DrawFullScreen(cmd, m_DeferredIndirectMaterialSRT, hdCamera, colorBuffers[0], stencilBuffer);
Utilities.DrawFullScreen(cmd, m_DeferredIndirectMaterialSRT, hdCamera, colorBuffers[0], depthStencilBuffer);
}
}
else

Utilities.SelectKeyword(m_DeferredAllMaterialMRT, "USE_CLUSTERED_LIGHTLIST", "USE_FPTL_LIGHTLIST", bUseClusteredForDeferred);
Utilities.DrawFullScreen(cmd, m_DeferredAllMaterialMRT, hdCamera, colorBuffers, stencilBuffer);
Utilities.DrawFullScreen(cmd, m_DeferredAllMaterialMRT, hdCamera, colorBuffers, depthStencilBuffer);
Utilities.DrawFullScreen(cmd, m_DeferredAllMaterialSRT, hdCamera, colorBuffers[0], stencilBuffer);
Utilities.DrawFullScreen(cmd, m_DeferredAllMaterialSRT, hdCamera, colorBuffers[0], depthStencilBuffer);
// Draw tile debugging
if (m_PassSettings.debugViewTilesFlags != 0)
if (m_PassSettings.tileDebugByCategory != TileLightLoopProducer.TileSettings.TileDebug.None)
Utilities.SetupMaterialHDCamera(hdCamera, m_DebugViewTilesMaterial);
m_DebugViewTilesMaterial.SetInt("_ViewTilesFlags", m_PassSettings.debugViewTilesFlags);
m_DebugViewTilesMaterial.SetVector("_MousePixelCoord", mousePixelCoord);
m_DebugViewTilesMaterial.EnableKeyword(bUseClusteredForDeferred ? "USE_CLUSTERED_LIGHTLIST" : "USE_FPTL_LIGHTLIST");
m_DebugViewTilesMaterial.DisableKeyword(!bUseClusteredForDeferred ? "USE_CLUSTERED_LIGHTLIST" : "USE_FPTL_LIGHTLIST");
// Debug tiles
PushGlobalParams(camera, renderContext, null, 0);
if (m_PassSettings.tileDebugByCategory == TileLightLoopProducer.TileSettings.TileDebug.FeatureVariants)
{
if(GetFeatureVariantsEnabled())
{
// featureVariants
Utilities.SetupMaterialHDCamera(hdCamera, m_DebugViewTilesMaterial);
m_DebugViewTilesMaterial.SetInt("_NumTiles", numTiles);
m_DebugViewTilesMaterial.SetInt("_ViewTilesFlags", (int)m_PassSettings.tileDebugByCategory);
m_DebugViewTilesMaterial.SetVector("_MousePixelCoord", mousePixelCoord);
m_DebugViewTilesMaterial.SetBuffer("g_TileList", s_TileList);
m_DebugViewTilesMaterial.SetBuffer("g_DispatchIndirectBuffer", s_DispatchIndirectBuffer);
m_DebugViewTilesMaterial.EnableKeyword(bUseClusteredForDeferred ? "USE_CLUSTERED_LIGHTLIST" : "USE_FPTL_LIGHTLIST");
m_DebugViewTilesMaterial.DisableKeyword(!bUseClusteredForDeferred ? "USE_CLUSTERED_LIGHTLIST" : "USE_FPTL_LIGHTLIST");
m_DebugViewTilesMaterial.DisableKeyword("SHOW_LIGHT_CATEGORIES");
m_DebugViewTilesMaterial.EnableKeyword("SHOW_FEATURE_VARIANTS");
cmd.SetRenderTarget(colorBuffers[0]);
cmd.DrawProcedural(Matrix4x4.identity, m_DebugViewTilesMaterial, 0, MeshTopology.Triangles, numTiles * 6);
}
}
else if (m_PassSettings.tileDebugByCategory != TileLightLoopProducer.TileSettings.TileDebug.None)
{
// lightCategories
Utilities.SetupMaterialHDCamera(hdCamera, m_DebugViewTilesMaterial);
m_DebugViewTilesMaterial.SetInt("_ViewTilesFlags", (int)m_PassSettings.tileDebugByCategory);
m_DebugViewTilesMaterial.SetVector("_MousePixelCoord", mousePixelCoord);
m_DebugViewTilesMaterial.EnableKeyword(bUseClusteredForDeferred ? "USE_CLUSTERED_LIGHTLIST" : "USE_FPTL_LIGHTLIST");
m_DebugViewTilesMaterial.DisableKeyword(!bUseClusteredForDeferred ? "USE_CLUSTERED_LIGHTLIST" : "USE_FPTL_LIGHTLIST");
m_DebugViewTilesMaterial.EnableKeyword("SHOW_LIGHT_CATEGORIES");
m_DebugViewTilesMaterial.DisableKeyword("SHOW_FEATURE_VARIANTS");
cmd.Blit(null, colorBuffers[0], m_DebugViewTilesMaterial, 0);
cmd.Blit(null, colorBuffers[0], m_DebugViewTilesMaterial, 0);
}
}
SetGlobalPropertyRedirect(null, 0, null);

var cmd = new CommandBuffer();
if (m_PassSettings.disableTileAndCluster)
if (!m_PassSettings.enableTileAndCluster)
{
cmd.name = "Forward pass";
cmd.EnableShaderKeyword("LIGHTLOOP_SINGLE_PASS");

14
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePass.cs.hlsl


#define MAX_NR_BIGTILE_LIGHTS_PLUSONE (512)
#define VIEWPORT_SCALE_Z (1)
#define USE_LEFTHAND_CAMERASPACE (1)
#define TILE_SIZE_FPTL (16)
#define TILE_SIZE_CLUSTERED (32)
#define FEATURE_FLAG_PUNCTUAL_LIGHT (1)
#define FEATURE_FLAG_AREA_LIGHT (2)
#define FEATURE_FLAG_DIRECTIONAL_LIGHT (4)
#define FEATURE_FLAG_ENV_LIGHT (8)
#define FEATURE_FLAG_SKY_LIGHT (16)
#define NUM_FEATURE_VARIANTS (8)
// Generated from UnityEngine.Experimental.Rendering.HDPipeline.TilePass.SFiniteLightBound
// PackingRules = Exact

float3 lightAxisZ;
float cotan;
float3 boxInnerDist;
float unused;
uint featureFlags;
float3 boxInvRange;
float unused2;
};

{
return value.boxInnerDist;
}
float GetUnused(LightVolumeData value)
uint GetFeatureFlags(LightVolumeData value)
return value.unused;
return value.featureFlags;
}
float3 GetBoxInvRange(LightVolumeData value)
{

47
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePass.hlsl


#if defined (LIGHTLOOP_TILE_DIRECT) || defined(LIGHTLOOP_TILE_ALL)
#if defined (LIGHTLOOP_TILE_DIRECT) || defined(LIGHTLOOP_TILE_ALL)
#define PROCESS_DIRECTIONAL_LIGHT
#define PROCESS_PUNCTUAL_LIGHT
#define PROCESS_AREA_LIGHT

#include "TilePass.cs.hlsl"
uint _NumTileX;
uint _NumTileY;
// For FPTL
uint _NumTileFtplX;
uint _NumTileFtplY;
#define TILE_SIZE 16 // This is fixed
#ifdef USE_FPTL_LIGHTLIST
#define TILE_SIZE TILE_SIZE_FPTL
#endif
// Don't do a "#else" so we can catch error if including call don't setup thing correctly
#ifdef USE_CLUSTERED_LIGHTLIST
#define TILE_SIZE TILE_SIZE_CLUSTERED
#endif
#define DWORD_PER_TILE 16 // See dwordsPerTile in TilePass.cs, we have roomm for 31 lights and a number of light value all store on 16 bit (ushort)
// these uniforms are only needed for when OPAQUES_ONLY is NOT defined

//#endif
//#ifdef USE_CLUSTERED_LIGHTLIST
uint _NumTileClusteredX;
uint _NumTileClusteredY;
StructuredBuffer<DirectionalLightData> _DirectionalLightDatas;
StructuredBuffer<LightData> _LightDatas;
StructuredBuffer<EnvLightData> _EnvLightDatas;
StructuredBuffer<ShadowData> _ShadowDatas;
StructuredBuffer<DirectionalLightData> _DirectionalLightDatas;
StructuredBuffer<LightData> _LightDatas;
StructuredBuffer<EnvLightData> _EnvLightDatas;
StructuredBuffer<ShadowData> _ShadowDatas;
// Use texture atlas for shadow map
//TEXTURE2D(_ShadowAtlas);

SAMPLER2D(sampler_CookieTextures);
// Used by point lights
TEXTURECUBE_ARRAY(_CookieCubeTextures);
SAMPLERCUBE(sampler_CookieCubeTextures);
TEXTURECUBE_ARRAY_ABSTRACT(_CookieCubeTextures);
SAMPLERCUBE_ABSTRACT(sampler_CookieCubeTextures);
#ifdef CUBE_ARRAY_NOT_SUPPORTED
TEXTURE2D_ARRAY(_EnvTextures);
SAMPLER2D(sampler_EnvTextures);
#else
TEXTURECUBE_ARRAY(_EnvTextures);
SAMPLERCUBE(sampler_EnvTextures);
#endif
TEXTURECUBE_ARRAY_ABSTRACT(_EnvTextures);
SAMPLERCUBE_ABSTRACT(sampler_EnvTextures);
TEXTURECUBE(_SkyTexture);
SAMPLERCUBE(sampler_SkyTexture); // NOTE: Sampler could be share here with _EnvTextures. Don't know if the shader compiler will complain...

// Returns the color in the RGB components, and the transparency (lack of occlusion) in A.
float4 SampleCookieCube(LightLoopContext lightLoopContext, float3 coord, int index)
{
return SAMPLE_TEXTURECUBE_ARRAY_LOD(_CookieCubeTextures, sampler_CookieCubeTextures, coord, index, 0);
return SAMPLE_TEXTURECUBE_ARRAY_LOD_ABSTRACT(_CookieCubeTextures, sampler_CookieCubeTextures, coord, index, 0);
}
//-----------------------------------------------------------------------------

// This code will be inlined as lightLoopContext is hardcoded in the light loop
if (lightLoopContext.sampleReflection == SINGLE_PASS_CONTEXT_SAMPLE_REFLECTION_PROBES)
{
#ifdef CUBE_ARRAY_NOT_SUPPORTED
return SAMPLE_TEXTURE2D_ARRAY_LOD(_EnvTextures, sampler_EnvTextures, DirectionToLatLongCoordinate(texCoord), index, lod);
#else
return SAMPLE_TEXTURECUBE_ARRAY_LOD(_EnvTextures, sampler_EnvTextures, texCoord, index, lod);
#endif
return SAMPLE_TEXTURECUBE_ARRAY_LOD_ABSTRACT(_EnvTextures, sampler_EnvTextures, texCoord, index, lod);
}
else // SINGLE_PASS_SAMPLE_SKY
{

716
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePassLoop.hlsl


//-----------------------------------------------------------------------------
// LightLoop
// ----------------------------------------------------------------------------
void ApplyDebug(inout float3 diffuseLighting, inout float3 specularLighting)
{
#ifdef LIGHTING_DEBUG
int lightDebugMode = (int)_DebugLightModeAndAlbedo.x;
if (lightDebugMode == LIGHTINGDEBUGMODE_DIFFUSE_LIGHTING)
{
specularLighting = float3(0.0, 0.0, 0.0);
}
else if (lightDebugMode == LIGHTINGDEBUGMODE_SPECULAR_LIGHTING)
{
diffuseLighting = float3(0.0, 0.0, 0.0);
}
#endif
}
#ifdef LIGHTLOOP_TILE_PASS
// Calculate the offset in global light index light for current light category
int GetTileOffset(PositionInputs posInput, uint lightCategory)
{
uint2 tileIndex = posInput.unPositionSS / TILE_SIZE;
return (tileIndex.y + lightCategory * _NumTileY) * _NumTileX + tileIndex.x;
}
void GetCountAndStartTile(PositionInputs posInput, uint lightCategory, out uint start, out uint lightCount)
{
const int tileOffset = GetTileOffset(posInput, lightCategory);
// The first entry inside a tile is the number of light for lightCategory (thus the +0)
lightCount = g_vLightListGlobal[DWORD_PER_TILE * tileOffset + 0] & 0xffff;
start = tileOffset;
}
uint FetchIndexTile(uint tileOffset, uint lightIndex)
{
const uint lightIndexPlusOne = lightIndex + 1; // Add +1 as first slot is reserved to store number of light
// Light index are store on 16bit
return (g_vLightListGlobal[DWORD_PER_TILE * tileOffset + (lightIndexPlusOne >> 1)] >> ((lightIndexPlusOne & 1) * DWORD_PER_TILE)) & 0xffff;
}
#ifdef USE_FPTL_LIGHTLIST
void GetCountAndStart(PositionInputs posInput, uint lightCategory, out uint start, out uint lightCount)
{
GetCountAndStartTile(posInput, lightCategory, start, lightCount);
}
uint FetchIndex(uint tileOffset, uint lightIndex)
{
return FetchIndexTile(tileOffset, lightIndex);
}
#elif defined(USE_CLUSTERED_LIGHTLIST)
#include "ClusteredUtils.hlsl"
void GetCountAndStartCluster(PositionInputs posInput, uint lightCategory, out uint start, out uint lightCount)
{
uint2 tileIndex = posInput.unPositionSS / TILE_SIZE;
float logBase = g_fClustBase;
if (g_isLogBaseBufferEnabled)
{
logBase = g_logBaseBuffer[tileIndex.y * _NumTileX + tileIndex.x];
}
int clustIdx = SnapToClusterIdxFlex(posInput.depthVS, logBase, g_isLogBaseBufferEnabled != 0);
int nrClusters = (1 << g_iLog2NumClusters);
const int idx = ((lightCategory * nrClusters + clustIdx) * _NumTileY + tileIndex.y) * _NumTileX + tileIndex.x;
uint dataPair = g_vLayeredOffsetsBuffer[idx];
start = dataPair & 0x7ffffff;
lightCount = (dataPair >> 27) & 31;
}
uint FetchIndexCluster(uint tileOffset, uint lightIndex)
{
return g_vLightListGlobal[tileOffset + lightIndex];
}
void GetCountAndStart(PositionInputs posInput, uint lightCategory, out uint start, out uint lightCount)
{
if (_UseTileLightList)
GetCountAndStartTile(posInput, lightCategory, start, lightCount);
else
GetCountAndStartCluster(posInput, lightCategory, start, lightCount);
}
uint FetchIndex(uint tileOffset, uint lightIndex)
{
if (_UseTileLightList)
return FetchIndexTile(tileOffset, lightIndex);
else
return FetchIndexCluster(tileOffset, lightIndex);
}
#endif
// bakeDiffuseLighting is part of the prototype so a user is able to implement a "base pass" with GI and multipass direct light (aka old unity rendering path)
void LightLoop( float3 V, PositionInputs posInput, PreLightData prelightData, BSDFData bsdfData, float3 bakeDiffuseLighting,
out float3 diffuseLighting,
out float3 specularLighting)
{
LightLoopContext context;
#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 < _DirectionalLightCount; ++i)
{
float3 localDiffuseLighting, localSpecularLighting;
EvaluateBSDF_Directional( context, V, posInput, prelightData, _DirectionalLightDatas[i], bsdfData,
localDiffuseLighting, localSpecularLighting);
diffuseLighting += localDiffuseLighting;
specularLighting += localSpecularLighting;
}
#endif
#ifdef PROCESS_PUNCTUAL_LIGHT
// TODO: Convert the for loop below to a while on each type as we know we are sorted!
uint punctualLightStart;
uint punctualLightCount;
GetCountAndStart(posInput, LIGHTCATEGORY_PUNCTUAL, punctualLightStart, punctualLightCount);
for (i = 0; i < punctualLightCount; ++i)
{
float3 localDiffuseLighting, localSpecularLighting;
EvaluateBSDF_Punctual( context, V, posInput, prelightData, _LightDatas[FetchIndex(punctualLightStart, i)], bsdfData,
localDiffuseLighting, localSpecularLighting);
diffuseLighting += localDiffuseLighting;
specularLighting += localSpecularLighting;
}
#endif
#ifdef PROCESS_AREA_LIGHT
// TODO: Convert the for loop below to a while on each type as we know we are sorted!
uint areaLightStart;
uint areaLightCount;
GetCountAndStart(posInput, LIGHTCATEGORY_AREA, areaLightStart, areaLightCount);
for (i = 0; i < areaLightCount; ++i)
{
float3 localDiffuseLighting, localSpecularLighting;
uint areaIndex = FetchIndex(areaLightStart, i);
if(_LightDatas[areaIndex].lightType == GPULIGHTTYPE_LINE)
{
EvaluateBSDF_Line( context, V, posInput, prelightData, _LightDatas[areaIndex], bsdfData,
localDiffuseLighting, localSpecularLighting);
}
else
{
EvaluateBSDF_Area( context, V, posInput, prelightData, _LightDatas[areaIndex], bsdfData,
localDiffuseLighting, localSpecularLighting);
}
diffuseLighting += localDiffuseLighting;
specularLighting += localSpecularLighting;
}
#endif
#ifdef PROCESS_ENV_LIGHT
float3 iblDiffuseLighting = float3(0.0, 0.0, 0.0);
float3 iblSpecularLighting = float3(0.0, 0.0, 0.0);
// Only apply sky IBL if the sky texture is available.
if (_EnvLightSkyEnabled)
{
float3 localDiffuseLighting, localSpecularLighting;
float2 weight;
// The sky is a single cubemap texture separate from the reflection probe texture array (different resolution and compression)
context.sampleReflection = SINGLE_PASS_CONTEXT_SAMPLE_SKY;
EnvLightData envLightSky = InitSkyEnvLightData(0); // The sky data are generated on the fly so the compiler can optimize the code
EvaluateBSDF_Env(context, V, posInput, prelightData, envLightSky, bsdfData, localDiffuseLighting, localSpecularLighting, weight);
iblDiffuseLighting = lerp(iblDiffuseLighting, localDiffuseLighting, weight.x); // Should be remove by the compiler if it is smart as all is constant 0
iblSpecularLighting = lerp(iblSpecularLighting, localSpecularLighting, weight.y);
}
uint envLightStart;
uint envLightCount;
GetCountAndStart(posInput, LIGHTCATEGORY_ENV, envLightStart, envLightCount);
for (i = 0; i < envLightCount; ++i)
{
float3 localDiffuseLighting, localSpecularLighting;
float2 weight;
context.sampleReflection = SINGLE_PASS_CONTEXT_SAMPLE_REFLECTION_PROBES;
EvaluateBSDF_Env(context, V, posInput, prelightData, _EnvLightDatas[FetchIndex(envLightStart, i)], bsdfData, localDiffuseLighting, localSpecularLighting, weight);
iblDiffuseLighting = lerp(iblDiffuseLighting, localDiffuseLighting, weight.x); // Should be remove by the compiler if it is smart as all is constant 0
iblSpecularLighting = lerp(iblSpecularLighting, localSpecularLighting, weight.y);
}
diffuseLighting += iblDiffuseLighting;
specularLighting += iblSpecularLighting;
#endif
// TODO: currently apply GI at the same time as reflection
#ifdef PROCESS_ENV_LIGHT
// Add indirect diffuse + emissive (if any)
diffuseLighting += bakeDiffuseLighting;
#endif
ApplyDebug(diffuseLighting, specularLighting);
}
#else // LIGHTLOOP_SINGLE_PASS
// bakeDiffuseLighting is part of the prototype so a user is able to implement a "base pass" with GI and multipass direct light (aka old unity rendering path)
void LightLoop( float3 V, PositionInputs posInput, PreLightData prelightData, BSDFData bsdfData, float3 bakeDiffuseLighting,
out float3 diffuseLighting,
out float3 specularLighting)
{
LightLoopContext context;
#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(diffuseLighting, specularLighting);
}
#endif
//-----------------------------------------------------------------------------
// LightLoop
// ----------------------------------------------------------------------------
void ApplyDebug(LightLoopContext lightLoopContext, float3 positionWS, inout float3 diffuseLighting, inout float3 specularLighting)
{
#ifdef LIGHTING_DEBUG
int lightDebugMode = (int)_DebugLightModeAndAlbedo.x;
if (lightDebugMode == LIGHTINGDEBUGMODE_DIFFUSE_LIGHTING)
{
specularLighting = float3(0.0, 0.0, 0.0);
}
else if (lightDebugMode == LIGHTINGDEBUGMODE_SPECULAR_LIGHTING)
{
diffuseLighting = float3(0.0, 0.0, 0.0);
}
else if (lightDebugMode == LIGHTINGDEBUGMODE_VISUALIZE_CASCADE)
{
specularLighting = float3(0.0, 0.0, 0.0);
const float3 s_CascadeColors[] = {
float3(1.0, 0.0, 0.0),
float3(0.0, 1.0, 0.0),
float3(0.0, 0.0, 1.0),
float3(1.0, 1.0, 0.0)
};
#ifdef SHADOWS_USE_SHADOWCTXT
float shadow = GetDirectionalShadowAttenuation(lightLoopContext.shadowContext, positionWS, float3(0.0, 1.0, 0.0 ), 0, float3(0.0, 0.0, 0.0), float2(0.0, 0.0));
float4 dirShadowSplitSpheres[4];
uint payloadOffset = EvalShadow_LoadSplitSpheres(lightLoopContext.shadowContext, 0, dirShadowSplitSpheres);
int shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows(positionWS, dirShadowSplitSpheres);
#else
float shadow = GetDirectionalShadowAttenuation(lightLoopContext, positionWS, 0, float3(0.0, 0.0, 0.0), float2(0.0, 0.0));
int shadowSplitIndex = GetSplitSphereIndexForDirshadows(positionWS, _DirShadowSplitSpheres);
#endif
if (shadowSplitIndex == -1)
diffuseLighting = float3(0.0, 0.0, 0.0);
else
{
diffuseLighting = s_CascadeColors[shadowSplitIndex] * shadow;
}
}
#endif
}
#ifdef LIGHTLOOP_TILE_PASS
// Calculate the offset in global light index light for current light category
int GetTileOffset(PositionInputs posInput, uint lightCategory)
{
uint2 tileIndex = posInput.unTileCoord;
return (tileIndex.y + lightCategory * _NumTileFtplY) * _NumTileFtplX + tileIndex.x;
}
void GetCountAndStartTile(PositionInputs posInput, uint lightCategory, out uint start, out uint lightCount)
{
const int tileOffset = GetTileOffset(posInput, lightCategory);
// The first entry inside a tile is the number of light for lightCategory (thus the +0)
lightCount = g_vLightListGlobal[DWORD_PER_TILE * tileOffset + 0] & 0xffff;
start = tileOffset;
}
uint FetchIndexTile(uint tileOffset, uint lightIndex)
{
const uint lightIndexPlusOne = lightIndex + 1; // Add +1 as first slot is reserved to store number of light
// Light index are store on 16bit
return (g_vLightListGlobal[DWORD_PER_TILE * tileOffset + (lightIndexPlusOne >> 1)] >> ((lightIndexPlusOne & 1) * DWORD_PER_TILE)) & 0xffff;
}
#ifdef USE_FPTL_LIGHTLIST
uint GetTileSize()
{
return TILE_SIZE_FPTL;
}
void GetCountAndStart(PositionInputs posInput, uint lightCategory, out uint start, out uint lightCount)
{
GetCountAndStartTile(posInput, lightCategory, start, lightCount);
}
uint FetchIndex(uint tileOffset, uint lightIndex)
{
return FetchIndexTile(tileOffset, lightIndex);
}
#elif defined(USE_CLUSTERED_LIGHTLIST)
#include "ClusteredUtils.hlsl"
uint GetTileSize()
{
return TILE_SIZE_CLUSTERED;
}
void GetCountAndStartCluster(PositionInputs posInput, uint lightCategory, out uint start, out uint lightCount)
{
uint2 tileIndex = posInput.unTileCoord;
float logBase = g_fClustBase;
if (g_isLogBaseBufferEnabled)
{
logBase = g_logBaseBuffer[tileIndex.y * _NumTileClusteredX + tileIndex.x];
}
int clustIdx = SnapToClusterIdxFlex(posInput.depthVS, logBase, g_isLogBaseBufferEnabled != 0);
int nrClusters = (1 << g_iLog2NumClusters);
const int idx = ((lightCategory * nrClusters + clustIdx) * _NumTileClusteredY + tileIndex.y) * _NumTileClusteredX + tileIndex.x;
uint dataPair = g_vLayeredOffsetsBuffer[idx];
start = dataPair & 0x7ffffff;
lightCount = (dataPair >> 27) & 31;
}
uint FetchIndexCluster(uint tileOffset, uint lightIndex)
{
return g_vLightListGlobal[tileOffset + lightIndex];
}
void GetCountAndStart(PositionInputs posInput, uint lightCategory, out uint start, out uint lightCount)
{
if (_UseTileLightList)
GetCountAndStartTile(posInput, lightCategory, start, lightCount);
else
GetCountAndStartCluster(posInput, lightCategory, start, lightCount);
}
uint FetchIndex(uint tileOffset, uint lightIndex)
{
if (_UseTileLightList)
return FetchIndexTile(tileOffset, lightIndex);
else
return FetchIndexCluster(tileOffset, lightIndex);
}
#endif
// bakeDiffuseLighting is part of the prototype so a user is able to implement a "base pass" with GI and multipass direct light (aka old unity rendering path)
void LightLoop( float3 V, PositionInputs posInput, PreLightData prelightData, BSDFData bsdfData, float3 bakeDiffuseLighting, uint featureFlags,
out float3 diffuseLighting,
out float3 specularLighting)
{
LightLoopContext context;
#ifndef SHADOWS_USE_SHADOWCTXT
ZERO_INITIALIZE(LightLoopContext, context);
#else
context.sampleShadow = 0;
context.sampleReflection = 0;
context.shadowContext = InitShadowContext();
#endif
diffuseLighting = float3(0.0, 0.0, 0.0);
specularLighting = float3(0.0, 0.0, 0.0);
uint i = 0; // Declare once to avoid the D3D11 compiler warning.
#ifdef PROCESS_DIRECTIONAL_LIGHT
if(featureFlags & FEATURE_FLAG_DIRECTIONAL_LIGHT)
{
for(i = 0; i < _DirectionalLightCount; ++i)
{
float3 localDiffuseLighting, localSpecularLighting;
EvaluateBSDF_Directional(context, V, posInput, prelightData, _DirectionalLightDatas[i], bsdfData,
localDiffuseLighting, localSpecularLighting);
diffuseLighting += localDiffuseLighting;
specularLighting += localSpecularLighting;
}
}
#endif
#ifdef PROCESS_PUNCTUAL_LIGHT
if(featureFlags & FEATURE_FLAG_PUNCTUAL_LIGHT)
{
// TODO: Convert the for loop below to a while on each type as we know we are sorted!
uint punctualLightStart;
uint punctualLightCount;
GetCountAndStart(posInput, LIGHTCATEGORY_PUNCTUAL, punctualLightStart, punctualLightCount);
for(i = 0; i < punctualLightCount; ++i)
{
float3 localDiffuseLighting, localSpecularLighting;
EvaluateBSDF_Punctual(context, V, posInput, prelightData, _LightDatas[FetchIndex(punctualLightStart, i)], bsdfData,
localDiffuseLighting, localSpecularLighting);
diffuseLighting += localDiffuseLighting;
specularLighting += localSpecularLighting;
}
}
#endif
#ifdef PROCESS_AREA_LIGHT
if(featureFlags & FEATURE_FLAG_AREA_LIGHT)
{
// TODO: Convert the for loop below to a while on each type as we know we are sorted!
uint areaLightStart;
uint areaLightCount;
GetCountAndStart(posInput, LIGHTCATEGORY_AREA, areaLightStart, areaLightCount);
for(i = 0; i < areaLightCount; ++i)
{
float3 localDiffuseLighting, localSpecularLighting;
uint areaIndex = FetchIndex(areaLightStart, i);
if(_LightDatas[areaIndex].lightType == GPULIGHTTYPE_LINE)
{
EvaluateBSDF_Line(context, V, posInput, prelightData, _LightDatas[areaIndex], bsdfData,
localDiffuseLighting, localSpecularLighting);
}
else
{
EvaluateBSDF_Area(context, V, posInput, prelightData, _LightDatas[areaIndex], bsdfData,
localDiffuseLighting, localSpecularLighting);
}
diffuseLighting += localDiffuseLighting;
specularLighting += localSpecularLighting;
}
}
#endif
#ifdef PROCESS_ENV_LIGHT
float3 iblDiffuseLighting = float3(0.0, 0.0, 0.0);
float3 iblSpecularLighting = float3(0.0, 0.0, 0.0);
// Only apply sky IBL if the sky texture is available.
if(featureFlags & FEATURE_FLAG_SKY_LIGHT)
{
if(_EnvLightSkyEnabled)
{
float3 localDiffuseLighting, localSpecularLighting;
float2 weight;
// The sky is a single cubemap texture separate from the reflection probe texture array (different resolution and compression)
context.sampleReflection = SINGLE_PASS_CONTEXT_SAMPLE_SKY;
EnvLightData envLightSky = InitSkyEnvLightData(0); // The sky data are generated on the fly so the compiler can optimize the code
EvaluateBSDF_Env(context, V, posInput, prelightData, envLightSky, bsdfData, localDiffuseLighting, localSpecularLighting, weight);
iblDiffuseLighting = lerp(iblDiffuseLighting, localDiffuseLighting, weight.x); // Should be remove by the compiler if it is smart as all is constant 0
iblSpecularLighting = lerp(iblSpecularLighting, localSpecularLighting, weight.y);
}
}
if(featureFlags & FEATURE_FLAG_ENV_LIGHT)
{
uint envLightStart;
uint envLightCount;
GetCountAndStart(posInput, LIGHTCATEGORY_ENV, envLightStart, envLightCount);
for(i = 0; i < envLightCount; ++i)
{
float3 localDiffuseLighting, localSpecularLighting;
float2 weight;
context.sampleReflection = SINGLE_PASS_CONTEXT_SAMPLE_REFLECTION_PROBES;
EvaluateBSDF_Env(context, V, posInput, prelightData, _EnvLightDatas[FetchIndex(envLightStart, i)], bsdfData, localDiffuseLighting, localSpecularLighting, weight);
iblDiffuseLighting = lerp(iblDiffuseLighting, localDiffuseLighting, weight.x); // Should be remove by the compiler if it is smart as all is constant 0
iblSpecularLighting = lerp(iblSpecularLighting, localSpecularLighting, weight.y);
}
}
diffuseLighting += iblDiffuseLighting;
specularLighting += iblSpecularLighting;
#endif
// TODO: currently apply GI at the same time as reflection
#ifdef PROCESS_ENV_LIGHT
// Add indirect diffuse + emissive (if any)
diffuseLighting += bakeDiffuseLighting;
#endif
ApplyDebug(context, posInput.positionWS, diffuseLighting, specularLighting);
}
#else // LIGHTLOOP_SINGLE_PASS
uint GetTileSize()
{
return 1;
}
// bakeDiffuseLighting is part of the prototype so a user is able to implement a "base pass" with GI and multipass direct light (aka old unity rendering path)
void LightLoop( float3 V, PositionInputs posInput, PreLightData prelightData, BSDFData bsdfData, float3 bakeDiffuseLighting, uint featureFlag,
out float3 diffuseLighting,
out float3 specularLighting)
{
LightLoopContext context;
#ifndef SHADOWS_USE_SHADOWCTXT
ZERO_INITIALIZE(LightLoopContext, context);
#else
context.sampleShadow = 0;
context.sampleReflection = 0;
context.shadowContext = InitShadowContext();
#endif
diffuseLighting = float3(0.0, 0.0, 0.0);
specularLighting = float3(0.0, 0.0, 0.0);
uint i = 0; // Declare once to avoid the D3D11 compiler warning.
for (i = 0; i < _DirectionalLightCount; ++i)
{
float3 localDiffuseLighting, localSpecularLighting;
EvaluateBSDF_Directional( context, V, posInput, prelightData, _DirectionalLightDatas[i], bsdfData,
localDiffuseLighting, localSpecularLighting);
diffuseLighting += localDiffuseLighting;
specularLighting += localSpecularLighting;
}
for (i = 0; i < _PunctualLightCount; ++i)
{
float3 localDiffuseLighting, localSpecularLighting;
EvaluateBSDF_Punctual( context, V, posInput, prelightData, _LightDatas[i], bsdfData,
localDiffuseLighting, localSpecularLighting);
diffuseLighting += localDiffuseLighting;
specularLighting += localSpecularLighting;
}
// Area are store with punctual, just offset the index
for (i = _PunctualLightCount; i < _AreaLightCount + _PunctualLightCount; ++i)
{
float3 localDiffuseLighting, localSpecularLighting;
if (_LightDatas[i].lightType == GPULIGHTTYPE_LINE)
{
EvaluateBSDF_Line( context, V, posInput, prelightData, _LightDatas[i], bsdfData,
localDiffuseLighting, localSpecularLighting);
}
else
{
EvaluateBSDF_Area( context, V, posInput, prelightData, _LightDatas[i], bsdfData,
localDiffuseLighting, localSpecularLighting);
}
diffuseLighting += localDiffuseLighting;
specularLighting += localSpecularLighting;
}
// TODO: Check the reflection hierarchy, for the current system (matching legacy unity) we must sort from bigger solid angle to lower (lower override bigger). So begging by sky
// TODO: Change the way it is done by reversing the order, from smaller solid angle to bigger, so we can early out when the weight is 1.
float3 iblDiffuseLighting = float3(0.0, 0.0, 0.0);
float3 iblSpecularLighting = float3(0.0, 0.0, 0.0);
// Only apply sky IBL if the sky texture is available.
if (_EnvLightSkyEnabled)
{
float3 localDiffuseLighting, localSpecularLighting;
float2 weight;
// The sky is a single cubemap texture separate from the reflection probe texture array (different resolution and compression)
context.sampleReflection = SINGLE_PASS_CONTEXT_SAMPLE_SKY;
EnvLightData envLightSky = InitSkyEnvLightData(0); // The sky data are generated on the fly so the compiler can optimize the code
EvaluateBSDF_Env(context, V, posInput, prelightData, envLightSky, bsdfData, localDiffuseLighting, localSpecularLighting, weight);
iblDiffuseLighting = lerp(iblDiffuseLighting, localDiffuseLighting, weight.x); // Should be remove by the compiler if it is smart as all is constant 0
iblSpecularLighting = lerp(iblSpecularLighting, localSpecularLighting, weight.y);
}
for (i = 0; i < _EnvLightCount; ++i)
{
float3 localDiffuseLighting, localSpecularLighting;
float2 weight;
context.sampleReflection = SINGLE_PASS_CONTEXT_SAMPLE_REFLECTION_PROBES;
EvaluateBSDF_Env(context, V, posInput, prelightData, _EnvLightDatas[i], bsdfData, localDiffuseLighting, localSpecularLighting, weight);
iblDiffuseLighting = lerp(iblDiffuseLighting, localDiffuseLighting, weight.x); // Should be remove by the compiler if it is smart as all is constant 0
iblSpecularLighting = lerp(iblSpecularLighting, localSpecularLighting, weight.y);
}
diffuseLighting += iblDiffuseLighting;
specularLighting += iblSpecularLighting;
// Add indirect diffuse + emissive (if any)
diffuseLighting += bakeDiffuseLighting;
ApplyDebug(context, posInput.positionWS, diffuseLighting, specularLighting);
}
#endif

8
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePassProducer.asset


m_Name: TilePassProducer
m_EditorClassIdentifier:
m_TileSettings:
enableDrawLightBoundsDebug: 0
disableTileAndCluster: 0
disableDeferredShadingInCompute: 1
enableTileAndCluster: 1
disableFptlWhenClustered: 0
enableFptlForOpaqueWhenClustered: 1
diffuseGlobalDimmer: 1
specularGlobalDimmer: 1
m_PassResources: {fileID: 11400000, guid: 7f2998544b2ac3848822b80ec3e6c446, type: 2}

2
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePassResources.asset


type: 3}
buildPerVoxelLightListShader: {fileID: 7200000, guid: 0bb1b7e0ddcd5c44baf3ddc7456eb196,
type: 3}
clearDispatchIndirectShader: {fileID: 7200000, guid: fc1f553acb80a6446a32d33e403d0656,
type: 3}
shadeOpaqueShader: {fileID: 7200000, guid: 0b64f79746d2daf4198eaf6eab9af259, type: 3}
m_DebugViewMaterialGBuffer: {fileID: 4800000, guid: 439949ea1bfa91b4ba0d04269fcde33d,
type: 3}

1
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePassResources.cs


public ComputeShader buildPerTileLightListShader = null; // FPTL
public ComputeShader buildPerBigTileLightListShader = null;
public ComputeShader buildPerVoxelLightListShader = null; // clustered
public ComputeShader clearDispatchIndirectShader = null;
public ComputeShader shadeOpaqueShader = null;
// Various set of material use in render loop

2
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Builtin/BuiltinData.hlsl


//TODO: return this original relative path include after fixing a bug in Unity side
//#include "BuiltinData.cs.hlsl"
#include "HDRenderPipeline/Material/Builtin/BuiltinData.cs.hlsl"
#include "../../Material/Builtin/BuiltinData.cs.hlsl"
//-----------------------------------------------------------------------------
// common Encode/Decode functions

18
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/LayeredLit/Editor/LayeredLitUI.cs


const string kObjectScaleAffectTile = "_ObjectScaleAffectTile";
MaterialProperty UVBlendMask = null;
const string kUVBlendMask = "_UVBlendMask";
MaterialProperty UVMappingPlanarBlendMask = null;
const string kUVMappingPlanarBlendMask = "_UVMappingPlanarBlendMask";
MaterialProperty layerTilingBlendMask = null;
const string kLayerTilingBlendMask = "_LayerTilingBlendMask";
MaterialProperty texWorldScaleBlendMask = null;

MaterialProperty[] layerTexWorldScale = new MaterialProperty[kMaxLayerCount];
MaterialProperty[] layerUVBase = new MaterialProperty[kMaxLayerCount];
MaterialProperty[] layerUVMappingMask = new MaterialProperty[kMaxLayerCount];
MaterialProperty[] layerUVMappingPlanar = new MaterialProperty[kMaxLayerCount];
MaterialProperty[] layerUVDetail = new MaterialProperty[kMaxLayerCount];
MaterialProperty[] layerUVDetailsMappingMask = new MaterialProperty[kMaxLayerCount];
// This one is specific to layer lit

vertexColorMode = FindProperty(kVertexColorMode, props);
objectScaleAffectTile = FindProperty(kObjectScaleAffectTile, props);
UVBlendMask = FindProperty(kUVBlendMask, props);
UVMappingPlanarBlendMask = FindProperty(kUVMappingPlanarBlendMask, props);
layerTilingBlendMask = FindProperty(kLayerTilingBlendMask, props);
texWorldScaleBlendMask = FindProperty(kTexWorldScaleBlendMask, props);

layerTexWorldScale[i] = FindProperty(string.Format("{0}{1}", kTexWorldScale, i), props);
layerUVBase[i] = FindProperty(string.Format("{0}{1}", kUVBase, i), props);
layerUVMappingMask[i] = FindProperty(string.Format("{0}{1}", kUVMappingMask, i), props);
layerUVMappingPlanar[i] = FindProperty(string.Format("{0}{1}", kUVMappingPlanar, i), props);
layerUVDetail[i] = FindProperty(string.Format("{0}{1}", kUVDetail, i), props);
layerUVDetailsMappingMask[i] = FindProperty(string.Format("{0}{1}", kUVDetailsMappingMask, i), props);
layerTiling[i] = FindProperty(string.Format("{0}{1}", kLayerTiling, i), props);

// put the name in the exclusionList below
static void SynchronizeLayerProperties(Material material, Material[] layers, int layerIndex)
{
string[] exclusionList = { kTexWorldScale, kUVBase, kUVMappingMask, kUVMappingPlanar, kUVDetail, kUVDetailsMappingMask };
string[] exclusionList = { kTexWorldScale, kUVBase, kUVMappingMask, kUVDetail, kUVDetailsMappingMask };
Material layerMaterial = layers[layerIndex];

result = true;
}
}
UVMappingPlanarBlendMask.floatValue = ((LayerUVBaseMapping)UVBlendMask.floatValue == LayerUVBaseMapping.Planar) ? 1.0f : 0.0f;
// We setup the masking map based on the enum for each layer.
// using mapping mask allow to reduce the number of generated combination for a very small increase in ALU

Z = (layerUVBaseMapping == LayerUVBaseMapping.UV2) ? 1.0f : 0.0f;
W = (layerUVBaseMapping == LayerUVBaseMapping.UV3) ? 1.0f : 0.0f;
layerUVMappingMask[layerIndex].colorValue = (layerIndex == 0) ? new Color(1.0f, 0.0f, 0.0f, 0.0f) : new Color(X, Y, Z, W); // Special case for Main Layer and Blend Mask, only UV0. As Layer0 is share by both here, need to force X to 1.0 in all case
layerUVMappingPlanar[layerIndex].floatValue = (layerUVBaseMapping == LayerUVBaseMapping.Planar) ? 1.0f : 0.0f; // Planar have priority on UV0
UVDetailMapping layerUVDetailMapping = (UVDetailMapping)layerUVDetail[layerIndex].floatValue;
X = (layerUVDetailMapping == UVDetailMapping.UV0) ? 1.0f : 0.0f;

static public void SetupLayersMappingKeywords(Material material)
{
// object scale affect tile
SetKeyword(material, "_LAYER_TILING_UNIFORM_SCALE", material.GetFloat(kObjectScaleAffectTile) > 0.0f);
SetKeyword(material, "_LAYER_TILING_COUPLED_WITH_UNIFORM_OBJECT_SCALE", material.GetFloat(kObjectScaleAffectTile) > 0.0f);
LayerUVBaseMapping UVBlendMaskMapping = (LayerUVBaseMapping)material.GetFloat(kUVBlendMask);
LayerUVBaseMapping UVBlendMaskMapping = (LayerUVBaseMapping)material.GetFloat(kUVBlendMask);
SetKeyword(material, "_LAYER_MAPPING_PLANAR_BLENDMASK", UVBlendMaskMapping == LayerUVBaseMapping.Planar);
SetKeyword(material, "_LAYER_MAPPING_TRIPLANAR_BLENDMASK", UVBlendMaskMapping == LayerUVBaseMapping.Triplanar);
int numLayer = (int)material.GetFloat(kLayerCount);

SetKeyword(material, "_LAYEREDLIT_3_LAYERS", false);
}
const string kLayerMappingPlanar = "_LAYER_MAPPING_PLANAR";
const string kLayerMappingTriplanar = "_LAYER_MAPPING_TRIPLANAR";
// We have to check for each layer if the UV2 or UV3 is needed.

{
string layerUVBaseParam = string.Format("{0}{1}", kUVBase, i);
LayerUVBaseMapping layerUVBaseMapping = (LayerUVBaseMapping)material.GetFloat(layerUVBaseParam);
string currentLayerMappingPlanar = string.Format("{0}{1}", kLayerMappingPlanar, i);
SetKeyword(material, currentLayerMappingPlanar, layerUVBaseMapping == LayerUVBaseMapping.Planar);
string currentLayerMappingTriplanar = string.Format("{0}{1}", kLayerMappingTriplanar, i);
SetKeyword(material, currentLayerMappingTriplanar, layerUVBaseMapping == LayerUVBaseMapping.Triplanar);

44
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/LayeredLit/LayeredLit.shader


[ToggleOff] _ObjectScaleAffectTile("_ObjectScaleAffectTile", Float) = 0.0
[Enum(UV0, 0, Planar, 4, Triplanar, 5)] _UVBlendMask("UV Set for blendMask", Float) = 0
[HideInInspector] _UVMappingPlanarBlendMask("_UVMappingPlanarBlendMask", Float) = 0.0
_TexWorldScaleBlendMask("Tiling", Float) = 1.0
// Following are builtin properties

[HideInInspector] _UVMappingMask0("_UVMappingMask0", Color) = (1, 0, 0, 0)
[HideInInspector] _UVMappingMask1("_UVMappingMask1", Color) = (1, 0, 0, 0)
[HideInInspector] _UVMappingMask2("_UVMappingMask2", Color) = (1, 0, 0, 0)
[HideInInspector] _UVMappingMask3("_UVMappingMask3", Color) = (1, 0, 0, 0)
[HideInInspector] _UVMappingPlanar0("_UVMappingPlanar0", Float) = 0.0
[HideInInspector] _UVMappingPlanar1("_UVMappingPlanar1", Float) = 0.0
[HideInInspector] _UVMappingPlanar2("_UVMappingPlanar2", Float) = 0.0
[HideInInspector] _UVMappingPlanar3("_UVMappingPlanar3", Float) = 0.0
[HideInInspector] _UVMappingMask3("_UVMappingMask3", Color) = (1, 0, 0, 0)
[Enum(UV0, 0, UV1, 1, UV2, 2, UV3, 3)] _UVDetail0("UV Set for detail0", Float) = 0
[Enum(UV0, 0, UV1, 1, UV2, 2, UV3, 3)] _UVDetail1("UV Set for detail1", Float) = 0

#pragma shader_feature _DOUBLESIDED_ON
#pragma shader_feature _PER_PIXEL_DISPLACEMENT
#pragma shader_feature _LAYER_TILING_UNIFORM_SCALE
#pragma shader_feature _LAYER_MAPPING_TRIPLANAR_BLENDMASK
#pragma shader_feature _LAYER_MAPPING_TRIPLANAR0
#pragma shader_feature _LAYER_MAPPING_TRIPLANAR1
#pragma shader_feature _LAYER_MAPPING_TRIPLANAR2
#pragma shader_feature _LAYER_MAPPING_TRIPLANAR3
#pragma shader_feature _LAYER_TILING_COUPLED_WITH_UNIFORM_OBJECT_SCALE
#pragma shader_feature _ _LAYER_MAPPING_PLANAR_BLENDMASK _LAYER_MAPPING_TRIPLANAR_BLENDMASK
#pragma shader_feature _ _LAYER_MAPPING_PLANAR0 _LAYER_MAPPING_TRIPLANAR0
#pragma shader_feature _ _LAYER_MAPPING_PLANAR1 _LAYER_MAPPING_TRIPLANAR1
#pragma shader_feature _ _LAYER_MAPPING_PLANAR2 _LAYER_MAPPING_TRIPLANAR2
#pragma shader_feature _ _LAYER_MAPPING_PLANAR3 _LAYER_MAPPING_TRIPLANAR3
#pragma shader_feature _NORMALMAP_TANGENT_SPACE0
#pragma shader_feature _NORMALMAP_TANGENT_SPACE1
#pragma shader_feature _NORMALMAP_TANGENT_SPACE2

#pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
#pragma multi_compile DIRLIGHTMAP_OFF DIRLIGHTMAP_COMBINED
#pragma multi_compile DYNAMICLIGHTMAP_OFF DYNAMICLIGHTMAP_ON
// enable dithering LOD crossfade
#pragma multi_compile _ LOD_FADE_CROSSFADE
// TODO: We should have this keyword only if VelocityInGBuffer is enable, how to do that ?
//#pragma multi_compile VELOCITYOUTPUT_OFF VELOCITYOUTPUT_ON

#define UNITY_MATERIAL_LIT // Need to be define before including Material.hlsl
// Use surface gradient normal mapping as it handle correctly triplanar normal mapping and multiple UVSet
#define SURFACE_GRADIENT
#include "ShaderLibrary/common.hlsl"
#include "HDRenderPipeline/ShaderConfig.cs.hlsl"
#include "HDRenderPipeline/ShaderVariables.hlsl"
#include "HDRenderPipeline/ShaderPass/FragInputs.hlsl"
#include "HDRenderPipeline/ShaderPass/ShaderPass.cs.hlsl"
#include "../../../ShaderLibrary/common.hlsl"
#include "../../ShaderConfig.cs.hlsl"
#include "../../ShaderVariables.hlsl"
#include "../../ShaderPass/FragInputs.hlsl"
#include "../../ShaderPass/ShaderPass.cs.hlsl"
//-------------------------------------------------------------------------------------
// variable declaration

// variable declaration
//-------------------------------------------------------------------------------------
#include "HDRenderPipeline/Material/Lit/LitProperties.hlsl"
#include "../../Material/Lit/LitProperties.hlsl"
// All our shaders use same name for entry point
#pragma vertex Vert

#define LIGHTING_DEBUG
#define SHADERPASS SHADERPASS_GBUFFER
#include "HDRenderPipeline/Debug/HDRenderPipelineDebug.cs.hlsl"
#include "HDRenderPipeline/Debug/DebugLighting.hlsl"
#include "../../Debug/HDRenderPipelineDebug.cs.hlsl"
#include "../../Debug/DebugLighting.hlsl"
#include "../../Material/Material.hlsl"
#include "../Lit/ShaderPass/LitSharePass.hlsl"
#include "../Lit/LitData.hlsl"

#define LIGHTING_DEBUG
#define SHADERPASS SHADERPASS_FORWARD
#include "../../Lighting/Forward.hlsl"
#include "HDRenderPipeline/Debug/HDRenderPipelineDebug.cs.hlsl"
#include "HDRenderPipeline/Debug/DebugLighting.hlsl"
#include "../../Debug/HDRenderPipelineDebug.cs.hlsl"
#include "../../Debug/DebugLighting.hlsl"
// TEMP until pragma work in include
#pragma multi_compile LIGHTLOOP_SINGLE_PASS LIGHTLOOP_TILE_PASS

87
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/LayeredLit/LayeredLitTessellation.shader


[HideInInspector] _LayerCount("_LayerCount", Float) = 2.0
[Enum(None, 0, Multiply, 1, Add, 2)] _VertexColorMode("Vertex color mode", Float) = 0
[HideInInspector] _UVMappingPlanarBlendMask("_UVMappingPlanarBlendMask", Float) = 0.0
_TexWorldScaleBlendMask("Tiling", Float) = 1.0
// Following are builtin properties

[HideInInspector] _UVMappingMask2("_UVMappingMask2", Color) = (1, 0, 0, 0)
[HideInInspector] _UVMappingMask3("_UVMappingMask3", Color) = (1, 0, 0, 0)
[HideInInspector] _UVMappingPlanar0("_UVMappingPlanar0", Float) = 0.0
[HideInInspector] _UVMappingPlanar1("_UVMappingPlanar1", Float) = 0.0
[HideInInspector] _UVMappingPlanar2("_UVMappingPlanar2", Float) = 0.0
[HideInInspector] _UVMappingPlanar3("_UVMappingPlanar3", Float) = 0.0
[Enum(UV0, 0, UV1, 1, UV2, 2, UV3, 3)] _UVDetail0("UV Set for detail0", Float) = 0
[Enum(UV0, 0, UV1, 1, UV2, 2, UV3, 3)] _UVDetail1("UV Set for detail1", Float) = 0
[Enum(UV0, 0, UV1, 1, UV2, 2, UV3, 3)] _UVDetail2("UV Set for detail2", Float) = 0

[HideInInspector] _UVDetailsMappingMask1("_UVDetailsMappingMask1", Color) = (1, 0, 0, 0)
[HideInInspector] _UVDetailsMappingMask2("_UVDetailsMappingMask2", Color) = (1, 0, 0, 0)
[HideInInspector] _UVDetailsMappingMask3("_UVDetailsMappingMask3", Color) = (1, 0, 0, 0)
_TessellationFactorTriangleSize("Tessellation triangle size", Float) = 100.0
_TessellationFactorTriangleSize("Tessellation triangle size", Float) = 100.0
[ToggleOff] _TessellationTilingScale("Tessellation tiling scale", Float) = 1.0
// TODO: Handle culling mode for backface culling
}

// Default is _TESSELLATION_PHONG
#pragma shader_feature _ _TESSELLATION_DISPLACEMENT _TESSELLATION_DISPLACEMENT_PHONG
#pragma shader_feature _TESSELLATION_OBJECT_SCALE
#pragma shader_feature _TESSELLATION_TILING_SCALE
#pragma shader_feature _LAYER_TILING_UNIFORM_SCALE
#pragma shader_feature _LAYER_MAPPING_TRIPLANAR_BLENDMASK
#pragma shader_feature _LAYER_MAPPING_TRIPLANAR0
#pragma shader_feature _LAYER_MAPPING_TRIPLANAR1
#pragma shader_feature _LAYER_MAPPING_TRIPLANAR2
#pragma shader_feature _LAYER_MAPPING_TRIPLANAR3
#pragma shader_feature _LAYER_TILING_COUPLED_WITH_UNIFORM_OBJECT_SCALE
#pragma shader_feature _ _LAYER_MAPPING_PLANAR_BLENDMASK _LAYER_MAPPING_TRIPLANAR_BLENDMASK
#pragma shader_feature _ _LAYER_MAPPING_PLANAR0 _LAYER_MAPPING_TRIPLANAR0
#pragma shader_feature _ _LAYER_MAPPING_PLANAR1 _LAYER_MAPPING_TRIPLANAR1
#pragma shader_feature _ _LAYER_MAPPING_PLANAR2 _LAYER_MAPPING_TRIPLANAR2
#pragma shader_feature _ _LAYER_MAPPING_PLANAR3 _LAYER_MAPPING_TRIPLANAR3
#pragma shader_feature _NORMALMAP_TANGENT_SPACE0
#pragma shader_feature _NORMALMAP_TANGENT_SPACE1
#pragma shader_feature _NORMALMAP_TANGENT_SPACE2

#pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
#pragma multi_compile DIRLIGHTMAP_OFF DIRLIGHTMAP_COMBINED
#pragma multi_compile DYNAMICLIGHTMAP_OFF DYNAMICLIGHTMAP_ON
// enable dithering LOD crossfade
#pragma multi_compile _ LOD_FADE_CROSSFADE
//#pragma multi_compile VELOCITYOUTPUT_OFF VELOCITYOUTPUT_ON
//#pragma multi_compile VELOCITYOUTPUT_OFF VELOCITYOUTPUT_ON
#define UNITY_MATERIAL_LIT // Need to be define before including Material.hlsl
#define UNITY_MATERIAL_LIT // Need to be define before including Material.hlsl
// Use surface gradient normal mapping as it handle correctly triplanar normal mapping and multiple UVSet
#define SURFACE_GRADIENT
#include "ShaderLibrary/common.hlsl"
#include "ShaderLibrary/tessellation.hlsl"
#include "HDRenderPipeline/ShaderConfig.cs.hlsl"
#include "HDRenderPipeline/ShaderVariables.hlsl"
#include "HDRenderPipeline/ShaderPass/FragInputs.hlsl"
#include "HDRenderPipeline/ShaderPass/ShaderPass.cs.hlsl"
#include "../../../ShaderLibrary/common.hlsl"
#include "../../../ShaderLibrary/tessellation.hlsl"
#include "../../ShaderConfig.cs.hlsl"
#include "../../ShaderVariables.hlsl"
#include "../../ShaderPass/FragInputs.hlsl"
#include "../../ShaderPass/ShaderPass.cs.hlsl"
//-------------------------------------------------------------------------------------
// variable declaration

// variable declaration
//-------------------------------------------------------------------------------------
#include "HDRenderPipeline/Material/Lit/LitProperties.hlsl"
#include "../../Material/Lit/LitProperties.hlsl"
// All our shaders use same name for entry point
#pragma vertex Vert

#define SHADERPASS SHADERPASS_GBUFFER
#include "../../Material/Material.hlsl"
#include "../Lit/ShaderPass/LitSharePass.hlsl"
#include "../../Material/Material.hlsl"
#include "../Lit/ShaderPass/LitSharePass.hlsl"
#include "../Lit/LitData.hlsl"
#include "../../ShaderPass/ShaderPassGBuffer.hlsl"

#define LIGHTING_DEBUG
#define SHADERPASS SHADERPASS_GBUFFER
#include "HDRenderPipeline/Debug/HDRenderPipelineDebug.cs.hlsl"
#include "HDRenderPipeline/Debug/DebugLighting.hlsl"
#include "../../Material/Material.hlsl"
#include "../Lit/ShaderPass/LitSharePass.hlsl"
#include "../../Debug/HDRenderPipelineDebug.cs.hlsl"
#include "../../Debug/DebugLighting.hlsl"
#include "../../Material/Material.hlsl"
#include "../Lit/ShaderPass/LitSharePass.hlsl"
#include "../Lit/LitData.hlsl"
#include "../../ShaderPass/ShaderPassGBuffer.hlsl"

#define SHADERPASS SHADERPASS_DEBUG_VIEW_MATERIAL
#include "../../Material/Material.hlsl"
#include "../../Material/Material.hlsl"
#include "../Lit/ShaderPass/LitSharePass.hlsl"
#include "../Lit/LitData.hlsl"
#include "../../ShaderPass/ShaderPassDebugViewMaterial.hlsl"

HLSLPROGRAM
// Lightmap memo
// DYNAMICLIGHTMAP_ON is used when we have an "enlighten lightmap" ie a lightmap updated at runtime by enlighten.This lightmap contain indirect lighting from realtime lights and realtime emissive material.Offline baked lighting(from baked material / light,
// DYNAMICLIGHTMAP_ON is used when we have an "enlighten lightmap" ie a lightmap updated at runtime by enlighten.This lightmap contain indirect lighting from realtime lights and realtime emissive material.Offline baked lighting(from baked material / light,
// both direct and indirect lighting) will hand up in the "regular" lightmap->LIGHTMAP_ON.
// No tessellation for Meta pass

#include "../../Material/Material.hlsl"
#include "../../Material/Material.hlsl"
#include "../Lit/ShaderPass/LitMetaPass.hlsl"
#include "../Lit/LitData.hlsl"
#include "../../ShaderPass/ShaderPassLightTransport.hlsl"

HLSLPROGRAM
// TODO: Tesselation can't work with velocity for now...
#include "../../Material/Material.hlsl"
#include "../../Material/Material.hlsl"
#include "../Lit/ShaderPass/LitVelocityPass.hlsl"
#include "../Lit/LitData.hlsl"
#include "../../ShaderPass/ShaderPassVelocity.hlsl"

Cull[_CullMode]
ZWrite On
ZWrite On
ZTest LEqual
HLSLPROGRAM

#define SHADERPASS SHADERPASS_DEPTH_ONLY
#include "../../Material/Material.hlsl"
#include "../../Material/Material.hlsl"
#include "../Lit/ShaderPass/LitDepthPass.hlsl"
#include "../Lit/LitData.hlsl"
#include "../../ShaderPass/ShaderPassDepthOnly.hlsl"

Cull[_CullMode]
ZWrite On
ZWrite On
HLSLPROGRAM

#define SHADERPASS SHADERPASS_DEPTH_ONLY
#include "../../Material/Material.hlsl"
#include "../../Material/Material.hlsl"
#include "../Lit/ShaderPass/LitDepthPass.hlsl"
#include "../Lit/LitData.hlsl"
#include "../../ShaderPass/ShaderPassDepthOnly.hlsl"

#pragma domain Domain
#define SHADERPASS SHADERPASS_DISTORTION
#include "../../Material/Material.hlsl"
#include "../../Material/Material.hlsl"
#include "../Lit/ShaderPass/LitDistortionPass.hlsl"
#include "../Lit/LitData.hlsl"
#include "../../ShaderPass/ShaderPassDistortion.hlsl"

// TEMP until pragma work in include
#pragma multi_compile LIGHTLOOP_SINGLE_PASS LIGHTLOOP_TILE_PASS
#include "../../Lighting/Lighting.hlsl"
#include "../../Lighting/Lighting.hlsl"
#include "../Lit/ShaderPass/LitSharePass.hlsl"
#include "../Lit/LitData.hlsl"
#include "../../ShaderPass/ShaderPassForward.hlsl"

#define LIGHTING_DEBUG
#define SHADERPASS SHADERPASS_FORWARD
#include "../../Lighting/Forward.hlsl"
#include "HDRenderPipeline/Debug/HDRenderPipelineDebug.cs.hlsl"
#include "HDRenderPipeline/Debug/DebugLighting.hlsl"
#include "../../Debug/HDRenderPipelineDebug.cs.hlsl"
#include "../../Debug/DebugLighting.hlsl"
#include "../../Lighting/Lighting.hlsl"
#include "../../Lighting/Lighting.hlsl"
#include "../Lit/ShaderPass/LitSharePass.hlsl"
#include "../Lit/LitData.hlsl"
#include "../../ShaderPass/ShaderPassForward.hlsl"

10
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Editor/BaseLitUI.cs


public static GUIContent tessellationShapeFactorText = new GUIContent("Shape factor", "Strength of Phong tessellation shape (lerp factor)");
public static GUIContent tessellationBackFaceCullEpsilonText = new GUIContent("Triangle culling Epsilon", "If -1.0 back face culling is enabled for tessellation, higher number mean more aggressive culling and better performance");
public static GUIContent tessellationObjectScaleText = new GUIContent("Enable object scale", "Tessellation displacement will take into account the object scale - Only work with uniform positive scale");
public static GUIContent tessellationTilingScaleText = new GUIContent("Enable tiling scale", "Tessellation displacement will take into account the tiling scale - Only work with uniform positive scale");
}
public enum TessellationMode

protected const string kTessellationBackFaceCullEpsilon = "_TessellationBackFaceCullEpsilon";
protected MaterialProperty tessellationObjectScale = null;
protected const string kTessellationObjectScale = "_TessellationObjectScale";
protected MaterialProperty tessellationTilingScale = null;
protected const string kTessellationTilingScale = "_TessellationTilingScale";
protected override void FindBaseMaterialProperties(MaterialProperty[] props)
{

tessellationShapeFactor = FindProperty(kTessellationShapeFactor, props, false);
tessellationBackFaceCullEpsilon = FindProperty(kTessellationBackFaceCullEpsilon, props, false);
tessellationObjectScale = FindProperty(kTessellationObjectScale, props, false);
tessellationTilingScale = FindProperty(kTessellationTilingScale, props, false);
}
void TessellationModePopup()

m_MaterialEditor.ShaderProperty(tessellationBackFaceCullEpsilon, StylesBaseLit.tessellationBackFaceCullEpsilonText);
}
m_MaterialEditor.ShaderProperty(tessellationObjectScale, StylesBaseLit.tessellationObjectScaleText);
m_MaterialEditor.ShaderProperty(tessellationTilingScale, StylesBaseLit.tessellationTilingScaleText);
EditorGUI.indentLevel--;
}
}

material.EnableKeyword("_TESSELLATION_DISPLACEMENT_PHONG");
}
bool tessellationObjectScaleEnable = material.GetFloat(kTessellationObjectScale) == 1.0;
bool tessellationObjectScaleEnable = material.GetFloat(kTessellationObjectScale) > 0.0;
bool tessellationTilingScaleEnable = material.GetFloat(kTessellationTilingScale) > 0.0;
SetKeyword(material, "_TESSELLATION_TILING_SCALE", tessellationTilingScaleEnable);
}
}

51
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Editor/LitUI.cs


using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Experimental.Rendering.HDPipeline;
namespace UnityEditor.Experimental.Rendering.HDPipeline

public static GUIContent emissiveText = new GUIContent("Emissive Color", "Emissive");
public static GUIContent emissiveIntensityText = new GUIContent("Emissive Intensity", "Emissive");
public static GUIContent emissiveColorModeText = new GUIContent("Emissive Color Usage", "Use emissive color or emissive mask");
public static GUIContent normalMapSpaceWarning = new GUIContent("Object space normal can't be use with triplanar mapping.");
}
public enum UVBaseMapping

protected const string kTexWorldScale = "_TexWorldScale";
protected MaterialProperty UVMappingMask = null;
protected const string kUVMappingMask = "_UVMappingMask";
protected MaterialProperty UVMappingPlanar = null;
protected const string kUVMappingPlanar = "_UVMappingPlanar";
protected MaterialProperty baseColor = null;
protected const string kBaseColor = "_BaseColor";

protected MaterialProperty detailSmoothnessScale = null;
protected const string kDetailSmoothnessScale = "_DetailSmoothnessScale";
protected MaterialProperty subsurfaceProfile = null;
protected const string kSubsurfaceProfile = "_SubsurfaceProfile";
protected SubsurfaceScatteringProfile subsurfaceProfile = null;
protected MaterialProperty subsurfaceProfileID = null;
protected const string kSubsurfaceProfileID = "_SubsurfaceProfile";
protected MaterialProperty subsurfaceRadius = null;
protected const string kSubsurfaceRadius = "_SubsurfaceRadius";
protected MaterialProperty subsurfaceRadiusMap = null;

UVBase = FindProperty(kUVBase, props);
TexWorldScale = FindProperty(kTexWorldScale, props);
UVMappingMask = FindProperty(kUVMappingMask, props);
UVMappingPlanar = FindProperty(kUVMappingPlanar, props);
baseColor = FindProperty(kBaseColor, props);
baseColorMap = FindProperty(kBaseColorMap, props);

detailSmoothnessScale = FindProperty(kDetailSmoothnessScale, props);
// Sub surface
subsurfaceProfile = FindProperty(kSubsurfaceProfile, props);
subsurfaceProfileID = FindProperty(kSubsurfaceProfileID, props);
subsurfaceRadius = FindProperty(kSubsurfaceRadius, props);
subsurfaceRadiusMap = FindProperty(kSubsurfaceRadiusMap, props);
thickness = FindProperty(kThickness, props);

protected void ShaderSSSInputGUI()
{
m_MaterialEditor.ShaderProperty(subsurfaceProfile, Styles.subsurfaceProfileText);
if (subsurfaceProfile == null)
{
int profileID = (int)subsurfaceProfileID.floatValue;
HDRenderPipelineInstance hdPipeline = RenderPipelineManager.currentPipeline as HDRenderPipelineInstance;
if (profileID >= 0 && profileID < hdPipeline.sssSettings.profiles.Length)
{
// This is a valid profile ID.
subsurfaceProfile = hdPipeline.sssSettings.profiles[profileID];
}
else
{
subsurfaceProfile = SubsurfaceScatteringProfile.defaultProfile;
}
// Refresh the ID of the profile.
hdPipeline.sssSettings.OnValidate();
}
// Extract the profile ID.
subsurfaceProfile = EditorGUILayout.ObjectField(Styles.subsurfaceProfileText, subsurfaceProfile, subsurfaceProfile.GetType(), false, null) as SubsurfaceScatteringProfile;
subsurfaceProfileID.floatValue = subsurfaceProfile.settingsIndex;
m_MaterialEditor.ShaderProperty(subsurfaceRadius, Styles.subsurfaceRadiusText);
m_MaterialEditor.TexturePropertySingleLine(Styles.subsurfaceRadiusMapText, subsurfaceRadiusMap);
m_MaterialEditor.ShaderProperty(thickness, Styles.thicknessText);

m_MaterialEditor.ShaderProperty(horizonFade, Styles.horizonFadeText);
m_MaterialEditor.ShaderProperty(normalMapSpace, Styles.normalMapSpaceText);
// Triplanar only work with tangent space normal
if ((NormalMapSpace)normalMapSpace.floatValue == NormalMapSpace.ObjectSpace && ((UVBaseMapping)UVBase.floatValue == UVBaseMapping.Triplanar))
{
EditorGUILayout.HelpBox(Styles.normalMapSpaceWarning.text, MessageType.Error);
}
m_MaterialEditor.TexturePropertySingleLine(Styles.normalMapText, normalMap, normalScale);
m_MaterialEditor.TexturePropertySingleLine(Styles.heightMapText, heightMap);

GUILayout.Label(" " + Styles.textureControlText, EditorStyles.label);
m_MaterialEditor.ShaderProperty(UVBase, Styles.UVBaseMappingText);
// UVSet0 is always set, planar and triplanar will override it.
UVMappingMask.colorValue = new Color(1.0f, 0.0f, 0.0f, 0.0f); // This is override in the shader anyway but just in case.
UVMappingPlanar.floatValue = ((UVBaseMapping)UVBase.floatValue == UVBaseMapping.Planar) ? 1.0f : 0.0f;
UVMappingMask.colorValue = new Color(1.0f, 0.0f, 0.0f, 0.0f); // This is override in the shader anyway but just in case.
if (((UVBaseMapping)UVBase.floatValue == UVBaseMapping.Planar) || ((UVBaseMapping)UVBase.floatValue == UVBaseMapping.Triplanar))
{
m_MaterialEditor.ShaderProperty(TexWorldScale, Styles.texWorldScaleText);

GUILayout.Label(" " + Styles.UVDetailMappingText.text + ": Triplanar");
}
// IF planar/triplanar is not chose, setup the UVSet chosen
// Setup the UVSet for detail, if planar/triplanar is use for base, it will override the mapping of detail (See shader code)
float X, Y, Z, W;
X = ((UVDetailMapping)UVDetail.floatValue == UVDetailMapping.UV0) ? 1.0f : 0.0f;
Y = ((UVDetailMapping)UVDetail.floatValue == UVDetailMapping.UV1) ? 1.0f : 0.0f;

// Note: keywords must be based on Material value not on MaterialProperty due to multi-edit & material animation
// (MaterialProperty value might come from renderer material property block)
SetKeyword(material, "_MAPPING_PLANAR", ((UVBaseMapping)material.GetFloat(kUVBase)) == UVBaseMapping.Planar);
SetKeyword(material, "_MAPPING_TRIPLANAR", ((UVBaseMapping)material.GetFloat(kUVBase)) == UVBaseMapping.Triplanar);
SetKeyword(material, "_NORMALMAP_TANGENT_SPACE", ((NormalMapSpace)material.GetFloat(kNormalMapSpace)) == NormalMapSpace.TangentSpace);
SetKeyword(material, "_EMISSIVE_COLOR", ((EmissiveColorMode)material.GetFloat(kEmissiveColorMode)) == EmissiveColorMode.UseEmissiveColor);

17
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Editor/StandardSpecularToHDLitMaterialUpgrader.cs


{
class StandardSpecularToHDLitMaterialUpgrader : MaterialUpgrader
{
public StandardSpecularToHDLitMaterialUpgrader()
public StandardSpecularToHDLitMaterialUpgrader() : this("Standard (Specular setup)", "HDRenderPipeline/Lit", LitGUI.SetupMaterialKeywordsAndPass) {}
public StandardSpecularToHDLitMaterialUpgrader(string sourceShaderName, string destShaderName, MaterialFinalizer finalizer)
RenameShader("Standard (Specular setup)", "HDRenderPipeline/LitLegacySupport");
RenameShader(sourceShaderName, destShaderName, finalizer);
RenameTexture("_MainTex", "_BaseColorMap");
RenameColor("_Color", "_BaseColor");

RenameColor("_EmissionColor", "_EmissiveColor");
RenameFloat("_DetailNormalMapScale", "_DetailNormalScale");
RenameFloat("_Cutoff", "_AlphaCutoff");
RenameKeywordToFloat("_ALPHATEST_ON", "_AlphaCutoffEnable", 1f, 0f);
// the HD renderloop packs detail albedo and detail normals into a single texture.
// mapping the detail normal map, if any, to the detail map, should do the right thing if
// there is no detail albedo.
RenameTexture("_DetailNormalMap", "_DetailMap");
// Anything reasonable that can be done here?

[Test]
public void UpgradeMaterial()
{
var newShader = Shader.Find("HDRenderPipeline/LitLegacySupport");
var newShader = Shader.Find("HDRenderPipeline/Lit");
var mat = new Material(Shader.Find("Standard (Specular setup)"));
var albedo = new Texture2D(1, 1);
var normals = new Texture2D(1, 1);

mat.color = color;
mat.SetTextureScale("_MainTex", baseScale);
MaterialUpgrader.Upgrade(mat, new StandardSpecularToHDLitMaterialUpgrader(), MaterialUpgrader.UpgradeFlags.CleanupNonUpgradedProperties);
MaterialUpgrader.Upgrade(mat, this, MaterialUpgrader.UpgradeFlags.CleanupNonUpgradedProperties);
Assert.AreEqual(newShader, mat.shader);
Assert.AreEqual(albedo, mat.GetTexture("_BaseColorMap"));

Assert.IsTrue(mat.IsKeywordEnabled("_NORMALMAP"));
}
}
}

17
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Editor/StandardToHDLitMaterialUpgrader.cs


using UnityEngine;
namespace UnityEditor.Experimental.Rendering.HDPipeline
class StandardToHDLitMaterialUpgrader : MaterialUpgrader
class StandardToHDLitMaterialUpgrader : MaterialUpgrader
public StandardToHDLitMaterialUpgrader()
public StandardToHDLitMaterialUpgrader() : this("Standard", "HDRenderPipeline/Lit", LitGUI.SetupMaterialKeywordsAndPass) { }
public StandardToHDLitMaterialUpgrader(string sourceShaderName, string destShaderName, MaterialFinalizer finalizer)
RenameShader("Standard", "HDRenderPipeline/LitLegacySupport");
RenameShader(sourceShaderName, destShaderName, finalizer);
RenameTexture("_MainTex", "_BaseColorMap");
RenameColor("_Color", "_BaseColor");

RenameColor("_EmissionColor", "_EmissiveColor");
RenameFloat("_DetailNormalMapScale", "_DetailNormalScale");
RenameFloat("_Cutoff", "_AlphaCutoff");
RenameKeywordToFloat("_ALPHATEST_ON", "_AlphaCutoffEnable", 1f, 0f);
// the HD renderloop packs detail albedo and detail normals into a single texture.
// mapping the detail normal map, if any, to the detail map, should do the right thing if

[Test]
public void UpgradeMaterial()
{
var newShader = Shader.Find("HDRenderPipeline/LitLegacySupport");
var newShader = Shader.Find("HDRenderPipeline/Lit");
var mat = new Material(Shader.Find("Standard"));
var albedo = new Texture2D(1, 1);
var normals = new Texture2D(1, 1);

mat.color = color;
mat.SetTextureScale("_MainTex", baseScale);
MaterialUpgrader.Upgrade(mat, new StandardToHDLitMaterialUpgrader(), MaterialUpgrader.UpgradeFlags.CleanupNonUpgradedProperties);
MaterialUpgrader.Upgrade(mat, this, MaterialUpgrader.UpgradeFlags.CleanupNonUpgradedProperties);
Assert.AreEqual(newShader, mat.shader);
Assert.AreEqual(albedo, mat.GetTexture("_BaseColorMap"));

Assert.IsTrue(mat.IsKeywordEnabled("_NORMALMAP"));
}
}
}

2
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.cs


public float subsurfaceRadius;
public float thickness;
public int subsurfaceProfile;
public bool enableTransmission;
public bool enableTransmission; // Read from the SSS profile
public Vector3 transmittance;
// Clearcoat

2
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.cs.hlsl


#define DEBUGVIEW_LIT_BSDFDATA_SUBSURFACE_RADIUS (1042)
#define DEBUGVIEW_LIT_BSDFDATA_THICKNESS (1043)
#define DEBUGVIEW_LIT_BSDFDATA_SUBSURFACE_PROFILE (1044)
#define DEBUGVIEW_LIT_BSDFDATA_ENABLE_TRANSMITTANCE (1045)
#define DEBUGVIEW_LIT_BSDFDATA_ENABLE_TRANSMISSION (1045)
#define DEBUGVIEW_LIT_BSDFDATA_TRANSMITTANCE (1046)
#define DEBUGVIEW_LIT_BSDFDATA_COAT_NORMAL_WS (1047)
#define DEBUGVIEW_LIT_BSDFDATA_COAT_ROUGHNESS (1048)

94
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.hlsl


//-----------------------------------------------------------------------------
// SurfaceData is define in Lit.cs which generate Lit.cs.hlsl
//TODO: return this original relative path include after fixing a bug in Unity side
//#include "Lit.cs.hlsl"
#include "HDRenderPipeline/Material/Lit/Lit.cs.hlsl"
#include "Lit.cs.hlsl"
// In case we pack data uint16 buffer we need to change the output render target format to uint16
// TODO: Is there a way to automate these output type based on the format declare in lit.cs ?

// Reference Lambert diffuse / GGX Specular for IBL and area lights
#ifdef HAS_LIGHTLOOP // Both reference define below need to be define only if LightLoop is present, else we get a compile error
// #define LIT_DISPLAY_REFERENCE_AREA
// #define LIT_DISPLAY_REFERENCE_IBL
//#define LIT_DISPLAY_REFERENCE_AREA
//#define LIT_DISPLAY_REFERENCE_IBL
#endif
// Use Lambert diffuse instead of Disney diffuse
// #define LIT_DIFFUSE_LAMBERT_BRDF

// TODO: Check if anisotropy with a dynamic if on anisotropy > 0 is performant. Because it may mean we always calculate both isotropy and anisotropy case.
// Maybe we should always calculate anisotropy in case of standard ? Don't think the compile can optimize correctly.
SamplerState ltc_linear_clamp_sampler;
// TODO: we can share the sampler here and name it SRL_BilinearSampler. However Unity currently doesn't support to set sampler in C#
// + to avoid the message Fragment program 'Frag' : sampler 'sampler_PreIntegratedFGD' has no matching texture and will be undefined.
SAMPLER2D(sampler_PreIntegratedFGD);
SAMPLER2D(sampler_LtcData);
#define N_PROFILES 8
uint _TransmissionFlags; // One bit per profile; 1 = enabled
float _ThicknessScales[N_PROFILES];
float4 _HalfRcpVariancesAndLerpWeights[N_PROFILES][2]; // 2x Gaussians per color channel, A is the the associated interpolation weight
#define SSS_N_PROFILES 8
#define SSS_UNIT_CONVERSION (1.0 / 300.0) // From meters to 1/3 centimeters
uint _TransmissionFlags; // One bit per profile; 1 = enabled
float _ThicknessRemaps[SSS_N_PROFILES][2]; // Remap: 0 = start, 1 = end - start
float4 _HalfRcpVariancesAndLerpWeights[SSS_N_PROFILES][2]; // 2x Gaussians per color channel, A is the the associated interpolation weight
//-----------------------------------------------------------------------------
// Helper functions/variable specific to this material

// _PreIntegratedFGD.y = Gv * Fc
// Pre integrate DisneyDiffuse FGD:
// _PreIntegratedFGD.z = DisneyDiffuse
float3 preFGD = SAMPLE_TEXTURE2D_LOD(_PreIntegratedFGD, sampler_PreIntegratedFGD, float2(NdotV, perceptualRoughness), 0).xyz;
float3 preFGD = SAMPLE_TEXTURE2D_LOD(_PreIntegratedFGD, ltc_linear_clamp_sampler, float2(NdotV, perceptualRoughness), 0).xyz;
// f0 * Gv * (1 - Fc) + Gv * Fc
specularFGD = fresnel0 * preFGD.x + preFGD.y;

#endif
}
void ConfigureTexturingForSSS(inout BSDFData bsdfData)
{
#ifdef SSS_PRE_SCATTER_TEXTURING
bsdfData.diffuseColor = bsdfData.diffuseColor;
#elif SSS_POST_SCATTER_TEXTURING
bsdfData.diffuseColor = float3(1, 1, 1);
#else // combine pre-scatter and post-scatter texturing
bsdfData.diffuseColor = sqrt(bsdfData.diffuseColor);
#endif
}
// Evaluates transmittance for a linear combination of two normalized 2D Gaussians.
// Computes results for each color channel separately.
// Ref: Real-Time Realistic Skin Translucency (2010), equation 9 (modified).

// Thickness and SSS radius are decoupled for artists.
// In theory, we should modify the thickness by the inverse of the radius scale of the profile.
// thickness /= radiusScale;
thickness *= 100;
thickness /= SSS_UNIT_CONVERSION;
float t2 = thickness * thickness;

bsdfData.diffuseColor = surfaceData.baseColor;
bsdfData.fresnel0 = 0.028; // TODO take from subsurfaceProfile
bsdfData.subsurfaceProfile = surfaceData.subsurfaceProfile;
bsdfData.subsurfaceRadius = surfaceData.subsurfaceRadius * 0.01;
bsdfData.thickness = surfaceData.thickness * 0.01 * _ThicknessScales[bsdfData.subsurfaceProfile];
// Make the Std. Dev. of 1 correspond to the effective radius of 1 cm (three-sigma rule).
bsdfData.subsurfaceRadius = SSS_UNIT_CONVERSION * surfaceData.subsurfaceRadius;
bsdfData.thickness = SSS_UNIT_CONVERSION * (_ThicknessRemaps[bsdfData.subsurfaceProfile][0] +
_ThicknessRemaps[bsdfData.subsurfaceProfile][1] * surfaceData.thickness);
bsdfData.enableTransmission = (1 << bsdfData.subsurfaceProfile) & _TransmissionFlags;
if (bsdfData.enableTransmission)
{

bsdfData.fresnel0 = surfaceData.specularColor;
}
#ifdef OUTPUT_SPLIT_LIGHTING
ConfigureTexturingForSSS(bsdfData);
#endif
return bsdfData;
}

}
else if (surfaceData.materialId == MATERIALID_LIT_SSS)
{
outGBuffer2 = float4(surfaceData.subsurfaceRadius, surfaceData.thickness, 0.0, surfaceData.subsurfaceProfile / 8.0); // Number of profile not define yet
outGBuffer2 = float4(surfaceData.subsurfaceRadius, surfaceData.thickness, 0.0, surfaceData.subsurfaceProfile * rcp(SSS_N_PROFILES));
}
else if (surfaceData.materialId == MATERIALID_LIT_CLEAR_COAT)
{

#endif
}
void DecodeFromGBuffer(
float4 DecodeGBuffer0(GBufferType0 encodedGBuffer0)
{
float4 decodedGBuffer0;
#if SHADEROPTIONS_PACK_GBUFFER_IN_U16
decodedGBuffer0.x = UnpackUIntToFloat(encodedGBuffer0.x, 8, 0);
decodedGBuffer0.y = UnpackUIntToFloat(encodedGBuffer0.x, 8, 8);
decodedGBuffer0.z = UnpackUIntToFloat(encodedGBuffer0.y, 8, 0);
decodedGBuffer0.w = UnpackUIntToFloat(encodedGBuffer0.y, 8, 8);
decodedGBuffer0.xyz = Gamma20ToLinear(encodedGBuffer0.xyz);
#else
decodedGBuffer0 = encodedGBuffer0;
#endif
return decodedGBuffer0;
}
void DecodeFromGBuffer(
#if SHADEROPTIONS_PACK_GBUFFER_IN_U16
GBufferType0 inGBufferU0,
GBufferType1 inGBufferU1,

#if SHADEROPTIONS_PACK_GBUFFER_IN_U16
float4 inGBuffer0, inGBuffer1, inGBuffer2, inGBuffer3;
inGBuffer0.x = UnpackUIntToFloat(inGBufferU0.x, 8, 0);
inGBuffer0.y = UnpackUIntToFloat(inGBufferU0.x, 8, 8);
inGBuffer0.z = UnpackUIntToFloat(inGBufferU0.y, 8, 0);
inGBuffer0.w = UnpackUIntToFloat(inGBufferU0.y, 8, 8);
inGBuffer0.xyz = Gamma20ToLinear(inGBuffer0.xyz);
inGBuffer0 = DecodeGBuffer0(inGBufferU0);
inGBuffer2.x = UnpackUIntToFloat(inGBufferU1.x, 8, 0);
inGBuffer2.y = UnpackUIntToFloat(inGBufferU1.x, 8, 8);
inGBuffer2.z = UnpackUIntToFloat(inGBufferU1.y, 8, 0);

{
bsdfData.diffuseColor = baseColor;
bsdfData.fresnel0 = 0.028; // TODO take from subsurfaceProfile
bsdfData.subsurfaceProfile = inGBuffer2.a * 8.0;
bsdfData.subsurfaceRadius = inGBuffer2.r * 0.01;
bsdfData.thickness = inGBuffer2.g * 0.01 * _ThicknessScales[bsdfData.subsurfaceProfile];
bsdfData.subsurfaceProfile = SSS_N_PROFILES * inGBuffer2.a;
// Make the Std. Dev. of 1 correspond to the effective radius of 1 cm (three-sigma rule).
bsdfData.subsurfaceRadius = SSS_UNIT_CONVERSION * inGBuffer2.r;
bsdfData.thickness = SSS_UNIT_CONVERSION * (_ThicknessRemaps[bsdfData.subsurfaceProfile][0] +
_ThicknessRemaps[bsdfData.subsurfaceProfile][1] * inGBuffer2.g);
bsdfData.enableTransmission = (1 << bsdfData.subsurfaceProfile) & _TransmissionFlags;
if (bsdfData.enableTransmission)
{

bakeDiffuseLighting = inGBuffer3.rgb;
#ifdef OUTPUT_SPLIT_LIGHTING
ConfigureTexturingForSSS(bsdfData);
#endif
ApplyDebugToBSDFData(bsdfData);
}

// Note we load the matrix transpose (avoid to have to transpose it in shader)
preLightData.ltcXformGGX = 0.0;
preLightData.ltcXformGGX._m22 = 1.0;
preLightData.ltcXformGGX._m00_m02_m11_m20 = SAMPLE_TEXTURE2D_ARRAY_LOD(_LtcData, sampler_LtcData, uv, LTC_GGX_MATRIX_INDEX, 0);
preLightData.ltcXformGGX._m00_m02_m11_m20 = SAMPLE_TEXTURE2D_ARRAY_LOD(_LtcData, ltc_linear_clamp_sampler, uv, LTC_GGX_MATRIX_INDEX, 0);
preLightData.ltcXformDisneyDiffuse._m00_m02_m11_m20 = SAMPLE_TEXTURE2D_ARRAY_LOD(_LtcData, sampler_LtcData, uv, LTC_DISNEY_DIFFUSE_MATRIX_INDEX, 0);
preLightData.ltcXformDisneyDiffuse._m00_m02_m11_m20 = SAMPLE_TEXTURE2D_ARRAY_LOD(_LtcData, ltc_linear_clamp_sampler, uv, LTC_DISNEY_DIFFUSE_MATRIX_INDEX, 0);
float3 ltcMagnitude = SAMPLE_TEXTURE2D_ARRAY_LOD(_LtcData, sampler_LtcData, uv, LTC_MULTI_GGX_FRESNEL_DISNEY_DIFFUSE_INDEX, 0).rgb;
float3 ltcMagnitude = SAMPLE_TEXTURE2D_ARRAY_LOD(_LtcData, ltc_linear_clamp_sampler, uv, LTC_MULTI_GGX_FRESNEL_DISNEY_DIFFUSE_INDEX, 0).rgb;
preLightData.ltcGGXFresnelMagnitudeDiff = ltcMagnitude.r;
preLightData.ltcGGXFresnelMagnitude = ltcMagnitude.g;
preLightData.ltcDisneyDiffuseMagnitude = ltcMagnitude.b;

29
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.shader


_Anisotropy("Anisotropy", Range(0.0, 1.0)) = 0
_AnisotropyMap("AnisotropyMap", 2D) = "white" {}
_SubsurfaceProfile("Subsurface Profile", Int) = 0
_SubsurfaceProfile("Subsurface Profile", Float) = 0
_SubsurfaceRadius("Subsurface Radius", Range(0.004, 1.0)) = 1.0
_SubsurfaceRadiusMap("Subsurface Radius Map", 2D) = "white" {}
_Thickness("Thickness", Range(0.004, 1.0)) = 1.0

[Enum(UV0, 0, Planar, 1, TriPlanar, 2)] _UVBase("UV Set for base", Float) = 0
_TexWorldScale("Scale to apply on world coordinate", Float) = 1.0
[HideInInspector] _UVMappingMask("_UVMappingMask", Color) = (1, 0, 0, 0)
[HideInInspector] _UVMappingPlanar("_UVMappingPlanar", Float) = 0
[Enum(TangentSpace, 0, ObjectSpace, 1)] _NormalMapSpace("NormalMap space", Float) = 0
[Enum(Standard, 0, Subsurface Scattering, 1, Clear Coat, 2, Specular Color, 3)] _MaterialID("MaterialId", Int) = 0

#pragma shader_feature _DOUBLESIDED_ON
#pragma shader_feature _PER_PIXEL_DISPLACEMENT
#pragma shader_feature _MAPPING_TRIPLANAR
#pragma shader_feature _ _MAPPING_PLANAR _MAPPING_TRIPLANAR
#pragma shader_feature _NORMALMAP_TANGENT_SPACE
#pragma shader_feature _ _REQUIRE_UV2 _REQUIRE_UV3
#pragma shader_feature _EMISSIVE_COLOR

#pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
#pragma multi_compile DIRLIGHTMAP_OFF DIRLIGHTMAP_COMBINED
#pragma multi_compile DYNAMICLIGHTMAP_OFF DYNAMICLIGHTMAP_ON
// enable dithering LOD crossfade
#pragma multi_compile _ LOD_FADE_CROSSFADE
// TODO: We should have this keyword only if VelocityInGBuffer is enable, how to do that ?
//#pragma multi_compile VELOCITYOUTPUT_OFF VELOCITYOUTPUT_ON

#define UNITY_MATERIAL_LIT // Need to be define before including Material.hlsl
// Use surface gradient normal mapping as it handle correctly triplanar normal mapping and multiple UVSet
#define SURFACE_GRADIENT
#include "ShaderLibrary/common.hlsl"
#include "HDRenderPipeline/ShaderConfig.cs.hlsl"
#include "HDRenderPipeline/ShaderVariables.hlsl"
#include "HDRenderPipeline/ShaderPass/FragInputs.hlsl"
#include "HDRenderPipeline/ShaderPass/ShaderPass.cs.hlsl"
#include "../../../ShaderLibrary/common.hlsl"
#include "../../ShaderConfig.cs.hlsl"
#include "../../ShaderVariables.hlsl"
#include "../../ShaderPass/FragInputs.hlsl"
#include "../../ShaderPass/ShaderPass.cs.hlsl"
#include "HDRenderPipeline/Material/Lit/LitProperties.hlsl"
#include "../../Material/Lit/LitProperties.hlsl"
// All our shaders use same name for entry point
#pragma vertex Vert

#define LIGHTING_DEBUG
#define SHADERPASS SHADERPASS_GBUFFER
#include "HDRenderPipeline/Debug/HDRenderPipelineDebug.cs.hlsl"
#include "HDRenderPipeline/Debug/DebugLighting.hlsl"
#include "../../Debug/HDRenderPipelineDebug.cs.hlsl"
#include "../../Debug/DebugLighting.hlsl"
#include "../../Material/Material.hlsl"
#include "ShaderPass/LitSharePass.hlsl"
#include "LitData.hlsl"

#define LIGHTING_DEBUG
#define SHADERPASS SHADERPASS_FORWARD
#include "../../Lighting/Forward.hlsl"
#include "HDRenderPipeline/Debug/HDRenderPipelineDebug.cs.hlsl"
#include "HDRenderPipeline/Debug/DebugLighting.hlsl"
#include "../../Debug/HDRenderPipelineDebug.cs.hlsl"
#include "../../Debug/DebugLighting.hlsl"
// TEMP until pragma work in include
#pragma multi_compile LIGHTLOOP_SINGLE_PASS LIGHTLOOP_TILE_PASS

462
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitData.hlsl


//-------------------------------------------------------------------------------------
// Fill SurfaceData/Builtin data function
//-------------------------------------------------------------------------------------
#include "ShaderLibrary/SampleUVMapping.hlsl"
#include "../SampleLayer.hlsl"
void GetBuiltinData(FragInputs input, SurfaceData surfaceData, float alpha, float depthOffset, out BuiltinData builtinData)
{

builtinData.depthOffset = depthOffset;
}
// Struct that gather UVMapping info of all layers + common calculation
// This is use to abstract the mapping that can differ on layers
LayerUV base;
LayerUV details;
UVMapping base;
UVMapping details;
LayerUV base0;
LayerUV base1;
LayerUV base2;
LayerUV base3;
UVMapping base0;
UVMapping base1;
UVMapping base2;
UVMapping base3;
LayerUV details0;
LayerUV details1;
LayerUV details2;
LayerUV details3;
UVMapping details0;
UVMapping details1;
UVMapping details2;
UVMapping details3;
LayerUV blendMask;
UVMapping blendMask;
// triplanar weight
float3 triplanarWeights;
// Store information that will be share by all UVMapping
float3 vertexNormalWS; // TODO: store also object normal map for object triplanar
float3 triplanarWeights;
#ifdef SURFACE_GRADIENT
// tangent basis for each UVSet - up to 4 for now
float3 vertexTangentWS0, vertexBitangentWS0;
float3 vertexTangentWS1, vertexBitangentWS1;
float3 vertexTangentWS2, vertexBitangentWS2;
float3 vertexTangentWS3, vertexBitangentWS3;
#endif
#ifdef SURFACE_GRADIENT
void GenerateLayerTexCoordBasisTB(FragInputs input, inout LayerTexCoord layerTexCoord)
{
float3 vertexNormalWS = input.worldToTangent[2];
layerTexCoord.vertexTangentWS0 = input.worldToTangent[0];
layerTexCoord.vertexBitangentWS0 = input.worldToTangent[1];
// TODO: We should use relative camera position here - This will be automatic when we will move to camera relative space.
float3 dPdx = ddx_fine(input.positionWS);
float3 dPdy = ddy_fine(input.positionWS);
float3 sigmaX = dPdx - dot(dPdx, vertexNormalWS) * vertexNormalWS;
float3 sigmaY = dPdy - dot(dPdy, vertexNormalWS) * vertexNormalWS;
//float flipSign = dot(sigmaY, cross(nrmVertexNormal, sigmaX) ) ? -1.0 : 1.0;
float flipSign = dot(dPdy, cross(vertexNormalWS, dPdx)) < 0.0 ? -1.0 : 1.0; // gives same as the commented out line above
// TODO: Optimize! The compiler will not be able to remove the tangent space that are not use because it can't know due to our UVMapping constant we use for both base and details
// To solve this we should track which UVSet is use for normal mapping... Maybe not as simple as it sounds
SurfaceGradientGenBasisTB(vertexNormalWS, sigmaX, sigmaY, flipSign, input.texCoord1, layerTexCoord.vertexTangentWS1, layerTexCoord.vertexBitangentWS1);
#if defined(_REQUIRE_UV2) || defined(_REQUIRE_UV3)
SurfaceGradientGenBasisTB(vertexNormalWS, sigmaX, sigmaY, flipSign, input.texCoord2, layerTexCoord.vertexTangentWS2, layerTexCoord.vertexBitangentWS2);
#endif
#if defined(_REQUIRE_UV3)
SurfaceGradientGenBasisTB(vertexNormalWS, sigmaX, sigmaY, flipSign, input.texCoord3, layerTexCoord.vertexTangentWS3, layerTexCoord.vertexBitangentWS3);
#endif
}
#endif
#ifndef LAYERED_LIT_SHADER
#define SAMPLER_NORMALMAP_IDX sampler_NormalMap

#endif
#include "LitDataInternal.hlsl"
// This maybe call directly by tessellation (domain) shader, thus all part regarding surface gradient must be done
// in function with FragInputs input as parameters
// layerTexCoord must have been initialize to 0 outside of this function
float3 positionWS, float3 normalWS, out LayerTexCoord layerTexCoord)
float3 positionWS, float3 vertexNormalWS, inout LayerTexCoord layerTexCoord)
ZERO_INITIALIZE(LayerTexCoord, layerTexCoord);
layerTexCoord.vertexNormalWS = vertexNormalWS;
layerTexCoord.triplanarWeights = ComputeTriplanarWeights(vertexNormalWS);
bool isTriplanar = false;
#ifdef _MAPPING_TRIPLANAR
// one weight for each direction XYZ - Use vertex normal for triplanar
layerTexCoord.triplanarWeights = ComputeTriplanarWeights(normalWS);
isTriplanar = true;
int mappingType = UV_MAPPING_UVSET;
#if defined(_MAPPING_PLANAR)
mappingType = UV_MAPPING_PLANAR;
#elif defined(_MAPPING_TRIPLANAR)
mappingType = UV_MAPPING_TRIPLANAR;
// Be sure that the compiler is aware that we don't touch UV1 to UV3 for main layer so it can optimize code
// Also we have always UVset to 1, if planar/triplanar is enable, it will override it.
// Be sure that the compiler is aware that we don't use UV1 to UV3 for main layer so it can optimize code
positionWS, normalWS, _UVMappingPlanar > 0.0, isTriplanar, _TexWorldScale, layerTexCoord);
positionWS, mappingType, _TexWorldScale, layerTexCoord);
}
// This is call only in this file
// layerTexCoord must have been initialize to 0 outside of this function
void GetLayerTexCoord(FragInputs input, inout LayerTexCoord layerTexCoord)
{
#ifdef SURFACE_GRADIENT
GenerateLayerTexCoordBasisTB(input, layerTexCoord);
#endif
GetLayerTexCoord( input.texCoord0, input.texCoord1, input.texCoord2, input.texCoord3,
input.positionWS, input.worldToTangent[2].xyz, layerTexCoord);
// Note: This function is call by both Per vertex and Per pixel displacement
float GetMaxDisplacement()
{
float maxDisplacement = 0.0;

float2 minUvSize = float2(FLT_MAX, FLT_MAX);
#if defined(_HEIGHTMAP)
if (layerTexCoord.base.isTriplanar)
if (layerTexCoord.base.mappingType == UV_MAPPING_TRIPLANAR)
{
minUvSize = min(layerTexCoord.base.uvZY * _HeightMap_TexelSize.zw, minUvSize);
minUvSize = min(layerTexCoord.base.uvXZ * _HeightMap_TexelSize.zw, minUvSize);

#include "ShaderLibrary/PerPixelDisplacement.hlsl"
void ApplyPerPixelDisplacement(FragInputs input, float3 V, inout LayerTexCoord layerTexCoord)
float ApplyPerPixelDisplacement(FragInputs input, float3 V, inout LayerTexCoord layerTexCoord)
{
bool ppdEnable = false;
bool isPlanar = false;

// All variable are compile time value
isPlanar = layerTexCoord.base.isPlanar;
isTriplanar = layerTexCoord.base.isTriplanar;
isPlanar = layerTexCoord.base.mappingType == UV_MAPPING_PLANAR;
isTriplanar = layerTexCoord.base.mappingType == UV_MAPPING_TRIPLANAR;
#endif
if (ppdEnable)

PerPixelHeightDisplacementParam ppdParam;
float height; // final height processed
float NdotV;
// planar/triplanar
float2 uvXZ;
float2 uvXY;
float2 uvZY;
GetTriplanarCoordinate(V, uvXZ, uvXY, uvZY);
// TODO: support object space planar/triplanar ?
// TODO: implement. Require 3 call to POM + dedicated viewDirTS based on triplanar convention
// apply the 3 offset on all layers
/*
float3 viewDirTS;
float planeHeight;
int numSteps;
ppdParam.uv = layerTexCoord.base0.uvZY;
// Perform a POM in each direction and modify appropriate texture coordinate
ppdParam.uv = layerTexCoord.base.uvZY;
viewDirTS = float3(V.x > 0.0 ? uvZY : -uvZY, V.x);
numSteps = (int)lerp(_PPDMaxSamples, _PPDMinSamples, viewDirTS.z);
float2 offsetZY = ParallaxOcclusionMapping(lod, _PPDLodThreshold, numSteps, viewDirTS, maxHeight, ppdParam, planeHeight);
float3 viewDirTS = ;
int numSteps = (int)lerp(_PPDMaxSamples, _PPDMinSamples, abs(viewDirTS.z));
ParallaxOcclusionMapping(lod, _PPDLodThreshold, numSteps, viewDirTS, maxHeight, ppdParam);
// Apply offset to all triplanar UVSet
layerTexCoord.base.uvZY += offsetZY;
layerTexCoord.details.uvZY += offsetZY;
height = layerTexCoord.triplanarWeights.x * planeHeight;
(...)
*/
ppdParam.uv = layerTexCoord.base.uvXZ;
viewDirTS = float3(V.y > 0.0 ? uvXZ : -uvXZ, V.y);
numSteps = (int)lerp(_PPDMaxSamples, _PPDMinSamples, viewDirTS.z);
float2 offsetXZ = ParallaxOcclusionMapping(lod, _PPDLodThreshold, numSteps, viewDirTS, maxHeight, ppdParam, planeHeight);
layerTexCoord.base.uvXZ += offsetXZ;
layerTexCoord.details.uvXZ += offsetXZ;
height += layerTexCoord.triplanarWeights.y * planeHeight;
ppdParam.uv = layerTexCoord.base.uvXY;
viewDirTS = float3(V.z > 0.0 ? uvXY : -uvXY, V.z);
numSteps = (int)lerp(_PPDMaxSamples, _PPDMinSamples, viewDirTS.z);
float2 offsetXY = ParallaxOcclusionMapping(lod, _PPDLodThreshold, numSteps, viewDirTS, maxHeight, ppdParam, planeHeight);
layerTexCoord.base.uvXY += offsetXY;
layerTexCoord.details.uvXY += offsetXY;
height += layerTexCoord.triplanarWeights.z * planeHeight;
NdotV = 1; // TODO.
ppdParam.uv = layerTexCoord.base.uv;
ppdParam.uv = layerTexCoord.base.uv; // For planar it is uv too, not uvXZ
// For planar the view vector is the world view vector (unless we want to support object triplanar ? and in this case used TransformWorldToObject)
// TODO: do we support object triplanar ? See ComputeLayerTexCoord
float3 viewDirTS = isPlanar ? float3(-V.xz, V.y) : TransformWorldToTangent(V, input.tangentToWorld);
float3x3 worldToTangent = input.worldToTangent;
#ifdef SURFACE_GRADIENT
// The TBN is not normalize, normalize it to do per pixel displacement
worldToTangent[1] = normalize(worldToTangent[1]);
worldToTangent[2] = normalize(worldToTangent[2]);
#endif
float3 viewDirTS = isPlanar ? float3(uvXZ, V.y) : TransformWorldToTangent(V, worldToTangent);
NdotV = viewDirTS.z;
float2 offset = ParallaxOcclusionMapping(lod, _PPDLodThreshold, numSteps, viewDirTS, maxHeight, ppdParam);
float2 offset = ParallaxOcclusionMapping(lod, _PPDLodThreshold, numSteps, viewDirTS, maxHeight, ppdParam, height);
// Apply offset to all UVSet
// Apply offset to all UVSet0 / planar
layerTexCoord.details.uv += offset;
layerTexCoord.details.uv += isPlanar ? offset : _UVDetailsMappingMask.x * offset; // Only apply offset if details map use UVSet0 _UVDetailsMappingMask.x will be 1 in this case, else 0
// Since POM "pushes" geometry inwards (rather than extrude it), { height = height - 1 }.
// Since the result is used as a 'depthOffsetVS', it needs to be positive, so we flip the sign.
float verticalDisplacement = maxHeight - height * maxHeight;
// IDEA: precompute the tiling scale? MOV-MUL vs MOV-MOV-MAX-RCP-MUL.
float tilingScale = rcp(max(_BaseColorMap_ST.x, _BaseColorMap_ST.y));
return tilingScale * verticalDisplacement / NdotV;
return 0.0;
return (SAMPLE_LAYER_TEXTURE2D_LOD(_HeightMap, sampler_HeightMap, layerTexCoord.base, lod).r - _HeightCenter) * _HeightAmplitude;
float height = (SAMPLE_UVMAPPING_TEXTURE2D_LOD(_HeightMap, sampler_HeightMap, layerTexCoord.base, lod).r - _HeightCenter) * _HeightAmplitude;
#ifdef _TESSELLATION_TILING_SCALE
// When we change the tiling, we have want to conserve the ratio with the displacement (and this is consistent with per pixel displacement)
// IDEA: precompute the tiling scale? MOV-MUL vs MOV-MOV-MAX-RCP-MUL.
float tilingScale = rcp(max(_BaseColorMap_ST.x, _BaseColorMap_ST.y));
height *= tilingScale;
#endif
return height;
#ifdef LOD_FADE_CROSSFADE // enable dithering LOD transition if user select CrossFade transition in LOD group
LODDitheringTransition(posInput.unPositionSS, unity_LODFade.y); // Note that we pass the quantized value of LOD fade
#endif
ApplyDoubleSidedFlipOrMirror(input); // Apply double sided flip on the vertex normal
GetLayerTexCoord(input.texCoord0, input.texCoord1, input.texCoord2, input.texCoord3,
input.positionWS, input.tangentToWorld[2].xyz, layerTexCoord);
ZERO_INITIALIZE(LayerTexCoord, layerTexCoord);
GetLayerTexCoord(input, layerTexCoord);
ApplyPerPixelDisplacement(input, V, layerTexCoord);
float depthOffset = 0.0;
float depthOffset = ApplyPerPixelDisplacement(input, V, layerTexCoord);
ApplyDepthOffsetPositionInput(V, depthOffset, posInput);
ApplyDepthOffsetPositionInput(V, depthOffset, GetWorldToHClipMatrix(), posInput);
#endif
// We perform the conversion to world of the normalTS outside of the GetSurfaceData

GetNormalAndTangentWS(input, V, normalTS, surfaceData.normalWS, surfaceData.tangentWS);
// Done one time for all layered - cumulate with spec occ alpha for now
surfaceData.specularOcclusion *= GetHorizonOcclusion(V, surfaceData.normalWS, input.tangentToWorld[2].xyz, _HorizonFade);
surfaceData.specularOcclusion *= GetHorizonOcclusion(V, surfaceData.normalWS, input.worldToTangent[2].xyz, _HorizonFade);
// Caution: surfaceData must be fully initialize before calling GetBuiltinData
GetBuiltinData(input, surfaceData, alpha, depthOffset, builtinData);

#define PROP_BLEND_SCALAR(name, mask) BlendLayeredScalar(name##0, name##1, name##2, name##3, mask);
void GetLayerTexCoord(float2 texCoord0, float2 texCoord1, float2 texCoord2, float2 texCoord3,
float3 positionWS, float3 normalWS, out LayerTexCoord layerTexCoord)
float3 positionWS, float3 vertexNormalWS, inout LayerTexCoord layerTexCoord)
ZERO_INITIALIZE(LayerTexCoord, layerTexCoord);
layerTexCoord.vertexNormalWS = vertexNormalWS;
layerTexCoord.triplanarWeights = ComputeTriplanarWeights(vertexNormalWS);
#if defined(_LAYER_MAPPING_TRIPLANAR_BLENDMASK) || defined(_LAYER_MAPPING_TRIPLANAR0) || defined(_LAYER_MAPPING_TRIPLANAR1) || defined(_LAYER_MAPPING_TRIPLANAR2) || defined(_LAYER_MAPPING_TRIPLANAR3)
// one weight for each direction XYZ - Use vertex normal for triplanar
layerTexCoord.triplanarWeights = ComputeTriplanarWeights(normalWS);
int mappingType = UV_MAPPING_UVSET;
#if defined(_LAYER_MAPPING_PLANAR_BLENDMASK)
mappingType = UV_MAPPING_PLANAR;
#elif defined(_LAYER_MAPPING_TRIPLANAR_BLENDMASK)
mappingType = UV_MAPPING_TRIPLANAR;
bool isTriplanar = false;
#ifdef _LAYER_MAPPING_TRIPLANAR_BLENDMASK
isTriplanar = true;
#endif
// Be sure that the compiler is aware that we don't use UV1 to UV3 for main layer and blend mask so it can optimize code
// Note: Blend mask have its dedicated mapping and tiling. And as Main layer it only use UV0
_UVMappingMask0 = float4(1.0, 0.0, 0.0, 0.0);
// Be sure that the compiler is aware that we don't touch UV1 to UV3 for main layer so it can optimize code
_UVMappingMask0.yzw = float3(0.0, 0.0, 0.0);
// Note: Blend mask have its dedicated mapping adn tiling. And as Main layer it only use UV0
// To share code, we simply call the regular code from the main layer for it save the result, then do regular call for all layers.
// To share code, we simply call the regular code from the main layer for it then save the result, then do regular call for all layers.
positionWS, normalWS, _UVMappingPlanarBlendMask > 0.0, isTriplanar, _TexWorldScaleBlendMask, layerTexCoord, _LayerTilingBlendMask);
positionWS, mappingType, _TexWorldScaleBlendMask, layerTexCoord, _LayerTilingBlendMask);
layerTexCoord.blendMask = layerTexCoord.base0;

#ifdef _LAYER_TILING_UNIFORM_SCALE
#ifdef _LAYER_TILING_COUPLED_WITH_UNIFORM_OBJECT_SCALE
// Extract scaling from world transform
float4x4 worldTransform = GetObjectToWorldMatrix();
// assuming uniform scaling, take only the first column

isTriplanar = false;
#ifdef _LAYER_MAPPING_TRIPLANAR0
isTriplanar = true;
mappingType = UV_MAPPING_UVSET;
#if defined(_LAYER_MAPPING_PLANAR0)
mappingType = UV_MAPPING_PLANAR;
#elif defined(_LAYER_MAPPING_TRIPLANAR0)
mappingType = UV_MAPPING_TRIPLANAR;
positionWS, normalWS, _UVMappingPlanar0 > 0.0, isTriplanar, _TexWorldScale0, layerTexCoord, _LayerTiling0
positionWS, mappingType, _TexWorldScale0, layerTexCoord, _LayerTiling0
isTriplanar = false;
#ifdef _LAYER_MAPPING_TRIPLANAR1
isTriplanar = true;
mappingType = UV_MAPPING_UVSET;
#if defined(_LAYER_MAPPING_PLANAR1)
mappingType = UV_MAPPING_PLANAR;
#elif defined(_LAYER_MAPPING_TRIPLANAR1)
mappingType = UV_MAPPING_TRIPLANAR;
positionWS, normalWS, _UVMappingPlanar1 > 0.0, isTriplanar, _TexWorldScale1, layerTexCoord, _LayerTiling1 * tileObjectScale);
positionWS, mappingType, _TexWorldScale1, layerTexCoord, _LayerTiling1 * tileObjectScale);
isTriplanar = false;
#ifdef _LAYER_MAPPING_TRIPLANAR2
isTriplanar = true;
mappingType = UV_MAPPING_UVSET;
#if defined(_LAYER_MAPPING_PLANAR2)
mappingType = UV_MAPPING_PLANAR;
#elif defined(_LAYER_MAPPING_TRIPLANAR2)
mappingType = UV_MAPPING_TRIPLANAR;
positionWS, normalWS, _UVMappingPlanar2 > 0.0, isTriplanar, _TexWorldScale2, layerTexCoord, _LayerTiling2 * tileObjectScale);
positionWS, mappingType, _TexWorldScale2, layerTexCoord, _LayerTiling2 * tileObjectScale);
isTriplanar = false;
#ifdef _LAYER_MAPPING_TRIPLANAR3
isTriplanar = true;
mappingType = UV_MAPPING_UVSET;
#if defined(_LAYER_MAPPING_PLANAR3)
mappingType = UV_MAPPING_PLANAR;
#elif defined(_LAYER_MAPPING_TRIPLANAR3)
mappingType = UV_MAPPING_TRIPLANAR;
positionWS, normalWS, _UVMappingPlanar3 > 0.0, isTriplanar, _TexWorldScale3, layerTexCoord, _LayerTiling3 * tileObjectScale);
positionWS, mappingType, _TexWorldScale3, layerTexCoord, _LayerTiling3 * tileObjectScale);
}
// This is call only in this file
// layerTexCoord must have been initialize to 0 outside of this function
void GetLayerTexCoord(FragInputs input, inout LayerTexCoord layerTexCoord)
{
#ifdef SURFACE_GRADIENT
GenerateLayerTexCoordBasisTB(input, layerTexCoord);
#endif
GetLayerTexCoord( input.texCoord0, input.texCoord1, input.texCoord2, input.texCoord3,
input.positionWS, input.worldToTangent[2].xyz, layerTexCoord);
}
void ApplyTessellationTileScale(inout float height0, inout float height1, inout float height2, inout float height3)
{
// When we change the tiling, we have want to conserve the ratio with the displacement (and this is consistent with per pixel displacement)
#ifdef _TESSELLATION_TILING_SCALE
float tileObjectScale = 1.0;
#ifdef _LAYER_TILING_COUPLED_WITH_UNIFORM_OBJECT_SCALE
// Extract scaling from world transform
float4x4 worldTransform = GetObjectToWorldMatrix();
// assuming uniform scaling, take only the first column
tileObjectScale = length(float3(worldTransform._m00, worldTransform._m01, worldTransform._m02));
#endif
height0 /= _LayerTiling0 * max(_BaseColorMap0_ST.x, _BaseColorMap0_ST.y);
#if !defined(_MAIN_LAYER_INFLUENCE_MODE)
height0 *= tileObjectScale; // We only affect layer0 in case we are not in influence mode (i.e we should not change the base object)
#endif
height1 /= tileObjectScale * _LayerTiling1 * max(_BaseColorMap1_ST.x, _BaseColorMap1_ST.y);
height2 /= tileObjectScale * _LayerTiling2 * max(_BaseColorMap2_ST.x, _BaseColorMap2_ST.y);
height3 /= tileObjectScale * _LayerTiling3 * max(_BaseColorMap3_ST.x, _BaseColorMap3_ST.y);
#endif
}
// This function is just syntaxic sugar to nullify height not used based on heightmap avaibility and layer

// Blend mask are Main Layer A - Layer 1 R - Layer 2 G - Layer 3 B
// Value for main layer is not use for blending itself but for alternate weighting like density.
// Settings this specific Main layer blend mask in alpha allow to be transparent in case we don't use it and 1 is provide by default.
float4 blendMasks = useLodSampling ? SAMPLE_LAYER_TEXTURE2D_LOD(_LayerMaskMap, sampler_LayerMaskMap, layerTexCoord.blendMask, lod) : SAMPLE_LAYER_TEXTURE2D(_LayerMaskMap, sampler_LayerMaskMap, layerTexCoord.blendMask);
float4 blendMasks = useLodSampling ? SAMPLE_UVMAPPING_TEXTURE2D_LOD(_LayerMaskMap, sampler_LayerMaskMap, layerTexCoord.blendMask, lod) : SAMPLE_UVMAPPING_TEXTURE2D(_LayerMaskMap, sampler_LayerMaskMap, layerTexCoord.blendMask);
#if defined(_LAYER_MASK_VERTEX_COLOR_MUL)
blendMasks *= vertexColor;

// Return the maximun amplitude use by all enabled heightmap
// use for tessellation culling and per pixel displacement
// TODO: For vertex displacement this should take into account the modification in ApplyTessellationTileScale but it should be conservative here (as long as tiling is not negative)
float GetMaxDisplacement()
{
float maxDisplacement = 0.0;

float2 minUvSize = float2(FLT_MAX, FLT_MAX);
#if defined(_HEIGHTMAP0)
if (layerTexCoord.base0.isTriplanar)
if (layerTexCoord.base0.mappingType == UV_MAPPING_TRIPLANAR)
{
minUvSize = min(layerTexCoord.base0.uvZY * _HeightMap0_TexelSize.zw, minUvSize);
minUvSize = min(layerTexCoord.base0.uvXZ * _HeightMap0_TexelSize.zw, minUvSize);

#endif
#if defined(_HEIGHTMAP1)
if (layerTexCoord.base1.isTriplanar)
if (layerTexCoord.base1.mappingType == UV_MAPPING_TRIPLANAR)
{
minUvSize = min(layerTexCoord.base1.uvZY * _HeightMap1_TexelSize.zw, minUvSize);
minUvSize = min(layerTexCoord.base1.uvXZ * _HeightMap1_TexelSize.zw, minUvSize);

#if _LAYER_COUNT >= 3
#if defined(_HEIGHTMAP2)
if (layerTexCoord.base2.isTriplanar)
if (layerTexCoord.base2.mappingType == UV_MAPPING_TRIPLANAR)
{
minUvSize = min(layerTexCoord.base2.uvZY * _HeightMap2_TexelSize.zw, minUvSize);
minUvSize = min(layerTexCoord.base2.uvXZ * _HeightMap2_TexelSize.zw, minUvSize);

#if _LAYER_COUNT >= 4
#if defined(_HEIGHTMAP3)
if (layerTexCoord.base3.isTriplanar)
if (layerTexCoord.base3.mappingType == UV_MAPPING_TRIPLANAR)
{
minUvSize = min(layerTexCoord.base3.uvZY * _HeightMap3_TexelSize.zw, minUvSize);
minUvSize = min(layerTexCoord.base3.uvXZ * _HeightMap3_TexelSize.zw, minUvSize);

// - Blend Mask use same mapping as main layer (UVO, Planar, Triplanar)
// From these rules it mean that PPD is enable only if the user 1) ask for it, 2) if there is one heightmap enabled on active layer, 3) if mapping is the same for all layer respecting 2), 4) if mapping is UV0, planar or triplanar mapping
// Most contraint are handled by the inspector (i.e the UI) like the mapping constraint and is assumed in the shader.
void ApplyPerPixelDisplacement(FragInputs input, float3 V, inout LayerTexCoord layerTexCoord)
float ApplyPerPixelDisplacement(FragInputs input, float3 V, inout LayerTexCoord layerTexCoord)
{
bool ppdEnable = false;
bool isPlanar = false;

// To know if we are planar or triplanar just need to check if any of the active heightmap layer is true as they are enforce to be the same mapping
#if defined(_HEIGHTMAP0)
ppdEnable = true;
isPlanar = layerTexCoord.base0.isPlanar;
isTriplanar = layerTexCoord.base0.isTriplanar;
isPlanar = layerTexCoord.base0.mappingType == UV_MAPPING_PLANAR;
isTriplanar = layerTexCoord.base0.mappingType == UV_MAPPING_TRIPLANAR;
isPlanar = layerTexCoord.base1.isPlanar;
isTriplanar = layerTexCoord.base1.isTriplanar;
isPlanar = layerTexCoord.base1.mappingType == UV_MAPPING_PLANAR;
isTriplanar = layerTexCoord.base1.mappingType == UV_MAPPING_TRIPLANAR;
isPlanar = layerTexCoord.base2.isPlanar;
isTriplanar = layerTexCoord.base2.isTriplanar;
isPlanar = layerTexCoord.base2.mappingType == UV_MAPPING_PLANAR;
isTriplanar = layerTexCoord.base2.mappingType == UV_MAPPING_TRIPLANAR;
#endif
#endif

isPlanar = layerTexCoord.base3.isPlanar;
isTriplanar = layerTexCoord.base3.isTriplanar;
isPlanar = layerTexCoord.base3.mappingType == UV_MAPPING_PLANAR;
isTriplanar = layerTexCoord.base3.mappingType == UV_MAPPING_TRIPLANAR;
#endif
#endif

ppdParam.mainHeightInfluence = 0.0;
#endif
float height; // final height processed
float NdotV;
// We need to calculate the texture space direction. It depends on the mapping.
if (isTriplanar)
{

// Apply to all layer that used triplanar
*/
height = 1;
NdotV = 1;
}
else
{

ppdParam.uv[3] = layerTexCoord.base3.uv;
float3x3 worldToTangent = input.worldToTangent;
#ifdef SURFACE_GRADIENT
// The TBN is not normalize, normalize it to do per pixel displacement
worldToTangent[1] = normalize(worldToTangent[1]);
worldToTangent[2] = normalize(worldToTangent[2]);
#endif
float3 viewDirTS = isPlanar ? float3(-V.xz, V.y) : TransformWorldToTangent(V, input.tangentToWorld);
float3 viewDirTS = isPlanar ? float3(-V.xz, V.y) : TransformWorldToTangent(V, worldToTangent);
NdotV = viewDirTS.z;
float2 offset = ParallaxOcclusionMapping(lod, _PPDLodThreshold, numSteps, viewDirTS, maxHeight, ppdParam);
// Apply offset to all planar uvset
// _UVMappingPlanar0 will be 1.0 is planar is used - _UVMappingMask0.x will be 1.0 is UVSet0 is used;
float4 offsetWeights = isPlanar ? float4(_UVMappingPlanar0, _UVMappingPlanar1, _UVMappingPlanar2, _UVMappingPlanar3) : float4(_UVMappingMask0.x, _UVMappingMask1.x, _UVMappingMask2.x, _UVMappingMask3.x);
float2 offset = ParallaxOcclusionMapping(lod, _PPDLodThreshold, numSteps, viewDirTS, maxHeight, ppdParam, height);
// Apply offset to all planar UV if applicable
float4 planarWeight = float4( layerTexCoord.base0.mappingType == UV_MAPPING_PLANAR ? 1.0 : 0.0,
layerTexCoord.base1.mappingType == UV_MAPPING_PLANAR ? 1.0 : 0.0,
layerTexCoord.base2.mappingType == UV_MAPPING_PLANAR ? 1.0 : 0.0,
layerTexCoord.base3.mappingType == UV_MAPPING_PLANAR ? 1.0 : 0.0);
// _UVMappingMask0.x will be 1.0 is UVSet0 is used;
float4 offsetWeights = isPlanar ? planarWeight : float4(_UVMappingMask0.x, _UVMappingMask1.x, _UVMappingMask2.x, _UVMappingMask3.x);
offsetWeights = isPlanar ? float4(_UVMappingPlanar0, _UVMappingPlanar1, _UVMappingPlanar2, _UVMappingPlanar3) : float4(_UVDetailsMappingMask0.x, _UVDetailsMappingMask1.x, _UVDetailsMappingMask2.x, _UVDetailsMappingMask3.x);
offsetWeights = isPlanar ? planarWeight : float4(_UVDetailsMappingMask0.x, _UVDetailsMappingMask1.x, _UVDetailsMappingMask2.x, _UVDetailsMappingMask3.x);
layerTexCoord.details0.uv += offsetWeights.x * offset;
layerTexCoord.details1.uv += offsetWeights.y * offset;

// Since POM "pushes" geometry inwards (rather than extrude it), { height = height - 1 }.
// Since the result is used as a 'depthOffsetVS', it needs to be positive, so we flip the sign.
float verticalDisplacement = maxHeight - height * maxHeight;
// IDEA: precompute the tiling scale? MOV-MUL vs MOV-MOV-MAX-RCP-MUL.
float tilingScale = rcp(max(_BaseColorMap0_ST.x, _BaseColorMap0_ST.y));
return tilingScale * verticalDisplacement / NdotV;
return 0.0;
}
// Calculate displacement for per vertex displacement mapping

ComputeMaskWeights(blendMasks, weights);
#if defined(_HEIGHTMAP0) || defined(_HEIGHTMAP1) || defined(_HEIGHTMAP2) || defined(_HEIGHTMAP3)
float height0 = (SAMPLE_LAYER_TEXTURE2D_LOD(_HeightMap0, SAMPLER_HEIGHTMAP_IDX, layerTexCoord.base0, lod).r - _LayerCenterOffset0) * _LayerHeightAmplitude0;
float height1 = (SAMPLE_LAYER_TEXTURE2D_LOD(_HeightMap1, SAMPLER_HEIGHTMAP_IDX, layerTexCoord.base1, lod).r - _LayerCenterOffset1) * _LayerHeightAmplitude1;
float height2 = (SAMPLE_LAYER_TEXTURE2D_LOD(_HeightMap2, SAMPLER_HEIGHTMAP_IDX, layerTexCoord.base2, lod).r - _LayerCenterOffset2) * _LayerHeightAmplitude2;
float height3 = (SAMPLE_LAYER_TEXTURE2D_LOD(_HeightMap3, SAMPLER_HEIGHTMAP_IDX, layerTexCoord.base3, lod).r - _LayerCenterOffset3) * _LayerHeightAmplitude3;
float height0 = (SAMPLE_UVMAPPING_TEXTURE2D_LOD(_HeightMap0, SAMPLER_HEIGHTMAP_IDX, layerTexCoord.base0, lod).r - _LayerCenterOffset0) * _LayerHeightAmplitude0;
float height1 = (SAMPLE_UVMAPPING_TEXTURE2D_LOD(_HeightMap1, SAMPLER_HEIGHTMAP_IDX, layerTexCoord.base1, lod).r - _LayerCenterOffset1) * _LayerHeightAmplitude1;
float height2 = (SAMPLE_UVMAPPING_TEXTURE2D_LOD(_HeightMap2, SAMPLER_HEIGHTMAP_IDX, layerTexCoord.base2, lod).r - _LayerCenterOffset2) * _LayerHeightAmplitude2;
float height3 = (SAMPLE_UVMAPPING_TEXTURE2D_LOD(_HeightMap3, SAMPLER_HEIGHTMAP_IDX, layerTexCoord.base3, lod).r - _LayerCenterOffset3) * _LayerHeightAmplitude3;
ApplyTessellationTileScale(height0, height1, height2, height3); // Only apply with per vertex displacement
SetEnabledHeightByLayer(height0, height1, height2, height3);
float heightResult = BlendLayeredScalar(height0, height1, height2, height3, weights);

#if defined(_HEIGHT_BASED_BLEND)
#if defined(_HEIGHTMAP0) || defined(_HEIGHTMAP1) || defined(_HEIGHTMAP2) || defined(_HEIGHTMAP3)
float height0 = (SAMPLE_LAYER_TEXTURE2D(_HeightMap0, SAMPLER_HEIGHTMAP_IDX, layerTexCoord.base0).r - _LayerCenterOffset0) * _LayerHeightAmplitude0;
float height1 = (SAMPLE_LAYER_TEXTURE2D(_HeightMap1, SAMPLER_HEIGHTMAP_IDX, layerTexCoord.base1).r - _LayerCenterOffset1) * _LayerHeightAmplitude1;
float height2 = (SAMPLE_LAYER_TEXTURE2D(_HeightMap2, SAMPLER_HEIGHTMAP_IDX, layerTexCoord.base2).r - _LayerCenterOffset2) * _LayerHeightAmplitude2;
float height3 = (SAMPLE_LAYER_TEXTURE2D(_HeightMap3, SAMPLER_HEIGHTMAP_IDX, layerTexCoord.base3).r - _LayerCenterOffset3) * _LayerHeightAmplitude3;
float height0 = (SAMPLE_UVMAPPING_TEXTURE2D(_HeightMap0, SAMPLER_HEIGHTMAP_IDX, layerTexCoord.base0).r - _LayerCenterOffset0) * _LayerHeightAmplitude0;
float height1 = (SAMPLE_UVMAPPING_TEXTURE2D(_HeightMap1, SAMPLER_HEIGHTMAP_IDX, layerTexCoord.base1).r - _LayerCenterOffset1) * _LayerHeightAmplitude1;
float height2 = (SAMPLE_UVMAPPING_TEXTURE2D(_HeightMap2, SAMPLER_HEIGHTMAP_IDX, layerTexCoord.base2).r - _LayerCenterOffset2) * _LayerHeightAmplitude2;
float height3 = (SAMPLE_UVMAPPING_TEXTURE2D(_HeightMap3, SAMPLER_HEIGHTMAP_IDX, layerTexCoord.base3).r - _LayerCenterOffset3) * _LayerHeightAmplitude3;
SetEnabledHeightByLayer(height0, height1, height2, height3);
float4 heights = float4(height0, height1, height2, height3);

float3 mainNormalTS = GetNormalTS0(input, layerTexCoord, float3(0.0, 0.0, 1.0), 0.0, true, maxMipBias * (1.0 - influenceFactor));
// Add on our regular normal a bit of Main Layer normal base on influence factor. Note that this affect only the "visible" normal.
#ifdef SURFACE_GRADIENT
return normalTS + influenceFactor * mainNormalTS;
#else
#endif
}
float3 ComputeMainBaseColorInfluence(float3 baseColor0, float3 baseColor1, float3 baseColor2, float3 baseColor3, float compoMask, LayerTexCoord layerTexCoord, float weights[_MAX_LAYER])

// We want to calculate the mean color of the texture. For this we will sample a low mipmap
float textureBias = 15.0; // Use maximum bias
float3 baseMeanColor0 = SAMPLE_LAYER_TEXTURE2D_BIAS(_BaseColorMap0, sampler_BaseColorMap0, layerTexCoord.base0, textureBias).rgb *_BaseColor0.rgb;
float3 baseMeanColor1 = SAMPLE_LAYER_TEXTURE2D_BIAS(_BaseColorMap1, sampler_BaseColorMap0, layerTexCoord.base1, textureBias).rgb *_BaseColor1.rgb;
float3 baseMeanColor2 = SAMPLE_LAYER_TEXTURE2D_BIAS(_BaseColorMap2, sampler_BaseColorMap0, layerTexCoord.base2, textureBias).rgb *_BaseColor2.rgb;
float3 baseMeanColor3 = SAMPLE_LAYER_TEXTURE2D_BIAS(_BaseColorMap3, sampler_BaseColorMap0, layerTexCoord.base3, textureBias).rgb *_BaseColor3.rgb;
float3 baseMeanColor0 = SAMPLE_UVMAPPING_TEXTURE2D_BIAS(_BaseColorMap0, sampler_BaseColorMap0, layerTexCoord.base0, textureBias).rgb *_BaseColor0.rgb;
float3 baseMeanColor1 = SAMPLE_UVMAPPING_TEXTURE2D_BIAS(_BaseColorMap1, sampler_BaseColorMap0, layerTexCoord.base1, textureBias).rgb *_BaseColor1.rgb;
float3 baseMeanColor2 = SAMPLE_UVMAPPING_TEXTURE2D_BIAS(_BaseColorMap2, sampler_BaseColorMap0, layerTexCoord.base2, textureBias).rgb *_BaseColor2.rgb;
float3 baseMeanColor3 = SAMPLE_UVMAPPING_TEXTURE2D_BIAS(_BaseColorMap3, sampler_BaseColorMap0, layerTexCoord.base3, textureBias).rgb *_BaseColor3.rgb;
float3 meanColor = BlendLayeredVector3(baseMeanColor0, baseMeanColor1, baseMeanColor2, baseMeanColor3, weights);

return saturate(influenceFactor * (baseColor0 - meanColor) + baseColor);
// saturate(influenceFactor * (baseColor0 - meanColor) + baseColor);
// There is a special case when baseColor < meanColor to avoid getting negative values.
float3 factor = baseColor > meanColor ? (baseColor0 - meanColor) : (baseColor0 * baseColor / meanColor - baseColor);
return influenceFactor * factor + baseColor;
#ifdef LOD_FADE_CROSSFADE // enable dithering LOD transition if user select CrossFade transition in LOD group
LODDitheringTransition(posInput.unPositionSS, unity_LODFade.y); // Note that we pass the quantized value of LOD fade
#endif
ApplyDoubleSidedFlipOrMirror(input); // Apply double sided flip on the vertex normal
GetLayerTexCoord(input.texCoord0, input.texCoord1, input.texCoord2, input.texCoord3,
input.positionWS, input.tangentToWorld[2].xyz, layerTexCoord);
ZERO_INITIALIZE(LayerTexCoord, layerTexCoord);
GetLayerTexCoord(input, layerTexCoord);
ApplyPerPixelDisplacement(input, V, layerTexCoord);
float depthOffset = ApplyPerPixelDisplacement(input, V, layerTexCoord);
float depthOffset = 0.0;
ApplyDepthOffsetPositionInput(V, depthOffset, posInput);
ApplyDepthOffsetPositionInput(V, depthOffset, GetWorldToHClipMatrix(), posInput);
#endif
SurfaceData surfaceData0, surfaceData1, surfaceData2, surfaceData3;

#endif
#if defined(_MAIN_LAYER_INFLUENCE_MODE)
surfaceData.baseColor = ComputeMainBaseColorInfluence(surfaceData0.baseColor, surfaceData1.baseColor, surfaceData2.baseColor, surfaceData3.baseColor, alpha, layerTexCoord, weights);
surfaceData.baseColor = ComputeMainBaseColorInfluence(surfaceData0.baseColor, surfaceData1.baseColor, surfaceData2.baseColor, surfaceData3.baseColor, alpha0, layerTexCoord, weights);
float3 normalTS = ComputeMainNormalInfluence(input, normalTS0, normalTS1, normalTS2, normalTS3, layerTexCoord, weights);
#else
surfaceData.baseColor = SURFACEDATA_BLEND_VECTOR3(surfaceData, baseColor, weights);

surfaceData.perceptualSmoothness = SURFACEDATA_BLEND_SCALAR(surfaceData, perceptualSmoothness, weights);
surfaceData.ambientOcclusion = SURFACEDATA_BLEND_SCALAR(surfaceData, ambientOcclusion, weights);
surfaceData.metallic = SURFACEDATA_BLEND_SCALAR(surfaceData, metallic, weights);
// Init other unused parameter
surfaceData.tangentWS = input.tangentToWorld[0].xyz;
#ifdef SURFACE_GRADIENT
surfaceData.tangentWS = normalize(input.worldToTangent[0].xyz); // The tangent is not normalize in worldToTangent when using surface gradient
#else
surfaceData.tangentWS = input.worldToTangent[0].xyz;
#endif
// Init other parameters
surfaceData.materialId = 0;
surfaceData.anisotropy = 0;
surfaceData.specular = 0.04;

GetNormalAndTangentWS(input, V, normalTS, surfaceData.normalWS, surfaceData.tangentWS);
// Done one time for all layered - cumulate with spec occ alpha for now
surfaceData.specularOcclusion = SURFACEDATA_BLEND_SCALAR(surfaceData, specularOcclusion, weights);
surfaceData.specularOcclusion *= GetHorizonOcclusion(V, surfaceData.normalWS, input.tangentToWorld[2].xyz, _HorizonFade);
surfaceData.specularOcclusion *= GetHorizonOcclusion(V, surfaceData.normalWS, input.worldToTangent[2].xyz, _HorizonFade);
GetBuiltinData(input, surfaceData, alpha, depthOffset, builtinData);
}

148
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitDataInternal.hlsl


void ADD_IDX(ComputeLayerTexCoord)( float2 texCoord0, float2 texCoord1, float2 texCoord2, float2 texCoord3,
float3 positionWS, float3 vertexNormalWS, bool isPlanar, bool isTriplanar, float worldScale, inout LayerTexCoord layerTexCoord, float additionalTiling = 1.0)
float3 positionWS, int mappingType, float worldScale, inout LayerTexCoord layerTexCoord, float additionalTiling = 1.0)
{
// Handle uv0, uv1, uv2, uv3 based on _UVMappingMask weight (exclusif 0..1)
float2 uvBase = ADD_IDX(_UVMappingMask).x * texCoord0 +

ADD_IDX(_UVDetailsMappingMask).y * texCoord1 +
ADD_IDX(_UVDetailsMappingMask).z * texCoord2 +
ADD_IDX(_UVDetailsMappingMask).w * texCoord3;
uvDetails *= additionalTiling.xx;
ADD_IDX(layerTexCoord.base).isPlanar = isPlanar;
ADD_IDX(layerTexCoord.base).isTriplanar = isTriplanar;
ADD_IDX(layerTexCoord.details).isPlanar = isPlanar;
ADD_IDX(layerTexCoord.details).isTriplanar = isTriplanar;
ADD_IDX(layerTexCoord.details).mappingType = ADD_IDX(layerTexCoord.base).mappingType = mappingType;
ADD_IDX(layerTexCoord.details).normalWS = ADD_IDX(layerTexCoord.base).normalWS = layerTexCoord.vertexNormalWS;
// Copy data for the uvmapping
ADD_IDX(layerTexCoord.details).triplanarWeights = ADD_IDX(layerTexCoord.base).triplanarWeights = layerTexCoord.triplanarWeights;
// TODO: Currently we only handle world planar/triplanar but we may want local planar/triplanar.
// In this case both position and normal need to be convert to object space.

float2 uvXY;
float2 uvZY;
GetTriplanarCoordinate(positionWS * worldScale, vertexNormalWS, uvXZ, uvXY, uvZY);
GetTriplanarCoordinate(positionWS * worldScale, uvXZ, uvXY, uvZY);
if (isPlanar)
// Planar is just XZ of triplanar
if (mappingType == UV_MAPPING_PLANAR)
{
uvBase = uvDetails = uvXZ;
}

ADD_IDX(layerTexCoord.details).uvXZ = TRANSFORM_TEX(uvXZ, ADD_IDX(_DetailMap));
ADD_IDX(layerTexCoord.details).uvXY = TRANSFORM_TEX(uvXY, ADD_IDX(_DetailMap));
ADD_IDX(layerTexCoord.details).uvZY = TRANSFORM_TEX(uvZY, ADD_IDX(_DetailMap));
#ifdef SURFACE_GRADIENT
// This part is only relevant for normal mapping with UV_MAPPING_UVSET
// Note: This code work only in pixel shader (as we rely on ddx), it should not be use in other context
ADD_IDX(layerTexCoord.base).tangentWS = ADD_IDX(_UVMappingMask).x * layerTexCoord.vertexTangentWS0 +
ADD_IDX(_UVMappingMask).y * layerTexCoord.vertexTangentWS1 +
ADD_IDX(_UVMappingMask).z * layerTexCoord.vertexTangentWS2 +
ADD_IDX(_UVMappingMask).w * layerTexCoord.vertexTangentWS3;
ADD_IDX(layerTexCoord.base).bitangentWS = ADD_IDX(_UVMappingMask).x * layerTexCoord.vertexBitangentWS0 +
ADD_IDX(_UVMappingMask).y * layerTexCoord.vertexBitangentWS1 +
ADD_IDX(_UVMappingMask).z * layerTexCoord.vertexBitangentWS2 +
ADD_IDX(_UVMappingMask).w * layerTexCoord.vertexBitangentWS3;
ADD_IDX(layerTexCoord.details).tangentWS = ADD_IDX(_UVDetailsMappingMask).x * layerTexCoord.vertexTangentWS0 +
ADD_IDX(_UVDetailsMappingMask).y * layerTexCoord.vertexTangentWS1 +
ADD_IDX(_UVDetailsMappingMask).z * layerTexCoord.vertexTangentWS2 +
ADD_IDX(_UVDetailsMappingMask).w * layerTexCoord.vertexTangentWS3;
ADD_IDX(layerTexCoord.details).bitangentWS = ADD_IDX(_UVDetailsMappingMask).x * layerTexCoord.vertexBitangentWS0 +
ADD_IDX(_UVDetailsMappingMask).y * layerTexCoord.vertexBitangentWS1 +
ADD_IDX(_UVDetailsMappingMask).z * layerTexCoord.vertexBitangentWS2 +
ADD_IDX(_UVDetailsMappingMask).w * layerTexCoord.vertexBitangentWS3;
#endif
}
float3 ADD_IDX(GetNormalTS)(FragInputs input, LayerTexCoord layerTexCoord, float3 detailNormalTS, float detailMask, bool useBias, float bias)

#ifdef _NORMALMAP_TANGENT_SPACE_IDX
if (useBias)
{
normalTS = SAMPLE_LAYER_NORMALMAP_BIAS(ADD_IDX(_NormalMap), SAMPLER_NORMALMAP_IDX, ADD_IDX(layerTexCoord.base), ADD_IDX(_NormalScale), bias);
normalTS = SAMPLE_UVMAPPING_NORMALMAP_BIAS(ADD_IDX(_NormalMap), SAMPLER_NORMALMAP_IDX, ADD_IDX(layerTexCoord.base), ADD_IDX(_NormalScale), bias);
normalTS = SAMPLE_LAYER_NORMALMAP(ADD_IDX(_NormalMap), SAMPLER_NORMALMAP_IDX, ADD_IDX(layerTexCoord.base), ADD_IDX(_NormalScale));
normalTS = SAMPLE_UVMAPPING_NORMALMAP(ADD_IDX(_NormalMap), SAMPLER_NORMALMAP_IDX, ADD_IDX(layerTexCoord.base), ADD_IDX(_NormalScale));
// to be able to combine object space normal with detail map we transform it to tangent space (object space normal composition is complex operation).
// to be able to combine object space normal with detail map or to apply a "scale" we transform it to tangent space (object space normal composition is complex operation).
// Note: There is no such a thing like triplanar with object space normal, so we call directly 2D function
float3 normalOS = SAMPLE_LAYER_NORMALMAP_RGB_BIAS(ADD_IDX(_NormalMap), SAMPLER_NORMALMAP_IDX, ADD_IDX(layerTexCoord.base), ADD_IDX(_NormalScale), bias).rgb;
normalTS = TransformObjectToTangent(normalOS, input.tangentToWorld);
#ifdef SURFACE_GRADIENT
// /We need to decompress the normal ourselve here as UnpackNormalRGB will return a surface gradient
float3 normalOS = SAMPLE_TEXTURE2D_BIAS(ADD_IDX(_NormalMap), SAMPLER_NORMALMAP_IDX, ADD_IDX(layerTexCoord.base).uv, bias).xyz * 2.0 - 1.0;
// normalize(normalOS) // TO CHECK: SurfaceGradientFromPerturbedNormal doesn't require normalOS to be normalize, to check
normalTS = SurfaceGradientFromPerturbedNormal(input.worldToTangent[2], normalOS);
normalTS *= ADD_IDX(_NormalScale);
#else
float3 normalOS = UnpackNormalRGB(SAMPLE_TEXTURE2D_BIAS(ADD_IDX(_NormalMap), SAMPLER_NORMALMAP_IDX, ADD_IDX(layerTexCoord.base).uv, bias), 1.0);
normalTS = TransformObjectToTangent(normalOS, input.worldToTangent);
normalTS.xy *= ADD_IDX(_NormalScale); // Scale in tangent space
normalTS = (normalTS);
#endif
float3 normalOS = SAMPLE_LAYER_NORMALMAP_RGB(ADD_IDX(_NormalMap), SAMPLER_NORMALMAP_IDX, ADD_IDX(layerTexCoord.base), ADD_IDX(_NormalScale)).rgb;
normalTS = TransformObjectToTangent(normalOS, input.tangentToWorld);
#ifdef SURFACE_GRADIENT
// /We need to decompress the normal ourselve here as UnpackNormalRGB will return a surface gradient
float3 normalOS = SAMPLE_TEXTURE2D(ADD_IDX(_NormalMap), SAMPLER_NORMALMAP_IDX, ADD_IDX(layerTexCoord.base).uv).xyz * 2.0 - 1.0;
// normalize(normalOS) // TO CHECK: SurfaceGradientFromPerturbedNormal doesn't require normalOS to be normalize, to check
normalTS = SurfaceGradientFromPerturbedNormal(input.worldToTangent[2], normalOS);
normalTS *= ADD_IDX(_NormalScale);
#else
float3 normalOS = UnpackNormalRGB(SAMPLE_TEXTURE2D(ADD_IDX(_NormalMap), SAMPLER_NORMALMAP_IDX, ADD_IDX(layerTexCoord.base).uv), 1.0);
normalTS = TransformObjectToTangent(normalOS, input.worldToTangent);
normalTS.xy *= ADD_IDX(_NormalScale); // Scale in tangent space
normalTS = (normalTS);
#endif
normalTS = lerp(normalTS, BlendNormalRNM(normalTS, detailNormalTS), detailMask);
#ifdef SURFACE_GRADIENT
normalTS += detailNormalTS;
#else
normalTS = lerp(normalTS, BlendNormalRNM(normalTS, detailNormalTS), detailMask);
#endif
#ifdef SURFACE_GRADIENT
normalTS = float3(0.0, 0.0, 0.0); // No gradient
#else
#endif
#ifdef _DOUBLESIDED_ON
// _DoubleSidedMode is float3(-1, -1, -1) in flip mode and float3(1, 1, -1) in mirror mode (Mirror the normal with the plane define by vertex normal)
float3 oppositeNormalTS = normalTS * _DoubleSidedConstants.xyz;
// TODO : Test if GetOddNegativeScale() is necessary here in case of normal map, as GetOddNegativeScale is take into account in CreateTangentToWorld();
normalTS = input.isFrontFace ? (GetOddNegativeScale() >= 0.0 ? normalTS : oppositeNormalTS) : (-GetOddNegativeScale() >= 0.0 ? normalTS : oppositeNormalTS);
#endif
#endif
return normalTS;

float ADD_IDX(GetSurfaceData)(FragInputs input, LayerTexCoord layerTexCoord, out SurfaceData surfaceData, out float3 normalTS)
{
float alpha = SAMPLE_LAYER_TEXTURE2D(ADD_IDX(_BaseColorMap), ADD_ZERO_IDX(sampler_BaseColorMap), ADD_IDX(layerTexCoord.base)).a * ADD_IDX(_BaseColor).a;
float alpha = SAMPLE_UVMAPPING_TEXTURE2D(ADD_IDX(_BaseColorMap), ADD_ZERO_IDX(sampler_BaseColorMap), ADD_IDX(layerTexCoord.base)).a * ADD_IDX(_BaseColor).a;
// Perform alha test very early to save performance (a killed pixel will not sample textures)
#if defined(_ALPHATEST_ON) && !defined(LAYERED_LIT_SHADER)

float3 detailNormalTS = float3(0.0, 0.0, 0.0);
float detailMask = 0.0;
#ifdef _DETAIL_MAP_IDX
detailMask = SAMPLE_LAYER_TEXTURE2D(ADD_IDX(_DetailMask), SAMPLER_DETAILMASK_IDX, ADD_IDX(layerTexCoord.base)).g;
float2 detailAlbedoAndSmoothness = SAMPLE_LAYER_TEXTURE2D(ADD_IDX(_DetailMap), SAMPLER_DETAILMAP_IDX, ADD_IDX(layerTexCoord.details)).rb;
detailMask = SAMPLE_UVMAPPING_TEXTURE2D(ADD_IDX(_DetailMask), SAMPLER_DETAILMASK_IDX, ADD_IDX(layerTexCoord.base)).g;
float2 detailAlbedoAndSmoothness = SAMPLE_UVMAPPING_TEXTURE2D(ADD_IDX(_DetailMap), SAMPLER_DETAILMAP_IDX, ADD_IDX(layerTexCoord.details)).rb;
detailNormalTS = SAMPLE_LAYER_NORMALMAP_AG(ADD_IDX(_DetailMap), SAMPLER_DETAILMAP_IDX, ADD_IDX(layerTexCoord.details), ADD_ZERO_IDX(_DetailNormalScale));
detailNormalTS = SAMPLE_UVMAPPING_NORMALMAP_AG(ADD_IDX(_DetailMap), SAMPLER_DETAILMAP_IDX, ADD_IDX(layerTexCoord.details), ADD_ZERO_IDX(_DetailNormalScale));
surfaceData.baseColor = SAMPLE_LAYER_TEXTURE2D(ADD_IDX(_BaseColorMap), ADD_ZERO_IDX(sampler_BaseColorMap), ADD_IDX(layerTexCoord.base)).rgb * ADD_IDX(_BaseColor).rgb;
surfaceData.baseColor = SAMPLE_UVMAPPING_TEXTURE2D(ADD_IDX(_BaseColorMap), ADD_ZERO_IDX(sampler_BaseColorMap), ADD_IDX(layerTexCoord.base)).rgb * ADD_IDX(_BaseColor).rgb;
#ifdef _DETAIL_MAP_IDX
surfaceData.baseColor *= LerpWhiteTo(2.0 * saturate(detailAlbedo * ADD_IDX(_DetailAlbedoScale)), detailMask);
#endif

surfaceData.specularOcclusion = SAMPLE_LAYER_TEXTURE2D(ADD_IDX(_SpecularOcclusionMap), SAMPLER_SPECULAROCCLUSIONMAP_IDX, ADD_IDX(layerTexCoord.base)).a;
surfaceData.specularOcclusion = SAMPLE_UVMAPPING_TEXTURE2D(ADD_IDX(_SpecularOcclusionMap), SAMPLER_SPECULAROCCLUSIONMAP_IDX, ADD_IDX(layerTexCoord.base)).a;
#else
// The specular occlusion will be perform outside the internal loop
surfaceData.specularOcclusion = 1.0;

normalTS = ADD_IDX(GetNormalTS)(input, layerTexCoord, detailNormalTS, detailMask, false, 0.0);
#if defined(_MASKMAP_IDX)
surfaceData.perceptualSmoothness = SAMPLE_LAYER_TEXTURE2D(ADD_IDX(_MaskMap), SAMPLER_MASKMAP_IDX, ADD_IDX(layerTexCoord.base)).a;
surfaceData.perceptualSmoothness = SAMPLE_UVMAPPING_TEXTURE2D(ADD_IDX(_MaskMap), SAMPLER_MASKMAP_IDX, ADD_IDX(layerTexCoord.base)).a;
#else
surfaceData.perceptualSmoothness = 1.0;
#endif

// MaskMap is RGBA: Metallic, Ambient Occlusion (Optional), emissive Mask (Optional), Smoothness
#ifdef _MASKMAP_IDX
surfaceData.metallic = SAMPLE_LAYER_TEXTURE2D(ADD_IDX(_MaskMap), SAMPLER_MASKMAP_IDX, ADD_IDX(layerTexCoord.base)).r;
surfaceData.ambientOcclusion = SAMPLE_LAYER_TEXTURE2D(ADD_IDX(_MaskMap), SAMPLER_MASKMAP_IDX, ADD_IDX(layerTexCoord.base)).g;
surfaceData.metallic = SAMPLE_UVMAPPING_TEXTURE2D(ADD_IDX(_MaskMap), SAMPLER_MASKMAP_IDX, ADD_IDX(layerTexCoord.base)).r;
surfaceData.ambientOcclusion = SAMPLE_UVMAPPING_TEXTURE2D(ADD_IDX(_MaskMap), SAMPLER_MASKMAP_IDX, ADD_IDX(layerTexCoord.base)).g;
#else
surfaceData.metallic = 1.0;
surfaceData.ambientOcclusion = 1.0;

// TODO: think about using BC5
#ifdef _TANGENTMAP
#ifdef _NORMALMAP_TANGENT_SPACE_IDX // Normal and tangent use same space
float3 tangentTS = SAMPLE_LAYER_NORMALMAP(ADD_IDX(_TangentMap), ADD_ZERO_IDX(sampler_TangentMap), ADD_IDX(layerTexCoord.base), 1.0);
surfaceData.tangentWS = TransformTangentToWorld(tangentTS, input.tangentToWorld);
#else // Object space
float3 tangentOS = SAMPLE_LAYER_NORMALMAP_RGB(ADD_IDX(_TangentMap), ADD_ZERO_IDX(sampler_TangentMap), ADD_IDX(layerTexCoord.base), 1.0).rgb;
#ifdef _NORMALMAP_TANGENT_SPACE_IDX // Normal and tangent use same space
float3 tangentTS = SAMPLE_UVMAPPING_NORMALMAP(_TangentMap, sampler_TangentMap, layerTexCoord.base, 1.0);
surfaceData.tangentWS = TransformTangentToWorld(tangentTS, input.worldToTangent);
#else // Object space
// Note: There is no such a thing like triplanar with object space normal, so we call directly 2D function
float3 tangentOS = UnpackNormalRGB(SAMPLE_TEXTURE2D(_TangentMap, sampler_TangentMap, layerTexCoord.base.uv), 1.0);
#endif
#endif
surfaceData.tangentWS = input.tangentToWorld[0].xyz;
#ifdef SURFACE_GRADIENT
surfaceData.tangentWS = normalize(input.worldToTangent[0].xyz); // The tangent is not normalize in worldToTangent when using surface gradient
#else
surfaceData.tangentWS = input.worldToTangent[0].xyz;
#endif
// TODO: Is there anything todo regarding flip normal but for the tangent ?
surfaceData.anisotropy = SAMPLE_LAYER_TEXTURE2D(ADD_IDX(_AnisotropyMap), ADD_ZERO_IDX(sampler_AnisotropyMap), ADD_IDX(layerTexCoord.base)).b;
surfaceData.anisotropy = SAMPLE_UVMAPPING_TEXTURE2D(_AnisotropyMap, sampler_AnisotropyMap, layerTexCoord.base).b;
#else
surfaceData.anisotropy = 1.0;
#endif

surfaceData.subsurfaceProfile = _SubsurfaceProfile;
#ifdef _SUBSURFACE_RADIUS_MAP
surfaceData.subsurfaceRadius = SAMPLE_LAYER_TEXTURE2D(ADD_IDX(_SubsurfaceRadiusMap), ADD_ZERO_IDX(sampler_SubsurfaceRadiusMap), ADD_IDX(layerTexCoord.base)).r * _SubsurfaceRadius;
surfaceData.subsurfaceRadius = SAMPLE_UVMAPPING_TEXTURE2D(_SubsurfaceRadiusMap, sampler_SubsurfaceRadiusMap, layerTexCoord.base).r * _SubsurfaceRadius;
surfaceData.thickness = SAMPLE_LAYER_TEXTURE2D(ADD_IDX(_ThicknessMap), ADD_ZERO_IDX(sampler_ThicknessMap), ADD_IDX(layerTexCoord.base)).r;
surfaceData.thickness = SAMPLE_UVMAPPING_TEXTURE2D(_ThicknessMap, sampler_ThicknessMap, layerTexCoord.base).r;
#else
surfaceData.thickness = _Thickness;
#endif

// Layered shader only support materialId 0
surfaceData.materialId = 0;
surfaceData.tangentWS = input.tangentToWorld[0].xyz;
surfaceData.anisotropy = 0;
surfaceData.specular = 0.04;
// All these parameters are ignore as they are re-setup outside of the layers function
surfaceData.tangentWS = float3(0.0, 0.0, 0.0);
surfaceData.anisotropy = 0.0;
surfaceData.specular = 0.0;
surfaceData.subsurfaceRadius = 1.0;
surfaceData.subsurfaceRadius = 0.0;
surfaceData.coatPerceptualSmoothness = 1.0;
surfaceData.coatPerceptualSmoothness = 0.0;
surfaceData.specularColor = float3(0.0, 0.0, 0.0);
#endif // #if !defined(LAYERED_LIT_SHADER)

4
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitProperties.hlsl


//SAMPLER2D(sampler_CoatRoughnessMap);
float _TexWorldScale;
float _UVMappingPlanar;
float4 _UVMappingMask;
float4 _UVDetailsMappingMask;

float _TexWorldScaleBlendMask;
PROP_DECL(float, _TexWorldScale);
float _UVMappingPlanarBlendMask;
PROP_DECL(float, _UVMappingPlanar);
PROP_DECL(float4, _UVMappingMask);
PROP_DECL(float4, _UVDetailsMappingMask);

float _TessellationShapeFactor;
float _TessellationBackFaceCullEpsilon;
float _TessellationObjectScale;
float _TessellationTilingScale;
#endif

13
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitTessellation.hlsl


bool frustumCulled = WorldViewFrustumCull(p0, p1, p2, maxDisplacement, (float4[4])unity_CameraWorldClipPlanes);
bool faceCull = false;
// We use the position of the primary (scene view) camera in order
// to have identical tessellation levels for both the scene view and
// shadow views. Otherwise, depth comparisons become meaningless!
float3 camPosWS = _WorldSpaceCameraPos;
faceCull = BackFaceCullTriangle(p0, p1, p2, _TessellationBackFaceCullEpsilon, _WorldSpaceCameraPos);
faceCull = BackFaceCullTriangle(p0, p1, p2, _TessellationBackFaceCullEpsilon, camPosWS);
}
#endif

// Distance based tessellation
if (_TessellationFactorMaxDistance > 0.0)
{
float3 distFactor = GetDistanceBasedTessFactor(p0, p1, p2, _WorldSpaceCameraPos, _TessellationFactorMinDistance, _TessellationFactorMaxDistance);
float3 distFactor = GetDistanceBasedTessFactor(p0, p1, p2, camPosWS, _TessellationFactorMinDistance, _TessellationFactorMaxDistance);
// We square the disance factor as it allow a better percptual descrease of vertex density.
tessFactor *= distFactor * distFactor;
}

{
// This call will work for both LayeredLit and Lit shader
LayerTexCoord layerTexCoord;
ZERO_INITIALIZE(LayerTexCoord, layerTexCoord);
GetLayerTexCoord(
#ifdef VARYINGS_DS_NEED_TEXCOORD0
input.texCoord0,

#else
float2(0.0, 0.0),
#endif
input.positionWS,
input.positionWS,
input.normalWS,
layerTexCoord);

38
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LitTessellation.shader


[Enum(UV0, 0, Planar, 1, TriPlanar, 2)] _UVBase("UV Set for base", Float) = 0
_TexWorldScale("Scale to apply on world coordinate", Float) = 1.0
[HideInInspector] _UVMappingMask("_UVMappingMask", Color) = (1, 0, 0, 0)
[HideInInspector] _UVMappingPlanar("_UVMappingPlanar", Float) = 0
[Enum(TangentSpace, 0, ObjectSpace, 1)] _NormalMapSpace("NormalMap space", Float) = 0
[Enum(Standard, 0, Subsurface Scattering, 1, Clear Coat, 2, Specular Color, 3)] _MaterialID("MaterialId", Int) = 0

_TessellationShapeFactor("Tessellation shape factor", Range(0.0, 1.0)) = 0.75 // Only use with Phong
_TessellationBackFaceCullEpsilon("Tessellation back face epsilon", Range(-1.0, 0.0)) = -0.25
[ToggleOff] _TessellationObjectScale("Tessellation object scale", Float) = 0.0
[ToggleOff] _TessellationTilingScale("Tessellation tiling height scale", Float) = 1.0
// TODO: Handle culling mode for backface culling
}

#pragma only_renderers d3d11 ps4// TEMP: until we go futher in dev
// #pragma enable_d3d11_debug_symbols
//-------------------------------------------------------------------------------------
// Variant

// Default is _TESSELLATION_PHONG
#pragma shader_feature _ _TESSELLATION_DISPLACEMENT _TESSELLATION_DISPLACEMENT_PHONG
#pragma shader_feature _TESSELLATION_OBJECT_SCALE
#pragma shader_feature _TESSELLATION_TILING_SCALE
#pragma shader_feature _MAPPING_TRIPLANAR
#pragma shader_feature _ _MAPPING_PLANAR _MAPPING_TRIPLANAR
#pragma shader_feature _NORMALMAP
#pragma shader_feature _NORMALMAP
#pragma shader_feature _MASKMAP
#pragma shader_feature _SPECULAROCCLUSIONMAP
#pragma shader_feature _EMISSIVE_COLOR_MAP

#pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
#pragma multi_compile DIRLIGHTMAP_OFF DIRLIGHTMAP_COMBINED
#pragma multi_compile DYNAMICLIGHTMAP_OFF DYNAMICLIGHTMAP_ON
// enable dithering LOD crossfade
#pragma multi_compile _ LOD_FADE_CROSSFADE
// TODO: We should have this keyword only if VelocityInGBuffer is enable, how to do that ?
//#pragma multi_compile VELOCITYOUTPUT_OFF VELOCITYOUTPUT_ON

#define UNITY_MATERIAL_LIT // Need to be define before including Material.hlsl
#define TESSELLATION_ON
// Use surface gradient normal mapping as it handle correctly triplanar normal mapping and multiple UVSet
#define SURFACE_GRADIENT
#include "ShaderLibrary/common.hlsl"
#include "ShaderLibrary/tessellation.hlsl"
#include "HDRenderPipeline/ShaderConfig.cs.hlsl"
#include "HDRenderPipeline/ShaderVariables.hlsl"
#include "HDRenderPipeline/ShaderPass/FragInputs.hlsl"
#include "HDRenderPipeline/ShaderPass/ShaderPass.cs.hlsl"
#include "../../../ShaderLibrary/common.hlsl"
#include "../../../ShaderLibrary/tessellation.hlsl"
#include "../../ShaderConfig.cs.hlsl"
#include "../../ShaderVariables.hlsl"
#include "../../ShaderPass/FragInputs.hlsl"
#include "../../ShaderPass/ShaderPass.cs.hlsl"
#include "HDRenderPipeline/Material/Lit/LitProperties.hlsl"
#include "../../Material/Lit/LitProperties.hlsl"
// All our shaders use same name for entry point
#pragma vertex Vert

#define LIGHTING_DEBUG
#define SHADERPASS SHADERPASS_GBUFFER
#include "HDRenderPipeline/Debug/HDRenderPipelineDebug.cs.hlsl"
#include "HDRenderPipeline/Debug/DebugLighting.hlsl"
#include "../../Debug/HDRenderPipelineDebug.cs.hlsl"
#include "../../Debug/DebugLighting.hlsl"
#include "../../Material/Material.hlsl"
#include "ShaderPass/LitSharePass.hlsl"
#include "LitData.hlsl"

HLSLPROGRAM
// Lightmap memo
// DYNAMICLIGHTMAP_ON is used when we have an "enlighten lightmap" ie a lightmap updated at runtime by enlighten.This lightmap contain indirect lighting from realtime lights and realtime emissive material.Offline baked lighting(from baked material / light,
// DYNAMICLIGHTMAP_ON is used when we have an "enlighten lightmap" ie a lightmap updated at runtime by enlighten.This lightmap contain indirect lighting from realtime lights and realtime emissive material.Offline baked lighting(from baked material / light,
// both direct and indirect lighting) will hand up in the "regular" lightmap->LIGHTMAP_ON.
// No tessellation for Meta pass

HLSLPROGRAM
// TODO: Tesselation can't work with velocity for now...
#pragma hull Hull
#pragma domain Domain
#define SHADERPASS SHADERPASS_VELOCITY
#include "../../Material/Material.hlsl"

#define LIGHTING_DEBUG
#define SHADERPASS SHADERPASS_FORWARD
#include "../../Lighting/Forward.hlsl"
#include "HDRenderPipeline/Debug/HDRenderPipelineDebug.cs.hlsl"
#include "HDRenderPipeline/Debug/DebugLighting.hlsl"
#include "../../Debug/HDRenderPipelineDebug.cs.hlsl"
#include "../../Debug/DebugLighting.hlsl"
// TEMP until pragma work in include
#pragma multi_compile LIGHTLOOP_SINGLE_PASS LIGHTLOOP_TILE_PASS

4
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LtcData.DisneyDiffuse.cs


{
public partial class RenderLoop : Object
{
static double[,] s_LtcDisneyDiffuseMatrixData = new double[k_LtcLUTResolution * k_LtcLUTResolution, k_LtcLUTMatrixDim * k_LtcLUTMatrixDim]
public static double[,] s_LtcDisneyDiffuseMatrixData = new double[k_LtcLUTResolution * k_LtcLUTResolution, k_LtcLUTMatrixDim * k_LtcLUTMatrixDim]
{
{1.018309, 0, 0.000000, 0, 1.018309, 0, 0.000000, 0, 1},
{1.018309, 0, 0.000000, 0, 1.018309, 0, 0.000000, 0, 1},

{1.106979, 0, 0.286686, 0, 1.061540, 0, -0.391058, 0, 1}
};
static float[] s_LtcDisneyDiffuseMagnitudeData = new float[k_LtcLUTResolution * k_LtcLUTResolution]
public static float[] s_LtcDisneyDiffuseMagnitudeData = new float[k_LtcLUTResolution * k_LtcLUTResolution]
{
0.978932f,
0.978932f,

8
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/LtcData.GGX.cs


using UnityEngine;
using UnityEngine;
using UnityEngine.Rendering;
using System;

// This table is precomputed for squared roughness and normalized so that last entry
// is 1 and thus does not need to be store in a texture.
static double[,] s_LtcGGXMatrixData = new double[k_LtcLUTResolution * k_LtcLUTResolution, k_LtcLUTMatrixDim * k_LtcLUTMatrixDim]
public static double[,] s_LtcGGXMatrixData = new double[k_LtcLUTResolution * k_LtcLUTResolution, k_LtcLUTMatrixDim * k_LtcLUTMatrixDim]
{
{499.999756, 0, 0.000000, 0, 499.999756, 0, 0.000000, 0, 1},
{499.999756, 0, 0.000000, 0, 499.999756, 0, 0.000000, 0, 1},

{0.609037, 0, -0.053470, 0, 0.607151, 0, 0.031450, 0, 1}
};
static float[] s_LtcGGXMagnitudeData = new float[k_LtcLUTResolution * k_LtcLUTResolution]
public static float[] s_LtcGGXMagnitudeData = new float[k_LtcLUTResolution * k_LtcLUTResolution]
{
1.000000f,
1.000000f,

0.887423f
};
static float[] s_LtcGGXFresnelData = new float[k_LtcLUTResolution * k_LtcLUTResolution]
public static float[] s_LtcGGXFresnelData = new float[k_LtcLUTResolution * k_LtcLUTResolution]
{
0.000000f,
0.000000f,

76
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Resources/CombineSubsurfaceScattering.shader


HLSLPROGRAM
#pragma target 4.5
#pragma only_renderers d3d11 ps4 metal // TEMP: until we go further in dev
// #pragma enable_d3d11_debug_symbols
#pragma multi_compile _ FILTER_HORIZONTAL
#pragma shader_feature _ SSS_PRE_SCATTER_TEXTURING SSS_POST_SCATTER_TEXTURING
#pragma multi_compile _ FILTER_HORIZONTAL_AND_COMBINE
#include "ShaderLibrary/Common.hlsl"
#include "HDRenderPipeline/ShaderVariables.hlsl"
#include "../../../../ShaderLibrary/Common.hlsl"
#include "../../../ShaderConfig.cs.hlsl"
#include "../../../ShaderVariables.hlsl"
#define UNITY_MATERIAL_LIT // Need to be defined before including Material.hlsl
#include "../../../Material/Material.hlsl"
//-------------------------------------------------------------------------------------
// Inputs & outputs

#define N_SAMPLES 7
#define N_SAMPLES 11
float4 _FilterKernels[N_PROFILES][N_SAMPLES]; // RGB = weights, A = radial distance
float4 _HalfRcpWeightedVariances[N_PROFILES]; // RGB for chromatic, A for achromatic
float4x4 _InvProjMatrix;
float4 _FilterKernels[N_PROFILES][N_SAMPLES]; // RGB = weights, A = radial distance
float4 _HalfRcpWeightedVariances[N_PROFILES]; // RGB for chromatic, A for achromatic
TEXTURE2D_FLOAT(_CameraDepthTexture);
TEXTURE2D(_GBufferTexture2);
TEXTURE2D(_IrradianceSource);
#ifndef SSS_PRE_SCATTER_TEXTURING
TEXTURE2D(_GBufferTexture0); // RGB = baseColor, A = spec. occlusion
#endif
TEXTURE2D(_GBufferTexture2); // R = SSS radius, G = SSS thickness, A = SSS profile
TEXTURE2D(_IrradianceSource); // RGB = irradiance on the back side of the object
//-------------------------------------------------------------------------------------
// Implementation

float4 Frag(Varyings input) : SV_Target
{
PositionInputs posInput = GetPositionInput(input.positionCS.xy, _ScreenSize.zw);
PositionInputs posInput = GetPositionInput(input.positionCS.xy, _ScreenSize.zw, uint2(0, 0));
int profileID = int(gBufferData.y * N_PROFILES);
float distScale = gBufferData.x * 0.01;
int profileID = N_PROFILES * gBufferData.y;
// Make the Std. Dev. of 1 correspond to the effective radius of 1 cm (three-sigma rule).
float distScale = (1.0 / 300.0) * gBufferData.x;
float rawDepth = LOAD_TEXTURE2D(_CameraDepthTexture, posInput.unPositionSS).r;
float rawDepth = LOAD_TEXTURE2D(_MainDepthTexture, posInput.unPositionSS).r;
float fragWidth = ddx(centerPosVS.x);
float fragheight = ddy(centerPosVS.y);
float fragWidth = ddx_fine(centerPosVS.x);
float fragheight = ddy_fine(centerPosVS.y);
#ifdef FILTER_HORIZONTAL
#ifdef FILTER_HORIZONTAL_AND_COMBINE
float stepSize = stepSizeX;
float2 unitDirection = float2(1, 0);
#else

float2 scaledDirection = distScale * stepSize * unitDirection;
float2 scaledDirection = distScale * stepSize * unitDirection;
float phi = 0; // Random rotation; unused for now
float2x2 rotationMatrix = float2x2(cos(phi), -sin(phi), sin(phi), cos(phi));
float2 rotatedDirection = mul(rotationMatrix, scaledDirection);
// Load (1 / (2 * WeightedVariance)) for bilateral weighting.
#ifdef RBG_BILATERAL_WEIGHTS

#endif
// Accumulate filtered irradiance (already weighted by (albedo / Pi)).
float3 totalIrradiance = sampleIrradiance * sampleWeight;
// Accumulate filtered irradiance.
float3 totalIrradiance = sampleWeight * sampleIrradiance;
// Make sure bilateral filtering does not cause energy loss.
// TODO: ask Morten if there is a better way to do this.

for (int i = 1; i < N_SAMPLES; i++)
{
samplePosition = posInput.unPositionSS + scaledDirection * _FilterKernels[profileID][i].a;
samplePosition = posInput.unPositionSS + rotatedDirection * _FilterKernels[profileID][i].a;
rawDepth = LOAD_TEXTURE2D(_CameraDepthTexture, samplePosition).r;
sampleIrradiance = LOAD_TEXTURE2D(_IrradianceSource, samplePosition).rgb;
rawDepth = LOAD_TEXTURE2D(_MainDepthTexture, samplePosition).r;
sampleIrradiance = LOAD_TEXTURE2D(_IrradianceSource, samplePosition).rgb;
// Apply bilateral weighting.
// Ref #1: Skin Rendering by Pseudo–Separable Cross Bilateral Filtering.

sampleWeight *= exp(-zDistance * zDistance * halfRcpVariance);
totalIrradiance += sampleIrradiance * sampleWeight;
totalIrradiance += sampleWeight * sampleIrradiance;
#ifdef SSS_PRE_SCATTER_TEXTURING
float3 diffuseContrib = float3(1, 1, 1);
#elif SSS_POST_SCATTER_TEXTURING
float3 diffuseColor = DecodeGBuffer0(LOAD_TEXTURE2D(_GBufferTexture0, posInput.unPositionSS)).rgb;
float3 diffuseContrib = diffuseColor;
#else // combine pre-scatter and post-scatter texturing
float3 diffuseColor = DecodeGBuffer0(LOAD_TEXTURE2D(_GBufferTexture0, posInput.unPositionSS)).rgb;
float3 diffuseContrib = sqrt(diffuseColor);
#endif
#ifdef FILTER_HORIZONTAL_AND_COMBINE
return float4(diffuseContrib * totalIrradiance / totalWeight, 1.0);
#else
#endif
}
ENDHLSL
}

6
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Resources/PreIntegratedFGD.shader


#pragma target 4.5
#pragma only_renderers d3d11 ps4 metal // TEMP: until we go further in dev
#include "ShaderLibrary/Common.hlsl"
#include "ShaderLibrary/ImageBasedLighting.hlsl"
#include "HDRenderPipeline/ShaderVariables.hlsl"
#include "../../../../ShaderLibrary/Common.hlsl"
#include "../../../../ShaderLibrary/ImageBasedLighting.hlsl"
#include "../../../ShaderVariables.hlsl"
struct Attributes

1
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/ShaderPass/LitDepthPass.hlsl


// Varying - Use for pixel shader
// This second set of define allow to say which varyings will be output in the vertex (no more tesselation)
#if REQUIRE_TANGENT_TO_WORLD
#define VARYINGS_NEED_POSITION_WS // Required to get view vector
#define VARYINGS_NEED_TANGENT_TO_WORLD
#endif

1
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/ShaderPass/LitDistortionPass.hlsl


// Varying - Use for pixel shader
// This second set of define allow to say which varyings will be output in the vertex (no more tesselation)
#if REQUIRE_TANGENT_TO_WORLD
#define VARYINGS_NEED_POSITION_WS // Required to get view vector
#define VARYINGS_NEED_TANGENT_TO_WORLD
#endif

1
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/ShaderPass/LitVelocityPass.hlsl


#define VARYINGS_NEED_POSITION_WS
#if REQUIRE_TANGENT_TO_WORLD
#define VARYINGS_NEED_POSITION_WS // Required to get view vector
#define VARYINGS_NEED_TANGENT_TO_WORLD
#endif

18
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Material.hlsl


#ifndef UNITY_MATERIAL_INCLUDED
#define UNITY_MATERIAL_INCLUDED
#include "ShaderLibrary/Color.hlsl"
#include "ShaderLibrary/Packing.hlsl"
#include "ShaderLibrary/BSDF.hlsl"
#include "ShaderLibrary/Debug.hlsl"
#include "ShaderLibrary/GeometricTools.hlsl"
#include "ShaderLibrary/CommonMaterial.hlsl"
#include "ShaderLibrary/EntityLighting.hlsl"
#include "ShaderLibrary/ImageBasedLighting.hlsl"
#include "../../ShaderLibrary/Color.hlsl"
#include "../../ShaderLibrary/Packing.hlsl"
#include "../../ShaderLibrary/BSDF.hlsl"
#include "../../ShaderLibrary/Debug.hlsl"
#include "../../ShaderLibrary/GeometricTools.hlsl"
#include "../../ShaderLibrary/CommonMaterial.hlsl"
#include "../../ShaderLibrary/EntityLighting.hlsl"
#include "../../ShaderLibrary/ImageBasedLighting.hlsl"
//-----------------------------------------------------------------------------
// BuiltinData

#include "Lit/Lit.hlsl"
#elif defined(UNITY_MATERIAL_UNLIT)
#include "Unlit/Unlit.hlsl"
#elif defined(UNITY_MATERIAL_IRIDESCENCE)
//#include "Iridescence/Iridescence.hlsl"
#endif
//-----------------------------------------------------------------------------

34
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/MaterialUtilities.hlsl


#endif
}
// Flipping or mirroring a normal can be done directly on the tangent space. This has the benefit to apply to the whole process either in surface gradient or not.
// This function will modify FragInputs and this is not propagate outside of GetSurfaceAndBuiltinData(). This is ok as tangent space is not use outside of GetSurfaceAndBuiltinData().
void ApplyDoubleSidedFlipOrMirror(inout FragInputs input)
{
#ifdef _DOUBLESIDED_ON
// _DoubleSidedConstants is float3(-1, -1, -1) in flip mode and float3(1, 1, -1) in mirror mode
// To get a flipped normal with the tangent space, we must flip bitangent (because it is construct from the normal) and normal
// To get a mirror normal with the tangent space, we only need to flip the normal and not the tangent
float2 flipSign = input.isFrontFace ? float2(1.0, 1.0) : _DoubleSidedConstants.yz; // TOCHECK : GetOddNegativeScale() is not necessary here as it is apply for tangent space creation.
input.worldToTangent[1] = flipSign.x * input.worldToTangent[1]; // bitangent
input.worldToTangent[2] = flipSign.y * input.worldToTangent[2]; // normal
#ifdef SURFACE_GRADIENT
// TOCHECK: seems that we don't need to invert any genBasisTB(), sign cancel. Which is expected as we deal with surface gradient.
#endif
#endif
}
void GetNormalAndTangentWS(FragInputs input, float3 V, float3 normalTS, inout float3 normalWS, inout float3 tangentWS, bool twoSided = false)
void GetNormalAndTangentWS(FragInputs input, float3 V, float3 normalTS, inout float3 normalWS, inout float3 tangentWS, bool wantNegativeNormal = false)
normalWS = TransformTangentToWorld(normalTS, input.tangentToWorld);
#ifdef SURFACE_GRADIENT
normalWS = SurfaceGradientResolveNormal(input.worldToTangent[2], normalTS);
#else
normalWS = TransformTangentToWorld(normalTS, input.worldToTangent);
#endif
// NdotV should not be negative for visible pixels, but it can happen due to the
// perspective projection and the normal mapping + decals. In that case, the normal
// should be modified to become valid (i.e facing the camera) to avoid weird artifacts.
// Note: certain applications (e.g. SpeedTree) require to still have negative normal to perform their own two sided lighting
// This will potentially reduce the length of the normal at edges of geometry.
GetShiftedNdotV(normalWS, V, twoSided);
GetShiftedNdotV(normalWS, V, wantNegativeNormal);
// This is use with anisotropic material
tangentWS = normalize(tangentWS - dot(tangentWS, normalWS));
}

8
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Unlit/Editor/BaseUnlitUI.cs


public static GUIContent distortionEnableText = new GUIContent("Distortion", "Enable distortion on this shader");
public static GUIContent distortionOnlyText = new GUIContent("Distortion Only", "This shader will only be use to render distortion");
public static GUIContent distortionDepthTestText = new GUIContent("Distortion Depth Test", "Enable the depth test for distortion");
public static GUIContent emissiveWarning = new GUIContent("Emissive value is animated but the material has not been configured to support emissive. Please make sure the material itself has some amount of emissive.");
public static GUIContent emissiveColorWarning = new GUIContent("Ensure emissive color is non-black for emission to have effect.");
}
public enum SurfaceType

}
SetKeyword(material, "_DISTORTION_ON", distortionEnable);
// A material's GI flag internally keeps track of whether emission is enabled at all, it's enabled but has no effect
// or is enabled and may be modified at runtime. This state depends on the values of the current flag and emissive color.
// The fixup routine makes sure that the material is in the correct state if/when changes are made to the mode or color.
MaterialEditor.FixupEmissiveFlag(material);
}
static public void SetupBaseUnlitMaterialPass(Material material)

12
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Unlit/Unlit.shader


// Include
//-------------------------------------------------------------------------------------
#include "ShaderLibrary/common.hlsl"
#include "HDRenderPipeline/ShaderConfig.cs.hlsl"
#include "HDRenderPipeline/ShaderVariables.hlsl"
#include "HDRenderPipeline/ShaderPass/FragInputs.hlsl"
#include "HDRenderPipeline/ShaderPass/ShaderPass.cs.hlsl"
#include "../../../ShaderLibrary/common.hlsl"
#include "../../ShaderConfig.cs.hlsl"
#include "../../ShaderVariables.hlsl"
#include "../../ShaderPass/FragInputs.hlsl"
#include "../../ShaderPass/ShaderPass.cs.hlsl"
#include "HDRenderPipeline/Material/Unlit/UnlitProperties.hlsl"
#include "../../Material/Unlit/UnlitProperties.hlsl"
// All our shaders use same name for entry point
#pragma vertex Vert

20
Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/Editor/PostProcessingSRPEditor.cs


namespace UnityEditor.Experimental.Rendering.HDPipeline
{
using GradingType = PostProcessing.ColorGradingSettings.GradingType;
using EyeAdaptationType = PostProcessing.EyeAdaptationSettings.EyeAdaptationType;
using GradingType = PostProcessingSRP.ColorGradingSettings.GradingType;
using EyeAdaptationType = PostProcessingSRP.EyeAdaptationSettings.EyeAdaptationType;
[CustomEditor(typeof(PostProcessing))]
[CustomEditor(typeof(PostProcessingSRP))]
public class PostProcessingEditor : Editor
{
#region Serialized settings

public VignetteSettings vignetteSettings;
public SerializedProperty globalDithering;
SerializedProperty FindProperty<TValue>(Expression<Func<PostProcessing, TValue>> expr)
SerializedProperty FindProperty<TValue>(Expression<Func<PostProcessingSRP, TValue>> expr)
{
var path = Utilities.GetFieldPath(expr);
return serializedObject.FindProperty(path);

void ColorGradingUI()
{
var camera = (target as PostProcessing).GetComponent<Camera>();
var camera = (target as PostProcessingSRP).GetComponent<Camera>();
if (camera != null)
{
using (new EditorGUILayout.HorizontalScope())

#region Color grading stuff
void SetLUTImportSettings()
{
var lut = (target as PostProcessing).colorGrading.logLut;
var lut = (target as PostProcessingSRP).colorGrading.logLut;
var importer = (TextureImporter)AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(lut));
importer.textureType = TextureImporterType.Default;
importer.filterMode = FilterMode.Bilinear;

bool ValidateLutImportSettings()
{
var lut = (target as PostProcessing).colorGrading.logLut;
var lut = (target as PostProcessingSRP).colorGrading.logLut;
if (lut == null)
return true;

var targetRt = RenderTexture.GetTemporary(width, height, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear);
// Render the current frame without post processing
var oldPPState = (target as PostProcessing).enabled;
(target as PostProcessing).enabled = false;
var oldPPState = (target as PostProcessingSRP).enabled;
(target as PostProcessingSRP).enabled = false;
var oldTarget = camera.targetTexture;
var oldActive = RenderTexture.active;
camera.targetTexture = targetRt;

texture.ReadPixels(new Rect(0, 0, targetRt.width, targetRt.height), 0, 0);
camera.targetTexture = oldTarget;
RenderTexture.active = oldActive;
(target as PostProcessing).enabled = oldPPState;
(target as PostProcessingSRP).enabled = oldPPState;
// Cleanup
RenderTexture.ReleaseTemporary(stampRt);

4
Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/Resources/EyeAdaptation.shader


HLSLINCLUDE
#pragma target 4.5
#include "ShaderLibrary/Common.hlsl"
#include "HDRenderPipeline/ShaderVariables.hlsl"
#include "../../../ShaderLibrary/Common.hlsl"
#include "../../ShaderVariables.hlsl"
#include "EyeAdaptation.hlsl"
TEXTURE2D(_MainTex);

2
Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/Resources/EyeHistogram.compute


// Put the following line to 0 or comment it to disable vignette weighting
#define USE_VIGNETTE_WEIGHTING 1
#include "ShaderLibrary/Common.hlsl"
#include "../../../ShaderLibrary/Common.hlsl"
#include "EyeAdaptation.hlsl"
RWStructuredBuffer<uint> _Histogram;

6
Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/Resources/FinalPass.shader


HLSLINCLUDE
#pragma target 4.5
#include "ShaderLibrary/Color.hlsl"
#include "ShaderLibrary/Common.hlsl"
#include "HDRenderPipeline/ShaderVariables.hlsl"
#include "../../../ShaderLibrary/Color.hlsl"
#include "../../../ShaderLibrary/Common.hlsl"
#include "../../ShaderVariables.hlsl"
#include "ColorGrading.hlsl"
TEXTURE2D(_MainTex);

6
Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/Resources/LutGen.shader


Shader "Hidden/HDRenderPipeline/LutGen"
Shader "Hidden/HDRenderPipeline/LutGen"
#include "ShaderLibrary/Common.hlsl"
#include "HDRenderPipeline/ShaderVariables.hlsl"
#include "../../../ShaderLibrary/Common.hlsl"
#include "../../ShaderVariables.hlsl"
#include "ColorGrading.hlsl"
float4 _LutParams;

6
Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/PostProcessingSRP.cs


namespace UnityEngine.Experimental.Rendering.HDPipeline
{
using GradingType = PostProcessing.ColorGradingSettings.GradingType;
using EyeAdaptationType = PostProcessing.EyeAdaptationSettings.EyeAdaptationType;
using GradingType = PostProcessingSRP.ColorGradingSettings.GradingType;
using EyeAdaptationType = PostProcessingSRP.EyeAdaptationSettings.EyeAdaptationType;
public sealed partial class PostProcessing : MonoBehaviour
public sealed partial class PostProcessingSRP : MonoBehaviour
{
public EyeAdaptationSettings eyeAdaptation = new EyeAdaptationSettings();
public ColorGradingSettings colorGrading = new ColorGradingSettings();

2
Assets/ScriptableRenderPipeline/HDRenderPipeline/PostProcess/PostProcessingSRP.Settings.cs


namespace UnityEngine.Experimental.Rendering.HDPipeline
{
partial class PostProcessing
partial class PostProcessingSRP
{
[Serializable]
public sealed class ColorGradingSettings

10
Assets/ScriptableRenderPipeline/HDRenderPipeline/SceneSettings/Resources/DrawGaussianProfile.shader


// Include
//-------------------------------------------------------------------------------------
#include "ShaderLibrary/Common.hlsl"
#include "ShaderLibrary/Color.hlsl"
#include "HDRenderPipeline/ShaderVariables.hlsl"
#include "../../../ShaderLibrary/Common.hlsl"
#include "../../../ShaderLibrary/Color.hlsl"
#include "../../ShaderVariables.hlsl"
//-------------------------------------------------------------------------------------
// Inputs & outputs

Varyings Vert(Attributes input)
{
Varyings output;
output.vertex = TransformWorldToHClip(input.vertex);
output.vertex = TransformWorldToHClip(input.vertex);
output.texcoord = input.texcoord.xy;
return output;
}

float dist = length(2 * input.texcoord - 1);
float dist = length(input.texcoord - 0.5);
float3 var1 = _StdDev1.rgb * _StdDev1.rgb;
float3 var2 = _StdDev2.rgb * _StdDev2.rgb;

22
Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/FragInputs.hlsl


// This structure gather all possible varying/interpolator for this shader.
//-------------------------------------------------------------------------------------
#include "HDRenderPipeline/Debug/DebugViewMaterial.cs.hlsl"
#include "../Debug/DebugViewMaterial.cs.hlsl"
struct FragInputs
{

float2 texCoord1;
float2 texCoord2;
float2 texCoord3;
float3 tangentToWorld[3]; // These 3 vectors are normalized (no need for the material to normalize) and these are only for UVSet 0
// TODO: confirm with Morten following statement
// Our TBN is orthogonal but is maybe not orthonormal in order to be compliant with external bakers (Like xnormal that use mikktspace).
// (xnormal for example take into account the interpolation when baking the normal and normalizing the tangent basis could cause distortion).
// When using worldToTangent with surface gradient, it doesn't normalize the tangent/bitangent vector (We instead use exact same scale as applied to interpolated vertex normal to avoid breaking compliance).
// this mean that any usage of worldToTangent[1] or worldToTangent[2] outside of the context of normal map (like for POM) must normalize the TBN (TCHECK if this make any difference ?)
// When not using surface gradient, each vector of worldToTangent are normalize (TODO: Maybe they should not even in case of no surface gradient ? Ask Morten)
float3x3 worldToTangent;
// For two sided lighting
bool isFrontFace;

FragInputs output;
ZERO_INITIALIZE(FragInputs, output);
output.tangentToWorld[0] = float3(0.0, 0.0, 1.0);
output.tangentToWorld[2] = float3(0.0, 0.0, 1.0);
// Init to some default value to make the computer quiet (else it output "divide by zero" warning even if value is not used).
output.worldToTangent[0] = float3(0.0, 0.0, 1.0);
output.worldToTangent[2] = float3(0.0, 0.0, 1.0);
return output;
}

result = float3(input.texCoord3, 0.0);
break;
case DEBUGVIEWVARYING_VERTEX_TANGENT_WS:
result = input.tangentToWorld[0].xyz * 0.5 + 0.5;
result = input.worldToTangent[0].xyz * 0.5 + 0.5;
result = input.tangentToWorld[1].xyz * 0.5 + 0.5;
result = input.worldToTangent[1].xyz * 0.5 + 0.5;
result = input.tangentToWorld[2].xyz * 0.5 + 0.5;
result = input.worldToTangent[2].xyz * 0.5 + 0.5;
break;
case DEBUGVIEWVARYING_VERTEX_COLOR:
result = input.color.rgb; needLinearToSRGB = true;

15
Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/ShaderPassDebugViewMaterial.hlsl


#endif // TESSELLATION_ON
float4 Frag(PackedVaryingsToPS packedInput) : SV_Target
void Frag( PackedVaryingsToPS packedInput
, out float4 outColor : SV_Target
#ifdef _DEPTHOFFSET_ON
, out float outputDepth : SV_Depth
#endif
)
PositionInputs posInput = GetPositionInput(input.unPositionSS.xy, _ScreenSize.zw);
PositionInputs posInput = GetPositionInput(input.unPositionSS.xy, _ScreenSize.zw, uint2(0, 0));
UpdatePositionInput(input.unPositionSS.z, input.unPositionSS.w, input.positionWS, posInput);
float3 V = GetWorldSpaceNormalizeViewDir(input.positionWS);

if (!needLinearToSRGB)
result = SRGBToLinear(max(0, result));
return float4(result, 0.0);
#ifdef _DEPTHOFFSET_ON
outputDepth = posInput.depthRaw;
#endif
outColor = float4(result, 1.0);
}

2
Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/ShaderPassDepthOnly.hlsl


FragInputs input = UnpackVaryingsMeshToFragInputs(packedInput.vmesh);
// input.unPositionSS is SV_Position
PositionInputs posInput = GetPositionInput(input.unPositionSS.xy, _ScreenSize.zw);
PositionInputs posInput = GetPositionInput(input.unPositionSS.xy, _ScreenSize.zw, uint2(0, 0));
UpdatePositionInput(input.unPositionSS.z, input.unPositionSS.w, input.positionWS, posInput);
float3 V = GetWorldSpaceNormalizeViewDir(input.positionWS);

2
Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/ShaderPassDistortion.hlsl


FragInputs input = UnpackVaryingsMeshToFragInputs(packedInput.vmesh);
// input.unPositionSS is SV_Position
PositionInputs posInput = GetPositionInput(input.unPositionSS.xy, _ScreenSize.zw);
PositionInputs posInput = GetPositionInput(input.unPositionSS.xy, _ScreenSize.zw, uint2(0, 0));
UpdatePositionInput(input.unPositionSS.z, input.unPositionSS.w, input.positionWS, posInput);
float3 V = GetWorldSpaceNormalizeViewDir(input.positionWS);

5
Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/ShaderPassForward.hlsl


FragInputs input = UnpackVaryingsMeshToFragInputs(packedInput.vmesh);
// input.unPositionSS is SV_Position
PositionInputs posInput = GetPositionInput(input.unPositionSS.xy, _ScreenSize.zw);
PositionInputs posInput = GetPositionInput(input.unPositionSS.xy, _ScreenSize.zw, uint2(input.unPositionSS.xy) / GetTileSize());
UpdatePositionInput(input.unPositionSS.z, input.unPositionSS.w, input.positionWS, posInput);
float3 V = GetWorldSpaceNormalizeViewDir(input.positionWS);

PreLightData preLightData = GetPreLightData(V, posInput, bsdfData);
uint featureFlags = 0xFFFFFFFF;
LightLoop(V, posInput, preLightData, bsdfData, bakeDiffuseLighting, diffuseLighting, specularLighting);
LightLoop(V, posInput, preLightData, bsdfData, bakeDiffuseLighting, featureFlags, diffuseLighting, specularLighting);
outColor = float4(diffuseLighting + specularLighting, builtinData.opacity);

2
Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/ShaderPassForwardUnlit.hlsl


FragInputs input = UnpackVaryingsMeshToFragInputs(packedInput.vmesh);
// input.unPositionSS is SV_Position
PositionInputs posInput = GetPositionInput(input.unPositionSS.xy, _ScreenSize.zw);
PositionInputs posInput = GetPositionInput(input.unPositionSS.xy, _ScreenSize.zw, uint2(0, 0));
UpdatePositionInput(input.unPositionSS.z, input.unPositionSS.w, input.positionWS, posInput);
float3 V = GetWorldSpaceNormalizeViewDir(input.positionWS);

2
Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/ShaderPassGBuffer.hlsl


FragInputs input = UnpackVaryingsMeshToFragInputs(packedInput.vmesh);
// input.unPositionSS is SV_Position
PositionInputs posInput = GetPositionInput(input.unPositionSS.xy, _ScreenSize.zw);
PositionInputs posInput = GetPositionInput(input.unPositionSS.xy, _ScreenSize.zw, uint2(0, 0));
UpdatePositionInput(input.unPositionSS.z, input.unPositionSS.w, input.positionWS, posInput);
float3 V = GetWorldSpaceNormalizeViewDir(input.positionWS);

2
Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/ShaderPassLightTransport.hlsl


FragInputs input = UnpackVaryingsMeshToFragInputs(packedInput.vmesh);
// input.unPositionSS is SV_Position
PositionInputs posInput = GetPositionInput(input.unPositionSS.xy, _ScreenSize.zw);
PositionInputs posInput = GetPositionInput(input.unPositionSS.xy, _ScreenSize.zw, uint2(0, 0));
// No position and depth in case of light transport
float3 V = float3(0, 0, 1); // No vector view in case of light transport

2
Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/ShaderPassVelocity.hlsl


FragInputs input = UnpackVaryingsMeshToFragInputs(packedInput.vmesh);
// input.unPositionSS is SV_Position
PositionInputs posInput = GetPositionInput(input.unPositionSS.xy, _ScreenSize.zw);
PositionInputs posInput = GetPositionInput(input.unPositionSS.xy, _ScreenSize.zw, uint2(0, 0));
UpdatePositionInput(input.unPositionSS.z, input.unPositionSS.w, input.positionWS, posInput);
float3 V = GetWorldSpaceNormalizeViewDir(input.positionWS);

34
Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderPass/VaryingMesh.hlsl


#endif
#ifdef VARYINGS_NEED_TANGENT_TO_WORLD
// Normalize the normal/tangent after interpolation
float4 tangentWS = float4(input.interpolators2.xyz, input.interpolators2.w > 0.0 ? 1.0 : -1.0);
// TODO: We should be able to not make distinction between the two path, but it mean material need to be aware to normalize the TBN when required, like for example for POM.
// For now do some test by keeping code consistent with previous visual.
#ifdef SURFACE_GRADIENT
// Normalize normalWS vector but keep the renormFactor to apply it to bitangent and tangent
float renormFactor = 1.0 / length(input.interpolators1);
float3 normalWS = renormFactor * input.interpolators1;
// no normalizes is mandatory for tangentWS
// bitangent on the fly option in xnormal to reduce vertex shader outputs.
float3x3 worldToTangent = CreateWorldToTangent(normalWS, tangentWS.xyz, tangentWS.w);
output.worldToTangent[0] = worldToTangent[0];
// prepare for surfgrad formulation without breaking compliance (use exact same scale as applied to interpolated vertex normal to avoid breaking compliance).
output.worldToTangent[1] = worldToTangent[1] * renormFactor;
output.worldToTangent[2] = worldToTangent[2] * renormFactor;
#else
// TODO: Check if we must do like for surface gradient (i.e not normalize ?) For now, for consistency with previous code we normalize
// Normalize after the interpolation
float4 tangentWS = float4(normalize(input.interpolators2.xyz), input.interpolators2.w);
float3x3 tangentToWorld = CreateTangentToWorld(normalWS, tangentWS.xyz, tangentWS.w);
output.tangentToWorld[0] = tangentToWorld[0];
output.tangentToWorld[1] = tangentToWorld[1];
output.tangentToWorld[2] = tangentToWorld[2];
tangentWS.xyz = normalize(tangentWS.xyz);
// bitangent on the fly option in xnormal to reduce vertex shader outputs.
float3x3 worldToTangent = CreateWorldToTangent(normalWS, tangentWS.xyz, tangentWS.w);
output.worldToTangent[0] = worldToTangent[0];
output.worldToTangent[1] = worldToTangent[1];
output.worldToTangent[2] = worldToTangent[2];
#endif // VARYINGS_NEED_TANGENT_TO_WORLD
#ifdef VARYINGS_NEED_TEXCOORD0
output.texCoord0 = input.interpolators3.xy;

104
Assets/ScriptableRenderPipeline/HDRenderPipeline/ShaderVariables.hlsl


float4 unity_SHC;
CBUFFER_END
// Use the regular depth camera texture sampler for sampling this: sampler_CameraDepthTexture
TEXTURE2D_FLOAT(_CameraDepthTextureCopy);
SAMPLER2D(sampler_CameraDepthTextureCopy);
TEXTURE2D_FLOAT(_MainDepthTexture);
SAMPLER2D(sampler_MainDepthTexture);
// Main lightmap
TEXTURE2D(unity_Lightmap);

// ----------------------------------------------------------------------------
// TODO: move this to constant buffer by Pass
float4x4 _InvViewProjMatrix;
float4 _ScreenSize;
float4 _ScreenSize;
float4x4 _InvViewProjMatrix;
float4x4 _InvProjMatrix;
float4 _InvProjParam;
float4x4 GetWorldToViewMatrix()
{

return mul(GetWorldToHClipMatrix(), float4(positionWS, 1.0));
}
float3x3 CreateTangentToWorld(float3 normal, float3 tangent, float tangentSign)
float3 GetCurrentCameraPosition()
// For odd-negative scale transforms we need to flip the sign
float sgn = tangentSign * GetOddNegativeScale();
float3 bitangent = cross(normal, tangent) * sgn;
#if defined(SHADERPASS) && (SHADERPASS != SHADERPASS_DEPTH_ONLY)
return _WorldSpaceCameraPos;
#else
// TEMP: this is rather expensive. Then again, we need '_WorldSpaceCameraPos'
// to represent the position of the primary (scene view) camera in order to
// have identical tessellation levels for both the scene view and shadow views.
// Otherwise, depth comparisons become meaningless!
float4x4 trViewMat = transpose(GetWorldToViewMatrix());
float3 rotCamPos = trViewMat[3].xyz;
return mul((float3x3)trViewMat, -rotCamPos);
#endif
}
return float3x3(tangent, bitangent, normal);
// Returns the forward direction of the current camera in the world space.
float3 GetCameraForwardDir()
{
float4x4 viewMat = GetWorldToViewMatrix();
return -viewMat[2].xyz;
// Computes world space view direction, from object space position
// Returns 'true' if the current camera performs a perspective projection.
bool IsPerspectiveCamera()
{
#if defined(SHADERPASS) && (SHADERPASS != SHADERPASS_DEPTH_ONLY)
return (unity_OrthoParams.w == 0);
#else
// TODO: set 'unity_OrthoParams' during the shadow pass.
return (GetWorldToHClipMatrix()[3].x != 0 ||
GetWorldToHClipMatrix()[3].y != 0 ||
GetWorldToHClipMatrix()[3].z != 0 ||
GetWorldToHClipMatrix()[3].w != 1);
#endif
}
// Computes the world space view direction (pointing towards the camera).
float3 V = _WorldSpaceCameraPos.xyz - positionWS;
if (IsPerspectiveCamera())
{
// Perspective
float3 V = GetCurrentCameraPosition() - positionWS;
return normalize(V);
}
else
{
// Orthographic
return -GetCameraForwardDir();
}
}
// Uncomment this once the compiler bug is fixed.
// if (unity_OrthoParams.w == 1.0)
// {
// float4x4 M = GetWorldToViewMatrix();
// V = M[1].xyz;
// }
float3x3 CreateWorldToTangent(float3 normal, float3 tangent, float flipSign)
{
// For odd-negative scale transforms we need to flip the sign
float sgn = flipSign * GetOddNegativeScale();
float3 bitangent = cross(normal, tangent) * sgn;
return normalize(V);
return float3x3(tangent, bitangent, normal);
float3 TransformTangentToWorld(float3 dirTS, float3 tangentToWorld[3])
float3 TransformTangentToWorld(float3 dirTS, float3x3 worldToTangent)
// TODO check: do we need to normalize ?
return normalize(mul(dirTS, float3x3(tangentToWorld[0].xyz, tangentToWorld[1].xyz, tangentToWorld[2].xyz)));
// Use transpose transformation to go from tangent to world as the matrix is orthogonal
return mul(dirTS, worldToTangent);
// Assume TBN is orthonormal.
float3 TransformWorldToTangent(float3 dirWS, float3 tangentToWorld[3])
float3 TransformWorldToTangent(float3 dirWS, float3x3 worldToTangent)
// TODO check: do we need to normalize ?
return normalize(mul(float3x3(tangentToWorld[0].xyz, tangentToWorld[1].xyz, tangentToWorld[2].xyz), dirWS));
return mul(worldToTangent, dirWS);
float3 TransformTangentToObject(float3 dirTS, float3 worldToTangent[3])
float3 TransformTangentToObject(float3 dirTS, float3x3 worldToTangent)
// TODO check: do we need to normalize ?
// worldToTangent is orthonormal so inverse <==> transpose
float3x3 mWorldToTangent = float3x3(worldToTangent[0].xyz, worldToTangent[1].xyz, worldToTangent[2].xyz);
float3 normalWS = mul(dirTS, mWorldToTangent);
return normalize(mul((float3x3)unity_WorldToObject, normalWS));
// Use transpose transformation to go from tangent to world as the matrix is orthogonal
float3 normalWS = mul(dirTS, worldToTangent);
return mul((float3x3)unity_WorldToObject, normalWS);
// Assume TBN is orthonormal.
float3 TransformObjectToTangent(float3 dirOS, float3 worldToTangent[3])
float3 TransformObjectToTangent(float3 dirOS, float3x3 worldToTangent)
// TODO check: do we need to normalize ?
return normalize(mul(float3x3(worldToTangent[0].xyz, worldToTangent[1].xyz, worldToTangent[2].xyz), mul((float3x3)unity_ObjectToWorld, dirOS)));
return mul(worldToTangent, mul((float3x3)unity_ObjectToWorld, dirOS));
}
#endif // UNITY_SHADER_VARIABLES_INCLUDED

4
Assets/ScriptableRenderPipeline/HDRenderPipeline/Shadow/Shadow.cs


base.PostUpdate( frameId, cb, rendertargetSlice, lights );
return;
}
base.PostUpdate( frameId, cb, rendertargetSlice, lights );
uint cnt = m_EntryCache.Count();
uint i = 0;

cb.DispatchCompute( m_MomentBlurCS, currentKernel, ((int) r.width) / k_MomentBlurThreadsPerWorkgroup, (int) r.height / k_MomentBlurThreadsPerWorkgroup, 1 );
i++;
}
base.PostUpdate( frameId, cb, rendertargetSlice, lights );
}
}
// -------------------------------------------------------------------------------------------------------------------------------------------------

float area = vl.screenRect.width * vl.screenRect.height;
long val = ShadowUtils.Asint( area );
val <<= 32;
val |= (long) vlidx;
val |= (long)(uint)vlidx;
m_TmpSortKeys.AddUnchecked( val );
}
m_TmpSortKeys.Sort();

12
Assets/ScriptableRenderPipeline/HDRenderPipeline/Shadow/ShadowAlgorithms.hlsl


//
// Directional shadows (cascaded shadow map)
//
uint EvalShadow_GetSplitSphereIndexForDirshadows( float3 positionWS, float4 dirShadowSplitSpheres[4] )
int EvalShadow_GetSplitSphereIndexForDirshadows( float3 positionWS, float4 dirShadowSplitSpheres[4] )
{
float3 fromCenter0 = positionWS.xyz - dirShadowSplitSpheres[0].xyz;
float3 fromCenter1 = positionWS.xyz - dirShadowSplitSpheres[1].xyz;

dirShadowSplitSphereSqRadii.z = dirShadowSplitSpheres[2].w;
dirShadowSplitSphereSqRadii.w = dirShadowSplitSpheres[3].w;
if( distances2.w > dirShadowSplitSphereSqRadii.w )
return -1;
return uint( 4.0 - dot( weights, float4(4.0, 3.0, 2.0, 1.0 ) ) );
return int( 4.0 - dot( weights, float4(4.0, 3.0, 2.0, 1.0 ) ) );
}
uint EvalShadow_LoadSplitSpheres( ShadowContext shadowContext, int index, out float4 splitSpheres[4] )

// load the right shadow data for the current face
float4 dirShadowSplitSpheres[4];
uint payloadOffset = EvalShadow_LoadSplitSpheres( shadowContext, index, dirShadowSplitSpheres );
uint shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres );
int shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres );
if( shadowSplitIndex < 0 )
return 1.0;
ShadowData sd = shadowContext.shadowDatas[index + 1 + shadowSplitIndex];
// normal based bias
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), sd.texelSizeRcp, sd.normalBias );

5
Assets/ScriptableRenderPipeline/HDRenderPipeline/Shadow/ShadowAlgorithmsCustom.hlsl


// load the right shadow data for the current face
float4 dirShadowSplitSpheres[4];
uint payloadOffset = EvalShadow_LoadSplitSpheres( shadowContext, shadowDataIndex, dirShadowSplitSpheres );
uint shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres );
int shadowSplitIndex = EvalShadow_GetSplitSphereIndexForDirshadows( positionWS, dirShadowSplitSpheres );
if (shadowSplitIndex < 0)
return 1.0;
ShadowData sd = shadowContext.shadowDatas[shadowDataIndex + 1 + shadowSplitIndex];
// normal based bias
positionWS += EvalShadow_NormalBias( normalWS, saturate( dot( normalWS, L ) ), sd.texelSizeRcp, sd.normalBias );

2
Assets/ScriptableRenderPipeline/HDRenderPipeline/Shadow/ShadowBase.cs.hlsl


//
//
// This file was automatically generated from Assets/ScriptableRenderPipeline/HDRenderPipeline/Shadow/ShadowBase.cs. Please don't edit by hand.
//

6
Assets/ScriptableRenderPipeline/HDRenderPipeline/Shadow/ShadowDispatch.hlsl


// by hardcoding the resources used and calling the shadow sampling routines that take an explicit texture and sampler.
// It is the responsibility of the author to make sure that ShadowContext.hlsl binds the correct texture to the right slot,
// and that on the C# side the shadowContext bindDelegate binds the correct resource to the correct texture id.
//#define SHADOW_DISPATCH_USE_CUSTOM_PUNCTUAL
#define SHADOW_DISPATCH_USE_CUSTOM_PUNCTUAL
Texture2DArray tex = shadowContext.tex2DArray[2];
SamplerComparisonState compSamp = shadowContext.compSamplers[1];
Texture2DArray tex = shadowContext.tex2DArray[3];
SamplerComparisonState compSamp = shadowContext.compSamplers[0];
#if SHADOW_USE_SEPARATE_ALGOS != 0
// example for choosing different algos for point and spot lights

8
Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/HDRISky/Resources/SkyHDRI.shader


#pragma target 4.5
#pragma only_renderers d3d11 ps4 metal // TEMP: until we go further in dev
#include "ShaderLibrary/Color.hlsl"
#include "ShaderLibrary/Common.hlsl"
#include "ShaderLibrary/CommonLighting.hlsl"
#include "../../../../ShaderLibrary/Color.hlsl"
#include "../../../../ShaderLibrary/Common.hlsl"
#include "../../../../ShaderLibrary/CommonLighting.hlsl"
TEXTURECUBE(_Cubemap);
SAMPLERCUBE(sampler_Cubemap);

ZWrite Off
ZTest Always
Blend One Zero
Cull Off
HLSLPROGRAM
ENDHLSL

ZWrite Off
ZTest LEqual
Blend One Zero
Cull Off
HLSLPROGRAM
ENDHLSL

5
Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/ProceduralSky/ProceduralSkyRenderer.cs


var cmd = new CommandBuffer { name = "" };
if (!renderForCubemap)
{
cmd.SetGlobalTexture("_CameraDepthTexture", builtinParams.depthBuffer);
}
cmd.DrawMesh(builtinParams.skyMesh, Matrix4x4.identity, m_ProceduralSkyMaterial, 0, 0, properties);
builtinParams.renderContext.ExecuteCommandBuffer(cmd);
cmd.Dispose();

18
Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/ProceduralSky/Resources/AtmosphericScattering.hlsl


uniform float _MiePhaseAnisotropy;
uniform float _MieExtinctionFactor;
SAMPLER2D(sampler_CameraDepthTexture);
#define SRL_BilinearSampler sampler_CameraDepthTexture // Used for all textures
SAMPLER2D(sampler_MainDepthTexture);
#define SRL_BilinearSampler sampler_MainDepthTexture // Used for all textures
TEXTURE2D_FLOAT(_CameraDepthTexture);
TEXTURE2D_FLOAT(_MainDepthTexture);
TEXTURE2D(_OcclusionTexture);
float HenyeyGreensteinPhase(float g, float cosTheta) {

#if defined(ATMOSPHERICS_OCCLUSION_EDGE_FIXUP)
float4 baseUV = float4(uv.x, uv.y, 0.f, 0.f);
float cDepth = SAMPLE_TEXTURE2D_LOD(_CameraDepthTexture, SRL_BilinearSampler, baseUV, 0.f).r;
float cDepth = SAMPLE_TEXTURE2D_LOD(_CMainDepthTexture, SRL_BilinearSampler, baseUV, 0.f).r;
baseUV.xy = uv + _DepthTextureScaledTexelSize.zy; xDepth.x = SAMPLE_TEXTURE2D_LOD(_CameraDepthTexture, SRL_BilinearSampler, baseUV);
baseUV.xy = uv + _DepthTextureScaledTexelSize.xy; xDepth.y = SAMPLE_TEXTURE2D_LOD(_CameraDepthTexture, SRL_BilinearSampler, baseUV);
baseUV.xy = uv + _DepthTextureScaledTexelSize.xw; xDepth.z = SAMPLE_TEXTURE2D_LOD(_CameraDepthTexture, SRL_BilinearSampler, baseUV);
baseUV.xy = uv + _DepthTextureScaledTexelSize.zw; xDepth.w = SAMPLE_TEXTURE2D_LOD(_CameraDepthTexture, SRL_BilinearSampler, baseUV);
baseUV.xy = uv + _DepthTextureScaledTexelSize.zy; xDepth.x = SAMPLE_TEXTURE2D_LOD(_MainDepthTexture, SRL_BilinearSampler, baseUV);
baseUV.xy = uv + _DepthTextureScaledTexelSize.xy; xDepth.y = SAMPLE_TEXTURE2D_LOD(_MainDepthTexture, SRL_BilinearSampler, baseUV);
baseUV.xy = uv + _DepthTextureScaledTexelSize.xw; xDepth.z = SAMPLE_TEXTURE2D_LOD(_MainDepthTexture, SRL_BilinearSampler, baseUV);
baseUV.xy = uv + _DepthTextureScaledTexelSize.zw; xDepth.w = SAMPLE_TEXTURE2D_LOD(_MainDepthTexture, SRL_BilinearSampler, baseUV);
xDepth.x = LinearEyeDepth(xDepth.x, _ZBufferParams);
xDepth.y = LinearEyeDepth(xDepth.y, _ZBufferParams);

#define SURFACE_SCATTER_APPLY(i, color) color += (i.worldPos + i.scatterCoords1.xyz + i.scatterCoords2.xyz) * 0.000001f
#endif
#endif //FILE_ATMOSPHERICSCATTERING
#endif //FILE_ATMOSPHERICSCATTERING

11
Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/ProceduralSky/Resources/SkyProcedural.shader


ZWrite Off
ZTest Always
Blend One OneMinusSrcAlpha, Zero One
Cull Off
HLSLPROGRAM
#pragma target 4.5

#pragma multi_compile _ ATMOSPHERICS_DEBUG
#pragma multi_compile _ PERFORM_SKY_OCCLUSION_TEST
#include "ShaderLibrary/Color.hlsl"
#include "ShaderLibrary/Common.hlsl"
#include "ShaderLibrary/CommonLighting.hlsl"
#include "../../../../ShaderLibrary/Color.hlsl"
#include "../../../../ShaderLibrary/Common.hlsl"
#include "../../../../ShaderLibrary/CommonLighting.hlsl"
TEXTURECUBE(_Cubemap);
SAMPLERCUBE(sampler_Cubemap);

float3 rotatedDir = float3(dot(rotDirX, dir), dir.y, dot(rotDirY, dir));
// input.positionCS is SV_Position
PositionInputs posInput = GetPositionInput(input.positionCS.xy, _ScreenSize.zw);
PositionInputs posInput = GetPositionInput(input.positionCS.xy, _ScreenSize.zw, uint2(0,0));
// An arbitrary value attempting to match the size of the sky mesh from the Blacksmith demo.
const float skyDepth = 0.00025;

// Do not perform blending with the environment map if the sky is occluded.
float depthRaw = max(skyDepth, LOAD_TEXTURE2D(_CameraDepthTexture, posInput.unPositionSS).r);
float depthRaw = max(skyDepth, LOAD_TEXTURE2D(_MainDepthTexture, posInput.unPositionSS).r);
float skyTexWeight = (depthRaw > skyDepth) ? 0.0 : 1.0;
#else
float depthRaw = skyDepth;

4
Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/Resources/BuildProbabilityTables.compute


// Ref: PBRT v3, 13.6.7 "Piecewise-Constant 2D Distributions".
// Note that we use the equiareal sphere-to-square mapping instead of the latitude-longitude one.
#include "ShaderLibrary/Common.hlsl"
#include "ShaderLibrary/ImageBasedLighting.hlsl"
#include "../../../ShaderLibrary/Common.hlsl"
#include "../../../ShaderLibrary/ImageBasedLighting.hlsl"
/* --- Input --- */

4
Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/Resources/ComputeGgxIblSampleData.compute


// Precomputes data for IntegrateLD(). See that function for a detailed description.
#include "ShaderLibrary/Common.hlsl"
#include "ShaderLibrary/ImageBasedLighting.hlsl"
#include "../../../ShaderLibrary/Common.hlsl"
#include "../../../ShaderLibrary/ImageBasedLighting.hlsl"
#define MAX_IBL_SAMPLE_CNT 89

4
Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/Resources/GGXConvolve.shader


#pragma vertex Vert
#pragma fragment Frag
#include "ShaderLibrary/Common.hlsl"
#include "ShaderLibrary/ImageBasedLighting.hlsl"
#include "../../../ShaderLibrary/Common.hlsl"
#include "../../../ShaderLibrary/ImageBasedLighting.hlsl"
#include "../SkyManager.cs.hlsl"
struct Attributes

2
Assets/ScriptableRenderPipeline/HDRenderPipeline/Sky/SkyManager.cs


get { return m_SkySettings; }
}
public Texture skyReflection { get { return m_SkyboxGGXCubemapRT; } }
protected Mesh BuildSkyMesh(Vector3 cameraPosition, Matrix4x4 cameraInvViewProjectionMatrix, bool forceUVBottom)
{
Vector4 vertData0 = new Vector4(-1.0f, -1.0f, 1.0f, 1.0f);

15
Assets/ScriptableRenderPipeline/HDRenderPipeline/Utilities.cs


var gpuProj = GL.GetGPUProjectionMatrix(camera.projectionMatrix, false);
var gpuVP = gpuProj * camera.worldToCameraMatrix;
// Ref: An Efficient Depth Linearization Method for Oblique View Frustums, Eq. 6.
Vector4 invProjectionParam = new Vector4(gpuProj.m20 / (gpuProj.m00 * gpuProj.m23),
gpuProj.m21 / (gpuProj.m11 * gpuProj.m23),
-1.0f / gpuProj.m23,
(-gpuProj.m22
+ gpuProj.m20 * gpuProj.m02 / gpuProj.m00
+ gpuProj.m21 * gpuProj.m12 / gpuProj.m11) / gpuProj.m23);
hdCamera.invProjectionParam = invProjectionParam;
return hdCamera;
}

material.SetVector("_ScreenSize", hdCamera.screenSize);
material.SetMatrix("_ViewProjMatrix", hdCamera.viewProjectionMatrix);
material.SetVector("_ScreenSize", hdCamera.screenSize);
material.SetMatrix("_ViewProjMatrix", hdCamera.viewProjectionMatrix);
material.SetMatrix("_InvProjMatrix", hdCamera.invProjectionMatrix);
material.SetVector("_InvProjParam", hdCamera.invProjectionParam);
}
// TEMP: These functions should be implemented C++ side, for now do it in C#

118
Assets/ScriptableRenderPipeline/ShaderLibrary/Common.hlsl


#elif defined(SHADER_API_PSSL)
#include "API/PSSL.hlsl"
#elif defined(SHADER_API_XBOXONE)
#include "API/D3D11.hlsl"
#include "API/D3D11_1.hlsl"
#elif defined(SHADER_API_METAL)
#include "API/Metal.hlsl"

// Some shader compiler don't support to do multiple ## for concatenation inside the same macro, it require an indirection.
// This is the purpose of this macro
#define MERGE_NAME(X, Y) X##Y
// These define are use to abstract the way we sample into a cubemap array.
// Some platform don't support cubemap array so we fallback on 2D latlong
#ifdef UNITY_NO_CUBEMAP_ARRAY
#define TEXTURECUBE_ARRAY_ABSTRACT TEXTURE2D_ARRAY
#define SAMPLERCUBE_ABSTRACT SAMPLER2D
#define TEXTURECUBE_ARRAY_ARGS_ABSTRACT TEXTURE2D_ARRAY_ARGS
#define TEXTURECUBE_ARRAY_PARAM_ABSTRACT TEXTURE2D_ARRAY_PARAM
#define SAMPLE_TEXTURECUBE_ARRAY_LOD_ABSTRACT(textureName, samplerName, coord3, index, lod) SAMPLE_TEXTURE2D_ARRAY_LOD(textureName, samplerName, DirectionToLatLongCoordinate(coord3), index, lod)
#else
#define TEXTURECUBE_ARRAY_ABSTRACT TEXTURECUBE_ARRAY
#define SAMPLERCUBE_ABSTRACT SAMPLERCUBE
#define TEXTURECUBE_ARRAY_ARGS_ABSTRACT TEXTURECUBE_ARRAY_ARGS
#define TEXTURECUBE_ARRAY_PARAM_ABSTRACT TEXTURECUBE_ARRAY_PARAM
#define SAMPLE_TEXTURECUBE_ARRAY_LOD_ABSTRACT(textureName, samplerName, coord3, index, lod) SAMPLE_TEXTURECUBE_ARRAY_LOD(textureName, samplerName, coord3, index, lod)
#endif
// ----------------------------------------------------------------------------
// Common intrinsic (general implementation of intrinsic available on some platform)

return float2(1.0 - 0.5 * INV_PI * atan2(dir.x, -dir.z), asin(dir.y) * INV_PI + 0.5);
}
float3 LatlongToDirectionCoordinate(float2 coord)
{
float theta = coord.y * PI;
float phi = (coord.x * 2.f * PI - PI*0.5f);
float cosTheta = cos(theta);
float sinTheta = sqrt(1.0f - min(1.0f, cosTheta*cosTheta));
float cosPhi = cos(phi);
float sinPhi = sin(phi);
float3 direction = float3(sinTheta*cosPhi, cosTheta, sinTheta*sinPhi);
direction.xy *= -1.0;
return direction;
}
// Z buffer to linear 0..1 depth (0 at near plane, 1 at far plane)
// Z buffer to linear 0..1 depth (0 at near plane, 1 at far plane).
// Does not correctly handle oblique view frustums.
// Z buffer to linear 0..1 depth (0 at camera position, 1 at far plane)
// Z buffer to linear 0..1 depth (0 at camera position, 1 at far plane).
// Does not correctly handle oblique view frustums.
// Z buffer to linear depth
// Z buffer to linear depth.
// Does not correctly handle oblique view frustums.
// Z buffer to linear depth.
// Correctly handles oblique view frustums. Only valid for projection matrices!
// Ref: An Efficient Depth Linearization Method for Oblique View Frustums, Eq. 6.
float LinearEyeDepth(float2 positionSS, float depthRaw, float4 invProjParam)
{
float4 positionCS = float4(positionSS * 2.0 - 1.0, depthRaw, 1.0);
float viewSpaceZ = rcp(dot(positionCS, invProjParam));
// The view space uses a right-handed coordinate system.
return -viewSpaceZ;
}
struct PositionInputs
{
// Normalize screen position (offset by 0.5)

uint2 unTileCoord;
float4 positionCS;
float3 positionWS;
};

// else it is current unormalized screen coordinate like return by SV_Position
PositionInputs GetPositionInput(float2 unPositionSS, float2 invScreenSize)
PositionInputs GetPositionInput(float2 unPositionSS, float2 invScreenSize, uint2 unTileCoord) // Specify explicit tile coordinates so that we can easily make it lane invariant for compute evaluation.
{
PositionInputs posInput;
ZERO_INITIALIZE(PositionInputs, posInput);

posInput.positionSS *= invScreenSize;
posInput.unPositionSS = uint2(unPositionSS);
posInput.unTileCoord = unTileCoord;
return posInput;
}

void UpdatePositionInput(float depthRaw, float depthVS, float3 positionWS, inout PositionInputs posInput)
{
posInput.depthRaw = depthRaw;
posInput.depthVS = depthVS;
// TODO: We revert for DX but maybe it is not the case of OGL ? Test the define ?
posInput.positionCS = float4((posInput.positionSS - 0.5) * float2(2.0, -2.0), depthRaw, 1.0) * depthVS; // depthVS is SV_Position.w
posInput.depthRaw = depthRaw;
posInput.depthVS = depthVS;
posInput.positionWS = positionWS;
}

// It may be necessary to flip the Y axis as the origin of the screen-space coordinate system
// of Direct3D is at the top left corner of the screen, with the Y axis pointing downwards.
void UpdatePositionInput(float depth, float4x4 invViewProjectionMatrix, float4x4 ViewProjectionMatrix,
void UpdatePositionInput(float depthRaw, float4x4 invViewProjMatrix, float4x4 viewProjMatrix,
posInput.depthRaw = depth;
posInput.depthRaw = depthRaw;
posInput.positionCS = float4(screenSpacePos * 2.0 - 1.0, depth, 1.0);
float4 hpositionWS = mul(invViewProjectionMatrix, posInput.positionCS);
float4 positionCS = float4(screenSpacePos * 2.0 - 1.0, depthRaw, 1.0);
float4 hpositionWS = mul(invViewProjMatrix, positionCS);
posInput.depthVS = mul(ViewProjectionMatrix, float4(posInput.positionWS, 1.0)).w;
posInput.positionCS *= posInput.depthVS;
posInput.depthVS = mul(viewProjMatrix, float4(posInput.positionWS, 1.0)).w;
float3 ComputeViewSpacePosition(float2 positionSS, float rawDepth, float4x4 invProjMatrix)
// It may be necessary to flip the Y axis as the origin of the screen-space coordinate system
// of Direct3D is at the top left corner of the screen, with the Y axis pointing downwards.
float3 ComputeViewSpacePosition(float2 positionSS, float depthRaw, float4x4 invProjMatrix, bool flipY = false)
float4 positionCS = float4(positionSS * 2.0 - 1.0, rawDepth, 1.0);
float2 screenSpacePos;
screenSpacePos.x = positionSS.x;
screenSpacePos.y = flipY ? 1.0 - positionSS.y : positionSS.y;
float4 positionCS = float4(screenSpacePos * 2.0 - 1.0, depthRaw, 1.0);
float4 positionVS = mul(invProjMatrix, positionCS);
// The view space uses a right-handed coordinate system.
positionVS.z = -positionVS.z;

// depthOffsetVS is always in the direction of the view vector (V)
void ApplyDepthOffsetPositionInput(float3 V, float depthOffsetVS, inout PositionInputs posInput)
// The view direction 'V' points towards the camera.
// 'depthOffsetVS' is always applied in the opposite direction (-V).
void ApplyDepthOffsetPositionInput(float3 V, float depthOffsetVS, float4x4 viewProjMatrix, inout PositionInputs posInput)
posInput.depthVS += depthOffsetVS;
// TODO: it is an approx, need a correct value where we use projection matrix to reproject the depth from VS
posInput.depthRaw = posInput.positionCS.z / posInput.depthVS;
posInput.positionWS += depthOffsetVS * (-V);
// TODO: Do we need to flip Y axis here on OGL ?
posInput.positionCS = float4(posInput.positionSS.xy * 2.0 - 1.0, posInput.depthRaw, 1.0) * posInput.depthVS;
// Just add the offset along the view vector is sufficiant for world position
posInput.positionWS += V * depthOffsetVS;
float4 positionCS = mul(viewProjMatrix, float4(posInput.positionWS, 1.0));
posInput.depthVS = positionCS.w;
posInput.depthRaw = positionCS.z / positionCS.w;
}
// Generates a triangle in homogeneous clip space, s.t.

{
float2 uv = float2((vertexID << 1) & 2, vertexID & 2);
return float4(uv * 2.0 - 1.0, 1.0, 1.0);
}
// LOD dithering transition helper
// ditherFactor should be a quantized value between 0..15/16, i.e the one provide by Unity
// LOD0 must use this function with ditherFactor 1..0
// LOD1 must use this functoin with ditherFactor 0..1
void LODDitheringTransition(uint2 unPositionSS, float ditherFactor)
{
// Generate a fixed pattern
float p = cos(dot(unPositionSS, float2(443.8975, 397.2973)));
p = frac(p * 491.1871);
// We want to have a symmetry between 0..0.5 ditherFactor and 0.5..1 so no pixels are transparent during the transition
// this is handled by this test which reverse the pattern
p = (ditherFactor >= 0.5) ? (15.0 / 16.0) - p : p;
clip(ditherFactor - p);
}
#endif // UNITY_COMMON_INCLUDED

8
Assets/ScriptableRenderPipeline/ShaderLibrary/CommonLighting.hlsl


// NdotV should not be negative for visible pixels, but it can happen due to the
// perspective projection and the normal mapping + decals. In that case, the normal
// should be modified to become valid (i.e facing the camera) to avoid weird artifacts.
// Note: certain applications (e.g. SpeedTree) require to still have negative normal to perform their own two sided lighting
// This will potentially reduce the length of the normal at edges of geometry.
float GetShiftedNdotV(inout float3 N, float3 V, bool twoSided)
// Note: certain applications (e.g. SpeedTree) require to still have negative normal to perform their own two sided lighting, they can use wantNegativeNormal
// This will potentially reduce the length of the normal at edges of geometry.
float GetShiftedNdotV(inout float3 N, float3 V, bool wantNegativeNormal)
if (!twoSided && NdotV < limit)
if (!wantNegativeNormal && NdotV < limit)
{
// We do not renormalize the normal because { abs(length(N) - 1.0) < limit }.
N += (-NdotV + limit) * V;

29
Assets/ScriptableRenderPipeline/ShaderLibrary/CommonMaterial.hlsl


// Parallax mapping
// ----------------------------------------------------------------------------
float2 ParallaxOffset(float3 viewDirTS, float height)
{
// Parallax mapping with offset limiting to reduce weird artifcat (i.e do not divide by z), also save performance
return viewDirTS.xy * height;
}
// ref https://www.gamedev.net/topic/678043-how-to-blend-world-space-normals/#entry5287707
// assume compositing in world space
// Note: Using vtxNormal = float3(0, 0, 1) give the BlendNormalRNM formulation.

return normalize(float3(n1.xy * n2.z + n2.xy * n1.z, n1.z * n2.z));
}
// Ref: http://http.developer.nvidia.com/GPUGems3/gpugems3_ch01.html
// Ref: http://http.developer.nvidia.com/GPUGems3/gpugems3_ch01.html / http://www.slideshare.net/icastano/cascades-demo-secrets
float3 ComputeTriplanarWeights(float3 normal)
{
// Determine the blend weights for the 3 planar projections.

blendWeights = blendWeights * blendWeights * blendWeights; // pow(blendWeights, 3);
// Force weights to sum to 1.0 (very important!)
blendWeights = max(blendWeights, float3(0.0, 0.0, 0.0));
blendWeights /= dot(blendWeights, 1.0);

// Planar/Triplanar convention for Unity
// position and vertex normal must be in the same space
void GetTriplanarCoordinate(float3 position, float3 vertexNormal, out float2 uvXZ, out float2 uvXY, out float2 uvZY)
{
float3 direction = sign(vertexNormal);
// In triplanar, if we are facing away from the world axis, a different axis will be flipped for each direction.
// This is particularly problematic for tangent space normal maps which need to be in the right direction.
// So we multiplying the offending coordinate by the sign of the normal.
uvXZ = -float2(position.x, direction.y * position.z);
uvXY = float2(-position.x, direction.z * position.y);
uvZY = float2(direction.x * position.z, position.y);
// Planar/Triplanar convention for Unity in world space
void GetTriplanarCoordinate(float3 position, out float2 uvXZ, out float2 uvXY, out float2 uvZY)
{
// Caution: This must follow the same rule as what is use for SurfaceGradient triplanar
// TODO: Currently the normal mapping looks wrong without SURFACE_GRADIENT option because we don't handle corretly the tangent space
uvXZ = float2(position.z, position.x);
uvXY = float2(position.x, position.y);
uvZY = float2(position.z, position.y);
}
float LerpWhiteTo(float b, float t)

17
Assets/ScriptableRenderPipeline/ShaderLibrary/PerPixelDisplacement.hlsl


// it return the offset to apply to the UVSet provide in PerPixelHeightDisplacementParam
// viewDirTS is view vector in texture space matching the UVSet
// ref: https://www.gamedev.net/resources/_/technical/graphics-programming-and-theory/a-closer-look-at-parallax-occlusion-mapping-r3262
float2 ParallaxOcclusionMapping(float lod, float lodThreshold, int numSteps, float3 viewDirTS, float maxHeight, PerPixelHeightDisplacementParam ppdParam)
float2 ParallaxOcclusionMapping(float lod, float lodThreshold, int numSteps, float3 viewDirTS, float maxHeight, PerPixelHeightDisplacementParam ppdParam, out float outHeight)
// TODO: explain this factor! Necessary to achieve parity between tessellation and POM w.r.t. height.
maxHeight *= 0.1;
// Convention: 1.0 is top, 0.0 is bottom - POM is always inward, no extrusion
float stepSize = 1.0 / (float)numSteps;

float pt1 = rayHeight;
float delta0 = pt0 - prevHeight;
float delta1 = pt1 - currHeight;
// Secant method to affine the search
// Ref: Faster Relief Mapping Using the Secant Method - Eric Risser
for (int i = 0; i < 5; ++i)

}
#else // regular POM intersection
//float pt1 = rayHeight;
//float pt1 = rayHeight;
//float delta0 = pt0 - prevHeight;
//float delta1 = pt1 - currHeight;
//float intersectionHeight = (pt0 * delta1 - pt1 * delta0) / (delta1 - delta0);

float ratio = delta0 / (delta0 + delta1);
float2 offset = texOffsetCurrent - ratio * texOffsetPerStep;
currHeight = ComputePerPixelHeightDisplacement(offset, lod, ppdParam);
outHeight = currHeight;
// Fade the effect with lod (allow to avoid pop when switching to a discrete LOD mesh)
offset *= (1.0 - saturate(lod - lodThreshold));

7
Assets/ScriptableRenderPipeline/common/ShaderBase.h


#ifndef __SHADERBASE_H__
#define __SHADERBASE_H__
//#define CUBE_ARRAY_NOT_SUPPORTED
half2 DirectionToSphericalTexCoordinate(half3 dir)
{
// coordinate frame is (-Z,X) meaning negative Z is primary axis and X is secondary axis.

#ifdef CUBE_ARRAY_NOT_SUPPORTED
#ifdef UNITY_NO_CUBEMAP_ARRAY
#define UNITY_DECLARE_ABSTRACT_CUBE_ARRAY UNITY_DECLARE_TEX2DARRAY
#define UNITY_PASS_ABSTRACT_CUBE_ARRAY UNITY_PASS_TEX2DARRAY
#define UNITY_ARGS_ABSTRACT_CUBE_ARRAY UNITY_ARGS_TEX2DARRAY

float FetchDepthMSAA(Texture2DMS<float> depthTexture, uint2 pixCoord, uint sampleIdx)
{
float zdpth = depthTexture.Load(uint3(pixCoord.xy, 0), sampleIdx).x;
float zdpth = depthTexture.Load(pixCoord.xy, sampleIdx).x;
#ifdef REVERSE_ZBUF
zdpth = 1.0 - zdpth;
#endif

415
Assets/ScriptableRenderPipeline/common/SkyboxHelper.cs


using UnityEngine;
using UnityEngine.Experimental.Rendering;
public class SkyboxHelper
namespace UnityEngine.Experimental.Rendering
public SkyboxHelper()
public class SkyboxHelper
}
const int k_NumFullSubdivisions = 3; // 3 subdivs == 2048 triangles
const int k_NumHorizonSubdivisions = 2;
public void CreateMesh()
{
var vertData = new Vector3[8 * 3];
for (int i = 0; i < 8 * 3; i++)
public SkyboxHelper()
vertData[i] = m_OctaVerts[i];
// Regular subdivisions
for (int i = 0; i < k_NumFullSubdivisions; i++)
const int k_NumFullSubdivisions = 3; // 3 subdivs == 2048 triangles
const int k_NumHorizonSubdivisions = 2;
public void CreateMesh()
var srcData = vertData.Clone() as Vector3[];
var verts = new List<Vector3>();
for (int k = 0; k < srcData.Length; k += 3)
var vertData = new Vector3[8 * 3];
for (int i = 0; i < 8 * 3; i++)
Subdivide(verts, srcData[k], srcData[k + 1], srcData[k + 2]);
vertData[i] = m_OctaVerts[i];
vertData = verts.ToArray();
}
// Horizon subdivisions
var horizonLimit = 1.0f;
for (int i = 0; i < k_NumHorizonSubdivisions; i++)
{
var srcData = vertData.Clone() as Vector3[];
var verts = new List<Vector3>();
horizonLimit *= 0.5f; // First iteration limit to y < +-0.5, next one 0.25 etc.
for (int k = 0; k < srcData.Length; k += 3)
// Regular subdivisions
for (int i = 0; i < k_NumFullSubdivisions; i++)
var maxAbsY = Mathf.Max(Mathf.Abs(srcData[k].y), Mathf.Abs(srcData[k + 1].y), Mathf.Abs(srcData[k + 2].y));
if (maxAbsY > horizonLimit)
{
// Pass through existing triangle
verts.Add(srcData[k]);
verts.Add(srcData[k + 1]);
verts.Add(srcData[k + 2]);
}
else
var srcData = vertData.Clone() as Vector3[];
var verts = new List<Vector3>();
for (int k = 0; k < srcData.Length; k += 3)
SubdivideYOnly(verts, srcData[k], srcData[k + 1], srcData[k + 2]);
Subdivide(verts, srcData[k], srcData[k + 1], srcData[k + 2]);
vertData = verts.ToArray();
vertData = verts.ToArray();
}
// Write out the mesh
var vertexCount = vertData.Length;
var triangles = new int[vertexCount];
for (int i = 0; i < vertexCount; i++)
{
triangles[i] = i;
}
// Horizon subdivisions
var horizonLimit = 1.0f;
for (int i = 0; i < k_NumHorizonSubdivisions; i++)
{
var srcData = vertData.Clone() as Vector3[];
var verts = new List<Vector3>();
m_Mesh = new Mesh
{
vertices = vertData,
triangles = triangles
};
}
horizonLimit *= 0.5f; // First iteration limit to y < +-0.5, next one 0.25 etc.
for (int k = 0; k < srcData.Length; k += 3)
{
var maxAbsY = Mathf.Max(Mathf.Abs(srcData[k].y), Mathf.Abs(srcData[k + 1].y), Mathf.Abs(srcData[k + 2].y));
if (maxAbsY > horizonLimit)
{
// Pass through existing triangle
verts.Add(srcData[k]);
verts.Add(srcData[k + 1]);
verts.Add(srcData[k + 2]);
}
else
{
SubdivideYOnly(verts, srcData[k], srcData[k + 1], srcData[k + 2]);
}
}
vertData = verts.ToArray();
}
public UnityEngine.Mesh mesh
{
get { return m_Mesh; }
}
// Write out the mesh
var vertexCount = vertData.Length;
var triangles = new int[vertexCount];
for (int i = 0; i < vertexCount; i++)
{
triangles[i] = i;
}
public void Draw(ScriptableRenderContext loop, Camera camera)
{
if (camera.clearFlags != CameraClearFlags.Skybox)
{
return;
m_Mesh = new Mesh
{
vertices = vertData,
triangles = triangles
};
var mat = RenderSettings.skybox;
if (mat == null)
public UnityEngine.Mesh mesh
return;
get { return m_Mesh; }
var cmd = new CommandBuffer { name = "Skybox" };
var looksLikeSixSidedShader = true;
looksLikeSixSidedShader &= (mat.passCount == 6); // should have six passes
//looksLikeSixSidedShader &= !mat.GetShader()->GetShaderLabShader()->HasLightingPasses();
if (looksLikeSixSidedShader)
public void Draw(ScriptableRenderContext loop, Camera camera)
Debug.LogWarning("Six sided skybox not yet supported.");
}
else
{
if (mesh == null)
if (camera.clearFlags != CameraClearFlags.Skybox)
CreateMesh();
return;
var dist = camera.farClipPlane * 10.0f;
var mat = RenderSettings.skybox;
var world = Matrix4x4.TRS(camera.transform.position, Quaternion.identity, new Vector3(dist, dist, dist));
if (mat == null)
{
return;
}
var skyboxProj = SkyboxHelper.GetProjectionMatrix(camera);
cmd.SetViewProjectionMatrices (camera.worldToCameraMatrix, skyboxProj);
cmd.DrawMesh(mesh, world, mat);
var cmd = new CommandBuffer { name = "Skybox" };
cmd.SetViewProjectionMatrices (camera.worldToCameraMatrix, camera.projectionMatrix);
}
var looksLikeSixSidedShader = true;
looksLikeSixSidedShader &= (mat.passCount == 6); // should have six passes
//looksLikeSixSidedShader &= !mat.GetShader()->GetShaderLabShader()->HasLightingPasses();
loop.ExecuteCommandBuffer(cmd);
cmd.Dispose();
}
if (looksLikeSixSidedShader)
{
Debug.LogWarning("Six sided skybox not yet supported.");
}
else
{
if (mesh == null)
{
CreateMesh();
}
public static Matrix4x4 GetProjectionMatrix(Camera camera)
{
var skyboxProj = Matrix4x4.Perspective(camera.fieldOfView, camera.aspect, camera.nearClipPlane, camera.farClipPlane);
var dist = camera.farClipPlane * 10.0f;
var nearPlane = camera.nearClipPlane * 0.01f;
skyboxProj = AdjustDepthRange(skyboxProj, camera.nearClipPlane, nearPlane, camera.farClipPlane);
return MakeProjectionInfinite(skyboxProj, nearPlane);
}
var world = Matrix4x4.TRS(camera.transform.position, Quaternion.identity, new Vector3(dist, dist, dist));
static Matrix4x4 MakeProjectionInfinite(Matrix4x4 m, float nearPlane)
{
const float epsilon = 1e-6f;
var skyboxProj = SkyboxHelper.GetProjectionMatrix(camera);
cmd.SetViewProjectionMatrices (camera.worldToCameraMatrix, skyboxProj);
cmd.DrawMesh(mesh, world, mat);
var r = m;
r[2, 2] = -1.0f + epsilon;
r[2, 3] = (-2.0f + epsilon) * nearPlane;
r[3, 2] = -1.0f;
return r;
}
cmd.SetViewProjectionMatrices (camera.worldToCameraMatrix, camera.projectionMatrix);
}
static Matrix4x4 AdjustDepthRange(Matrix4x4 mat, float origNear, float newNear, float newFar)
{
var x = mat[0, 0];
var y = mat[1, 1];
var w = mat[0, 2];
var z = mat[1, 2];
loop.ExecuteCommandBuffer(cmd);
cmd.Dispose();
}
var r = ((2.0f * origNear) / x) * ((w + 1) * 0.5f);
var t = ((2.0f * origNear) / y) * ((z + 1) * 0.5f);
var l = ((2.0f * origNear) / x) * (((w + 1) * 0.5f) - 1);
var b = ((2.0f * origNear) / y) * (((z + 1) * 0.5f) - 1);
public static Matrix4x4 GetProjectionMatrix(Camera camera)
{
var skyboxProj = Matrix4x4.Perspective(camera.fieldOfView, camera.aspect, camera.nearClipPlane, camera.farClipPlane);
var ratio = (newNear / origNear);
var nearPlane = camera.nearClipPlane * 0.01f;
skyboxProj = AdjustDepthRange(skyboxProj, camera.nearClipPlane, nearPlane, camera.farClipPlane);
return MakeProjectionInfinite(skyboxProj, nearPlane);
}
r *= ratio;
t *= ratio;
l *= ratio;
b *= ratio;
var ret = new Matrix4x4();
static Matrix4x4 MakeProjectionInfinite(Matrix4x4 m, float nearPlane)
{
const float epsilon = 1e-6f;
ret[0, 0] = (2.0f * newNear) / (r - l); ret[0, 1] = 0; ret[0, 2] = (r + l) / (r - l); ret[0, 3] = 0;
ret[1, 0] = 0; ret[1, 1] = (2.0f * newNear) / (t - b); ret[1, 2] = (t + b) / (t - b); ret[1, 3] = 0;
ret[2, 0] = 0; ret[2, 1] = 0; ret[2, 2] = -(newFar + newNear) / (newFar - newNear); ret[2, 3] = -(2.0f * newFar * newNear) / (newFar - newNear);
ret[3, 0] = 0; ret[3, 1] = 0; ret[3, 2] = -1.0f; ret[3, 3] = 0;
var r = m;
r[2, 2] = -1.0f + epsilon;
r[2, 3] = (-2.0f + epsilon) * nearPlane;
r[3, 2] = -1.0f;
return r;
}
return ret;
}
static Matrix4x4 AdjustDepthRange(Matrix4x4 mat, float origNear, float newNear, float newFar)
{
var x = mat[0, 0];
var y = mat[1, 1];
var w = mat[0, 2];
var z = mat[1, 2];
// Octahedron vertices
readonly Vector3[] m_OctaVerts =
{
new Vector3(0.0f, 1.0f, 0.0f), new Vector3(0.0f, 0.0f, -1.0f), new Vector3(1.0f, 0.0f, 0.0f),
new Vector3(0.0f, 1.0f, 0.0f), new Vector3(1.0f, 0.0f, 0.0f), new Vector3(0.0f, 0.0f, 1.0f),
new Vector3(0.0f, 1.0f, 0.0f), new Vector3(0.0f, 0.0f, 1.0f), new Vector3(-1.0f, 0.0f, 0.0f),
new Vector3(0.0f, 1.0f, 0.0f), new Vector3(-1.0f, 0.0f, 0.0f), new Vector3(0.0f, 0.0f, -1.0f),
new Vector3(0.0f, -1.0f, 0.0f), new Vector3(1.0f, 0.0f, 0.0f), new Vector3(0.0f, 0.0f, -1.0f),
new Vector3(0.0f, -1.0f, 0.0f), new Vector3(0.0f, 0.0f, 1.0f), new Vector3(1.0f, 0.0f, 0.0f),
new Vector3(0.0f, -1.0f, 0.0f), new Vector3(-1.0f, 0.0f, 0.0f), new Vector3(0.0f, 0.0f, 1.0f),
new Vector3(0.0f, -1.0f, 0.0f), new Vector3(0.0f, 0.0f, -1.0f), new Vector3(-1.0f, 0.0f, 0.0f),
};
var r = ((2.0f * origNear) / x) * ((w + 1) * 0.5f);
var t = ((2.0f * origNear) / y) * ((z + 1) * 0.5f);
var l = ((2.0f * origNear) / x) * (((w + 1) * 0.5f) - 1);
var b = ((2.0f * origNear) / y) * (((z + 1) * 0.5f) - 1);
Vector3 SubDivVert(Vector3 v1, Vector3 v2)
{
return Vector3.Normalize(v1 + v2);
}
var ratio = (newNear / origNear);
void Subdivide(ICollection<Vector3> dest, Vector3 v1, Vector3 v2, Vector3 v3)
{
var v12 = SubDivVert(v1, v2);
var v23 = SubDivVert(v2, v3);
var v13 = SubDivVert(v1, v3);
r *= ratio;
t *= ratio;
l *= ratio;
b *= ratio;
dest.Add(v1);
dest.Add(v12);
dest.Add(v13);
dest.Add(v12);
dest.Add(v2);
dest.Add(v23);
dest.Add(v23);
dest.Add(v13);
dest.Add(v12);
dest.Add(v3);
dest.Add(v13);
dest.Add(v23);
}
var ret = new Matrix4x4();
void SubdivideYOnly(ICollection<Vector3> dest, Vector3 v1, Vector3 v2, Vector3 v3)
{
// Find out which vertex is furthest out from the others on the y axis
ret[0, 0] = (2.0f * newNear) / (r - l); ret[0, 1] = 0; ret[0, 2] = (r + l) / (r - l); ret[0, 3] = 0;
ret[1, 0] = 0; ret[1, 1] = (2.0f * newNear) / (t - b); ret[1, 2] = (t + b) / (t - b); ret[1, 3] = 0;
ret[2, 0] = 0; ret[2, 1] = 0; ret[2, 2] = -(newFar + newNear) / (newFar - newNear); ret[2, 3] = -(2.0f * newFar * newNear) / (newFar - newNear);
ret[3, 0] = 0; ret[3, 1] = 0; ret[3, 2] = -1.0f; ret[3, 3] = 0;
var d12 = Mathf.Abs(v2.y - v1.y);
var d23 = Mathf.Abs(v2.y - v3.y);
var d31 = Mathf.Abs(v3.y - v1.y);
return ret;
}
Vector3 top, va, vb;
// Octahedron vertices
readonly Vector3[] m_OctaVerts =
{
new Vector3(0.0f, 1.0f, 0.0f), new Vector3(0.0f, 0.0f, -1.0f), new Vector3(1.0f, 0.0f, 0.0f),
new Vector3(0.0f, 1.0f, 0.0f), new Vector3(1.0f, 0.0f, 0.0f), new Vector3(0.0f, 0.0f, 1.0f),
new Vector3(0.0f, 1.0f, 0.0f), new Vector3(0.0f, 0.0f, 1.0f), new Vector3(-1.0f, 0.0f, 0.0f),
new Vector3(0.0f, 1.0f, 0.0f), new Vector3(-1.0f, 0.0f, 0.0f), new Vector3(0.0f, 0.0f, -1.0f),
new Vector3(0.0f, -1.0f, 0.0f), new Vector3(1.0f, 0.0f, 0.0f), new Vector3(0.0f, 0.0f, -1.0f),
new Vector3(0.0f, -1.0f, 0.0f), new Vector3(0.0f, 0.0f, 1.0f), new Vector3(1.0f, 0.0f, 0.0f),
new Vector3(0.0f, -1.0f, 0.0f), new Vector3(-1.0f, 0.0f, 0.0f), new Vector3(0.0f, 0.0f, 1.0f),
new Vector3(0.0f, -1.0f, 0.0f), new Vector3(0.0f, 0.0f, -1.0f), new Vector3(-1.0f, 0.0f, 0.0f),
};
if (d12 < d23 && d12 < d31)
Vector3 SubDivVert(Vector3 v1, Vector3 v2)
top = v3;
va = v1;
vb = v2;
}
else if (d23 < d12 && d23 < d31)
{
top = v1;
va = v2;
vb = v3;
}
else
{
top = v2;
va = v3;
vb = v1;
return Vector3.Normalize(v1 + v2);
var v12 = SubDivVert(top, va);
var v13 = SubDivVert(top, vb);
dest.Add(top);
dest.Add(v12);
dest.Add(v13);
// A bit of extra logic to prevent triangle slivers: choose the shorter of (13->va), (12->vb) as triangle base
if ((v13 - va).sqrMagnitude > (v12 - vb).sqrMagnitude)
void Subdivide(ICollection<Vector3> dest, Vector3 v1, Vector3 v2, Vector3 v3)
var v12 = SubDivVert(v1, v2);
var v23 = SubDivVert(v2, v3);
var v13 = SubDivVert(v1, v3);
dest.Add(v1);
dest.Add(va);
dest.Add(vb);
dest.Add(v13);
dest.Add(v12);
dest.Add(v2);
dest.Add(v23);
dest.Add(v23);
dest.Add(vb);
dest.Add(v3);
dest.Add(v13);
dest.Add(v23);
else
void SubdivideYOnly(ICollection<Vector3> dest, Vector3 v1, Vector3 v2, Vector3 v3)
dest.Add(v13);
// Find out which vertex is furthest out from the others on the y axis
var d12 = Mathf.Abs(v2.y - v1.y);
var d23 = Mathf.Abs(v2.y - v3.y);
var d31 = Mathf.Abs(v3.y - v1.y);
Vector3 top, va, vb;
if (d12 < d23 && d12 < d31)
{
top = v3;
va = v1;
vb = v2;
}
else if (d23 < d12 && d23 < d31)
{
top = v1;
va = v2;
vb = v3;
}
else
{
top = v2;
va = v3;
vb = v1;
}
var v12 = SubDivVert(top, va);
var v13 = SubDivVert(top, vb);
dest.Add(top);
dest.Add(va);
dest.Add(va);
dest.Add(vb);
// A bit of extra logic to prevent triangle slivers: choose the shorter of (13->va), (12->vb) as triangle base
if ((v13 - va).sqrMagnitude > (v12 - vb).sqrMagnitude)
{
dest.Add(v12);
dest.Add(va);
dest.Add(vb);
dest.Add(v13);
dest.Add(v12);
dest.Add(vb);
}
else
{
dest.Add(v13);
dest.Add(v12);
dest.Add(va);
dest.Add(v13);
dest.Add(va);
dest.Add(vb);
}
}
Mesh m_Mesh;
Mesh m_Mesh;
}
}

667
Assets/ScriptableRenderPipeline/common/TextureCache.cs


using UnityEngine;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor;
#endif
public class TextureCache2D : TextureCache
namespace UnityEngine.Experimental.Rendering
private Texture2DArray m_Cache;
public override void TransferToSlice(int sliceIndex, Texture texture)
public class TextureCache2D : TextureCache
var mismatch = (m_Cache.width != texture.width) || (m_Cache.height != texture.height);
private Texture2DArray m_Cache;
if (texture is Texture2D)
public override void TransferToSlice(int sliceIndex, Texture texture)
mismatch |= (m_Cache.format != (texture as Texture2D).format);
var mismatch = (m_Cache.width != texture.width) || (m_Cache.height != texture.height);
if (texture is Texture2D)
{
mismatch |= (m_Cache.format != (texture as Texture2D).format);
}
if (mismatch)
{
if (!Graphics.ConvertTexture(texture, 0, m_Cache, sliceIndex))
{
Debug.LogErrorFormat(texture, "Unable to convert texture \"{0}\" to match renderloop settings ({1}x{2} {3})",
texture.name, m_Cache.width, m_Cache.height, m_Cache.format);
}
}
else
{
Graphics.CopyTexture(texture, 0, m_Cache, sliceIndex);
}
if (mismatch)
public override Texture GetTexCache()
if (!Graphics.ConvertTexture(texture, 0, m_Cache, sliceIndex))
return m_Cache;
}
public bool AllocTextureArray(int numTextures, int width, int height, TextureFormat format, bool isMipMapped)
{
var res = AllocTextureArray(numTextures);
m_NumMipLevels = GetNumMips(width, height);
m_Cache = new Texture2DArray(width, height, numTextures, format, isMipMapped)
Debug.LogErrorFormat(texture, "Unable to convert texture \"{0}\" to match renderloop settings ({1}x{2} {3})",
texture.name, m_Cache.width, m_Cache.height, m_Cache.format);
}
hideFlags = HideFlags.HideAndDontSave,
wrapMode = TextureWrapMode.Clamp
};
return res;
else
public void Release()
Graphics.CopyTexture(texture, 0, m_Cache, sliceIndex);
Texture.DestroyImmediate(m_Cache); // do I need this?
public override Texture GetTexCache()
public class TextureCacheCubemap : TextureCache
return m_Cache;
}
private CubemapArray m_Cache;
public bool AllocTextureArray(int numTextures, int width, int height, TextureFormat format, bool isMipMapped)
{
var res = AllocTextureArray(numTextures);
m_NumMipLevels = GetNumMips(width, height);
// the member variables below are only in use when TextureCache.supportsCubemapArrayTextures is false
private Texture2DArray m_CacheNoCubeArray;
private RenderTexture[] m_StagingRTs;
private int m_NumPanoMipLevels;
private Material m_CubeBlitMaterial;
private int m_CubeMipLevelPropName;
private int m_cubeSrcTexPropName;
m_Cache = new Texture2DArray(width, height, numTextures, format, isMipMapped)
public override void TransferToSlice(int sliceIndex, Texture texture)
hideFlags = HideFlags.HideAndDontSave,
wrapMode = TextureWrapMode.Clamp
};
if(!TextureCache.supportsCubemapArrayTextures)
TransferToPanoCache(sliceIndex, texture);
else
{
var mismatch = (m_Cache.width != texture.width) || (m_Cache.height != texture.height);
return res;
}
if (texture is Cubemap)
{
mismatch |= (m_Cache.format != (texture as Cubemap).format);
}
public void Release()
{
Texture.DestroyImmediate(m_Cache); // do I need this?
}
}
if (mismatch)
{
bool failed = false;
public class TextureCacheCubemap : TextureCache
{
private CubemapArray m_Cache;
for (int f = 0; f < 6; f++)
{
if (!Graphics.ConvertTexture(texture, f, m_Cache, 6 * sliceIndex + f))
{
failed = true;
break;
}
}
// alternative panorama path intended for mobile
// the member variables below are only in use when m_IsNoCubeArray is true.
private bool m_IsNoCubeArray = false;
private Texture2DArray m_CacheNoCubeArray;
private RenderTexture[] m_StagingRTs;
private int m_NumPanoMipLevels;
private Material m_CubeBlitMaterial;
private int m_CubeMipLevelPropName;
private int m_cubeSrcTexPropName;
// alternative panorama path intended for mobile
// the member variables below are only in use when m_IsNoCubeArray is true.
if (failed)
{
Debug.LogErrorFormat(texture, "Unable to convert texture \"{0}\" to match renderloop settings ({1}x{2} {3})",
texture.name, m_Cache.width, m_Cache.height, m_Cache.format);
}
}
else
{
for (int f = 0; f < 6; f++)
Graphics.CopyTexture(texture, f, m_Cache, 6 * sliceIndex + f);
}
}
}
public override Texture GetTexCache()
{
return !TextureCache.supportsCubemapArrayTextures ? (Texture) m_CacheNoCubeArray : m_Cache;
}
public override void TransferToSlice(int sliceIndex, Texture texture)
{
if(m_IsNoCubeArray)
TransferToPanoCache(sliceIndex, texture);
else
public bool AllocTextureArray(int numCubeMaps, int width, TextureFormat format, bool isMipMapped)
var mismatch = (m_Cache.width != texture.width) || (m_Cache.height != texture.height);
if (texture is Cubemap)
var res = AllocTextureArray(numCubeMaps);
m_NumMipLevels = GetNumMips(width, width); // will calculate same way whether we have cube array or not
if(!TextureCache.supportsCubemapArrayTextures)
mismatch |= (m_Cache.format != (texture as Cubemap).format);
}
if(!m_CubeBlitMaterial) m_CubeBlitMaterial = new Material(Shader.Find("Hidden/CubeToPano"));
if (mismatch)
{
bool failed = false;
int panoWidthTop = 4*width;
int panoHeightTop = 2*width;
for (int f = 0; f < 6; f++)
// create panorama 2D array. Hardcoding the render target for now. No convenient way atm to
// map from TextureFormat to RenderTextureFormat and don't want to deal with sRGB issues for now.
m_CacheNoCubeArray = new Texture2DArray(panoWidthTop, panoHeightTop, numCubeMaps, TextureFormat.RGBAHalf, isMipMapped)
if (!Graphics.ConvertTexture(texture, f, m_Cache, 6 * sliceIndex + f))
{
failed = true;
break;
}
hideFlags = HideFlags.HideAndDontSave,
wrapMode = TextureWrapMode.Repeat,
wrapModeV = TextureWrapMode.Clamp,
filterMode = FilterMode.Trilinear,
anisoLevel = 0
};
m_NumPanoMipLevels = isMipMapped ? GetNumMips(panoWidthTop, panoHeightTop) : 1;
m_StagingRTs = new RenderTexture[m_NumPanoMipLevels];
for(int m=0; m<m_NumPanoMipLevels; m++)
{
m_StagingRTs[m] = new RenderTexture(Mathf.Max(1,panoWidthTop>>m), Mathf.Max(1,panoHeightTop>>m), 0, RenderTextureFormat.ARGBHalf);
if (failed)
if(m_CubeBlitMaterial)
Debug.LogErrorFormat(texture, "Unable to convert texture \"{0}\" to match renderloop settings ({1}x{2} {3})",
texture.name, m_Cache.width, m_Cache.height, m_Cache.format);
m_CubeMipLevelPropName = Shader.PropertyToID("_cubeMipLvl");
m_cubeSrcTexPropName = Shader.PropertyToID("_srcCubeTexture");
for (int f = 0; f < 6; f++)
Graphics.CopyTexture(texture, f, m_Cache, 6 * sliceIndex + f);
m_Cache = new CubemapArray(width, numCubeMaps, format, isMipMapped)
{
hideFlags = HideFlags.HideAndDontSave,
wrapMode = TextureWrapMode.Clamp,
filterMode = FilterMode.Trilinear,
anisoLevel = 0 // It is important to set 0 here, else unity force anisotropy filtering
};
return res;
}
public override Texture GetTexCache()
{
return m_IsNoCubeArray ? (Texture) m_CacheNoCubeArray : m_Cache;
}
public bool AllocTextureArray(int numCubeMaps, int width, TextureFormat format, bool isMipMapped)
{
var res = AllocTextureArray(numCubeMaps);
m_NumMipLevels = GetNumMips(width, width); // will calculate same way whether we have cube array or not
if(m_IsNoCubeArray)
public void Release()
if(!m_CubeBlitMaterial) m_CubeBlitMaterial = new Material(Shader.Find("Hidden/CubeToPano"));
int panoWidthTop = 4*width;
int panoHeightTop = 2*width;
// create panorama 2D array. Hardcoding the render target for now when m_IsNoCubeArray is true. No convenient way atm. to
// map from TextureFormat to RenderTextureFormat and don't want to deal with sRGB issues for now.
m_CacheNoCubeArray = new Texture2DArray(panoWidthTop, panoHeightTop, numCubeMaps, TextureFormat.RGBAHalf, isMipMapped)
if (m_CacheNoCubeArray)
hideFlags = HideFlags.HideAndDontSave,
wrapMode = TextureWrapMode.Repeat,
filterMode = FilterMode.Trilinear,
anisoLevel = 0
};
Texture.DestroyImmediate(m_CacheNoCubeArray);
for(int m=0; m<m_NumPanoMipLevels; m++)
{
m_StagingRTs[m].Release();
}
m_StagingRTs=null;
if(m_CubeBlitMaterial) Material.DestroyImmediate(m_CubeBlitMaterial);
}
if (m_Cache)
Texture.DestroyImmediate(m_Cache);
}
m_NumPanoMipLevels = isMipMapped ? GetNumMips(panoWidthTop, panoHeightTop) : 1;
m_StagingRTs = new RenderTexture[m_NumPanoMipLevels];
private void TransferToPanoCache(int sliceIndex, Texture texture)
{
m_CubeBlitMaterial.SetTexture(m_cubeSrcTexPropName, texture);
m_StagingRTs[m] = new RenderTexture(Mathf.Max(1,panoWidthTop>>m), Mathf.Max(1,panoHeightTop>>m), 0, RenderTextureFormat.ARGBHalf);
m_CubeBlitMaterial.SetInt(m_CubeMipLevelPropName, Mathf.Min(m_NumMipLevels-1,m) );
Graphics.SetRenderTarget(m_StagingRTs[m]);
Graphics.Blit(null, m_CubeBlitMaterial, 0);
if(m_CubeBlitMaterial)
for(int m=0; m<m_NumPanoMipLevels; m++)
Graphics.CopyTexture(m_StagingRTs[m], 0, 0, m_CacheNoCubeArray, sliceIndex, m);
}
}
public abstract class TextureCache
{
protected int m_NumMipLevels;
static int s_GlobalTextureCacheVersion = 0;
int m_TextureCacheVersion = 0;
#if UNITY_EDITOR
internal class AssetReloader : UnityEditor.AssetPostprocessor
{
void OnPostprocessTexture(Texture texture)
m_CubeMipLevelPropName = Shader.PropertyToID("_cubeMipLvl");
m_cubeSrcTexPropName = Shader.PropertyToID("_srcCubeTexture");
s_GlobalTextureCacheVersion++;
else
#endif
public static bool isMobileBuildTarget
m_Cache = new CubemapArray(width, numCubeMaps, format, isMipMapped)
get
hideFlags = HideFlags.HideAndDontSave,
wrapMode = TextureWrapMode.Clamp,
filterMode = FilterMode.Trilinear,
anisoLevel = 0 // It is important to set 0 here, else unity force anisotropy filtering
};
#if UNITY_EDITOR
switch (EditorUserBuildSettings.activeBuildTarget)
{
case BuildTarget.iOS:
case BuildTarget.Android:
case BuildTarget.Tizen:
case BuildTarget.WSAPlayer:
// Note: We return true on purpose even if Windows Store Apps are running on Desktop.
return true;
default:
return false;
}
#else
return Application.isMobilePlatform;
#endif
}
return res;
}
public void Release()
{
if(m_IsNoCubeArray)
public static TextureFormat GetPreferredCompressedTextureFormat
Texture.DestroyImmediate(m_CacheNoCubeArray);
for(int m=0; m<m_NumPanoMipLevels; m++)
get
m_StagingRTs[m].Release();
var format = TextureFormat.RGBAHalf;
var probeFormat = TextureFormat.BC6H;
// On editor the texture is uncompressed when operating against mobile build targets
if (SystemInfo.SupportsTextureFormat(probeFormat) && !TextureCache.isMobileBuildTarget)
format = probeFormat;
return format;
m_StagingRTs=null;
if(m_CubeBlitMaterial) Material.DestroyImmediate(m_CubeBlitMaterial);
else Texture.DestroyImmediate(m_Cache);
}
private void TransferToPanoCache(int sliceIndex, Texture texture)
{
m_CubeBlitMaterial.SetTexture(m_cubeSrcTexPropName, texture);
for(int m=0; m<m_NumPanoMipLevels; m++)
public static bool supportsCubemapArrayTextures
m_CubeBlitMaterial.SetInt(m_CubeMipLevelPropName, Mathf.Min(m_NumMipLevels-1,m) );
Graphics.SetRenderTarget(m_StagingRTs[m]);
Graphics.Blit(null, m_CubeBlitMaterial, 0);
get
{
return (SystemInfo.supportsCubemapArrayTextures && !TextureCache.isMobileBuildTarget);
}
for(int m=0; m<m_NumPanoMipLevels; m++)
Graphics.CopyTexture(m_StagingRTs[m], 0, 0, m_CacheNoCubeArray, sliceIndex, m);
}
}
private struct SSliceEntry
{
public uint texId;
public uint countLRU;
};
private int m_NumTextures;
private int[] m_SortedIdxArray;
private SSliceEntry[] m_SliceArray;
public abstract class TextureCache
{
protected int m_NumMipLevels;
Dictionary<uint, int> m_LocatorInSliceArray;
static int s_GlobalTextureCacheVersion = 0;
int m_TextureCacheVersion = 0;
private static uint g_MaxFrameCount = unchecked((uint)(-1));
private static uint g_InvalidTexID = (uint)0;
#if UNITY_EDITOR
internal class AssetReloader : UnityEditor.AssetPostprocessor
{
void OnPostprocessTexture(Texture texture)
public int FetchSlice(Texture texture)
s_GlobalTextureCacheVersion++;
}
}
#endif
var texId = (uint)texture.GetInstanceID();
private struct SSliceEntry
{
public uint texId;
public uint countLRU;
};
//assert(TexID!=g_InvalidTexID);
if (texId == g_InvalidTexID) return 0;
private int m_NumTextures;
private int[] m_SortedIdxArray;
private SSliceEntry[] m_SliceArray;
var bSwapSlice = false;
var bFoundAvailOrExistingSlice = false;
var sliceIndex = -1;
Dictionary<uint, int> m_LocatorInSliceArray;
// search for existing copy
if (m_LocatorInSliceArray.ContainsKey(texId))
{
if (m_TextureCacheVersion != s_GlobalTextureCacheVersion)
{
m_LocatorInSliceArray.Remove(texId);
m_TextureCacheVersion++;
Debug.Assert(m_TextureCacheVersion <= s_GlobalTextureCacheVersion);
}
else
{
sliceIndex = m_LocatorInSliceArray[texId];
bFoundAvailOrExistingSlice = true;
}
//assert(m_SliceArray[sliceIndex].TexID==TexID);
}
private static uint g_MaxFrameCount = unchecked((uint)(-1));
private static uint g_InvalidTexID = (uint)0;
// If no existing copy found in the array
if (!bFoundAvailOrExistingSlice)
{
// look for first non zero entry. Will by the least recently used entry
// since the array was pre-sorted (in linear time) in NewFrame()
var bFound = false;
int j = 0, idx = 0;
while ((!bFound) && j < m_NumTextures)
{
idx = m_SortedIdxArray[j];
if (m_SliceArray[idx].countLRU == 0) ++j; // if entry already snagged by a new texture in this frame then ++j
else bFound = true;
}
public int FetchSlice(Texture texture)
{
var texId = (uint)texture.GetInstanceID();
if (bFound)
{
// if we are replacing an existing entry delete it from m_locatorInSliceArray.
if (m_SliceArray[idx].texId != g_InvalidTexID)
{
m_LocatorInSliceArray.Remove(m_SliceArray[idx].texId);
}
//assert(TexID!=g_InvalidTexID);
if (texId == g_InvalidTexID) return 0;
m_LocatorInSliceArray.Add(texId, idx);
m_SliceArray[idx].texId = texId;
sliceIndex = idx;
bFoundAvailOrExistingSlice = true;
bSwapSlice = true;
}
}
var bSwapSlice = false;
var bFoundAvailOrExistingSlice = false;
var sliceIndex = -1;
// search for existing copy
if (m_LocatorInSliceArray.ContainsKey(texId))
{
if (m_TextureCacheVersion != s_GlobalTextureCacheVersion)
// wrap up
//assert(bFoundAvailOrExistingSlice);
if (bFoundAvailOrExistingSlice)
m_LocatorInSliceArray.Remove(texId);
m_TextureCacheVersion++;
Debug.Assert(m_TextureCacheVersion <= s_GlobalTextureCacheVersion);
}
else
{
sliceIndex = m_LocatorInSliceArray[texId];
bFoundAvailOrExistingSlice = true;
m_SliceArray[sliceIndex].countLRU = 0; // mark slice as in use this frame
if (bSwapSlice) // if this was a miss
{
// transfer new slice to sliceIndex from source texture
TransferToSlice(sliceIndex, texture);
}
//assert(m_SliceArray[sliceIndex].TexID==TexID);
return sliceIndex;
// If no existing copy found in the array
if (!bFoundAvailOrExistingSlice)
public void NewFrame()
// look for first non zero entry. Will by the least recently used entry
// since the array was pre-sorted (in linear time) in NewFrame()
var bFound = false;
int j = 0, idx = 0;
while ((!bFound) && j < m_NumTextures)
var numNonZeros = 0;
var tmpBuffer = new int[m_NumTextures];
for (int i = 0; i < m_NumTextures; i++)
idx = m_SortedIdxArray[j];
if (m_SliceArray[idx].countLRU == 0) ++j; // if entry already snagged by a new texture in this frame then ++j
else bFound = true;
tmpBuffer[i] = m_SortedIdxArray[i]; // copy buffer
if (m_SliceArray[m_SortedIdxArray[i]].countLRU != 0) ++numNonZeros;
if (bFound)
int nonZerosBase = 0, zerosBase = 0;
for (int i = 0; i < m_NumTextures; i++)
// if we are replacing an existing entry delete it from m_locatorInSliceArray.
if (m_SliceArray[idx].texId != g_InvalidTexID)
if (m_SliceArray[tmpBuffer[i]].countLRU == 0)
m_LocatorInSliceArray.Remove(m_SliceArray[idx].texId);
m_SortedIdxArray[zerosBase + numNonZeros] = tmpBuffer[i];
++zerosBase;
}
else
{
m_SortedIdxArray[nonZerosBase] = tmpBuffer[i];
++nonZerosBase;
}
m_LocatorInSliceArray.Add(texId, idx);
m_SliceArray[idx].texId = texId;
sliceIndex = idx;
bFoundAvailOrExistingSlice = true;
bSwapSlice = true;
for (int i = 0; i < m_NumTextures; i++)
{
if (m_SliceArray[i].countLRU < g_MaxFrameCount) ++m_SliceArray[i].countLRU; // next frame
//for(int q=1; q<m_numTextures; q++)
// assert(m_SliceArray[m_SortedIdxArray[q-1]].CountLRU>=m_SliceArray[m_SortedIdxArray[q]].CountLRU);
protected TextureCache()
{
m_NumTextures = 0;
m_NumMipLevels = 0;
}
// wrap up
//assert(bFoundAvailOrExistingSlice);
if (bFoundAvailOrExistingSlice)
public virtual void TransferToSlice(int sliceIndex, Texture texture)
m_SliceArray[sliceIndex].countLRU = 0; // mark slice as in use this frame
if (bSwapSlice) // if this was a miss
{
// transfer new slice to sliceIndex from source texture
TransferToSlice(sliceIndex, texture);
}
return sliceIndex;
}
public void NewFrame()
{
var numNonZeros = 0;
var tmpBuffer = new int[m_NumTextures];
for (int i = 0; i < m_NumTextures; i++)
public virtual Texture GetTexCache()
tmpBuffer[i] = m_SortedIdxArray[i]; // copy buffer
if (m_SliceArray[m_SortedIdxArray[i]].countLRU != 0) ++numNonZeros;
return null;
int nonZerosBase = 0, zerosBase = 0;
for (int i = 0; i < m_NumTextures; i++)
protected bool AllocTextureArray(int numTextures)
if (m_SliceArray[tmpBuffer[i]].countLRU == 0)
if (numTextures > 0)
m_SortedIdxArray[zerosBase + numNonZeros] = tmpBuffer[i];
++zerosBase;
m_SliceArray = new SSliceEntry[numTextures];
m_SortedIdxArray = new int[numTextures];
m_LocatorInSliceArray = new Dictionary<uint, int>();
m_NumTextures = numTextures;
for (int i = 0; i < m_NumTextures; i++)
{
m_SliceArray[i].countLRU = g_MaxFrameCount; // never used before
m_SliceArray[i].texId = g_InvalidTexID;
m_SortedIdxArray[i] = i;
}
else
{
m_SortedIdxArray[nonZerosBase] = tmpBuffer[i];
++nonZerosBase;
}
//return m_SliceArray != NULL && m_SortedIdxArray != NULL && numTextures > 0;
return numTextures > 0;
for (int i = 0; i < m_NumTextures; i++)
// should not really be used in general. Assuming lights are culled properly entries will automatically be replaced efficiently.
public void RemoveEntryFromSlice(Texture texture)
if (m_SliceArray[i].countLRU < g_MaxFrameCount) ++m_SliceArray[i].countLRU; // next frame
}
var texId = (uint)texture.GetInstanceID();
//for(int q=1; q<m_numTextures; q++)
// assert(m_SliceArray[m_SortedIdxArray[q-1]].CountLRU>=m_SliceArray[m_SortedIdxArray[q]].CountLRU);
}
//assert(TexID!=g_InvalidTexID);
if (texId == g_InvalidTexID) return;
protected TextureCache()
{
m_NumTextures = 0;
m_NumMipLevels = 0;
}
// search for existing copy
if (!m_LocatorInSliceArray.ContainsKey(texId))
return;
public virtual void TransferToSlice(int sliceIndex, Texture texture)
{
}
public virtual Texture GetTexCache()
{
return null;
}
var sliceIndex = m_LocatorInSliceArray[texId];
protected bool AllocTextureArray(int numTextures)
{
if (numTextures > 0)
{
m_SliceArray = new SSliceEntry[numTextures];
m_SortedIdxArray = new int[numTextures];
m_LocatorInSliceArray = new Dictionary<uint, int>();
//assert(m_SliceArray[sliceIndex].TexID==TexID);
m_NumTextures = numTextures;
for (int i = 0; i < m_NumTextures; i++)
// locate entry sorted by uCountLRU in m_pSortedIdxArray
var foundIdxSortLRU = false;
var i = 0;
while ((!foundIdxSortLRU) && i < m_NumTextures)
m_SliceArray[i].countLRU = g_MaxFrameCount; // never used before
m_SliceArray[i].texId = g_InvalidTexID;
m_SortedIdxArray[i] = i;
if (m_SortedIdxArray[i] == sliceIndex) foundIdxSortLRU = true;
else ++i;
}
//return m_SliceArray != NULL && m_SortedIdxArray != NULL && numTextures > 0;
return numTextures > 0;
}
// should not really be used in general. Assuming lights are culled properly entries will automatically be replaced efficiently.
public void RemoveEntryFromSlice(Texture texture)
{
var texId = (uint)texture.GetInstanceID();
if (!foundIdxSortLRU)
return;
//assert(TexID!=g_InvalidTexID);
if (texId == g_InvalidTexID) return;
// relocate sliceIndex to front of m_pSortedIdxArray since uCountLRU will be set to maximum.
for (int j = 0; j < i; j++)
{
m_SortedIdxArray[j + 1] = m_SortedIdxArray[j];
}
m_SortedIdxArray[0] = sliceIndex;
// search for existing copy
if (!m_LocatorInSliceArray.ContainsKey(texId))
return;
var sliceIndex = m_LocatorInSliceArray[texId];
// delete from m_locatorInSliceArray and m_pSliceArray.
m_LocatorInSliceArray.Remove(texId);
m_SliceArray[sliceIndex].countLRU = g_MaxFrameCount; // never used before
m_SliceArray[sliceIndex].texId = g_InvalidTexID;
}
//assert(m_SliceArray[sliceIndex].TexID==TexID);
// locate entry sorted by uCountLRU in m_pSortedIdxArray
var foundIdxSortLRU = false;
var i = 0;
while ((!foundIdxSortLRU) && i < m_NumTextures)
protected int GetNumMips(int width, int height)
if (m_SortedIdxArray[i] == sliceIndex) foundIdxSortLRU = true;
else ++i;
return GetNumMips(width > height ? width : height);
if (!foundIdxSortLRU)
return;
// relocate sliceIndex to front of m_pSortedIdxArray since uCountLRU will be set to maximum.
for (int j = 0; j < i; j++)
protected int GetNumMips(int dim)
m_SortedIdxArray[j + 1] = m_SortedIdxArray[j];
var uDim = (uint)dim;
var iNumMips = 0;
while (uDim > 0)
{ ++iNumMips; uDim >>= 1; }
return iNumMips;
m_SortedIdxArray[0] = sliceIndex;
// delete from m_locatorInSliceArray and m_pSliceArray.
m_LocatorInSliceArray.Remove(texId);
m_SliceArray[sliceIndex].countLRU = g_MaxFrameCount; // never used before
m_SliceArray[sliceIndex].texId = g_InvalidTexID;
}
protected int GetNumMips(int width, int height)
{
return GetNumMips(width > height ? width : height);
}
protected int GetNumMips(int dim)
{
var uDim = (uint)dim;
var iNumMips = 0;
while (uDim > 0)
{ ++iNumMips; uDim >>= 1; }
return iNumMips;
}
}

27
Assets/ScriptableRenderPipeline/fptl/ClusteredUtils.h


#define FLT_EPSILON 1.192092896e-07f
#endif
// Using pow often result to a warning like this
// "pow(f, e) will not work for negative f, use abs(f) or conditionally handle negative values if you expect them"
// PositivePow remove this warning when you know the value is positive and avoid inf/NAN.
float PositivePow(float base, float power)
{
return pow(max(abs(base), float(FLT_EPSILON)), power);
}
float2 PositivePow(float2 base, float2 power)
{
return pow(max(abs(base), float2(FLT_EPSILON, FLT_EPSILON)), power);
}
float3 PositivePow(float3 base, float3 power)
{
return pow(max(abs(base), float3(FLT_EPSILON, FLT_EPSILON, FLT_EPSILON)), power);
}
float4 PositivePow(float4 base, float4 power)
{
return pow(max(abs(base), float4(FLT_EPSILON, FLT_EPSILON, FLT_EPSILON, FLT_EPSILON)), power);
}
const float geomSeries = (1.0 - pow(base, C)) / (1 - base); // geometric series: sum_k=0^{C-1} base^k
const float geomSeries = (1.0 - PositivePow(base, C)) / (1 - base); // geometric series: sum_k=0^{C-1} base^k
return geomSeries / (g_fFarPlane - g_fNearPlane);
}

if (logBasePerTile)
userscale = GetScaleFromBase(suggestedBase);
float dist = (pow(suggestedBase, (float)k) - 1.0) / (userscale * (suggestedBase - 1.0f));
float dist = (PositivePow(suggestedBase, (float)k) - 1.0) / (userscale * (suggestedBase - 1.0f));
res = dist + g_fNearPlane;
#if USE_LEFTHAND_CAMERASPACE

4
Assets/ScriptableRenderPipeline/fptl/FPTLRenderPipeline.asset


directionalLightCascades: {x: 0.05, y: 0.2, z: 0.3}
directionalLightNearPlaneOffset: 5
m_TextureSettings:
spotCookieSize: 128
pointCookieSize: 512
spotCookieSize: 512
pointCookieSize: 128
reflectionCubemapSize: 128
deferredShader: {fileID: 4800000, guid: 1c102a89f3460254a8c413dbdcd63a2a, type: 3}
deferredReflectionShader: {fileID: 4800000, guid: 3899e06d641c2cb4cbff794df0da536b,

部分文件因为文件数量过多而无法显示

正在加载...
取消
保存