浏览代码

Merge remote-tracking branch 'origin/master' into HDRP_GraphicTests

/HDRP_GraphicTests
Remy 7 年前
当前提交
75cf5fa5
共有 105 个文件被更改,包括 8058 次插入625 次删除
  1. 4
      README.md
  2. 16
      ScriptableRenderPipeline/Core/CoreRP/Editor/Debugging/DebugWindow.cs
  3. 45
      ScriptableRenderPipeline/Core/CoreRP/GeometryUtils.cs
  4. 18
      ScriptableRenderPipeline/Core/CoreRP/GeometryUtils.cs.hlsl
  5. 16
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Common.hlsl
  6. 52
      ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Shadow/ShadowAlgorithms.hlsl
  7. 9
      ScriptableRenderPipeline/Core/CoreRP/Shadow/DebugDisplayShadowMap.shader
  8. 19
      ScriptableRenderPipeline/Core/CoreRP/Shadow/Shadow.cs
  9. 19
      ScriptableRenderPipeline/Core/CoreRP/Shadow/ShadowBase.cs
  10. 870
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/HDRenderPipeline.md
  11. 3
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Camera/HDCamera.cs
  12. 17
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Debug/DebugDisplay.cs
  13. 1
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Debug/DebugDisplay.hlsl
  14. 6
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Debug/DebugDisplayLatlong.shader
  15. 4
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Debug/LightingDebug.cs
  16. 12
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Decal/DecalProjectorComponent.cs
  17. 5
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Decal/DecalSystem.cs
  18. 3
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/HDAssetFactory.cs
  19. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Lighting/HDLightEditor.cs
  20. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/LayeredLit/LayeredLitUI.cs
  21. 10
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/Lit/LitUI.cs
  22. 4
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/RenderLoopSettings/GlobalLightLoopSettingsUI.cs
  23. 5
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Shadows/HDShadowSettingsEditor.cs
  24. 70
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDRenderPipeline.cs
  25. 6
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDStringConstants.cs
  26. 26
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDUtils.cs
  27. 1
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightEvaluation.hlsl
  28. 102
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/LightLoop.cs
  29. 3
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/LightLoop.cs.hlsl
  30. 5
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/LightLoop.hlsl
  31. 22
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/LightLoopDef.hlsl
  32. 3
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/lightlistbuild-bigtile.compute
  33. 12
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/lightlistbuild-clustered.compute
  34. 19
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/lightlistbuild.compute
  35. 10
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/HomogeneousDensityVolume.cs
  36. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/HomogeneousDensityVolume.cs.meta
  37. 324
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/VolumetricLighting.cs
  38. 10
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/VolumetricLighting.cs.hlsl
  39. 1
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/DBufferManager.cs
  40. 1
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/Decal.hlsl
  41. 44
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/DecalUtilities.hlsl
  42. 20
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/Lit.hlsl
  43. 4
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/RenderPipelineResources/HDRenderPipelineResources.asset
  44. 1
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/RenderPipelineResources/RenderPipelineResources.cs
  45. 1
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/ShaderPass/ShaderPass.cs
  46. 5
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/ShaderPass/ShaderPass.cs.hlsl
  47. 6
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Shadows/HDShadowSettings.cs
  48. 8
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Sky/SkyManager.cs
  49. 50
      ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightPipeline.cs
  50. 17
      ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/Core.hlsl
  51. 53
      ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/InputBuiltin.hlsl
  52. 19
      ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/InputSurface.hlsl
  53. 19
      ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/Lighting.hlsl
  54. 66
      ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/LightweightPassLit.hlsl
  55. 15
      ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/LightweightPassMeta.hlsl
  56. 10
      ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/Shadows.hlsl
  57. 3
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightStandard.shader
  58. 5
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightStandardSimpleLighting.shader
  59. 3
      ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightStandardTerrain.shader
  60. 6
      build.py
  61. 478
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/VolumetricLighting.compute
  62. 303
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/VolumeVoxelization.compute
  63. 8
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/VolumeVoxelization.compute.meta
  64. 8
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/VolumetricLighting.compute.meta
  65. 110
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader1.png
  66. 162
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader10.png
  67. 6
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader11.png
  68. 512
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader12.png
  69. 11
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader13.png
  70. 1001
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader14.png
  71. 1001
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader15.png
  72. 16
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader16.png
  73. 175
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader17.png
  74. 9
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader18.png
  75. 1001
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader19.png
  76. 546
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader2.png
  77. 19
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader20.png
  78. 190
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader21.png
  79. 18
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader22.png
  80. 8
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader23.png
  81. 23
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader24.png
  82. 27
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader25.png
  83. 23
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader26.png
  84. 19
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader27.png
  85. 23
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader3.png
  86. 15
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader4.png
  87. 38
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader5.png
  88. 50
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader6.png
  89. 17
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader7.png
  90. 26
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader8.png
  91. 324
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader9.png
  92. 33
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/SkyAndFog1.png
  93. 41
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/SkyAndFog2.png
  94. 28
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/SkyAndFog3.png
  95. 39
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/SkyAndFog4.png
  96. 45
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/SkyAndFog5.png
  97. 17
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/SkyAndFog7.png
  98. 179
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/SkyAndFog8.png
  99. 20
      ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/SkyandFog6.png

4
README.md


This feature is currently a work in progress. We cannot promise that features will work as expected in their current state. Some features may change or be removed before we move to a full release.
[Lightweight Pipeline Blogpost](https://blogs.unity3d.com/2018/02/21/the-lightweight-render-pipeline-optimizing-real-time-performance/)
[High Definition Pipeline Blogpost](https://blogs.unity3d.com/2018/03/16/the-high-definition-render-pipeline-focused-on-visual-quality/)
## How to use the latest version
__Note: The Master branch is our current development branch and may not work on the latest publicly available version of Unity. You should always use the latest release tag and latest Unity beta version for testing purposes.__
To use the latest version of the SRP, follow the instructions below:

16
ScriptableRenderPipeline/Core/CoreRP/Editor/Debugging/DebugWindow.cs


if (m_Settings == null)
m_Settings = CreateInstance<DebugWindowSettings>();
if (m_WidgetStates == null)
// States are ScriptableObjects (necessary for Undo/Redo) but are not saved on disk so when the editor is closed then reopened, any existing debug window will have its states set to null
// Since we don't care about persistance in this case, we just re-init everything.
if (m_WidgetStates == null || !AreWidgetStatesValid())
m_WidgetStates = new WidgetStateDictionary();
if (s_WidgetStateMap == null || s_WidgetDrawerMap == null || s_TypeMapDirty)

m_WidgetStates.Clear();
}
}
bool AreWidgetStatesValid()
{
foreach (var state in m_WidgetStates)
{
if(state.Value == null)
{
return false;
}
}
return true;
}
void MarkDirty()

45
ScriptableRenderPipeline/Core/CoreRP/GeometryUtils.cs


using System;
using System;
namespace UnityEngine.Experimental.Rendering
{

[GenerateHLSL]
public struct OrientedBBox
{
public Vector3 center;
public float extentX;
// 3 x float4 = 48 bytes.
// TODO: pack the axes into 16-bit UNORM per channel, and consider a quaternionic representation.
public float extentX;
public Vector3 up;
public Vector3 up;
public Vector3 center;
public Vector3 forward { get { return Vector3.Cross(up, right); } }
Vector3 vecX = t.localToWorldMatrix.GetColumn(0);
Vector3 vecY = t.localToWorldMatrix.GetColumn(1);
Vector3 vecZ = t.localToWorldMatrix.GetColumn(2);
obb.right = t.right;
obb.up = t.up;
obb.extentX = 0.5f * t.localScale.x;
obb.extentY = 0.5f * t.localScale.y;
obb.extentZ = 0.5f * t.localScale.z;
obb.right = vecX * (1.0f / vecX.magnitude);
obb.up = vecY * (1.0f / vecY.magnitude);
obb.extentX = 0.5f * vecX.magnitude;
obb.extentY = 0.5f * vecY.magnitude;
obb.extentZ = 0.5f * vecZ.magnitude;
return obb;
}

{
// Returns 'true' if the OBB intersects (or is inside) the frustum, 'false' otherwise.
// 'cameraRelativeOffset' can be used to intersect a world-space OBB with a camera-relative frustum.
public static bool Overlap(OrientedBBox obb, Vector3 cameraRelativeOffset,
Frustum frustum, int numPlanes, int numCorners)
public static bool Overlap(OrientedBBox obb, Frustum frustum, int numPlanes, int numCorners)
Vector3 center = obb.center + cameraRelativeOffset;
Vector3 forward = Vector3.Cross(obb.up, obb.right);
// Test the OBB against frustum planes. Frustum planes have inward-facing.
// Test the OBB against frustum planes. Frustum planes are inward-facing.
// The OBB is outside if it's entirely behind one of the frustum planes.
// See "Real-Time Rendering", 3rd Edition, 16.10.2.
for (int i = 0; overlap && i < numPlanes; i++)

// Max projection of the half-diagonal onto the normal (always positive).
float maxHalfDiagProj = obb.extentX * Mathf.Abs(Vector3.Dot(n, obb.right))
+ obb.extentY * Mathf.Abs(Vector3.Dot(n, obb.up))
+ obb.extentZ * Mathf.Abs(Vector3.Dot(n, forward));
+ obb.extentZ * Mathf.Abs(Vector3.Dot(n, obb.forward));
// Positive distance -> center in front of the plane.
float centerToPlaneDist = Vector3.Dot(n, center) + d;
float centerToPlaneDist = Vector3.Dot(n, obb.center) + d;
// outside = maxHalfDiagProj < -centerToPlaneDist
// outside = maxHalfDiagProj + centerToPlaneDist < 0

planes[0].distance = obb.extentX;
planes[1].normal = obb.up;
planes[1].distance = obb.extentY;
planes[2].normal = forward;
planes[2].normal = obb.forward;
planes[2].distance = obb.extentZ;
for (int i = 0; overlap && i < 3; i++)

// Merge 2 loops. Continue as long as all points are outside either plane.
for (int j = 0; j < numCorners; j++)
{
float proj = Vector3.Dot(plane.normal, frustum.corners[j] - center);
float proj = Vector3.Dot(plane.normal, frustum.corners[j] - obb.center);
outsidePos = outsidePos && ( proj > plane.distance);
outsideNeg = outsideNeg && (-proj > plane.distance);
}

18
ScriptableRenderPipeline/Core/CoreRP/GeometryUtils.cs.hlsl


// PackingRules = Exact
struct OrientedBBox
{
float3 center;
float3 right;
float3 right;
float3 up;
float3 up;
float3 center;
float extentZ;
};

float3 GetCenter(OrientedBBox value)
float3 GetRight(OrientedBBox value)
return value.center;
return value.right;
float3 GetRight(OrientedBBox value)
float3 GetUp(OrientedBBox value)
return value.right;
return value.up;
float3 GetUp(OrientedBBox value)
float3 GetCenter(OrientedBBox value)
return value.up;
return value.center;
}
float GetExtentZ(OrientedBBox value)
{

16
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Common.hlsl


#define real3x3 half3x3
#define real3x4 half3x4
#define real4x3 half4x3
#define real4x4 half4x4
#define real4x4 half4x4
#define half min16float
#define half2 min16float2
#define half3 min16float3
#define half4 min16float4
#define half2x2 min16float2x2
#define half2x3 min16float2x3
#define half3x2 min16float3x2
#define half3x3 min16float3x3
#define half3x4 min16float3x4
#define half4x3 min16float4x3
#define half4x4 min16float4x4
#define REAL_MIN HALF_MIN
#define REAL_MAX HALF_MAX

// 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
// TODO: replace the test (ditherFactor >= 0.5) with (isLod0) to avoid the distracting pattern flip around 0.5.
p = (ditherFactor >= 0.5) ? p : 1 - p;
clip(ditherFactor - p);
}

52
ScriptableRenderPipeline/Core/CoreRP/ShaderLibrary/Shadow/ShadowAlgorithms.hlsl


sd.viewBias.w = shadowContext.shadowDatas[index].viewBias.w;
}
int EvalShadow_GetSplitIndex( ShadowContext shadowContext, int index, real3 positionWS, out uint payloadOffset, out real alpha )
int EvalShadow_GetSplitIndex( ShadowContext shadowContext, int index, real3 positionWS, out uint payloadOffset, out real alpha, out int cascadeCount )
{
payloadOffset = shadowContext.shadowDatas[index].payloadOffset;

payloadOffset = shadowContext.shadowDatas[index].payloadOffset + kMaxShadowCascades;
real3 cascadeDir = asfloat( shadowContext.payloads[payloadOffset].xyz );
cascadeCount = shadowContext.payloads[payloadOffset].w;
payloadOffset++;
real border = asfloat( shadowContext.payloads[payloadOffset][shadowSplitIndex] );
payloadOffset++;

real EvalShadow_CascadedDepth_Blend( ShadowContext shadowContext, real3 positionWS, real3 normalWS, int index, real3 L )
{
// load the right shadow data for the current face
uint payloadOffset;
real alpha;
int shadowSplitIndex = EvalShadow_GetSplitIndex( shadowContext, index, positionWS, payloadOffset, alpha );
uint payloadOffset;
real alpha;
int cascadeCount;
int shadowSplitIndex = EvalShadow_GetSplitIndex( shadowContext, index, positionWS, payloadOffset, alpha, cascadeCount );
if( shadowSplitIndex < 0 )
return 1.0;

real shadow1 = 1.0;
shadowSplitIndex++;
if( shadowSplitIndex < kMaxShadowCascades )
if( shadowSplitIndex < cascadeCount )
{
shadow1 = shadow;

{ \
uint payloadOffset; \
real alpha; \
int shadowSplitIndex = EvalShadow_GetSplitIndex(shadowContext, index, positionWS, payloadOffset, alpha ); \
int cascadeCount; \
int shadowSplitIndex = EvalShadow_GetSplitIndex(shadowContext, index, positionWS, payloadOffset, alpha, cascadeCount ); \
\
if( shadowSplitIndex < 0 ) \
return 1.0; \

real shadow1 = 1.0; \
\
shadowSplitIndex++; \
if( shadowSplitIndex < kMaxShadowCascades ) \
if( shadowSplitIndex < cascadeCount ) \
{ \
shadow1 = shadow; \
\

real EvalShadow_CascadedDepth_Dither( ShadowContext shadowContext, real3 positionWS, real3 normalWS, int index, real3 L )
{
// load the right shadow data for the current face
uint payloadOffset;
real alpha;
int shadowSplitIndex = EvalShadow_GetSplitIndex(shadowContext, index, positionWS, payloadOffset, alpha);
uint payloadOffset;
real alpha;
int cascadeCount;
int shadowSplitIndex = EvalShadow_GetSplitIndex( shadowContext, index, positionWS, payloadOffset, alpha, cascadeCount );
if( shadowSplitIndex < 0 )
return 1.0;

// get shadowmap texcoords
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS, false );
int nextSplit = min( shadowSplitIndex+1, kMaxShadowCascades-1 );
int nextSplit = min( shadowSplitIndex+1, cascadeCount-1 );
if( shadowSplitIndex < nextSplit && step( EvalShadow_hash12( posTC.xy ), alpha ) )
{

// sample the texture
real2 sampleBias = EvalShadow_SampleBias_Ortho( sd, normalWS );
real shadow = SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sampleBias, shadowAlgorithm, texIdx, sampIdx );
return shadowSplitIndex < (kMaxShadowCascades-1) ? shadow : lerp( shadow, 1.0, alpha );
return shadowSplitIndex < (cascadeCount-1) ? shadow : lerp( shadow, 1.0, alpha );
}
#define EvalShadow_CascadedDepth_( _samplerType ) \

uint payloadOffset; \
real alpha; \
int shadowSplitIndex = EvalShadow_GetSplitIndex(shadowContext, index, positionWS, payloadOffset, alpha ); \
int cascadeCount; \
int shadowSplitIndex = EvalShadow_GetSplitIndex( shadowContext, index, positionWS, payloadOffset, alpha, cascadeCount ); \
\
if( shadowSplitIndex < 0 ) \
return 1.0; \

/* get shadowmap texcoords */ \
real3 posTC = EvalShadow_GetTexcoords( sd, positionWS, false ); \
\
int nextSplit = min( shadowSplitIndex+1, kMaxShadowCascades-1 ); \
int nextSplit = min( shadowSplitIndex+1, cascadeCount-1 ); \
\
if( shadowSplitIndex != nextSplit && step( EvalShadow_hash12( posTC.xy ), alpha ) ) \
{ \

/* sample the texture */ \
real2 sampleBias = EvalShadow_SampleBias_Ortho( sd, normalWS ); \
real shadow = SampleShadow_SelectAlgorithm( shadowContext, sd, payloadOffset, posTC, sampleBias, shadowAlgorithms[shadowSplitIndex], tex, samp ); \
return shadowSplitIndex < (kMaxShadowCascades-1) ? shadow : lerp( shadow, 1.0, alpha ); \
return shadowSplitIndex < (cascadeCount-1) ? shadow : lerp( shadow, 1.0, alpha ); \
} \
\
real EvalShadow_CascadedDepth_Dither( ShadowContext shadowContext, uint shadowAlgorithm, Texture2DArray tex, _samplerType samp, real3 positionWS, real3 normalWS, int index, real3 L ) \

// load the right shadow data for the current face
uint payloadOffset;
real alpha;
int shadowSplitIndex = EvalShadow_GetSplitIndex( shadowContext, index, positionWS, payloadOffset, alpha );
int cascadeCount;
int shadowSplitIndex = EvalShadow_GetSplitIndex( shadowContext, index, positionWS, payloadOffset, alpha, cascadeCount );
if( shadowSplitIndex < 0 )
return 0.0;

// load the right shadow data for the current face
uint payloadOffset;
real alpha;
int shadowSplitIndex = EvalShadow_GetSplitIndex( shadowContext, index, positionWS, payloadOffset, alpha );
int cascadeCount;
int shadowSplitIndex = EvalShadow_GetSplitIndex( shadowContext, index, positionWS, payloadOffset, alpha, cascadeCount );
if( shadowSplitIndex < 0 )
return 0.0;

}
real EvalShadow_SampleClosestDistance_Cascade( ShadowContext shadowContext, Texture2DArray tex, SamplerState sampl,
real3 positionWS, real3 normalWS, int index, real4 L, out real3 nearPlanePositionWS )
real3 positionWS, real3 normalWS, int index, real4 L, out real3 nearPlanePositionWS )
int shadowSplitIndex = EvalShadow_GetSplitIndex( shadowContext, index, positionWS, payloadOffset, alpha );
int cascadeCount;
int shadowSplitIndex = EvalShadow_GetSplitIndex( shadowContext, index, positionWS, payloadOffset, alpha, cascadeCount );
if( shadowSplitIndex < 0 )
return 0.0;

9
ScriptableRenderPipeline/Core/CoreRP/Shadow/DebugDisplayShadowMap.shader


float4 _TextureScaleBias;
float _TextureSlice;
float2 _ValidRange;
float _RequireToFlipInputTexture;
SamplerState ltc_linear_clamp_sampler;
TEXTURE2D_ARRAY(_AtlasTexture);

{
Varyings output;
output.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID);
output.texcoord = GetFullScreenTriangleTexCoord(input.vertexID) * _TextureScaleBias.xy + _TextureScaleBias.zw;
output.texcoord = GetFullScreenTriangleTexCoord(input.vertexID);
if (_RequireToFlipInputTexture > 0.0f)
{
output.texcoord.y = 1.0f - output.texcoord.y;
}
output.texcoord = output.texcoord *_TextureScaleBias.xy + _TextureScaleBias.zw;
return output;
}
ENDHLSL

19
ScriptableRenderPipeline/Core/CoreRP/Shadow/Shadow.cs


sp.Set( (m_TmpSplits[second] - m_TmpSplits[first]).normalized );
else
sp.Set( 0.0f, 0.0f, 0.0f, 0.0f );
sp.p3 = (int) sr.facecount;
payload[payloadOffset] = sp;
payloadOffset++;

// shadow atlas layouting
CachedEntry ce = m_EntryCache[i];
Rect vp = ce.current.viewport;
curh = curh >= vp.height ? curh : vp.height;
curh = vp.height;
}
if( curx + vp.width > xmax || cury + curh > ymax )
{

curh = vp.height;
}
if( curx + vp.width > xmax || cury + curh > ymax || curslice == m_Slices )
{

ce.current.slice = curslice;
m_EntryCache[i] = ce;
curx += vp.width;
curh = curh >= vp.height ? curh : vp.height;
}
return true;
}

m_EntryPool.Add( ce );
}
override public void DisplayShadowMap(CommandBuffer debugCB, Material debugMaterial, Vector4 scaleBias, uint slice, float screenX, float screenY, float screenSizeX, float screenSizeY, float minValue, float maxValue)
override public void DisplayShadowMap(CommandBuffer debugCB, Material debugMaterial, Vector4 scaleBias, uint slice, float screenX, float screenY, float screenSizeX, float screenSizeY, float minValue, float maxValue, bool flipY)
{
Vector4 validRange = new Vector4(minValue, 1.0f / (maxValue - minValue));

propertyBlock.SetFloat("_TextureSlice", (float)slice);
propertyBlock.SetVector("_ValidRange", validRange);
propertyBlock.SetFloat("_RequireToFlipInputTexture", flipY ? 1.0f : 0.0f);
debugCB.SetViewport(new Rect(screenX, screenY, screenSizeX, screenSizeY));
debugCB.DrawProcedural(Matrix4x4.identity, debugMaterial, debugMaterial.FindPass("REGULARSHADOW"), MeshTopology.Triangles, 3, 1, propertyBlock);
}

cb.EndSample("VSM conversion");
}
override public void DisplayShadowMap(CommandBuffer debugCB, Material debugMaterial, Vector4 scaleBias, uint slice, float screenX, float screenY, float screenSizeX, float screenSizeY, float minValue, float maxValue)
override public void DisplayShadowMap(CommandBuffer debugCB, Material debugMaterial, Vector4 scaleBias, uint slice, float screenX, float screenY, float screenSizeX, float screenSizeY, float minValue, float maxValue, bool flipY)
{
Vector4 validRange = new Vector4(minValue, 1.0f / (maxValue - minValue));

propertyBlock.SetFloat("_TextureSlice", (float)slice);
propertyBlock.SetVector("_ValidRange", validRange);
propertyBlock.SetFloat("_RequireToFlipInputTexture", flipY ? 1.0f : 0.0f);
debugCB.SetViewport(new Rect(screenX, screenY, screenSizeX, screenSizeY));
debugCB.DrawProcedural(Matrix4x4.identity, debugMaterial, debugMaterial.FindPass("VARIANCESHADOW"), MeshTopology.Triangles, 3, 1, propertyBlock);
}

}
}
public override void DisplayShadow(CommandBuffer cmd, Material debugMaterial, int shadowRequestIndex, uint faceIndex, float screenX, float screenY, float screenSizeX, float screenSizeY, float minValue, float maxValue)
public override void DisplayShadow(CommandBuffer cmd, Material debugMaterial, int shadowRequestIndex, uint faceIndex, float screenX, float screenY, float screenSizeX, float screenSizeY, float minValue, float maxValue, bool flipY)
{
if (m_ShadowIndices.Count() == 0)
return;

ShadowData faceData = shadowDatas[(uint)(m_ShadowIndices[index] + offset + faceIndex)];
uint texID, samplerID;
faceData.UnpackShadowmapId(out texID, out samplerID);
m_Shadowmaps[texID].DisplayShadowMap(cmd, debugMaterial, faceData.scaleOffset, (uint) faceData.slice, screenX, screenY, screenSizeX, screenSizeY, minValue, maxValue);
m_Shadowmaps[texID].DisplayShadowMap(cmd, debugMaterial, faceData.scaleOffset, (uint) faceData.slice, screenX, screenY, screenSizeX, screenSizeY, minValue, maxValue, flipY);
public override void DisplayShadowMap(CommandBuffer cmd, Material debugMaterial, uint shadowMapIndex, uint sliceIndex, float screenX, float screenY, float screenSizeX, float screenSizeY, float minValue, float maxValue)
public override void DisplayShadowMap(CommandBuffer cmd, Material debugMaterial, uint shadowMapIndex, uint sliceIndex, float screenX, float screenY, float screenSizeX, float screenSizeY, float minValue, float maxValue, bool flipY)
m_Shadowmaps[index].DisplayShadowMap(cmd, debugMaterial, new Vector4(1.0f, 1.0f, 0.0f, 0.0f), sliceIndex, screenX, screenY, screenSizeX, screenSizeY, minValue, maxValue);
m_Shadowmaps[index].DisplayShadowMap(cmd, debugMaterial, new Vector4(1.0f, 1.0f, 0.0f, 0.0f), sliceIndex, screenX, screenY, screenSizeX, screenSizeY, minValue, maxValue, flipY);
}
public override void SyncData()

19
ScriptableRenderPipeline/Core/CoreRP/Shadow/ShadowBase.cs


m_HeightRcp = 1.0f / initializer.height;
m_MaxPayloadCount = initializer.maxPayloadCount;
m_ShadowSupport = initializer.shadowSupport;
if( IsNativeDepth() && m_Slices > 1 )
{
// TODO: Right now when using any of the SetRendertarget functions we ultimately end up in RenderTextureD3D11.cpp
// SetRenderTargetD3D11Internal. This function sets the correct slice only for RTVs, whereas depth textures only
// support one DSV. So there's currently no way to have individual DSVs per slice to render into (ignoring going through a geometry shader and selecting the slice there).
Debug.LogError( "Unity does not allow direct rendering into specific depth slices, yet. Defaulting back to one array slice." );
m_Slices = 1;
}
}
protected bool IsNativeDepth()

abstract public void Fill( ShadowContextStorage cs );
abstract public void CreateShadowmap();
abstract protected void Register( GPUShadowType type, ShadowRegistry registry );
abstract public void DisplayShadowMap(CommandBuffer cmd, Material debugMaterial, Vector4 scaleBias, uint slice, float screenX, float screenY, float screenSizeX, float screenSizeY, float minValue, float maxValue);
abstract public void DisplayShadowMap(CommandBuffer cmd, Material debugMaterial, Vector4 scaleBias, uint slice, float screenX, float screenY, float screenSizeX, float screenSizeY, float minValue, float maxValue, bool flipY);
}
public interface IShadowManager

// Renders all shadows for lights the were deemed shadow casters after the last call to ProcessShadowRequests
void RenderShadows( FrameId frameId, ScriptableRenderContext renderContext, CommandBuffer cmd, CullResults cullResults, List<VisibleLight> lights);
// Debug function to display a shadow at the screen coordinate
void DisplayShadow(CommandBuffer cmd, Material debugMaterial, int shadowIndex, uint faceIndex, float screenX, float screenY, float screenSizeX, float screenSizeY, float minValue, float maxValue);
void DisplayShadowMap(CommandBuffer cmd, Material debugMaterial, uint shadowMapIndex, uint sliceIndex, float screenX, float screenY, float screenSizeX, float screenSizeY, float minValue, float maxValue);
void DisplayShadow(CommandBuffer cmd, Material debugMaterial, int shadowIndex, uint faceIndex, float screenX, float screenY, float screenSizeX, float screenSizeY, float minValue, float maxValue, bool flipY);
void DisplayShadowMap(CommandBuffer cmd, Material debugMaterial, uint shadowMapIndex, uint sliceIndex, float screenX, float screenY, float screenSizeX, float screenSizeY, float minValue, float maxValue, bool flipY);
// Synchronize data with GPU buffers
void SyncData();
// Binds resources to shader stages just before rendering the lighting pass

{
public abstract void ProcessShadowRequests( FrameId frameId, CullResults cullResults, Camera camera, bool cameraRelativeRendering, List<VisibleLight> lights, ref uint shadowRequestsCount, int[] shadowRequests, out int[] shadowDataIndices );
public abstract void RenderShadows( FrameId frameId, ScriptableRenderContext renderContext, CommandBuffer cmd, CullResults cullResults, List<VisibleLight> lights);
public abstract void DisplayShadow(CommandBuffer cmd, Material debugMaterial, int shadowIndex, uint faceIndex, float screenX, float screenY, float screenSizeX, float screenSizeY, float minValue, float maxValue);
public abstract void DisplayShadowMap(CommandBuffer cmd, Material debugMaterial, uint shadowMapIndex, uint sliceIndex, float screenX, float screenY, float screenSizeX, float screenSizeY, float minValue, float maxValue);
public abstract void DisplayShadow(CommandBuffer cmd, Material debugMaterial, int shadowIndex, uint faceIndex, float screenX, float screenY, float screenSizeX, float screenSizeY, float minValue, float maxValue, bool flipY);
public abstract void DisplayShadowMap(CommandBuffer cmd, Material debugMaterial, uint shadowMapIndex, uint sliceIndex, float screenX, float screenY, float screenSizeX, float screenSizeY, float minValue, float maxValue, bool flipY);
public abstract void SyncData();
public abstract void BindResources( CommandBuffer cmd, ComputeShader computeShader, int computeKernel);
public abstract void UpdateCullingParameters( ref ScriptableCullingParameters cullingParams );

870
ScriptableRenderPipeline/HDRenderPipeline/Documentation/HDRenderPipeline.md


# High Definition Render Pipeline
![](https://blogs.unity3d.com/wp-content/uploads/2018/01/image2.jpg)
The High Definition Render Pipeline (HDRP) is a high-fidelity Scriptable Render Pipeline built by Unity to target modern (Compute Shader compatible) platforms.

* Modern consoles (Sony PS4 and Microsoft Xbox One)
__HDRP does not support OpenGL or OpenGL ES devices.__
# Getting Started with High Definition Render Pipeline
This page details the initial setup of a project using the High Definition Render Pipeline (HDRP) and notes on upgrading existing projects to HDRP.
## Setting up a new Project
### Using Unity Hub
To set up a new HDRP project using Unity Hub, click the New button, then select High Definition - Preview from the Template drop-down box. After clicking Create Project, Unity will automatically create a Project with the High Definition Render Pipeline package installed.
![](Images/GettingStarted1.png)
## Upgrading an Existing Project
To upgrade an existing Project, you must first download the High Definition Render Pipeline using the Package Manager UI.
Navigate to **Window > Package Manager** to open the Package Manager UI. Then click the All button to open the packages list.
Left click on Render-pipelines.high-definition to select it, then click the Install button to add HDRP to your project.
![](Images/GettingStarted2.png)
After you have installed HDRP from the Package Manager UI you must add the HDRP Asset to the Scriptable Render Pipeline Graphics settings field.
Navigate to Edit > Settings > Graphics Settings, then Assign the HDRP Asset to the Scriptable Render Pipeline field by dragging in the HDRP Asset, or using the radio button to select the Asset from the popup window.
## Building from source code
The latest version of the Scriptable Render Pipeline (SRP) repo can be found at the following link: https://github.com/Unity-Technologies/ScriptableRenderPipeline
### Github Desktop or Git command line tools
#### Cloning the repo using the GitHub Desktop App:
Open the GitHub Desktop App and click Clone a Repository.
Click the URL tab in the Clone a Repository window
Enter the following URL: https://github.com/Unity-Technologies/ScriptableRenderPipeline
Click the Choose… button to navigate to your project’s Asset folder.
Click the Clone button.
After the repo has been cloned you must run the following console commands from the ScriptableRenderPipeline folder:
`git checkout Unity-2018.1.0b2 (or the latest tag)`
`git submodule update --init --recursive --remote`
#### Cloning the repo using Git console commands:
Enter the following commands in your console application of choice:
`cd <Path to your Unity project>/Assets`
`git clone https://github.com/Unity-Technologies/ScriptableRenderPipeline`
`cd ScriptableRenderPipeline`
`git checkout Unity-2018.1.0b2 (or the latest tag)`
`git submodule update --init --recursive --remote`
Once you have cloned the repo, re-open your project and follow the below instructions:
Navigate to **Edit > Project Settings > Graphics** and add the HDRenderPipelineAsset Asset to the Render Pipeline Settings field.
Create a copy of the HDRenderPipelineAsset and store it outside of the Scriptable Render Pipeline folder. This ensures that your HDRP settings are not lost when merging new changes from the SRP repo.
HDRP will be ready to use in your project after following the above instructions.
## Upgrading Shaders
The built-in Unity shaders are incompatible with Scriptable Render Pipelines, as such, any preexisting Shaders in your project must be updated to work with the HDRP.
Navigate to **Edit > Render Pipelines > Upgrade Project Materials to High Definition Materials** to run the automatic upgrade script. This script with automatically update all preexisting shaders in your project to the new HDRP shaders.
# The HD Render Pipeline Lit Shader
The lit shader is the default shader when using HDRenderPipeline (HDRP). This shader can be set with subsurface scattering, iridescence, vertex or pixel displacement and many other new parameters. This shader allows to users to produce more realistic assets with the use of HDRP. A version call LitTessellation is used to activate the tessellation.
## Creating a Lit Shader
In HDRP, when a new material is created it is by default a lit shader.
![](/Images/LitShader1.png)
![](Images/LitShader2.png)
## How to set a Lit Shader?
### Surface options
__Surface type:__
![](/Images/LitShader3.png)
Surface can be set as Opaque or Transparent. Transparent is an alpha blend and it is more costly.
__Alpha Cutoff:__
![](Images/LitShader4.png)
This check box enable the alpha cutoff to use an alpha test. The handle set the value of the test. All the values under the handle value is totally transparent and the values equal or above the handle value is opaque.
__Double sided:__
![](Images/LitShader5.png)
This option allows the double side. The faces are rendered on the two sides. The normal mode manages the normal behaviour on the backfaces. By default the mode is mirror.
__Material type:__
Material type introduces new behaviour for shaders to create realistic assets.
* Standard: Common use with basic parameters. The standard type uses a metallic workflow.
* Subsurface scattering (SSS): Mainly use to do a skin shader. This material type simulates the light transport inside a material and create softer micro shadows.
Also a new parameter appears: Enable transmission. This parameter simulate the translucency of an object and it is managed by a thickness map.
SSS and transmission are setting by a diffusion profile explain later in this document.
* Anisotropy: The anisotropy determines the shape of the highlight. The surface vector is managed by a tangent map, an anisotropy map modulate the anisotropy intensity and a handle modulate and orient to horizontally or vertical the anisotropic effect. These parameters are more explain later in the documentation.
* Iridescence: Use to create an iridescent effect. The effect is modulate by an iridescence mask, iridescence thickness map and an handle iridescence thickness.
* Specular Color: Instead of standard type, the specular color type uses a specular workflow. In this way the specular can be colorize even for a not metallic matter.
* Translucent: This type is used to simulate only the transmission. It can be handy for vegetation and more light than a SSS type.This type use a profile like the SSS type to manage the transmission.
__Enable Decal:__
Allow the material to receive decals.
__Enable MotionVector For Vertex Animation:__
Use it to remove ghosting coming from vertex animation.
__Displacement mode:__
* None: no change.
* Vertex displacement: Use a height map to displace the vertices.
* Pixel displacement: Use a height map to displace the pixels. Use it only on plane surface. The surface can be only digged.
## Vertex animation / Enable wind
Prototype feature, don’t use it.
## Inputs
__Base color + opacity__: RGB channels are used as base color and alpha channel is used for opacity.
__Smoothness__ handle: This handle modulate (0 to 1) the smoothness value coming from the Mask map alpha channel.
__Mask map:__
* Red channel: Metallic mask. 0 = not metallic, 1 = metallic.
* Green channel: Ambient occlusion.
* Blue channel: Detail map mask.
* Alpha channel: Smoothness.
__Normal map space:__
By default the normal map space is in tangent space. The normal map space can be set to object space.
__Normal map:__
Use to assign the normal map. The handle modulate the normal intensity between 0 and 2.
__Bent normal map:__
The bent normal is used to have a better ambient occlusion. It works only with diffuse lighting like lightmap or light probe.
__Coat Mask:__
By default the value is 0. The mask is used to modulate the clear coat effect base on the handle value (0 to 1).
__Base UV mapping:__
UV can be set to UV0, UV1 (used by the lightmap), UV2, UV3, planar or triplanar.
Planar and triplanar use a world scale. This ratio depends about the size of the textures and the texel ratio wanted. By default it is 1, that means the material is applied on 1 meter. A value of 0.5 applies the material on 2 meters.
__Tiling:__
Set the X/Y values to tile the material.
__Offset:__
Set on X/Y offset for the UV.
## Detail inputs
The detail map is a composited map used to add micro details into the material. The detail map visibility is managed by the blue channel of the Mask map.
![](Images/LitShader6.png)
__Detail map:__
* Red channel: Grey scale used as albedo.
* Green channel: Green channel of the detail normal map.
* Blue channel: Detail smoothness.
* Alpha channel: Red channel of the detail normal map.
Channels are organised like this due the different compressions quality of each channels.
__Detail UV mapping:__
UV0, UV1, UV2 or UV3 can be set. If the material UV are set to planar or triplanar, the detail UV are also set to planar or triplanar.
__Lock to base Tiling/Offset:__
By default a detail texture is linked to the material aspect because it is done to add a micro detail in it. If for any reason the link have to be removed, just uncheck this checkbox.
__Tiling:__
Set the tiling of the detail texture inside a tile of the material.
For example if the material is tiled by 2 on a plane and the detail texture is also tile by 2, the detail will appears tile by 4 on the plane.
In this condition the tile of the material can be changed without set another time the detail UV to keep the good appearance.
__Offset:__
Set on X/Y offset for the detail UV.
__Detail AlbedoScale:__
This handle modulate (0 to 2) the detail albedo (red channel) like an overlay effect. The default value is 1 and has no scale.
__Detail NormalScale:__
This handle modulate (0 to 2) the intensity of the detail normal map. The default value is 1 and has no scale.
__Detail SmoothnessScale:__
This handle modulate (0 to 2) the detail smoothness (blue channel) like an overlay effect. The default value is 1 and has no scale.
## Emissive inputs
__Emissive color:__
The emissive color can be managed by a map or a single color. If both are used they are multiplied.
__Emissive intensity:__
Set the power of the emissive effect. By default the value is 0 and doesn’t produce any emissive effect.
__Albedo Affect Emissive:__
By default it is on and allows the albedo to produce color for the emissive. In this case the albedo is multiplied by emissive color and color picker to produce the emissive final color.
For example the emissive color map can be used as an emissive mask, the albedo used to do the color and the color picker to modulate it.
## Advanced options:
__Enable GPU instancing:__
If objects are not static batched and identical, all objects with this material become instanced.
For example, objects with an animation base on the object pivot can’t be static batched (unique pivot for all) but they can be instanced by GPU.
__Enable Specular Occlusion from Bent normal:__
This option used the bent normal assign in the bent normal slot to do a specular occlusion for the reflection probe.
## Specific setting from material type
### Subsurface scattering
![](Images/LitShader7.png)
__Enable transmission: __
On/off the transmission effect. The transmission is managed by a profile and a thickness map. More the object is set thin more lighting cross it.
__Specific subsurface settings:__
![](Images/LitShader8.png)
Diffusion profile:
Rollout menu to choose the profile. Profiles are set in the SSSSettings.asset file. Goto button select the the SSSSettings file.
Subsurface mask map:
This map uses the red channel to manage the visibility (0 = not visible, 1= totally visible) of the SSS effect. This map is modulated by the handle value (0 to 1, 1 is the default).
Thickness map:
This map uses the red channel to set the thickness inside the range set in the profile. 0 is the min range value and 1 is the max range value.
__The profile:__
![](Images/LitShader9.png)
* Name: Name of the profile
* Scattering value: It is a HDR value to manage the color and the scatter of the SSS.
* Max radius: It is an information value and linked to the scattering value. It is the effective radius in millimeters. The blur is energy-preserving, so a wide result in a large area provides a small contribution of individual samples. A short distance increases the sharpness of the result.
* Index of Refraction: To set the real index of refraction. It is 1.4 for skin and between 1.3 and 1.5 for most other material.
* World scale: Set the size of the world unit in meters. Default it is 1 and shouldn’t be modified except if the world unit used is customized.
__Subsurface scattering only:__
Texturing mode: Specifies when the diffuse texture should be applied.
__Transmission only:__
Transmission mode: Regular or Thin object. Really thin object need a specific use.
Transmission tint: Set a HDR value to color the transmission.
Min/Max thickness (mm): Set the range of the thickness. This range is modulate by the thickness map (0 = min, 1 = max).
Thickness remap: This setting allows to remap the thickness without to change the min/max values. The range can be moved without losing the thickness values.
Profile preview: Shows the fraction of lights scattered from the source located in the center.The distance to the boundary of the image corresponds to the max radius. Display is not HDR, so the intensity of pixels around the center may be clipped.
![](Images/LitShader10.png)
Transmission preview: Shows the fraction of light passing through the object for thickness values from the remap. Can be viewed as a cross section of a slab of material illuminated by white light from the left.
![](Images/LitShader11.png)
### Anisotropy
Anisotropic materials don’t have an uniform specular shape.
Real anisotropy example:
![](Images/LitShader12.png)
Anisotropy is used to deform the specular shape on an axe.
![](Images/LitShader13.png)
__Tangent map: __
It is a vector map. Red and Green channel orient the specular shape.
__Anisotropy:__
This handle modulate the intensity of the anisotropic effect and modify the shape orientation, horizontally or vertically, coming from the tangent map.
![](Images/LitShader14.png)
__Anisotropy map:__
This map uses the red channel to modulate the anisotropic effect intensity.
### Iridescence
The iridescence (Thin-film interference) is a natural phenomenon in which lightwaves reflected by the upper and lower boundaries of a thin film interfere with one another, either enhancing or reducing the reflected[ ](https://en.wikipedia.org/wiki/Reflected_light)light.
![](Images/LitShader15.png)
![](Images/LitShader16.png)
__Iridescence Mask:__
This map uses the red channel to manage the visibility of the iridescence effect. The handle can modulate the mask or the visibility if no mask is assigned.
__Iridescence Layer thickness map:__
If no map is assigned, by default the value is 1. The iridescence gradient color is linked to the thickness. When the thickness change the gradient color change too. The handle modulate the thickness also and it is multiplied when a map is assigned.
![](Images/LitShader17.png)
FYI: If the base color is white no iridescence can be visible. For a white base color no lighting enter the matter. All the lighting is reflected to produce a pure white color, so no iridescence can be produce.
### Specular color
When the specular color shader type is chosen, the specular color is defined by a dedicated map not anymore by the albedo value.
![](Images/LitShader18.png)
__Specular color:__
RGB map to set the specular color. When no map is assigned the default value is 1.
__Picker color:__
Uniform color used for the specular. It is multiply by the Specular color map.
## Translucent
The translucency is the transmission of a part of light across the matter.
![](Images/LitShader19.png)
![](Images/LitShader20.png)
The translucency is manage by a profile and a thickness map like for the subsurface scattering.
## How to set a Lit Shader Tessellation?
From a lit shader, use the shader rollout menu to choose the LayeredLitTessellation shader.
![](Images/LitShader21.png)
In case of lit shader tessellation only standard, subsurface scattering and translucent types are available.
__Displacement mode:__
![](Images/LitShader22.png)
None: No displacement is applied. The tessellation is used only to smooth the surface.
Tessellation displacement: A height map (red channel) is used in the inputs to displace the mesh vertices.
![](Images/LitShader23.png)
![](Images/LitShader24.png)
* Lock with object scale: the height map appearance doesn’t change when the object is scaled.
* Lock with height map tiling rate: the height map appearance doesn’t change when the material is tiled.
__Tessellations options:__
![](Images/LitShader25.png)
Tessellation mode:
* None: no smooth is aplied.
* Phong: the tessellation applied a smooth effect.
Tessellation factor:
Between 0 and 64 this factor modulate the tessellation quantity. Higher value mean a surface more tessellated. Above 15 is costly. For XBox one and Playstation4 the maximum is set to 15.
Start fade distance:
It is the distance (in Unity unit) to the camera where the tessellation start to fade out.
End fade distance:
It is the maximum distance (in Unity unit) to the camera where triangle are tessellated.
Triangle size:
Desired screen space size of triangle (in pixel). A smaller value mean smaller triangle.
__Height map parameterization:__
Two parametrizations are available.
Min/Max:
![](Images/LitShader26.png)
In this mode the base of the height map is linked to the base of the mesh. It is used if the height map has uniform values on the map.
Min: Set the height value for the 0 value on the map.
Max: Set the height value for the 1 (255) value on the map.
Offset: Can up and down the height map without modify the min/max values.
Amplitude:
![](Images/LitShader27.png)
Amplitude mode is more used in case of height map with a dedicated center. In this case the height map uses often none uniform values. In case of non uniform values a range of the map is not used to store values, it is clamped in positive or negative.
Amplitude: The amplitude is the double value of the maximum value in negative or in positive.
Base: It is the reference of the base mesh into the height map. By default the base is at 0.5.
Offset: Can up and down the height map without modify the other values.
# Sky and Fog
In HDRP, sky and fog are setup via the interpolation volume framework. The goal is for the user to be able to dynamically change the look of the sky and fog depending on the camera position.
We also provide the necessary tools to offer consistent baking of lightmaps and probes.
The Sky Framework used by HDRP is also designed in a way that it is easy for users to write their own custom sky and use it in their project with minimal effort.
As part of the Volume framework, all local settings components described below are actually VolumeComponents which need to be added to a VolumeComponent on a regular GameObject. As such, all their parameters can be interpolated between different volumes.
## Setting up the Sky
Setting up a sky has two goals: The first one is to define what will be displayed in the background of the scene for a given camera. The second one is to define environment lighting, namely sky reflection and sky ambient probe which is then later used to render lightmaps (real-time or baked).
Settings are split between global settings which are per project/platform and local settings that use the volume framework and can change depending on the scene or camera position.
### Global Sky Settings
Global settings for the sky are in the HDRenderPipeline configuration asset:
![](Images/SkyAndFog1.png)
__Sky Reflection Size__
This parameter drives the size of the cubemap generated from the sky and used for fallback reflection when no local reflection probes are present. It has no effect on the quality of the sky rendered in the background.
__Sky Lighting Override Mask__
In some cases, users may want to dissociate lighting environment from what is rendered in the background (a typical example is to have a very dark sky at night but have a brighter lighting so that the player can still see).
In order to achieve this, users can define the sky lighting override mask which is a Layer mask. If any volumes are present in this layer then environment lighting will use these volumes instead of those from the main camera. If this mask is set to **Nothing**or if there are no volume in this mask then lighting will come from volumes setup in the main camera volume layer mask.
In practice this means that user can define two sets of masks, one for the visual sky and the other for the lighting. Both sets of volume will then be interpolated independently from each other.
Note that lighting override does not affect baked lighting.
### Local Sky Settings
Once global parameters are set, users need to setup volumes with the correct components to setup local parameters for the sky. Currently HDRP provides two different kind of skies.
__Procedural Sky__
This sky is similar to the procedural sky provided with the built-in Unity Render Pipelines.
![](Images/SkyAndFog2.png)
| Property| Function |
|:---|:---|
| __Enable Sun Disk__| Display sun disk |
| __Sun Size__| Size of the sun disk |
| __Sun Size Convergence__| |
| __Atmospheric Thickness__| |
| __Sky Tint__| Color of the sky hemisphere |
| __Ground Color__| Color of the ground hemisphere |
| __Exposure__| Exposure applied to the sky |
| __Multiplier__| Multiplier applied to the sky |
| __Update Mode__| Rate at which the sky environment (reflection en ambient probe) should be updated |
| On Changed| Sky environment is updated when one of its parameter changes |
| On Demand| Sky Environment is explicitly updated by the script |
| Realtime| Sky environment is updated regularly |
| Update Period| Period (in seconds) at which the realtime sky is updated (0 means every frame) |
__HDRI Sky__
Simple sky represented by a cubemap texture.
![](Images/SkyAndFog3.png)
| Property| Function |
|:---|:---|
| __Hdri sky__| Cubemap representing the sky |
| __Exposure__| Exposure applied to the sky |
| __Multiplier__| Multiplier applied to the sky |
| __Rotation__| Rotation applied to the cubemap in degrees |
| __Update Mode__| Rate at which the sky environment (reflection en ambient probe) should be updated |
| On Changed| Sky environment is updated when one of its parameter changes |
| On Demand| Sky Environment is explicitly updated by the script |
| Realtime| Sky environment is updated regularly |
| Update Period| Period (in seconds) at which the realtime sky is updated (0 means every frame) |
### Baking Global Illumination with the sky
In HDRP the sky is completely controlled by the volume system. It means that in the editor, the current state of the sky will depend on the camera position. The consequence is that for users to get a consistent lighting baking, we can’t rely on what is in the scene.
Instead the sky used for baking is set explicitly by the user through the Baking Sky component.
![](Images/SkyAndFog4.png)
User should select a volume profile which contains the sky intended to be used for baking and then choose the right type (in case the profile contains different kinds of skies). If the component is added to a game object that already has a Volume, the profile property will be automatically populated with the corresponding profile asset.
This sky setting will live outside of the volume framework and thus will never be interpolated based on the camera position. Any time the baking is required, this is the sky that will be used.
Only one such component can be present in the editor at any given time. Any additional component of the same type will generate a warning and be ignored.
## Setting up the Fog
Fog is the effect of overlaying a color onto objects dependant on the distance from the camera. This is used to simulate fog or mist in outdoor environments and is also typically used to hide clipping of objects when a camera’s far clip plane has been moved forward for performance.
In HDRP, users can choose between two different kind of fogs, linear and exponential fog. All types of materials (lit or unlit) will react correctly to the fog. Depending on the type of fog, density will evolve differently with respect to distance from camera and world space height.
Instead of using a constant color, both types of fog can choose to use the background sky as a source for color. In this case, the color will be sampled from different mip maps of the cubemap generated from the current sky settings. Chosen mip will vary linearly between the blurriest one to the highest resolution one depending on the distance from camera and the "Mip Fog" parameters. Users can also choose to limit the resolution of the higher mip used.
For both types of fog, density is computed from camera distance and world space height independently and then multiplied together to obtain the final result.
__Linear Fog__
Density will increase linearly with view distance and world space height depending on the provided parameters.
![](Images/SkyAndFog5.png)
| Property| Function |
|:---|:---|
| __Density__| Global multiplier for the fog density |
| __Color Mode__| Source of the fog color |
| Constant Color| Fog is a constant color |
| Color| Color of the fog |
| Sky Color| Fog color is sampled from the sky |
| Mip Fog Near| Distance at which the blurriest sky mip is used |
| Mip Fog Far| Distance at which the higher sky mip (see "Mip Fog Max Mip" ) is used |
| Mip Fog Max Mip| Maximum mip map used to sample the color (1.0 being highest resolution and 0.0 lowest resolution). |
| __Fog Start__| Distance from camera at which fog density starts to increase from zero. |
| __Fog End__| Distance from camera at which fog density is maximum. |
| __Fog Height Start__| Height at which fog density starts to decrease |
| __Fog Height End__| Height at which fog density is zero |
__Exponential Fog__
Density will increase exponentially with view distance and world space height depending on the provided parameters.
![](Images/SkyAndFog6.png)
| Property| Function |
|:---|:---|
| __Density__| Global multiplier for the fog density |
| __Color Mode__| Source of the fog color |
| Constant Color| Fog is a constant color |
| Color| Color of the fog |
| Sky Color| Fog color is sampled from the sky |
| Mip Fog Near| Distance at which the blurriest sky mip is used |
| Mip Fog Far| Distance at which the higher sky mip (see "Mip Fog Max Mip" ) is used |
| Mip Fog Max Mip| Maximum mip map used to sample the color (1.0 being highest resolution and 0.0 lowest resolution). |
| __Fog Distance__| Distance from camera at will reach maximum |
| __Fog Base Height__| World space height at which fog density starts to decrease from 1.0 |
| __Fog Height Attenuation__| Fall off of height fog attenuation (bigger values will make attenuation sharper) |
## Visual Environment
Once the proper components have been setup, users need to specify what kind of sky and fog should be used for rendering. This is done through the Visual Environment component.
![](Images/SkyAndFog7.png)
| Property| Function |
|:---|:---|
| __Sky Type__| Type of sky used for rendering. This list will be automatically updated with any custom sky written by users |
| __Fog Type__| Type of fog used for rendering |
To help setting things up more easily, users can use the contextual menu to directly create a game object named "Scene Settings" and go from there. This game object is already setup with a default procedural sky and exponential fog inside a global Volume (it also contains default shadow settings).
![](Images/SkyAndFog8.png)
## Writing Custom Sky Renderers
The sky system is setup in a way that allows users to develop their own kind of sky with their own parameters and shaders.
Three things are needed in order to write your own sky.
__SkySettings__
Create a new class that inherits from *SkySettings*. This class will contain all parameters specific to the particular sky renderer user is writing. Please refer to the Volume system documentation to learn how to declare volume parameters.
Three things are mandatory to write:
* SkyUniqueID attribute: This must be an integer unique to this particular sky. Must not clash with any other sky settings. The SkyType enum is available for users to see what values are already used by HDRP.
* GetHashCode: This is used by the sky system to determine when to re-render the sky reflection cubemap.
* CreateRenderer: This is used by the sky system to instantiate the proper renderer.
Exemple: HDRI Sky
```
[SkyUniqueID(87248]<br/> public class HDRISky : SkySettings
{
[Tooltip("Cubemap used to render the sky.")]
public CubemapParameter hdriSky = new CubemapParameter(null);
public override SkyRenderer CreateRenderer()
{
return new HDRISkyRenderer(this);
}
public override int GetHashCode()
{
int hash = base.GetHashCode();
unchecked
{
hash = hdriSky.value != null ? hash * 23 + hdriSky.GetHashCode() : hash;
}
return hash;
}
}
```
__SkyRenderer__
This is the class that will actually render the sky, either into a cubemap for lighting or on the background. This is where users must implement all their specific rendering.
It must implement this interface:
```
public abstract class SkyRenderer
{
// Method used to initialize any resource for the sky rendering (shaders, …)
public abstract void Build();
// Method used to clean up any resource previously allocated
public abstract void Cleanup();
// SkyRenderer is responsible for setting up render targets provided in builtinParams
public abstract void SetRenderTargets(BuiltinSkyParameters builtinParams);
// renderForCubemap: When rendering into a cube map, no depth buffer is available so user has to make sure not to use depth testing or the depth texture.
public abstract void RenderSky(BuiltinSkyParameters builtinParams, bool renderForCubemap);
// Returns true if provided sky setting parameters are valid.
public abstract bool IsValid();
}
```
Exemple: HDRISkyRenderer:
```
public class HDRISkyRenderer : SkyRenderer<br/>{
Material m_SkyHDRIMaterial; // Renders a cubemap into a render texture (can be cube or 2D)
MaterialPropertyBlock m_PropertyBlock;
HDRISky m_HdriSkyParams;
public HDRISkyRenderer(HDRISky hdriSkyParams)
{
m_HdriSkyParams = hdriSkyParams;
m_PropertyBlock = new MaterialPropertyBlock();
}
public override void Build()
{
var hdrp = GraphicsSettings.renderPipelineAsset as HDRenderPipelineAsset;
m_SkyHDRIMaterial = CoreUtils.CreateEngineMaterial(hdrp.renderPipelineResources.hdriSky);
}
public override void Cleanup()
{
CoreUtils.Destroy(m_SkyHDRIMaterial);
}
public override void SetRenderTargets(BuiltinSkyParameters builtinParams)
{
if (builtinParams.depthBuffer == BuiltinSkyParameters.nullRT)
{
HDUtils.SetRenderTarget(builtinParams.commandBuffer, builtinParams.hdCamera, builtinParams.colorBuffer);
}
else
{
HDUtils.SetRenderTarget(builtinParams.commandBuffer, builtinParams.hdCamera, builtinParams.colorBuffer, builtinParams.depthBuffer);
}
}
public override void RenderSky(BuiltinSkyParameters builtinParams, bool renderForCubemap)
{
m_PropertyBlock.SetTexture(HDShaderIDs._Cubemap, m_HdriSkyParams.hdriSky);
m_PropertyBlock.SetVector(HDShaderIDs._SkyParam, new Vector4(m_HdriSkyParams.exposure, m_HdriSkyParams.multiplier, -m_HdriSkyParams.rotation, 0.0f)); // -rotation to match Legacy...
// This matrix needs to be updated at the draw call frequency.
m_PropertyBlock.SetMatrix(HDShaderIDs._PixelCoordToViewDirWS, builtinParams.pixelCoordToViewDirMatrix);
CoreUtils.DrawFullScreen(builtinParams.commandBuffer, m_SkyHDRIMaterial, m_PropertyBlock, renderForCubemap ? 0 : 1);
}
public override bool IsValid()
{
return m_HdriSkyParams != null && m_SkyHDRIMaterial != null;
}
}
```
__Rendering Shader__
This is highly dependent on what the particular sky is supposed to look like. Here we’ll just show the example of HDRISky.
Note that we implemented two passes, one that uses Depth Test for rendering the sky in the background (so that it’s occluded by geometry) and the other that does not for when the sky is rendered into the reflection cubemap.
```
Shader "Hidden/HDRenderPipeline/Sky/HDRISky"<br/>{
HLSLINCLUDE
#pragma vertex Vert
#pragma fragment Frag
#pragma target 4.5
#pragma only_renderers d3d11 ps4 xboxone vulkan metal
#include "CoreRP/ShaderLibrary/Common.hlsl"
#include "CoreRP/ShaderLibrary/Color.hlsl"
#include "CoreRP/ShaderLibrary/CommonLighting.hlsl"
TEXTURECUBE(_Cubemap);
SAMPLER(sampler_Cubemap);
float4 _SkyParam; // x exposure, y multiplier, z rotation
float4x4 _PixelCoordToViewDirWS; // Actually just 3x3, but Unity can only set 4x4
struct Attributes
{
uint vertexID : SV_VertexID;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
};
Varyings Vert(Attributes input)
{
Varyings output;
output.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID, UNITY_RAW_FAR_CLIP_VALUE);
return output;
}
float4 Frag(Varyings input) : SV_Target
{
// Points towards the camera
float3 viewDirWS = normalize(mul(float3(input.positionCS.xy, 1.0), (float3x3)_PixelCoordToViewDirWS));
// Reverse it to point into the scene
float3 dir = -viewDirWS;
// Rotate direction
float phi = DegToRad(_SkyParam.z);
float cosPhi, sinPhi;
sincos(phi, sinPhi, cosPhi);
float3 rotDirX = float3(cosPhi, 0, -sinPhi);
float3 rotDirY = float3(sinPhi, 0, cosPhi);
dir = float3(dot(rotDirX, dir), dir.y, dot(rotDirY, dir));
float3 skyColor = ClampToFloat16Max(SAMPLE_TEXTURECUBE_LOD(_Cubemap, sampler_Cubemap, dir, 0).rgb * exp2(_SkyParam.x) * _SkyParam.y);
return float4(skyColor, 1.0);
}
ENDHLSL
SubShader
{
Pass
{
ZWrite Off
ZTest Always
Blend Off
Cull Off
HLSLPROGRAM
ENDHLSL
}
Pass
{
ZWrite Off
ZTest LEqual
Blend Off
Cull Off
HLSLPROGRAM
ENDHLSL
}
}
Fallback Off
}
```
After doing all this, the new Sky should automatically appear in the combo box in the *Visual Environment* component.

3
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Camera/HDCamera.cs


// If TAA is enabled projMatrix will hold a jittered projection matrix. The original,
// non-jittered projection matrix can be accessed via nonJitteredProjMatrix.
bool taaEnabled = camera.cameraType == CameraType.Game &&
CoreUtils.IsTemporalAntialiasingActive(postProcessLayer);
CoreUtils.IsTemporalAntialiasingActive(postProcessLayer) &&
frameSettings.enablePostprocess;
var nonJitteredCameraProj = camera.projectionMatrix;
var cameraProj = taaEnabled

17
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Debug/DebugDisplay.cs


{
children =
{
new DebugUI.UIntField { displayName = "Shadow Atlas Index", getter = () => lightingDebugSettings.shadowAtlasIndex, setter = value => lightingDebugSettings.shadowAtlasIndex = value, min = () => 0u, max = () => (uint)(RenderPipelineManager.currentPipeline as HDRenderPipeline).GetShadowAtlasCount() - 1u }
new DebugUI.UIntField { displayName = "Shadow Atlas Index", getter = () => lightingDebugSettings.shadowAtlasIndex, setter = value => lightingDebugSettings.shadowAtlasIndex = value, min = () => 0u, max = () => (uint)(RenderPipelineManager.currentPipeline as HDRenderPipeline).GetShadowAtlasCount() - 1u },
new DebugUI.UIntField { displayName = "Shadow Slice Index", getter = () => lightingDebugSettings.shadowSliceIndex, setter = value => lightingDebugSettings.shadowSliceIndex = value, min = () => 0u, max = () => (uint)(RenderPipelineManager.currentPipeline as HDRenderPipeline).GetShadowSliceCount(lightingDebugSettings.shadowAtlasIndex) - 1u }
}
});
}

list.Add(new DebugUI.BoolField { displayName = "Override Normal", getter = () => lightingDebugSettings.overrideNormal, setter = value => lightingDebugSettings.overrideNormal = value });
list.Add(new DebugUI.BoolField { displayName = "Override Specular Color", getter = () => lightingDebugSettings.overrideSpecularColor, setter = value => lightingDebugSettings.overrideSpecularColor = value, onValueChanged = RefreshLightingDebug });
if (lightingDebugSettings.overrideSpecularColor)
{
list.Add(new DebugUI.Container
{
children =
{
new DebugUI.ColorField { displayName = "Specular Color", getter = () => lightingDebugSettings.overrideSpecularColorValue, setter = value => lightingDebugSettings.overrideSpecularColorValue = value, showAlpha = false, hdr = false }
}
});
}
list.Add(new DebugUI.EnumField { displayName = "Tile/Cluster Debug", getter = () => (int)lightingDebugSettings.tileClusterDebug, setter = value => lightingDebugSettings.tileClusterDebug = (LightLoop.TileClusterDebug)value, autoEnum = typeof(LightLoop.TileClusterDebug), onValueChanged = RefreshLightingDebug });
if (lightingDebugSettings.tileClusterDebug != LightLoop.TileClusterDebug.None && lightingDebugSettings.tileClusterDebug != LightLoop.TileClusterDebug.MaterialFeatureVariants)
{

UnregisterDebugItems(k_PanelDisplayStats, m_DebugDisplayStatsItems);
UnregisterDebugItems(k_PanelMaterials, m_DebugMaterialItems);
UnregisterDebugItems(k_PanelLighting, m_DebugLightingItems);
UnregisterDebugItems(k_PanelRendering, m_DebugLightingItems);
UnregisterDebugItems(k_PanelRendering, m_DebugRenderingItems);
}
void UnregisterDebugItems(string panelName, DebugUI.Widget[] items)

1
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Debug/DebugDisplay.hlsl


float4 _DebugLightingAlbedo; // x == bool override, yzw = albedo for diffuse
float4 _DebugLightingSmoothness; // x == bool override, y == override value
float4 _DebugLightingNormal; // x == bool override
float4 _DebugLightingSpecularColor; // x == bool override, yzw = specular color
float4 _MousePixelCoord; // xy unorm, zw norm
float _DebugEnvironmentProxyDepthScale;
CBUFFER_END

6
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Debug/DebugDisplayLatlong.shader


TEXTURECUBE(_InputCubemap);
SAMPLER(sampler_InputCubemap);
float _Mipmap;
float _RequireToFlipInputTexture;
struct Attributes
{

Varyings output;
output.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID);
output.texcoord = GetFullScreenTriangleTexCoord(input.vertexID);// *_TextureScaleBias.xy + _TextureScaleBias.zw;
if (_RequireToFlipInputTexture > 0.0f)
{
output.texcoord.y = 1.0f - output.texcoord.y;
}
return output;
}

4
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Debug/LightingDebug.cs


public bool shadowDebugUseSelection = false;
public uint shadowMapIndex = 0;
public uint shadowAtlasIndex = 0;
public uint shadowSliceIndex = 0;
public float shadowMinValue = 0.0f;
public float shadowMaxValue = 1.0f;

public Color overrideAlbedoValue = new Color(0.5f, 0.5f, 0.5f);
public bool overrideNormal = false;
public bool overrideSpecularColor = false;
public Color overrideSpecularColorValue = new Color(1.0f, 1.0f, 1.0f);
public bool displaySkyReflection = false;
public float skyReflectionMipmap = 0.0f;

12
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Decal/DecalProjectorComponent.cs


}
}
public void Update()
{
if (m_Handle != null)
{
if (transform.hasChanged == true)
{
DecalSystem.instance.UpdateCachedData(transform, m_DrawDistance, m_FadeScale, m_Handle);
transform.hasChanged = false;
}
}
}
private void DrawGizmo(bool selected)
{
var col = new Color(0.0f, 0.7f, 1f, 1.0f);

5
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Decal/DecalSystem.cs


{
public class DecalSystem
{
public const int kInvalidIndex = -1;
public const int kInvalidIndex = -1;
public const int kDecalAtlasSize = 128;
public class DecalHandle
{

if (m_DecalAtlas == null)
{
m_DecalAtlas = new TextureCache2D("DecalAtlas");
m_DecalAtlas.AllocTextureArray(2048, 128, 128, TextureFormat.RGBA32, true);
m_DecalAtlas.AllocTextureArray(2048, kDecalAtlasSize, kDecalAtlasSize, TextureFormat.ARGB32, true);
}
return m_DecalAtlas;
}

3
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/HDAssetFactory.cs


newAsset.deferredComputeShader = Load<ComputeShader>(HDRenderPipelinePath + "Lighting/LightLoop/Deferred.compute");
newAsset.deferredDirectionalShadowComputeShader = Load<ComputeShader>(HDRenderPipelinePath + "Lighting/DeferredDirectionalShadow.compute");
newAsset.volumetricLightingCS = Load<ComputeShader>(HDRenderPipelinePath + "Lighting/Volumetrics/Resources/VolumetricLighting.compute");
newAsset.volumeVoxelizationCS = Load<ComputeShader>(HDRenderPipelinePath + "Lighting/Volumetrics/VolumeVoxelization.compute");
newAsset.volumetricLightingCS = Load<ComputeShader>(HDRenderPipelinePath + "Lighting/Volumetrics/VolumetricLighting.compute");
newAsset.subsurfaceScatteringCS = Load<ComputeShader>(HDRenderPipelinePath + "Material/SubsurfaceScattering/SubsurfaceScattering.compute");
newAsset.subsurfaceScattering = Load<Shader>(HDRenderPipelinePath + "Material/SubsurfaceScattering/SubsurfaceScattering.shader");

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Lighting/HDLightEditor.cs


UpdateLightIntensity();
}
settings.DrawBounceIntensity();
settings.DrawLightmapping();
EditorGUI.BeginChangeCheck(); // For GI we need to detect any change on additional data and call SetLightDirty

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/LayeredLit/LayeredLitUI.cs


namespace UnityEditor.Experimental.Rendering.HDPipeline
{
internal class LayeredLitGUI : LitGUI
public class LayeredLitGUI : LitGUI
{
public enum VertexColorMode
{

10
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/Lit/LitUI.cs


namespace UnityEditor.Experimental.Rendering.HDPipeline
{
class LitGUI : BaseLitGUI
public class LitGUI : BaseLitGUI
{
protected static class Styles
{

public static GUIContent thicknessRemapText = new GUIContent("Thickness Remap", "Remaps values of the thickness map from [0, 1] to the specified range.");
// Iridescence
public static GUIContent iridescenceMaskText = new GUIContent("Iridescence Mask", "Control intensity of the iridescence");
public static GUIContent iridescenceMaskText = new GUIContent("Iridescence Mask (R)", "Control intensity of the iridescence");
public static GUIContent iridescenceThicknessMapText = new GUIContent("Iridescence Layer Thickness map");
public static GUIContent iridescenceThicknessMapText = new GUIContent("Iridescence Layer Thickness map (R)");
public static GUIContent iridescenceThicknessRemapText = new GUIContent("Iridescence Layer Thickness remap");
// Clear Coat

{
m_MaterialEditor.TexturePropertySingleLine(Styles.iridescenceMaskText, iridescenceMaskMap, iridescenceMask);
m_MaterialEditor.TexturePropertySingleLine(Styles.iridescenceThicknessMapText, iridescenceThicknessMap);
m_MaterialEditor.TexturePropertySingleLine(Styles.iridescenceThicknessMapText, iridescenceThicknessMap);
// Display the remap of texture values.
Vector2 remap = iridescenceThicknessRemap.vectorValue;
EditorGUI.BeginChangeCheck();

else
{
// Allow the user to set the constant value of thickness if no thickness map is provided.
m_MaterialEditor.ShaderProperty(iridescenceThickness, Styles.iridescenceThicknessText);
m_MaterialEditor.TexturePropertySingleLine(Styles.iridescenceThicknessMapText, iridescenceThicknessMap, iridescenceThickness);
}
}

4
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/RenderLoopSettings/GlobalLightLoopSettingsUI.cs


++EditorGUI.indentLevel;
EditorGUILayout.PropertyField(d.skyReflectionSize, _.GetContent("Sky Reflection Size"));
EditorGUILayout.PropertyField(d.skyLightingOverrideLayerMask, _.GetContent("Sky Lighting Override Mask|This layer mask will define in which layers the sky system will look for sky settings volumes for lighting override"));
if(d.skyLightingOverrideLayerMask.intValue == -1)
{
EditorGUILayout.HelpBox("Be careful, Sky Lighting Override Mask is set to Everything. This is most likely a mistake as it serves no purpose.", MessageType.Warning);
}
--EditorGUI.indentLevel;
}
}

5
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Shadows/HDShadowSettingsEditor.cs


SerializedDataParameter[] m_CascadeShadowSplits = new SerializedDataParameter[3];
SerializedDataParameter[] m_CascadeShadowBorders = new SerializedDataParameter[4];
// For now we don't use borders so we hide the UI.
bool m_bShowBorders = false;
public override void OnEnable()
{
var o = new PropertyFetcher<HDShadowSettings>(serializedObject);

PropertyField(m_CascadeShadowSplits[i], CoreEditorUtils.GetContent(string.Format("Split {0}", i + 1)));
}
if(m_bShowBorders)
if(LightLoop.s_UseCascadeBorders)
{
EditorGUILayout.Space();

70
ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDRenderPipeline.cs


public int GetCurrentShadowCount() { return m_LightLoop.GetCurrentShadowCount(); }
public int GetShadowAtlasCount() { return m_LightLoop.GetShadowAtlasCount(); }
public int GetShadowSliceCount(uint atlasIndex) { return m_LightLoop.GetShadowSliceCount(atlasIndex); }
readonly VolumetricLightingModule m_VolumetricLightingModule = new VolumetricLightingModule();
readonly VolumetricLightingSystem m_VolumetricLightingSystem = new VolumetricLightingSystem();
// Debugging
MaterialPropertyBlock m_SharedPropertyBlock = new MaterialPropertyBlock();

m_SkyManager.Build(asset, m_IBLFilterGGX);
m_VolumetricLightingModule.Build(asset);
m_VolumetricLightingSystem.Build(asset);
m_DebugDisplaySettings.RegisterDebug();
#if UNITY_EDITOR

m_SSSBufferManager.Cleanup();
m_SkyManager.Cleanup();
m_VolumetricLightingModule.Cleanup();
m_VolumetricLightingSystem.Cleanup();
m_IBLFilterGGX.Cleanup();
DestroyRenderTextures();

}
// Warning: (resolutionChanged == false) if you open a new Editor tab of the same size!
m_VolumetricLightingModule.ResizeVBuffer(hdCamera, hdCamera.actualWidth, hdCamera.actualHeight);
m_VolumetricLightingSystem.ResizeVBuffer(hdCamera, hdCamera.actualWidth, hdCamera.actualHeight);
// update recorded window resolution
m_CurrentWidth = hdCamera.actualWidth;

m_DbufferManager.PushGlobalParams(cmd, m_FrameSettings);
m_VolumetricLightingModule.PushGlobalParams(hdCamera, cmd);
m_VolumetricLightingSystem.PushGlobalParams(hdCamera, cmd);
}
}

}
else
{
// Temporary hack. For scene view, by default, we don't want to have the lighting override layers in the current sky.
// Temporary hack:
// For scene view, by default, we use the "main" camera volume layer mask if it exists
// Otherwise we just remove the lighting override layers in the current sky to avoid conflicts
layerMask = (-1 & ~m_Asset.renderPipelineSettings.lightLoopSettings.skyLightingOverrideLayerMask);
var mainCamera = Camera.main;
bool needFallback = true;
if (mainCamera != null)
{
var mainCamAdditionalData = mainCamera.GetComponent<HDAdditionalCameraData>();
if (mainCamAdditionalData != null)
{
layerMask = mainCamAdditionalData.volumeLayerMask;
needFallback = false;
}
}
if (needFallback)
{
// If the override layer is "Everything", we fall-back to "Everything" for the current layer mask to avoid issues by having no current layer
// In practice we should never have "Everything" as an override mask as it does not make sense (a warning is issued in the UI)
if (m_Asset.renderPipelineSettings.lightLoopSettings.skyLightingOverrideLayerMask == -1)
layerMask = -1;
else
layerMask = (-1 & ~m_Asset.renderPipelineSettings.lightLoopSettings.skyLightingOverrideLayerMask);
}
}
}
VolumeManager.instance.Update(camera.transform, layerMask);

// Disable postprocess if we enable debug mode
if (m_CurrentDebugDisplaySettings.fullScreenDebugMode == FullScreenDebugMode.None && m_CurrentDebugDisplaySettings.IsDebugDisplayEnabled())
var postProcessLayer = camera.GetComponent<PostProcessLayer>();
// Disable post process if we enable debug mode or if the post process layer is disabled
if (m_CurrentDebugDisplaySettings.fullScreenDebugMode != FullScreenDebugMode.None || m_CurrentDebugDisplaySettings.IsDebugDisplayEnabled() || !CoreUtils.IsPostProcessingActive(postProcessLayer))
var postProcessLayer = camera.GetComponent<PostProcessLayer>();
var hdCamera = HDCamera.Get(camera, postProcessLayer, m_FrameSettings);
Resize(hdCamera);

continue;
}
// Frustum cull density volumes on the CPU. Can be performed as soon as the camera is set up.
DensityVolumeList densityVolumes = m_VolumetricLightingSystem.PrepareVisibleDensityVolumeList(hdCamera, cmd);
// Note: Legacy Unity behave like this for ShadowMask
// When you select ShadowMask in Lighting panel it recompile shaders on the fly with the SHADOW_MASK keyword.
// However there is no C# function that we can query to know what mode have been select in Lighting Panel and it will be wrong anyway. Lighting Panel setup what will be the next bake mode. But until light is bake, it is wrong.

bool enableBakeShadowMask;
using (new ProfilingSample(cmd, "TP_PrepareLightsForGPU", CustomSamplerId.TPPrepareLightsForGPU.GetSampler()))
{
enableBakeShadowMask = m_LightLoop.PrepareLightsForGPU(cmd, m_ShadowSettings, m_CullResults, m_ReflectionProbeCullResults, camera) && m_FrameSettings.enableShadowMask;
enableBakeShadowMask = m_LightLoop.PrepareLightsForGPU(cmd, camera, m_ShadowSettings, m_CullResults, m_ReflectionProbeCullResults, densityVolumes) && m_FrameSettings.enableShadowMask;
}
ConfigureForShadowMask(enableBakeShadowMask, cmd);

renderContext.ExecuteCommandBuffer(cmd);
cmd.Clear();
buildGPULightListsCompleteFence = m_LightLoop.BuildGPULightListsAsyncBegin(hdCamera, renderContext, m_CameraDepthStencilBuffer, m_CameraStencilBufferCopy, startFence, m_SkyManager.IsSkyValid());
buildGPULightListsCompleteFence = m_LightLoop.BuildGPULightListsAsyncBegin(hdCamera, renderContext, m_CameraDepthStencilBuffer, m_CameraStencilBufferCopy, startFence, m_SkyManager.IsLightingSkyValid());
}
using (new ProfilingSample(cmd, "Render shadows", CustomSamplerId.RenderShadows.GetSampler()))

{
using (new ProfilingSample(cmd, "Build Light list", CustomSamplerId.BuildLightList.GetSampler()))
{
m_LightLoop.BuildGPULightLists(hdCamera, cmd, m_CameraDepthStencilBuffer, m_CameraStencilBufferCopy, m_SkyManager.IsSkyValid());
m_LightLoop.BuildGPULightLists(hdCamera, cmd, m_CameraDepthStencilBuffer, m_CameraStencilBufferCopy, m_SkyManager.IsLightingSkyValid());
// The pass only requires the volume properties, and can run async.
m_VolumetricLightingModule.VoxelizeDensityVolumes(hdCamera, cmd);
// Perform the voxelization step which fills the density 3D texture.
// Requires the clustered lighting data structure to be built, and can run async.
m_VolumetricLightingSystem.VolumeVoxelizationPass(densityVolumes, hdCamera, cmd, m_FrameSettings);
m_VolumetricLightingModule.VolumetricLightingPass(hdCamera, cmd, m_FrameSettings);
m_VolumetricLightingSystem.VolumetricLightingPass(hdCamera, cmd, m_FrameSettings);
RenderDeferredLighting(hdCamera, cmd);

StartStereoRendering(renderContext, hdCamera.camera);
// Final blit
if (m_FrameSettings.enablePostprocess && CoreUtils.IsPostProcessingActive(postProcessLayer))
if (m_FrameSettings.enablePostprocess)
{
RenderPostProcess(hdCamera, cmd, postProcessLayer);
}

m_SkyManager.RenderSky(hdCamera, m_LightLoop.GetCurrentSunLight(), m_CameraColorBuffer, m_CameraDepthStencilBuffer, cmd);
if (visualEnv.fogType != FogType.None || m_VolumetricLightingModule.preset != VolumetricLightingModule.VolumetricLightingPreset.Off)
if (visualEnv.fogType != FogType.None || m_VolumetricLightingSystem.preset != VolumetricLightingSystem.VolumetricLightingPreset.Off)
m_SkyManager.RenderOpaqueAtmosphericScattering(cmd);
}

var debugAlbedo = new Vector4(lightingDebugSettings.overrideAlbedo ? 1.0f : 0.0f, lightingDebugSettings.overrideAlbedoValue.r, lightingDebugSettings.overrideAlbedoValue.g, lightingDebugSettings.overrideAlbedoValue.b);
var debugSmoothness = new Vector4(lightingDebugSettings.overrideSmoothness ? 1.0f : 0.0f, lightingDebugSettings.overrideSmoothnessValue, 0.0f, 0.0f);
var debugNormal = new Vector4(lightingDebugSettings.overrideNormal ? 1.0f : 0.0f, 0.0f, 0.0f, 0.0f);
var debugSpecularColor = new Vector4(lightingDebugSettings.overrideSpecularColor ? 1.0f : 0.0f, lightingDebugSettings.overrideSpecularColorValue.r, lightingDebugSettings.overrideSpecularColorValue.g, lightingDebugSettings.overrideSpecularColorValue.b);
cmd.SetGlobalInt(HDShaderIDs._DebugViewMaterial, (int)m_CurrentDebugDisplaySettings.GetDebugMaterialIndex());
cmd.SetGlobalInt(HDShaderIDs._DebugLightingMode, (int)m_CurrentDebugDisplaySettings.GetDebugLightingMode());

cmd.SetGlobalVector(HDShaderIDs._DebugLightingSmoothness, debugSmoothness);
cmd.SetGlobalVector(HDShaderIDs._DebugLightingNormal, debugNormal);
cmd.SetGlobalVector(HDShaderIDs._DebugLightingSpecularColor, debugSpecularColor);
cmd.SetGlobalTexture(HDShaderIDs._DebugFont, m_Asset.renderPipelineResources.debugFontTexture);
}
else

var skyReflection = m_SkyManager.skyReflection;
m_SharedPropertyBlock.SetTexture(HDShaderIDs._InputCubemap, skyReflection);
m_SharedPropertyBlock.SetFloat(HDShaderIDs._Mipmap, lightingDebug.skyReflectionMipmap);
m_SharedPropertyBlock.SetFloat(HDShaderIDs._RequireToFlipInputTexture, hdCamera.camera.cameraType != CameraType.SceneView ? 1.0f : 0.0f);
cmd.SetViewport(new Rect(x, y, overlaySize, overlaySize));
cmd.DrawProcedural(Matrix4x4.identity, m_DebugDisplayLatlong, 0, MeshTopology.Triangles, 3, 1, m_SharedPropertyBlock);
HDUtils.NextOverlayCoord(ref x, ref y, overlaySize, overlaySize, hdCamera.actualWidth);

{
if (hdCamera.clearColorMode == HDAdditionalCameraData.ClearColorMode.BackgroundColor ||
// If we want the sky but the sky don't exist, still clear with background color
(hdCamera.clearColorMode == HDAdditionalCameraData.ClearColorMode.Sky && !m_SkyManager.IsSkyValid()) ||
(hdCamera.clearColorMode == HDAdditionalCameraData.ClearColorMode.Sky && !m_SkyManager.IsVisualSkyValid()) ||
// Special handling for Preview we force to clear with background color (i.e black)
// Note that the sky use in this case is the last one setup. If there is no scene or game, there is no sky use as reflection in the preview
hdCamera.camera.cameraType == CameraType.Preview

6
ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDStringConstants.cs


public static readonly int g_LayeredSingleIdxBuffer = Shader.PropertyToID("g_LayeredSingleIdxBuffer");
public static readonly int _EnvLightIndexShift = Shader.PropertyToID("_EnvLightIndexShift");
public static readonly int _DensityVolumeIndexShift = Shader.PropertyToID("_DensityVolumeIndexShift");
public static readonly int g_isOrthographic = Shader.PropertyToID("g_isOrthographic");
public static readonly int g_iNrVisibLights = Shader.PropertyToID("g_iNrVisibLights");

public static readonly int _DebugLightingAlbedo = Shader.PropertyToID("_DebugLightingAlbedo");
public static readonly int _DebugLightingSmoothness = Shader.PropertyToID("_DebugLightingSmoothness");
public static readonly int _DebugLightingNormal = Shader.PropertyToID("_DebugLightingNormal");
public static readonly int _DebugLightingSpecularColor = Shader.PropertyToID("_DebugLightingSpecularColor");
public static readonly int _AmbientOcclusionTexture = Shader.PropertyToID("_AmbientOcclusionTexture");
public static readonly int _DebugMipMapMode = Shader.PropertyToID("_DebugMipMapMode");

public static readonly int _IrradianceSource = Shader.PropertyToID("_IrradianceSource");
public static readonly int _EnableDBuffer = Shader.PropertyToID("_EnableDBuffer");
public static readonly int _DecalAtlasResolution = Shader.PropertyToID("_DecalAtlasResolution");
public static readonly int[] _GBufferTexture =
{

public static readonly int _VBufferLightingHistory = Shader.PropertyToID("_VBufferLightingHistory");
public static readonly int _VBufferLightingFeedback = Shader.PropertyToID("_VBufferLightingFeedback");
public static readonly int _VBufferSampleOffset = Shader.PropertyToID("_VBufferSampleOffset");
public static readonly int _VolumeBounds = Shader.PropertyToID("_VolumeBounds");
public static readonly int _VolumeProperties = Shader.PropertyToID("_VolumeProperties");
public static readonly int _NumVisibleDensityVolumes = Shader.PropertyToID("_NumVisibleDensityVolumes");
}
}

26
ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDUtils.cs


return Matrix4x4.Transpose(worldToViewMatrix.transpose * viewSpaceRasterTransform);
}
private static void SetViewportAndClear(CommandBuffer cmd, HDCamera camera, RTHandle buffer, ClearFlag clearFlag, Color clearColor)
{
// Clearing a partial viewport currently does not go through the hardware clear.
// Instead it goes through a quad rendered with a specific shader.
// When enabling wireframe mode in the scene view, unfortunately it overrides this shader thus breaking every clears.
// That's why in the editor we don't set the viewport before clearing (it's set to full screen by the previous SetRenderTarget) but AFTER so that we benefit from un-bugged hardware clear.
// We consider that the small loss in performance is acceptable in the editor.
// A refactor of wireframe is needed before we can fix this properly (with not doing anything!)
#if !UNITY_EDITOR
SetViewport(cmd, camera, buffer);
#endif
CoreUtils.ClearRenderTarget(cmd, clearFlag, clearColor);
#if UNITY_EDITOR
SetViewport(cmd, camera, buffer);
#endif
}
SetViewport(cmd, camera, buffer);
CoreUtils.ClearRenderTarget(cmd, clearFlag, clearColor);
SetViewportAndClear(cmd, camera, buffer, clearFlag, clearColor);
}
public static void SetRenderTarget(CommandBuffer cmd, HDCamera camera, RTHandle buffer, ClearFlag clearFlag = ClearFlag.None, int miplevel = 0, CubemapFace cubemapFace = CubemapFace.Unknown, int depthSlice = 0)

public static void SetRenderTarget(CommandBuffer cmd, HDCamera camera, RTHandle colorBuffer, RTHandle depthBuffer, ClearFlag clearFlag, Color clearColor, int miplevel = 0, CubemapFace cubemapFace = CubemapFace.Unknown, int depthSlice = 0)
{
CoreUtils.SetRenderTarget(cmd, colorBuffer, depthBuffer, miplevel, cubemapFace, depthSlice);
SetViewport(cmd, camera, colorBuffer);
CoreUtils.ClearRenderTarget(cmd, clearFlag, clearColor);
SetViewportAndClear(cmd, camera, colorBuffer, clearFlag, clearColor);
}
public static void SetRenderTarget(CommandBuffer cmd, HDCamera camera, RenderTargetIdentifier[] colorBuffers, RTHandle depthBuffer)

public static void SetRenderTarget(CommandBuffer cmd, HDCamera camera, RenderTargetIdentifier[] colorBuffers, RTHandle depthBuffer, ClearFlag clearFlag = ClearFlag.None)
{
CoreUtils.SetRenderTarget(cmd, colorBuffers, depthBuffer); // Don't clear here, viewport needs to be set before we do.
SetViewport(cmd, camera, depthBuffer);
CoreUtils.ClearRenderTarget(cmd, clearFlag, CoreUtils.clearColorAllBlack);
SetViewportAndClear(cmd, camera, depthBuffer, clearFlag, CoreUtils.clearColorAllBlack);
}
public static void SetRenderTarget(CommandBuffer cmd, HDCamera camera, RenderTargetIdentifier[] colorBuffers, RTHandle depthBuffer, ClearFlag clearFlag, Color clearColor)

1
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightEvaluation.hlsl


lightData.angleScale, lightData.angleOffset);
#if (SHADEROPTIONS_VOLUMETRIC_LIGHTING_PRESET != 0)
// TODO: sample the extinction from the density V-buffer.
float distVol = (lightData.lightType == GPULIGHTTYPE_PROJECTOR_BOX) ? distances.w : distances.x;
attenuation *= TransmittanceHomogeneousMedium(_GlobalExtinction, distVol);
#endif

102
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/LightLoop.cs


Area,
Env,
Decal,
DensityVolume,
Count
}

EnvironmentAndPunctual = 5,
EnvironmentAndArea = 6,
EnvironmentAndAreaAndPunctual = 7,
Decal = 8
Decal = 8,
DensityVolumes = 16
};
public const int k_MaxDirectionalLightsOnScreen = 4;

TextureCache2D m_CookieTexArray;
TextureCacheCubemap m_CubeCookieTexArray;
List<Matrix4x4> m_Env2DCaptureVP = new List<Matrix4x4>();
// For now we don't use shadow cascade borders.
static public readonly bool s_UseCascadeBorders = false;
public class LightList
{

int m_punctualLightCount = 0;
int m_areaLightCount = 0;
int m_lightCount = 0;
int m_densityVolumeCount = 0;
bool m_enableBakeShadowMask = false; // Track if any light require shadow mask. In this case we will need to enable the keyword shadow mask
float m_maxShadowDistance = 0.0f; // Save value from shadow settings

}
}
public void AddBoxVolumeDataAndBound(OrientedBBox obb, LightCategory category, LightFeatureFlags featureFlags, Matrix4x4 worldToView)
{
var bound = new SFiniteLightBound();
var volumeData = new LightVolumeData();
// transform to camera space (becomes a left hand coordinate frame in Unity since Determinant(worldToView)<0)
var positionVS = worldToView.MultiplyPoint(obb.center);
var rightVS = worldToView.MultiplyVector(obb.right);
var upVS = worldToView.MultiplyVector(obb.up);
var forwardVS = Vector3.Cross(upVS, rightVS);
var extents = new Vector3(obb.extentX, obb.extentY, obb.extentZ);
volumeData.lightVolume = (uint)LightVolumeType.Box;
volumeData.lightCategory = (uint)category;
volumeData.featureFlags = (uint)featureFlags;
bound.center = positionVS;
bound.boxAxisX = obb.extentX * rightVS;
bound.boxAxisY = obb.extentY * upVS;
bound.boxAxisZ = obb.extentZ * forwardVS;
bound.radius = extents.magnitude;
bound.scaleXY.Set(1.0f, 1.0f);
// The culling system culls pixels that are further
// than a threshold to the box influence extents.
// So we use an arbitrary threshold here (k_BoxCullingExtentOffset)
volumeData.lightPos = positionVS;
volumeData.lightAxisX = rightVS;
volumeData.lightAxisY = upVS;
volumeData.lightAxisZ = forwardVS;
volumeData.boxInnerDist = extents - k_BoxCullingExtentThreshold; // We have no blend range, but the culling code needs a small EPS value for some reason???
volumeData.boxInvRange.Set(1.0f / k_BoxCullingExtentThreshold.x, 1.0f / k_BoxCullingExtentThreshold.y, 1.0f / k_BoxCullingExtentThreshold.z);
m_lightList.bounds.Add(bound);
m_lightList.lightVolumes.Add(volumeData);
}
public int GetCurrentShadowCount()
{
return m_ShadowRequests.Count;

return (m_ShadowMgr == null) ? 0 : (int)m_ShadowMgr.GetShadowMapCount();
}
public int GetShadowSliceCount(uint atlasIndex)
{
return (m_ShadowMgr == null) ? 0 : (int)m_ShadowMgr.GetShadowMapSliceCount(atlasIndex);
}
public void UpdateCullingParameters(ref ScriptableCullingParameters cullingParams)
{
m_ShadowMgr.UpdateCullingParameters( ref cullingParams );

}
// Return true if BakedShadowMask are enabled
public bool PrepareLightsForGPU(CommandBuffer cmd, ShadowSettings shadowSettings, CullResults cullResults, ReflectionProbeCullResults reflectionProbeCullResults, Camera camera)
public bool PrepareLightsForGPU(CommandBuffer cmd, Camera camera, ShadowSettings shadowSettings, CullResults cullResults,
ReflectionProbeCullResults reflectionProbeCullResults, DensityVolumeList densityVolumes)
{
using (new ProfilingSample(cmd, "Prepare Lights For GPU"))
{

if (ShaderConfig.s_CameraRelativeRendering != 0)
{
// Caution: 'DirectionalLightData.positionWS' is camera-relative after this point.
int n = m_lightList.directionalLights.Count;
DirectionalLightData lightData = m_lightList.directionalLights[n - 1];
int last = m_lightList.directionalLights.Count - 1;
DirectionalLightData lightData = m_lightList.directionalLights[last];
m_lightList.directionalLights[n - 1] = lightData;
m_lightList.directionalLights[last] = lightData;
}
}
continue;

if (ShaderConfig.s_CameraRelativeRendering != 0)
{
// Caution: 'LightData.positionWS' is camera-relative after this point.
int n = m_lightList.lights.Count;
LightData lightData = m_lightList.lights[n - 1];
int last = m_lightList.lights.Count - 1;
LightData lightData = m_lightList.lights[last];
m_lightList.lights[n - 1] = lightData;
m_lightList.lights[last] = lightData;
}
}
}

if (ShaderConfig.s_CameraRelativeRendering != 0)
{
// Caution: 'EnvLightData.positionWS' is camera-relative after this point.
int n = m_lightList.envLights.Count;
EnvLightData envLightData = m_lightList.envLights[n - 1];
int last = m_lightList.envLights.Count - 1;
EnvLightData envLightData = m_lightList.envLights[last];
m_lightList.envLights[n - 1] = envLightData;
m_lightList.envLights[last] = envLightData;
// Inject density volumes into the clustered data structure for efficient look up.
m_densityVolumeCount = densityVolumes.bounds != null ? densityVolumes.bounds.Count : 0;
Matrix4x4 worldToViewCR = worldToView;
if (ShaderConfig.s_CameraRelativeRendering != 0)
{
// The OBBs are camera-relative, the matrix is not. Fix it.
worldToViewCR.SetColumn(3, new Vector4(0, 0, 0, 1));
}
for (int i = 0, n = m_densityVolumeCount; i < n; i++)
{
// Density volumes are not lights and therefore should not affect light classification.
LightFeatureFlags featureFlags = 0;
AddBoxVolumeDataAndBound(densityVolumes.bounds[i], LightCategory.DensityVolume, featureFlags, worldToViewCR);
}
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);
m_lightCount = m_lightList.lights.Count + m_lightList.envLights.Count + m_densityVolumeCount;
Debug.Assert(m_lightCount == m_lightList.bounds.Count);
Debug.Assert(m_lightCount == m_lightList.lightVolumes.Count);
int decalDatasCount = Math.Min(DecalSystem.m_DecalDatasCount, k_MaxDecalsOnScreen);
if (decalDatasCount > 0)

cmd.SetComputeBufferParam(buildPerVoxelLightListShader, s_ClearVoxelAtomicKernel, HDShaderIDs.g_LayeredSingleIdxBuffer, s_GlobalLightListAtomic);
cmd.DispatchCompute(buildPerVoxelLightListShader, s_ClearVoxelAtomicKernel, 1, 1, 1);
int decalDatasCount = Math.Min(DecalSystem.m_DecalDatasCount, k_MaxDecalsOnScreen);
cmd.SetComputeIntParam(buildPerVoxelLightListShader, HDShaderIDs._DensityVolumeIndexShift, m_lightList.lights.Count + m_lightList.envLights.Count + decalDatasCount);
cmd.SetComputeIntParam(buildPerVoxelLightListShader, HDShaderIDs.g_iNrVisibLights, m_lightCount);
cmd.SetComputeMatrixArrayParam(buildPerVoxelLightListShader, HDShaderIDs.g_mScrProjectionArr, projscrArr);
cmd.SetComputeMatrixArrayParam(buildPerVoxelLightListShader, HDShaderIDs.g_mInvScrProjectionArr, invProjscrArr);

uint faceCount = m_ShadowMgr.GetShadowRequestFaceCount((uint)index);
for (uint i = 0; i < faceCount; ++i)
{
m_ShadowMgr.DisplayShadow(cmd, m_DebugShadowMapMaterial, index, i, x, y, overlaySize, overlaySize, lightingDebug.shadowMinValue, lightingDebug.shadowMaxValue);
m_ShadowMgr.DisplayShadow(cmd, m_DebugShadowMapMaterial, index, i, x, y, overlaySize, overlaySize, lightingDebug.shadowMinValue, lightingDebug.shadowMaxValue, hdCamera.camera.cameraType != CameraType.SceneView);
HDUtils.NextOverlayCoord(ref x, ref y, overlaySize, overlaySize, hdCamera.actualWidth);
}
}

m_ShadowMgr.DisplayShadowMap(cmd, m_DebugShadowMapMaterial, lightingDebug.shadowAtlasIndex, 0, x, y, overlaySize, overlaySize, lightingDebug.shadowMinValue, lightingDebug.shadowMaxValue);
m_ShadowMgr.DisplayShadowMap(cmd, m_DebugShadowMapMaterial, lightingDebug.shadowAtlasIndex, lightingDebug.shadowSliceIndex, x, y, overlaySize, overlaySize, lightingDebug.shadowMinValue, lightingDebug.shadowMaxValue, hdCamera.camera.cameraType != CameraType.SceneView);
HDUtils.NextOverlayCoord(ref x, ref y, overlaySize, overlaySize, hdCamera.actualWidth);
}
}

3
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/LightLoop.cs.hlsl


#define LIGHTCATEGORY_AREA (1)
#define LIGHTCATEGORY_ENV (2)
#define LIGHTCATEGORY_DECAL (3)
#define LIGHTCATEGORY_COUNT (4)
#define LIGHTCATEGORY_DENSITY_VOLUME (4)
#define LIGHTCATEGORY_COUNT (5)
//
// UnityEngine.Experimental.Rendering.HDPipeline.LightFeatureFlags: static fields

5
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/LightLoop.hlsl


float3(1.0, 1.0, 1.0)
};
diffuseLighting = float3(0.0, 0.0, 0.0);
diffuseLighting = float3(1.0, 1.0, 1.0);
if (_DirectionalLightCount > 0)
{
int shadowIdx = _DirectionalLightDatas[0].shadowIndex;

int shadowSplitIndex = EvalShadow_GetSplitIndex(lightLoopContext.shadowContext, shadowIdx, positionWS, payloadOffset, alpha);
int cascadeCount;
int shadowSplitIndex = EvalShadow_GetSplitIndex(lightLoopContext.shadowContext, shadowIdx, positionWS, payloadOffset, alpha, cascadeCount);
if (shadowSplitIndex >= 0)
{
diffuseLighting = lerp(s_CascadeColors[shadowSplitIndex], s_CascadeColors[shadowSplitIndex+1], alpha) * shadow;

22
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/LightLoopDef.hlsl


return 1;
}
uint FetchIndex(uint globalOffset, uint lightIndex)
{
return globalOffset + lightIndex;
}
uint FetchIndexWithBoundsCheck(uint start, uint count, uint i)
{
if (i < count)
{
return FetchIndex(start, i);
}
else
{
return UINT_MAX;
}
}
#ifdef LIGHTLOOP_TILE_PASS
#else
int j = start + i;
#endif
return _LightDatas[j];
}

3
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/lightlistbuild-bigtile.compute


uniform float g_fNearPlane;
uniform float g_fFarPlane;
uniform uint g_isOrthographic;
// TODO: These aren't used, we should remove them
uniform int _EnvLightIndexShift;
uniform int _DecalIndexShift;
StructuredBuffer<float3> g_vBoundsBuffer : register( t1 );
StructuredBuffer<LightVolumeData> _LightVolumeData : register(t2);

12
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/lightlistbuild-clustered.compute


uint g_isOrthographic;
int _EnvLightIndexShift;
int _DecalIndexShift;
int _DensityVolumeIndexShift;
float g_fClustScale;
float g_fClustBase;

int shiftIndex[LIGHTCATEGORY_COUNT];
ZERO_INITIALIZE_ARRAY(int, shiftIndex, LIGHTCATEGORY_COUNT);
// NOTE: Why is this indexed like this?
shiftIndex[LIGHTCATEGORY_COUNT - 2] = _EnvLightIndexShift;
shiftIndex[LIGHTCATEGORY_COUNT - 1] = _DecalIndexShift;
shiftIndex[LIGHTCATEGORY_COUNT - 3] = _EnvLightIndexShift;
shiftIndex[LIGHTCATEGORY_COUNT - 2] = _DecalIndexShift;
shiftIndex[LIGHTCATEGORY_COUNT - 1] = _DensityVolumeIndexShift;
int categoryListCount[LIGHTCATEGORY_COUNT]; // direct light count and reflection lights
int categoryListCount[LIGHTCATEGORY_COUNT]; // number of direct lights, reflection probes, decals and density volumes
ZERO_INITIALIZE_ARRAY(int, categoryListCount, LIGHTCATEGORY_COUNT);
uint offs = start;

const int lightVolIndex = GenerateLightCullDataIndex(coarseList[l], g_iNrVisibLights, eyeIndex);
uint lightCategory = _LightVolumeData[lightVolIndex].lightCategory;
++categoryListCount[lightCategory];
g_vLayeredLightList[offs++] = coarseList[l] - shiftIndex[lightCategory]; // reflection lights will be last since we sorted
}
g_vLayeredLightList[offs++] = coarseList[l] - shiftIndex[lightCategory];
}
}
#if !defined(SHADER_API_XBOXONE) && !defined(SHADER_API_PSSL)

19
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/lightlistbuild.compute


#define MAX_NR_COARSE_ENTRIES 64
#define MAX_NR_PRUNED_ENTRIES 24
#define CATEGORY_LIST_SIZE (LIGHTCATEGORY_COUNT - 1) // Skip density volumes
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

#endif
groupshared int ldsNrLightsFinal;
groupshared int ldsCategoryListCount[LIGHTCATEGORY_COUNT];
groupshared int ldsCategoryListCount[CATEGORY_LIST_SIZE];
#ifdef PERFORM_SPHERICAL_INTERSECTION_TESTS
groupshared uint lightOffsSph;

for(int l=(int) t; l<(int) g_iNrVisibLights; l += NR_THREADS)
{
#endif
// Skip density volumes (lights are sorted by category). TODO: improve data locality
if (_LightVolumeData[l].lightCategory == LIGHTCATEGORY_DENSITY_VOLUME) { break; }
const float3 vMi = g_vBoundsBuffer[l];
const float3 vMa = g_vBoundsBuffer[l+g_iNrVisibLights];

}
#endif
//
if(t<LIGHTCATEGORY_COUNT) ldsCategoryListCount[t]=0;
if(t<CATEGORY_LIST_SIZE) ldsCategoryListCount[t]=0;
#ifdef USE_FEATURE_FLAGS
if(t==0) ldsFeatureFlags=0;
#endif

// All our cull data are in the same list, but at render time envLights are separated so we need to shift the index
// to make it work correctly
int shiftIndex[LIGHTCATEGORY_COUNT];
ZERO_INITIALIZE_ARRAY(int, shiftIndex, LIGHTCATEGORY_COUNT);
shiftIndex[LIGHTCATEGORY_COUNT - 2] = _EnvLightIndexShift;
shiftIndex[LIGHTCATEGORY_COUNT - 1] = _DecalIndexShift;
int shiftIndex[CATEGORY_LIST_SIZE];
ZERO_INITIALIZE_ARRAY(int, shiftIndex, CATEGORY_LIST_SIZE);
shiftIndex[CATEGORY_LIST_SIZE - 2] = _EnvLightIndexShift;
shiftIndex[CATEGORY_LIST_SIZE - 1] = _DecalIndexShift;
for(int category=0; category<LIGHTCATEGORY_COUNT; category++)
for(int category=0; category<CATEGORY_LIST_SIZE; category++)
{
int nrLightsFinal = ldsCategoryListCount[category];
int nrLightsFinalClamped = nrLightsFinal<MAX_NR_PRUNED_ENTRIES ? nrLightsFinal : MAX_NR_PRUNED_ENTRIES;

10
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/HomogeneousDensityVolume.cs


[AddComponentMenu("Rendering/Homogeneous Density Volume", 1100)]
public class HomogeneousDensityVolume : MonoBehaviour
{
public VolumeParameters volumeParameters = new VolumeParameters();
public DensityVolumeParameters parameters = new DensityVolumeParameters();
private void Awake()
{

private void OnValidate()
{
volumeParameters.Constrain();
parameters.Constrain();
if (volumeParameters.IsLocalVolume())
if (parameters.IsLocalVolume())
Gizmos.color = volumeParameters.albedo;
Gizmos.color = parameters.albedo;
Gizmos.matrix = transform.localToWorldMatrix;
Gizmos.DrawWireCube(Vector3.zero, Vector3.one);
}

foreach (HomogeneousDensityVolume volume in volumes)
{
if (volume.enabled && !volume.volumeParameters.IsLocalVolume())
if (volume.enabled && !volume.parameters.IsLocalVolume())
{
globalVolume = volume;
break;

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/HomogeneousDensityVolume.cs.meta


fileFormatVersion: 2
guid: 1c273c50d71d46a4f98a1d23256a8c63
guid: e1fbb15bf92b84f40a1eb030765b5afe
MonoImporter:
externalObjects: {}
serializedVersion: 2

324
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/VolumetricLighting.cs


namespace UnityEngine.Experimental.Rendering.HDPipeline
{
[GenerateHLSL]
public struct VolumeProperties
public struct DensityVolumeProperties
public static VolumeProperties GetNeutralVolumeProperties()
public static DensityVolumeProperties GetNeutralProperties()
VolumeProperties properties = new VolumeProperties();
DensityVolumeProperties properties = new DensityVolumeProperties();
properties.scattering = Vector3.zero;
properties.extinction = 0;

} // struct VolumeProperties
[Serializable]
public class VolumeParameters
public class DensityVolumeParameters
public bool isLocal; // Enables voxelization
public Color albedo; // Single scattering albedo [0, 1]
public float meanFreePath; // In meters [1, inf]. Should be chromatic - this is an optimization!
public float asymmetry; // Single global parameter for all volumes. TODO: UX
public bool isLocal; // Enables voxelization
public Color albedo; // Single scattering albedo [0, 1]
public float meanFreePath; // In meters [1, inf]. Should be chromatic - this is an optimization!
public float asymmetry; // Only used if (isLocal == false)
public VolumeParameters()
public DensityVolumeParameters()
{
isLocal = true;
albedo = new Color(0.5f, 0.5f, 0.5f);

asymmetry = Mathf.Clamp(asymmetry, -1.0f, 1.0f);
}
public VolumeProperties GetProperties()
public DensityVolumeProperties GetProperties()
VolumeProperties properties = new VolumeProperties();
DensityVolumeProperties properties = new DensityVolumeProperties();
properties.scattering = GetScatteringCoefficient();
properties.extinction = GetExtinctionCoefficient();

} // class VolumeParameters
public class VolumetricLightingModule
public struct DensityVolumeList
{
public List<OrientedBBox> bounds;
public List<DensityVolumeProperties> properties;
}
public class VolumetricLightingSystem
{
public enum VolumetricLightingPreset
{

}
class VBuffer
{
public long viewID = -1; // -1 is invalid; positive for Game Views, 0 otherwise
public RenderTexture[] lightingRTEX = null;
public RenderTargetIdentifier[] lightingRTID = null;
public RenderTexture densityRTEX = null;
public RenderTargetIdentifier densityRTID = -1; // RenderTargetIdentifier cannot be NULL
const int k_IndexDensity = 0;
const int k_IndexIntegral = 1;
const int k_IndexHistory = 2; // Depends on frame ID
const int k_IndexFeedback = 3; // Depends on frame ID
long m_ViewID = -1; // -1 is invalid; positive for Game Views, 0 otherwise
RenderTexture[] m_Textures = null;
RenderTargetIdentifier[] m_Identifiers = null;
public RenderTargetIdentifier GetDensityBuffer()
{
Debug.Assert(m_ViewID >= 0);
return m_Identifiers[k_IndexDensity];
}
Debug.Assert(viewID >= 0);
return lightingRTID[0];
Debug.Assert(m_ViewID >= 0);
return m_Identifiers[k_IndexIntegral];
Debug.Assert(viewID > 0); // Game View only
return lightingRTID[1 + ((Time.renderedFrameCount + 0) & 1)];
Debug.Assert(m_ViewID > 0); // Game View only
return m_Identifiers[k_IndexHistory + (Time.renderedFrameCount & 1)];
Debug.Assert(viewID > 0); // Game View only
return lightingRTID[1 + ((Time.renderedFrameCount + 1) & 1)];
}
public RenderTargetIdentifier GetDensityBuffer()
{
Debug.Assert(viewID >= 0);
return densityRTID;
Debug.Assert(m_ViewID > 0); // Game View only
return m_Identifiers[k_IndexFeedback - (Time.renderedFrameCount & 1)];
}
public void Create(long viewID, int w, int h, int d)

// Clean up first.
Destroy();
// The required number of buffers depends on the view type.
// Only Game Views need history and feedback buffers.
int n = isGameView ? 3 : 1;
int n = isGameView ? 4 : 2;
this.viewID = viewID;
this.lightingRTEX = new RenderTexture[n];
this.lightingRTID = new RenderTargetIdentifier[n];
m_ViewID = viewID;
m_Textures = new RenderTexture[n];
m_Identifiers = new RenderTargetIdentifier[n];
this.lightingRTEX[i] = new RenderTexture(w, h, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear);
this.lightingRTEX[i].hideFlags = HideFlags.HideAndDontSave;
this.lightingRTEX[i].filterMode = FilterMode.Trilinear; // Custom
this.lightingRTEX[i].dimension = TextureDimension.Tex3D; // TODO: request the thick 3D tiling layout
this.lightingRTEX[i].volumeDepth = d;
this.lightingRTEX[i].enableRandomWrite = true;
this.lightingRTEX[i].name = CoreUtils.GetRenderTargetAutoName(w, h, RenderTextureFormat.ARGBHalf, String.Format("Volumetric{0}", i));
this.lightingRTEX[i].Create();
this.lightingRTID[i] = new RenderTargetIdentifier(this.lightingRTEX[i]);
m_Textures[i] = new RenderTexture(w, h, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear);
m_Textures[i].hideFlags = HideFlags.HideAndDontSave;
m_Textures[i].filterMode = FilterMode.Trilinear; // Custom
m_Textures[i].dimension = TextureDimension.Tex3D; // TODO: request the thick 3D tiling layout
m_Textures[i].volumeDepth = d;
m_Textures[i].enableRandomWrite = true;
m_Textures[i].name = CoreUtils.GetRenderTargetAutoName(w, h, RenderTextureFormat.ARGBHalf, String.Format("VBuffer{0}", i));
m_Textures[i].Create();
// TODO: clear the texture. Clearing 3D textures does not appear to work right now.
m_Identifiers[i] = new RenderTargetIdentifier(m_Textures[i]);
if (this.lightingRTEX != null)
if (m_Textures != null)
for (int i = 0, n = this.lightingRTEX.Length; i < n; i++)
for (int i = 0, n = m_Textures.Length; i < n; i++)
if (this.lightingRTEX[i] != null)
if (m_Textures[i] != null)
this.lightingRTEX[i].Release();
m_Textures[i].Release();
this.viewID = -1;
this.lightingRTEX = null;
this.lightingRTID = null;
m_ViewID = -1;
m_Textures = null;
m_Identifiers = null;
}
public void GetResolution(ref int w, ref int h, ref int d)
{
Debug.Assert(m_Textures != null);
Debug.Assert(m_Textures[0] != null);
Debug.Assert(m_Identifiers != null);
w = m_Textures[0].width;
h = m_Textures[0].height;
d = m_Textures[0].volumeDepth;
}
public long GetViewID()
{
return m_ViewID;
}
public bool IsValid()
{
return m_ViewID >= 0 && m_Textures != null && m_Textures[0] != null;
ComputeShader m_VolumeVoxelizationCS = null;
List<VBuffer> m_VBuffers = null;
List<OrientedBBox> m_VisibleVolumes = null;
List<VolumeProperties> m_VisibleVolumeProperties = null;
public const int k_MaxVisibleVolumeCount = 512;
List<VBuffer> m_VBuffers = null;
List<OrientedBBox> m_VisibleVolumeBounds = null;
List<DensityVolumeProperties> m_VisibleVolumeProperties = null;
public const int k_MaxVisibleVolumeCount = 512;
static ComputeBuffer s_VisibleVolumesBuffer = null;
static ComputeBuffer s_VisibleVolumeBoundsBuffer = null;
const float k_LogScale = 0.5f;
const float k_LogScale = 0.5f; // Tweak constant, controls the logarithmic depth distribution
m_VolumeVoxelizationCS = asset.renderPipelineResources.volumeVoxelizationCS;
m_VisibleVolumes = new List<OrientedBBox>();
m_VisibleVolumeProperties = new List<VolumeProperties>();
s_VisibleVolumesBuffer = new ComputeBuffer(k_MaxVisibleVolumeCount, System.Runtime.InteropServices.Marshal.SizeOf(typeof(OrientedBBox)));
s_VisibleVolumePropertiesBuffer = new ComputeBuffer(k_MaxVisibleVolumeCount, System.Runtime.InteropServices.Marshal.SizeOf(typeof(VolumeProperties)));
m_VisibleVolumeBounds = new List<OrientedBBox>();
m_VisibleVolumeProperties = new List<DensityVolumeProperties>();
s_VisibleVolumeBoundsBuffer = new ComputeBuffer(k_MaxVisibleVolumeCount, System.Runtime.InteropServices.Marshal.SizeOf(typeof(OrientedBBox)));
s_VisibleVolumePropertiesBuffer = new ComputeBuffer(k_MaxVisibleVolumeCount, System.Runtime.InteropServices.Marshal.SizeOf(typeof(DensityVolumeProperties)));
}
public void Cleanup()

m_VolumeVoxelizationCS = null;
m_VolumetricLightingCS = null;
for (int i = 0, n = m_VBuffers.Count; i < n; i++)

m_VBuffers = null;
m_VisibleVolumes = null;
m_VisibleVolumeBounds = null;
CoreUtils.SafeRelease(s_VisibleVolumesBuffer);
CoreUtils.SafeRelease(s_VisibleVolumeBoundsBuffer);
CoreUtils.SafeRelease(s_VisibleVolumePropertiesBuffer);
}

if (vBuffer != null)
{
Debug.Assert(vBuffer.lightingRTEX != null);
Debug.Assert(vBuffer.lightingRTEX[0] != null);
Debug.Assert(vBuffer.lightingRTID != null);
int width = 0, height = 0, depth = 0;
vBuffer.GetResolution(ref width, ref height, ref depth);
if (w == vBuffer.lightingRTEX[0].width &&
h == vBuffer.lightingRTEX[0].height &&
d == vBuffer.lightingRTEX[0].volumeDepth)
if (w == width && h == height && d == depth)
{
// Everything matches, nothing to do here.
return;

for (int i = 0; i < n; i++)
{
// Check whether domain reload killed it...
if (viewID == m_VBuffers[i].viewID && m_VBuffers[i].lightingRTEX != null && m_VBuffers[i].lightingRTEX[0] != null)
if (viewID == m_VBuffers[i].GetViewID() && m_VBuffers[i].IsValid())
{
vBuffer = m_VBuffers[i];
}

HomogeneousDensityVolume globalVolume = HomogeneousDensityVolume.GetGlobalHomogeneousDensityVolume();
// TODO: may want to cache these results somewhere.
VolumeProperties globalVolumeProperties = (globalVolume != null) ? globalVolume.volumeParameters.GetProperties()
: VolumeProperties.GetNeutralVolumeProperties();
DensityVolumeProperties globalVolumeProperties = (globalVolume != null) ? globalVolume.parameters.GetProperties()
: DensityVolumeProperties.GetNeutralProperties();
float asymmetry = globalVolume != null ? globalVolume.volumeParameters.asymmetry : 0;
float asymmetry = globalVolume != null ? globalVolume.parameters.asymmetry : 0;
int w = 0, h = 0, d = 0;
ComputeVBufferResolutionAndScale(preset, (int)camera.screenSize.x, (int)camera.screenSize.y, ref w, ref h, ref d);
int w = 0, h = 0, d = 0;
vBuffer.GetResolution(ref w, ref h, ref d);
SetPreconvolvedAmbientLightProbe(cmd, asymmetry);
cmd.SetGlobalVector( HDShaderIDs._VBufferResolution, new Vector4(w, h, 1.0f / w, 1.0f / h));
cmd.SetGlobalVector( HDShaderIDs._VBufferSliceCount, new Vector4(d, 1.0f / d));

}
public void VoxelizeDensityVolumes(HDCamera camera, CommandBuffer cmd)
public DensityVolumeList PrepareVisibleDensityVolumeList(HDCamera camera, CommandBuffer cmd)
if (preset == VolumetricLightingPreset.Off) return;
DensityVolumeList densityVolumes = new DensityVolumeList();
Vector3 camPosition = camera.camera.transform.position;
Vector3 camOffset = Vector3.zero; // World-origin-relative
if (preset == VolumetricLightingPreset.Off) return densityVolumes;
if (ShaderConfig.s_CameraRelativeRendering != 0)
using (new ProfilingSample(cmd, "Prepare Visible Density Volume List"))
camOffset = -camPosition; // Camera-relative
}
Vector3 camPosition = camera.camera.transform.position;
Vector3 camOffset = Vector3.zero; // World-origin-relative
m_VisibleVolumes.Clear();
m_VisibleVolumeProperties.Clear();
if (ShaderConfig.s_CameraRelativeRendering != 0)
{
camOffset = camPosition; // Camera-relative
}
// Collect all the visible volume data, and upload it to the GPU.
HomogeneousDensityVolume[] volumes = Object.FindObjectsOfType(typeof(HomogeneousDensityVolume)) as HomogeneousDensityVolume[];
m_VisibleVolumeBounds.Clear();
m_VisibleVolumeProperties.Clear();
foreach (HomogeneousDensityVolume volume in volumes)
{
// Only test active finite volumes.
if (volume.enabled && volume.volumeParameters.IsLocalVolume())
// Collect all visible finite volume data, and upload it to the GPU.
HomogeneousDensityVolume[] volumes = Object.FindObjectsOfType(typeof(HomogeneousDensityVolume)) as HomogeneousDensityVolume[];
for (int i = 0; i < Math.Min(volumes.Length, k_MaxVisibleVolumeCount); i++)
// TODO: cache these?
var obb = OrientedBBox.Create(volume.transform);
HomogeneousDensityVolume volume = volumes[i];
// Frustum cull on the CPU for now. TODO: do it on the GPU.
if (GeometryUtils.Overlap(obb, camOffset, camera.frustum, 6, 8))
// Only test active finite volumes.
if (volume.enabled && volume.parameters.IsLocalVolume())
var properties = volume.volumeParameters.GetProperties();
var obb = OrientedBBox.Create(volume.transform);
m_VisibleVolumes.Add(obb);
m_VisibleVolumeProperties.Add(properties);
// Handle camera-relative rendering.
obb.center -= camOffset;
// Frustum cull on the CPU for now. TODO: do it on the GPU.
if (GeometryUtils.Overlap(obb, camera.frustum, 6, 8))
{
// TODO: cache these?
var properties = volume.parameters.GetProperties();
m_VisibleVolumeBounds.Add(obb);
m_VisibleVolumeProperties.Add(properties);
}
s_VisibleVolumeBoundsBuffer.SetData(m_VisibleVolumeBounds);
s_VisibleVolumePropertiesBuffer.SetData(m_VisibleVolumeProperties);
// Fill the struct with pointers in order to share the data with the light loop.
densityVolumes.bounds = m_VisibleVolumeBounds;
densityVolumes.properties = m_VisibleVolumeProperties;
return densityVolumes;
}
s_VisibleVolumesBuffer.SetData(m_VisibleVolumes);
s_VisibleVolumePropertiesBuffer.SetData(m_VisibleVolumeProperties);
public void VolumeVoxelizationPass(DensityVolumeList densityVolumes, HDCamera camera, CommandBuffer cmd, FrameSettings settings)
{
if (preset == VolumetricLightingPreset.Off) return;
using (new ProfilingSample(cmd, "Volume Voxelization"))
{
int numVisibleVolumes = m_VisibleVolumeBounds.Count;
if (numVisibleVolumes == 0)
{
// Clear the render target instead of running the shader.
// CoreUtils.SetRenderTarget(cmd, vBuffer.GetDensityBuffer(), ClearFlag.Color, CoreUtils.clearColorAllBlack);
// return;
// Clearing 3D textures does not seem to work!
// Use the workaround by running the full shader with 0 density.
}
VBuffer vBuffer = FindVBuffer(camera.GetViewID());
Debug.Assert(vBuffer != null);
int w = 0, h = 0, d = 0;
vBuffer.GetResolution(ref w, ref h, ref d);
bool enableClustered = settings.lightLoopSettings.enableTileAndCluster;
int kernel = m_VolumeVoxelizationCS.FindKernel(enableClustered ? "VolumeVoxelizationClustered"
: "VolumeVoxelizationBruteforce");
float vFoV = camera.camera.fieldOfView * Mathf.Deg2Rad;
Vector4 resolution = new Vector4(w, h, 1.0f / w, 1.0f / h);
Matrix4x4 transform = HDUtils.ComputePixelCoordToWorldSpaceViewDirectionMatrix(vFoV, resolution, camera.viewMatrix, false);
camera.SetupComputeShader( m_VolumeVoxelizationCS, cmd);
cmd.SetComputeTextureParam(m_VolumeVoxelizationCS, kernel, HDShaderIDs._VBufferDensity, vBuffer.GetDensityBuffer());
cmd.SetComputeBufferParam( m_VolumeVoxelizationCS, kernel, HDShaderIDs._VolumeBounds, s_VisibleVolumeBoundsBuffer);
cmd.SetComputeBufferParam( m_VolumeVoxelizationCS, kernel, HDShaderIDs._VolumeProperties, s_VisibleVolumePropertiesBuffer);
// TODO: set the constant buffer data only once.
cmd.SetComputeMatrixParam( m_VolumeVoxelizationCS, HDShaderIDs._VBufferCoordToViewDirWS, transform);
cmd.SetComputeIntParam( m_VolumeVoxelizationCS, HDShaderIDs._NumVisibleDensityVolumes, numVisibleVolumes);
// The shader defines GROUP_SIZE_1D = 8.
cmd.DispatchCompute(m_VolumeVoxelizationCS, kernel, (w + 7) / 8, (h + 7) / 8, 1);
}
}
// Ref: https://en.wikipedia.org/wiki/Close-packing_of_equal_spheres

return coords;
}
public void VolumetricLightingPass(HDCamera camera, CommandBuffer cmd, FrameSettings frameSettings)
public void VolumetricLightingPass(HDCamera camera, CommandBuffer cmd, FrameSettings settings)
{
if (preset == VolumetricLightingPreset.Off) return;

Debug.Assert(vBuffer != null);
HomogeneousDensityVolume globalVolume = HomogeneousDensityVolume.GetGlobalHomogeneousDensityVolume();
float asymmetry = globalVolume != null ? globalVolume.volumeParameters.asymmetry : 0;
float asymmetry = globalVolume != null ? globalVolume.parameters.asymmetry : 0;
// CoreUtils.SetRenderTarget(cmd, GetVBufferLightingIntegral(viewOffset), ClearFlag.Color, CoreUtils.clearColorAllBlack);
// CoreUtils.SetRenderTarget(cmd, vBuffer.GetLightingIntegralBuffer(), ClearFlag.Color, CoreUtils.clearColorAllBlack);
// CoreUtils.SetRenderTarget(cmd, vBuffer.GetLightingFeedbackBuffer(), ClearFlag.Color, CoreUtils.clearColorAllBlack);
// Use the workaround by running the full shader with no volume.
// Use the workaround by running the full shader with 0 density.
bool enableClustered = frameSettings.lightLoopSettings.enableTileAndCluster;
// Only available in the Play Mode because all the frame counters in the Edit Mode are broken.
bool enableClustered = settings.lightLoopSettings.enableTileAndCluster;
bool enableReprojection = Application.isPlaying && camera.camera.cameraType == CameraType.Game;
int kernel;

// Only available in the Play Mode because all the frame counters in the Edit Mode are broken.
: "VolumetricLightingAllLightsReproj");
: "VolumetricLightingBruteforceReproj");
: "VolumetricLightingAllLights");
: "VolumetricLightingBruteforce");
ComputeVBufferResolutionAndScale(preset, (int)camera.screenSize.x, (int)camera.screenSize.y, ref w, ref h, ref d);
vBuffer.GetResolution(ref w, ref h, ref d);
// Compose the matrix which allows us to compute the world space view direction.
float vFoV = camera.camera.fieldOfView * Mathf.Deg2Rad;

Vector4 offset = new Vector4(xySeq[sampleIndex].x, xySeq[sampleIndex].y, zSeq[sampleIndex], rfc);
// TODO: set 'm_VolumetricLightingPreset'.
cmd.SetComputeFloatParam( m_VolumetricLightingCS, HDShaderIDs._CornetteShanksConstant, CornetteShanksPhasePartConstant(asymmetry));
cmd.SetComputeVectorParam( m_VolumetricLightingCS, HDShaderIDs._VBufferSampleOffset, offset);
// TODO: set the constant buffer data only once.
cmd.SetComputeVectorParam( m_VolumetricLightingCS, HDShaderIDs._VBufferSampleOffset, offset);
cmd.SetComputeFloatParam( m_VolumetricLightingCS, HDShaderIDs._CornetteShanksConstant, CornetteShanksPhasePartConstant(asymmetry));
cmd.SetComputeTextureParam(m_VolumetricLightingCS, kernel, HDShaderIDs._VBufferDensity, vBuffer.GetDensityBuffer()); // Read
cmd.SetComputeTextureParam(m_VolumetricLightingCS, kernel, HDShaderIDs._VBufferLightingIntegral, vBuffer.GetLightingIntegralBuffer()); // Write
if (enableReprojection)
{

// The shader defines GROUP_SIZE_1D = 16.
cmd.DispatchCompute(m_VolumetricLightingCS, kernel, (w + 15) / 16, (h + 15) / 16, 1);
// The shader defines GROUP_SIZE_1D = 8.
cmd.DispatchCompute(m_VolumetricLightingCS, kernel, (w + 7) / 8, (h + 7) / 8, 1);
}
}
} // class VolumetricLightingModule

10
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/VolumetricLighting.cs.hlsl


#ifndef VOLUMETRICLIGHTING_CS_HLSL
#define VOLUMETRICLIGHTING_CS_HLSL
// Generated from UnityEngine.Experimental.Rendering.HDPipeline.VolumeProperties
// Generated from UnityEngine.Experimental.Rendering.HDPipeline.DensityVolumeProperties
struct VolumeProperties
struct DensityVolumeProperties
{
float3 scattering;
float extinction;

// Accessors for UnityEngine.Experimental.Rendering.HDPipeline.VolumeProperties
// Accessors for UnityEngine.Experimental.Rendering.HDPipeline.DensityVolumeProperties
float3 GetScattering(VolumeProperties value)
float3 GetScattering(DensityVolumeProperties value)
float GetExtinction(VolumeProperties value)
float GetExtinction(DensityVolumeProperties value)
{
return value.extinction;
}

1
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/DBufferManager.cs


if (frameSettings.enableDBuffer)
{
cmd.SetGlobalInt(HDShaderIDs._EnableDBuffer, vsibleDecalCount > 0 ? 1 : 0);
cmd.SetGlobalVector(HDShaderIDs._DecalAtlasResolution, new Vector2(DecalSystem.kDecalAtlasSize, DecalSystem.kDecalAtlasSize));
BindBufferAsTextures(cmd);
}
else

1
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/Decal.hlsl


CBUFFER_START(UnityDecalParameters)
uint _EnableDBuffer;
float2 _DecalAtlasResolution;
CBUFFER_END
UNITY_INSTANCING_BUFFER_START(Decal)

44
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Decal/DecalUtilities.hlsl


// Caution: We can't compute LOD inside a dynamic loop. The gradient are not accessible.
// we need to find a way to calculate mips. For now just fetch first mip of the decals
void ApplyBlendNormal(inout float4 dst, inout int matMask, float2 texCoords, int sliceIndex, int mapMask, float3x3 decalToWorld, float blend)
void ApplyBlendNormal(inout float4 dst, inout int matMask, float2 texCoords, int sliceIndex, int mapMask, float3x3 decalToWorld, float blend, float lod)
src.xyz = mul(decalToWorld, UnpackNormalmapRGorAG(SAMPLE_TEXTURE2D_ARRAY_LOD(_DecalAtlas, sampler_DecalAtlas, texCoords, sliceIndex, 0 /* ComputeTextureLOD(texCoords) */))) * 0.5f + 0.5f;
src.xyz = mul(decalToWorld, UnpackNormalmapRGorAG(SAMPLE_TEXTURE2D_ARRAY_LOD(_DecalAtlas, sampler_DecalAtlas, texCoords, sliceIndex, lod))) * 0.5f + 0.5f;
src.w = blend;
dst.xyz = src.xyz * src.w + dst.xyz * (1.0f - src.w);
dst.w = dst.w * (1.0f - src.w);

void ApplyBlendDiffuse(inout float4 dst, inout int matMask, float2 texCoords, int sliceIndex, int mapMask, float blend)
void ApplyBlendDiffuse(inout float4 dst, inout int matMask, float2 texCoords, int sliceIndex, int mapMask, float blend, float lod)
float4 src = SAMPLE_TEXTURE2D_ARRAY_LOD(_DecalAtlas, sampler_DecalAtlas, texCoords, sliceIndex, 0 /* ComputeTextureLOD(texCoords) */);
float4 src = SAMPLE_TEXTURE2D_ARRAY_LOD(_DecalAtlas, sampler_DecalAtlas, texCoords, sliceIndex, lod);
src.w *= blend;
dst.xyz = src.xyz * src.w + dst.xyz * (1.0f - src.w);
dst.w = dst.w * (1.0f - src.w);

void ApplyBlendMask(inout float4 dst, inout int matMask, float2 texCoords, int sliceIndex, int mapMask, float blend)
void ApplyBlendMask(inout float4 dst, inout int matMask, float2 texCoords, int sliceIndex, int mapMask, float blend, float lod)
float4 src = SAMPLE_TEXTURE2D_ARRAY_LOD(_DecalAtlas, sampler_DecalAtlas, texCoords, sliceIndex, 0 /* ComputeTextureLOD(texCoords) */);
float4 src = SAMPLE_TEXTURE2D_ARRAY_LOD(_DecalAtlas, sampler_DecalAtlas, texCoords, sliceIndex, lod);
src.z = src.w;
src.w = blend;
dst.xyz = src.xyz * src.w + dst.xyz * (1.0f - src.w);

#endif
float3 positionWS = GetAbsolutePositionWS(posInput.positionWS);
uint i = 0;
UNITY_LOOP
for (i = 0; i < decalCount; i++)
{
DecalData decalData = FetchDecal(decalStart, i);

int diffuseIndex = decalData.normalToWorld[1][3];
int normalIndex = decalData.normalToWorld[2][3];
int maskIndex = decalData.normalToWorld[3][3];
if((all(positionDS.xyz > 0.0f) && all(1.0f - positionDS.xyz > 0.0f))) // clip to decal space
float lod = ComputeTextureLOD(positionDS.xz, _DecalAtlasResolution);
decalBlend = ((all(positionDS.xyz > 0.0f) && all(1.0f - positionDS.xyz > 0.0f))) ? decalBlend : 0; // use blend of 0 instead of an 'if' because compiler moves the lod calculation inside the 'if' which causes incorrect values
// if any of the pixels in the 2x2 quad gets rejected
// Verified that lod calculation works with a test texture, looking at the shader code in Razor the lod calculation is outside the dynamic branches where the texture fetch happens,
// however compiler was placing it inside the branch that was rejecting the pixel, which was causing incorrect lod to be calculated for any 2x2 quad where any of the pixels were rejected,
// so had to use alpha blend of 0 instead of branching to solve that issue."
if(diffuseIndex != -1)
if(diffuseIndex != -1)
{
ApplyBlendDiffuse(DBuffer0, mask, positionDS.xz, diffuseIndex, DBUFFERHTILEBIT_DIFFUSE, decalBlend);
}
ApplyBlendDiffuse(DBuffer0, mask, positionDS.xz, diffuseIndex, DBUFFERHTILEBIT_DIFFUSE, decalBlend, lod);
}
if(normalIndex != -1)
{
ApplyBlendNormal(DBuffer1, mask, positionDS.xz, normalIndex, DBUFFERHTILEBIT_NORMAL, (float3x3)decalData.normalToWorld, decalBlend);
}
if(normalIndex != -1)
{
ApplyBlendNormal(DBuffer1, mask, positionDS.xz, normalIndex, DBUFFERHTILEBIT_NORMAL, (float3x3)decalData.normalToWorld, decalBlend, lod);
}
if(maskIndex != -1)
{
ApplyBlendMask(DBuffer2, mask, positionDS.xz, maskIndex, DBUFFERHTILEBIT_MASK, decalBlend);
}
if(maskIndex != -1)
{
ApplyBlendMask(DBuffer2, mask, positionDS.xz, maskIndex, DBUFFERHTILEBIT_MASK, decalBlend, lod);
}
}
#else

20
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/Lit.hlsl


#endif
}
// This function is similar to ApplyDebugToSurfaceData but for BSDFData
void ApplyDebugToBSDFData(inout BSDFData bsdfData)
{
#ifdef DEBUG_DISPLAY
// Override value if requested by user
// this can be use also in case of debug lighting mode like specular only
bool overrideSpecularColor = _DebugLightingSpecularColor.x != 0.0;
if (overrideSpecularColor)
{
float3 overrideSpecularColor = _DebugLightingSpecularColor.yzw;
bsdfData.fresnel0 = overrideSpecularColor;
}
#endif
}
SSSData ConvertSurfaceDataToSSSData(SurfaceData surfaceData)
{
SSSData sssData;

FillMaterialTransparencyData( surfaceData.baseColor, surfaceData.metallic, surfaceData.ior, surfaceData.transmittanceColor, surfaceData.atDistance,
surfaceData.thickness, surfaceData.transmittanceMask, bsdfData);
#endif
ApplyDebugToBSDFData(bsdfData);
return bsdfData;
}

// perceptualRoughness is not clamped, and is meant to be used for IBL.
// perceptualRoughness can be modify by FillMaterialClearCoatData, so ConvertAnisotropyToClampRoughness must be call after
ConvertAnisotropyToClampRoughness(bsdfData.perceptualRoughness, bsdfData.anisotropy, bsdfData.roughnessT, bsdfData.roughnessB);
ApplyDebugToBSDFData(bsdfData);
return pixelFeatureFlags;
}

4
ScriptableRenderPipeline/HDRenderPipeline/HDRP/RenderPipelineResources/HDRenderPipelineResources.asset


type: 3}
deferredDirectionalShadowComputeShader: {fileID: 7200000, guid: fbde6fae193b2a94e9fd97c163c204f4,
type: 3}
volumetricLightingCS: {fileID: 7200000, guid: 799166e2ee6a4b041bba9e74f6942097,
volumeVoxelizationCS: {fileID: 7200000, guid: c20b371db720da244b73830ec74a343a,
type: 3}
volumetricLightingCS: {fileID: 7200000, guid: b4901a10df2d1e24282725e9fbc77c97,
type: 3}
subsurfaceScatteringCS: {fileID: 7200000, guid: b06a7993621def248addd55d0fe931b1,
type: 3}

1
ScriptableRenderPipeline/HDRenderPipeline/HDRP/RenderPipelineResources/RenderPipelineResources.cs


public ComputeShader buildMaterialFlagsShader;
public ComputeShader deferredComputeShader;
public ComputeShader deferredDirectionalShadowComputeShader;
public ComputeShader volumeVoxelizationCS;
public ComputeShader volumetricLightingCS;
public ComputeShader subsurfaceScatteringCS; // Disney SSS

1
ScriptableRenderPipeline/HDRenderPipeline/HDRP/ShaderPass/ShaderPass.cs


LightTransport,
Shadows,
SubsurfaceScattering,
VolumeVoxelization,
VolumetricLighting,
DBuffer
}

5
ScriptableRenderPipeline/HDRenderPipeline/HDRP/ShaderPass/ShaderPass.cs.hlsl


#define SHADERPASS_LIGHT_TRANSPORT (7)
#define SHADERPASS_SHADOWS (8)
#define SHADERPASS_SUBSURFACE_SCATTERING (9)
#define SHADERPASS_VOLUMETRIC_LIGHTING (10)
#define SHADERPASS_DBUFFER (11)
#define SHADERPASS_VOLUME_VOXELIZATION (10)
#define SHADERPASS_VOLUMETRIC_LIGHTING (11)
#define SHADERPASS_DBUFFER (12)
#endif

6
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Shadows/HDShadowSettings.cs


m_CascadeShadowBorders[1] = cascadeShadowBorder1;
m_CascadeShadowBorders[2] = cascadeShadowBorder2;
m_CascadeShadowBorders[3] = cascadeShadowBorder3;
// For now we don't use shadow cascade borders but we still want to have the last split fading out.
if(!LightLoop.s_UseCascadeBorders)
{
m_CascadeShadowBorders[cascadeShadowSplitCount - 1] = 0.2f;
}
return m_CascadeShadowBorders;
}
}

8
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Sky/SkyManager.cs


m_SkyRenderingContext.Cleanup();
}
public bool IsSkyValid()
public bool IsLightingSkyValid()
public bool IsVisualSkyValid()
{
return m_VisualSky.IsValid();
}
void BlitCubemap(CommandBuffer cmd, Cubemap source, RenderTexture dest)
{

m_UpdateRequired = false;
SetGlobalSkyTexture(cmd);
if (IsSkyValid())
if (IsLightingSkyValid())
{
cmd.SetGlobalInt(HDShaderIDs._EnvLightSkyEnabled, 1);
}

50
ScriptableRenderPipeline/LightweightPipeline/LWRP/LightweightPipeline.cs


private int m_ScreenSpaceShadowMapRTID;
private Matrix4x4[] m_ShadowMatrices = new Matrix4x4[kMaxCascades + 1];
private RenderTargetIdentifier m_CurrCameraColorRT;
private RenderTargetIdentifier m_ShadowMapRT;
private RenderTexture m_ShadowMapRT;
private RenderTargetIdentifier m_ScreenSpaceShadowMapRT;
private RenderTargetIdentifier m_ColorRT;
private RenderTargetIdentifier m_CopyColorRT;

CameraRenderTargetID.depth = Shader.PropertyToID("_CameraDepthTexture");
CameraRenderTargetID.depthCopy = Shader.PropertyToID("_CameraCopyDepthTexture");
m_ShadowMapRT = new RenderTargetIdentifier(m_ShadowMapRTID);
m_ScreenSpaceShadowMapRT = new RenderTargetIdentifier(m_ScreenSpaceShadowMapRTID);
m_ColorRT = new RenderTargetIdentifier(CameraRenderTargetID.color);

if (shadows && m_ShadowSettings.screenSpace)
ShadowCollectPass(visibleLights, ref context, ref lightData, frameRenderingConfiguration);
if (!shadows)
{
var setRT = CommandBufferPool.Get("Generate Small Shadow Buffer");
if (m_ShadowSettings.screenSpace)
setRT.GetTemporaryRT(m_ScreenSpaceShadowMapRTID, 4, 4, 0, FilterMode.Bilinear, m_ShadowSettings.screenspaceShadowmapTextureFormat);
else
setRT.GetTemporaryRT(m_ShadowMapRTID, 4, 4, 0, FilterMode.Bilinear, m_ShadowSettings.shadowmapTextureFormat);
setRT.Blit(Texture2D.whiteTexture, m_ScreenSpaceShadowMapRT);
context.ExecuteCommandBuffer(setRT);
}
ForwardPass(visibleLights, frameRenderingConfiguration, ref context, ref lightData, stereoEnabled);

CopyTexture(cmd, CameraRenderTargetID.depth, BuiltinRenderTextureType.CameraTarget, m_CopyDepthMaterial, true);
#endif
cmd.ReleaseTemporaryRT(m_ShadowMapRTID);
cmd.ReleaseTemporaryRT(m_ScreenSpaceShadowMapRTID);
cmd.ReleaseTemporaryRT(CameraRenderTargetID.depthCopy);
cmd.ReleaseTemporaryRT(CameraRenderTargetID.depth);

CommandBufferPool.Release(cmd);
context.Submit();
if (m_ShadowMapRT)
{
RenderTexture.ReleaseTemporary(m_ShadowMapRT);
m_ShadowMapRT = null;
}
m_ShadowMapRT = null;
if (m_Asset.AreShadowsEnabled() && lightData.mainLightIndex != -1)
{
VisibleLight mainLight = visibleLights[lightData.mainLightIndex];

float invShadowResolution = 1.0f / m_Asset.ShadowAtlasResolution;
float invHalfShadowResolution = 0.5f * invShadowResolution;
cmd.Clear();
cmd.SetGlobalTexture(m_ShadowMapRTID, m_ShadowMapRT);
cmd.SetGlobalMatrixArray(ShadowConstantBuffer._WorldToShadow, m_ShadowMatrices);
cmd.SetGlobalVector(ShadowConstantBuffer._ShadowData, new Vector4(light.shadowStrength, 0.0f, 0.0f, 0.0f));
cmd.SetGlobalVectorArray(ShadowConstantBuffer._DirShadowSplitSpheres, m_DirectionalShadowSplitDistances);

CoreUtils.SetKeyword(cmd, "_MIXED_LIGHTING_SUBTRACTIVE", m_MixedLightingSetup == MixedLightingSetup.Subtractive);
CoreUtils.SetKeyword(cmd, "_VERTEX_LIGHTS", vertexLightsCount > 0);
CoreUtils.SetKeyword(cmd, "SOFTPARTICLES_ON", m_RequireDepthTexture && m_Asset.RequireSoftParticles);
bool linearFogModeEnabled = false;
bool exponentialFogModeEnabled = false;
if (RenderSettings.fog)
{
if (RenderSettings.fogMode == FogMode.Linear)
linearFogModeEnabled = true;
else
exponentialFogModeEnabled = true;
}
CoreUtils.SetKeyword(cmd, "FOG_LINEAR", linearFogModeEnabled);
CoreUtils.SetKeyword(cmd, "FOG_EXP2", exponentialFogModeEnabled);
}
private void SetShadowCollectPassKeywords(CommandBuffer cmd, VisibleLight shadowLight, ref LightData lightData)

bool success = false;
var cmd = CommandBufferPool.Get("Prepare Shadowmap");
cmd.GetTemporaryRT(m_ShadowMapRTID, m_ShadowSettings.shadowAtlasWidth,
m_ShadowSettings.shadowAtlasHeight, kShadowBufferBits, FilterMode.Bilinear, m_ShadowSettings.shadowmapTextureFormat);
RenderTextureDescriptor shadowmapDescriptor = new RenderTextureDescriptor(m_ShadowSettings.shadowAtlasWidth,
m_ShadowSettings.shadowAtlasHeight, m_ShadowSettings.shadowmapTextureFormat, kShadowBufferBits);
shadowmapDescriptor.shadowSamplingMode = ShadowSamplingMode.CompareDepths;
m_ShadowMapRT = RenderTexture.GetTemporary(shadowmapDescriptor);
m_ShadowMapRT.filterMode = FilterMode.Bilinear;
m_ShadowMapRT.wrapMode = TextureWrapMode.Clamp;
// LightweightPipeline.SetRenderTarget is meant to be used with camera targets, not shadowmaps
CoreUtils.SetRenderTarget(cmd, m_ShadowMapRT, ClearFlag.Depth, CoreUtils.ConvertSRGBToActiveColorSpace(m_CurrCamera.backgroundColor));

{
cmd.SetViewport(new Rect(m_ShadowSlices[cascadeIndex].atlasX, m_ShadowSlices[cascadeIndex].atlasY,
m_ShadowSlices[cascadeIndex].shadowResolution, m_ShadowSlices[cascadeIndex].shadowResolution));
cmd.EnableScissorRect(new Rect(m_ShadowSlices[cascadeIndex].atlasX + 4, m_ShadowSlices[cascadeIndex].atlasY + 4,
m_ShadowSlices[cascadeIndex].shadowResolution - 8, m_ShadowSlices[cascadeIndex].shadowResolution - 8));
cmd.Clear();
cmd.DisableScissorRect();
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
}

17
ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/Core.hlsl


#endif
#endif
#ifndef BUMP_SCALE_NOT_SUPPORTED
#define BUMP_SCALE_NOT_SUPPORTED !SHADER_HINT_NICE_QUALITY
#endif
///////////////////////////////////////////////////////////////////////////////
#ifdef _NORMALMAP
#define OUTPUT_NORMAL(IN, OUT) OutputTangentToWorld(IN.tangent, IN.normal, OUT.tangent.xyz, OUT.binormal.xyz, OUT.normal.xyz)

void OutputTangentToWorld(half4 vertexTangent, half3 vertexNormal, out half3 tangentWS, out half3 binormalWS, out half3 normalWS)
{
// mikkts space compliant. only normalize when extracting normal at frag.
tangentWS = normalize(mul((half3x3)UNITY_MATRIX_M, vertexTangent.xyz));
tangentWS = TransformObjectToWorldDir(vertexTangent.xyz);
binormalWS = cross(normalWS, tangentWS) * sign;
}

// factor = (end-z)/(end-start) = z * (-1/(end-start)) + (end/(end-start))
float fogFactor = saturate(clipZ_01 * unity_FogParams.z + unity_FogParams.w);
return half(fogFactor);
#elif defined(FOG_EXP2)
#elif defined(FOG_EXP) || defined(FOG_EXP2)
// factor = exp(-(density*z)^2)
// -density * z computed at vertex
return half(unity_FogParams.x * clipZ_01);

void ApplyFogColor(inout half3 color, half3 fogColor, half fogFactor)
{
#if defined (FOG_LINEAR) || defined(FOG_EXP2)
#if defined(FOG_EXP2)
#if defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)
#if defined(FOG_EXP)
// factor = exp(-density*z)
// fogFactor = density*z compute at vertex
fogFactor = saturate(exp2(-fogFactor));
#elif defined(FOG_EXP2)
// factor = exp(-(density*z)^2)
// fogFactor = density*z compute at vertex
fogFactor = saturate(exp2(-fogFactor*fogFactor));

53
ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/InputBuiltin.hlsl


float4x4 unity_ObjectToWorld;
float4x4 unity_WorldToObject;
float4 unity_LODFade; // x is the fade value ranging within [0,1]. y is x quantized into 16 levels
real4 unity_LODFade; // x is the fade value ranging within [0,1]. y is x quantized into 16 levels
float4 unity_DynamicLightmapST;
float4 unity_SHAr;
float4 unity_SHAg;
float4 unity_SHAb;
float4 unity_SHBr;
float4 unity_SHBg;
float4 unity_SHBb;
float4 unity_SHC;
// x = Disabled(0)/Enabled(1)
// y = Computation are done in global space(0) or local space(1)
// z = Texel size on U texture coordinate
float4 unity_ProbeVolumeParams;
float4x4 unity_ProbeVolumeWorldToObject;
float3 unity_ProbeVolumeSizeInv;
float3 unity_ProbeVolumeMin;
real4 unity_SHAr;
real4 unity_SHAg;
real4 unity_SHAb;
real4 unity_SHBr;
real4 unity_SHBg;
real4 unity_SHBb;
real4 unity_SHC;
float4 unity_ProbesOcclusion;
real4 unity_ProbesOcclusion;
half4 unity_SpecCube0_HDR;
real4 unity_SpecCube0_HDR;
half4 unity_Lightmap_HDR;
real4 unity_Lightmap_HDR;
half4 unity_LightIndicesOffsetAndCount;
half4 unity_4LightIndices0;
half4 unity_4LightIndices1;
real4 unity_LightIndicesOffsetAndCount;
real4 unity_4LightIndices0;
real4 unity_4LightIndices1;
CBUFFER_END

#if defined(USING_STEREO_MATRICES) && defined(UNITY_STEREO_MULTIVIEW_ENABLED)
CBUFFER_START(UnityStereoEyeIndices)
float4 unity_StereoEyeIndices[2];
real4 unity_StereoEyeIndices[2];
CBUFFER_END
#endif

// ----------------------------------------------------------------------------
CBUFFER_START(UnityPerFrame)
float4 glstate_lightmodel_ambient;
float4 unity_AmbientSky;
float4 unity_AmbientEquator;
float4 unity_AmbientGround;
float4 unity_IndirectSpecColor;
real4 glstate_lightmodel_ambient;
real4 unity_AmbientSky;
real4 unity_AmbientEquator;
real4 unity_AmbientGround;
real4 unity_IndirectSpecColor;
half4 unity_FogColor;
real4 unity_FogColor;
#if !defined(USING_STEREO_MATRICES)
float4x4 glstate_matrix_projection;

int unity_StereoEyeIndex;
#endif
float4 unity_ShadowColor;
real4 unity_ShadowColor;
CBUFFER_END
// ----------------------------------------------------------------------------

19
ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/InputSurface.hlsl


#endif
CBUFFER_START(UnityPerMaterial)
half4 _MainTex_ST;
float4 _MainTex_ST;
half4 _SpecColor;
half4 _EmissionColor;
half _SmoothnessTextureChannel;
half4 _SpecColor;
half4 _EmissionColor;
TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex);
TEXTURE2D(_MetallicGlossMap); SAMPLER(sampler_MetallicGlossMap);
TEXTURE2D(_SpecGlossMap); SAMPLER(sampler_SpecGlossMap);
TEXTURE2D(_BumpMap); SAMPLER(sampler_BumpMap);
TEXTURE2D(_OcclusionMap); SAMPLER(sampler_OcclusionMap);
TEXTURE2D(_EmissionMap); SAMPLER(sampler_EmissionMap);
TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex);
TEXTURE2D(_MetallicGlossMap); SAMPLER(sampler_MetallicGlossMap);
TEXTURE2D(_SpecGlossMap); SAMPLER(sampler_SpecGlossMap);
TEXTURE2D(_BumpMap); SAMPLER(sampler_BumpMap);
TEXTURE2D(_OcclusionMap); SAMPLER(sampler_OcclusionMap);
TEXTURE2D(_EmissionMap); SAMPLER(sampler_EmissionMap);
// Must match Lightweigth ShaderGraph master node
struct SurfaceData

19
ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/Lighting.hlsl


half roughness;
half roughness2;
half grazingTerm;
// We save some light invariant BRDF terms so we don't have to recompute
// them in the light loop. Take a look at DirectBRDF function for detailed explaination.
half normalizationTerm; // roughness * 4.0 + 2.0
half roughness2MinusOne; // roughness² - 1.0
};
half ReflectivitySpecular(half3 specular)

outBRDFData.roughness = PerceptualRoughnessToRoughness(outBRDFData.perceptualRoughness);
outBRDFData.roughness2 = outBRDFData.roughness * outBRDFData.roughness;
outBRDFData.normalizationTerm = outBRDFData.roughness * 4.0h + 2.0h;
outBRDFData.roughness2MinusOne = outBRDFData.roughness2 - 1.0h;
#ifdef _ALPHAPREMULTIPLY_ON
outBRDFData.diffuse *= alpha;
alpha = alpha * oneMinusReflectivity + reflectivity;

half LoH = saturate(dot(lightDirectionWS, halfDir));
// GGX Distribution multiplied by combined approximation of Visibility and Fresnel
// BRDFspec = (D * V * F) / 4.0
// D = roughness² / ( NoH² * (roughness² - 1) + 1 )²
// V * F = 1.0 / ( LoH² * (roughness + 0.5) )
half d = NoH * NoH * (brdfData.roughness2 - 1.h) + 1.00001h;
// Final BRDFspec = roughness² / ( NoH² * (roughness² - 1) + 1 )² * (LoH² * (roughness + 0.5) * 4.0)
// We further optimize a few light invariant terms
// brdfData.normalizationTerm = (roughness + 0.5) * 4.0 rewritten as roughness * 4.0 + 2.0 to a fit a MAD.
half d = NoH * NoH * brdfData.roughness2MinusOne + 1.00001h;
half specularTerm = brdfData.roughness2 / ((d * d) * max(0.1h, LoH2) * (brdfData.roughness + 0.5h) * 4);
half specularTerm = brdfData.roughness2 / ((d * d) * max(0.1h, LoH2) * brdfData.normalizationTerm);
// on mobiles (where half actually means something) denominator have risk of overflow
// clamp below was added specifically to "fix" that, but dx compiler (we convert bytecode to metal/gles)

66
ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/LightweightPassLit.hlsl


half4 fogFactorAndVertexLight : TEXCOORD6; // x: fogFactor, yzw: vertex light
#ifdef _SHADOWS_ENABLED
#endif
float4 clipPos : SV_POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID

#endif
inputData.viewDirectionWS = FragmentViewDirWS(viewDir);
#ifdef _SHADOWS_ENABLED
#else
inputData.shadowCoord = float4(0, 0, 0, 0);
#endif
inputData.fogCoord = IN.fogFactorAndVertexLight.x;
inputData.vertexLighting = IN.fogFactorAndVertexLight.yzw;
inputData.bakedGI = SAMPLE_GI(IN.lightmapUV, IN.vertexSH, inputData.normalWS);

// Vertex and Fragment functions //
///////////////////////////////////////////////////////////////////////////////
// Vertex: Used for Standard and StandardSimpleLighting shaders
// Used in Standard (Physically Based) shader
LightweightVertexOutput LitPassVertex(LightweightVertexInput v)
{
LightweightVertexOutput o = (LightweightVertexOutput)0;

o.uv = TransformMainTextureCoord(v.texcoord);
o.posWSShininess.xyz = TransformObjectToWorld(v.vertex.xyz);
o.posWSShininess.w = _Shininess * 128.0;
o.clipPos = TransformWorldToHClip(o.posWSShininess.xyz);
half3 viewDir = VertexViewDirWS(GetCameraPositionWS() - o.posWSShininess.xyz);

half fogFactor = ComputeFogFactor(o.clipPos.z);
o.fogFactorAndVertexLight = half4(fogFactor, vertexLight);
#ifdef _SHADOWS_ENABLED
#endif
// Used for Standard shader
// Used in Standard (Physically Based) shader
half4 LitPassFragment(LightweightVertexOutput IN) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(IN);

ApplyFog(color.rgb, inputData.fogCoord);
return color;
}
// Used in Standard (Simple Lighting) shader
// TODO: we only need to specialise this because of _Shininess prop
// Once we refactor SimpleLighting shader we will be able to share vertex
// between PBS and Simple
LightweightVertexOutput LitPassVertexSimple(LightweightVertexInput v)
{
LightweightVertexOutput o = (LightweightVertexOutput)0;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_TRANSFER_INSTANCE_ID(v, o);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
o.uv = TransformMainTextureCoord(v.texcoord);
o.posWSShininess.xyz = TransformObjectToWorld(v.vertex.xyz);
o.posWSShininess.w = _Shininess * 128.0;
o.clipPos = TransformWorldToHClip(o.posWSShininess.xyz);
half3 viewDir = VertexViewDirWS(GetCameraPositionWS() - o.posWSShininess.xyz);
#ifdef _NORMALMAP
o.normal.w = viewDir.x;
o.tangent.w = viewDir.y;
o.binormal.w = viewDir.z;
#else
o.viewDir = viewDir;
#endif
// initializes o.normal and if _NORMALMAP also o.tangent and o.binormal
OUTPUT_NORMAL(v, o);
// We either sample GI from lightmap or SH.
// Lightmap UV and vertex SH coefficients use the same interpolator ("float2 lightmapUV" for lightmap or "half3 vertexSH" for SH)
// see DECLARE_LIGHTMAP_OR_SH macro.
// The following funcions initialize the correct variable with correct data
OUTPUT_LIGHTMAP_UV(v.lightmapUV, unity_LightmapST, o.lightmapUV);
OUTPUT_SH(o.normal.xyz, o.vertexSH);
half3 vertexLight = VertexLighting(o.posWSShininess.xyz, o.normal.xyz);
half fogFactor = ComputeFogFactor(o.clipPos.z);
o.fogFactorAndVertexLight = half4(fogFactor, vertexLight);
#ifdef _SHADOWS_ENABLED
#if SHADOWS_SCREEN
o.shadowCoord = ComputeShadowCoord(o.clipPos);
#else
o.shadowCoord = TransformWorldToShadowCoord(o.posWSShininess.xyz);
#endif
#endif
return o;
}
// Used for StandardSimpleLighting shader

15
ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/LightweightPassMeta.hlsl


float2 uv : TEXCOORD0;
};
float4 MetaVertexPosition(float4 vertex, float2 uv1, float2 uv2, float4 lightmapST, float4 dynlightmapST)
float4 MetaVertexPosition(float4 vertex, float2 uv1, float2 uv2, float4 lightmapST)
{
if (unity_MetaVertexControl.x)
{

vertex.z = vertex.z > 0 ? 1.0e-4f : 0.0f;
}
if (unity_MetaVertexControl.y)
{
vertex.xy = uv2 * dynlightmapST.xy + dynlightmapST.zw;
// OpenGL right now needs to actually use incoming vertex position,
// so use it in a very dummy way
vertex.z = vertex.z > 0 ? 1.0e-4f : 0.0f;
vertex.z = vertex.z > 0 ? REAL_MIN : 0.0f;
}
return TransformWorldToHClip(vertex.xyz); // Need to transfer from world to clip compared to legacy
}

MetaVertexOuput LightweightVertexMeta(MetaVertexInput v)
{
MetaVertexOuput o;
o.pos = MetaVertexPosition(v.vertex, v.uv1.xy, v.uv2.xy, unity_LightmapST, unity_DynamicLightmapST);
o.uv = TRANSFORM_TEX(v.uv0, _MainTex);
o.pos = MetaVertexPosition(v.vertex, v.uv1.xy, v.uv2.xy, unity_LightmapST);
o.uv = TransformMainTextureCoord(v.uv0);
return o;
}

10
ScriptableRenderPipeline/LightweightPipeline/LWRP/ShaderLibrary/Shadows.hlsl


#define BEYOND_SHADOW_FAR(shadowCoord) shadowCoord.z >= UNITY_RAW_FAR_CLIP_VALUE
#endif
#define OUTSIDE_SHADOW_BOUNDS(shadowCoord) shadowCoord.x <= 0 || shadowCoord.x >= 1 || shadowCoord.y <= 0 || shadowCoord.y >= 1 || BEYOND_SHADOW_FAR(shadowCoord)
half GetShadowStrength()
{
return _ShadowData.x;

#endif
// Shadow coords that fall out of the light frustum volume must always return attenuation 1.0
return (OUTSIDE_SHADOW_BOUNDS(shadowCoord)) ? 1.0 : attenuation;
return BEYOND_SHADOW_FAR(shadowCoord) ? 1.0 : attenuation;
}
inline half ComputeCascadeIndex(float3 positionWS)

half RealtimeShadowAttenuation(float4 shadowCoord)
{
#if NO_SHADOWS
#ifndef _SHADOWS_ENABLED
return 1.0h;
#endif
#if defined(NO_SHADOWS)
return 1.0h;
#elif SHADOWS_SCREEN
return SampleScreenSpaceShadowMap(shadowCoord);

3
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightStandard.shader


#pragma multi_compile _ _ADDITIONAL_LIGHTS
#pragma multi_compile _ _VERTEX_LIGHTS
#pragma multi_compile _ _MIXED_LIGHTING_SUBTRACTIVE
#pragma multi_compile _ FOG_LINEAR FOG_EXP2
#pragma multi_compile _ _SHADOWS_ENABLED
#pragma multi_compile_fog
//--------------------------------------
// GPU Instancing

5
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightStandardSimpleLighting.shader


#pragma multi_compile _ _ADDITIONAL_LIGHTS
#pragma multi_compile _ _VERTEX_LIGHTS
#pragma multi_compile _ _MIXED_LIGHTING_SUBTRACTIVE
#pragma multi_compile _ FOG_LINEAR FOG_EXP2
#pragma multi_compile _ _SHADOWS_ENABLED
#pragma multi_compile_fog
#pragma vertex LitPassVertex
#pragma vertex LitPassVertexSimple
#pragma fragment LitPassFragmentSimple
#define BUMP_SCALE_NOT_SUPPORTED 1
#include "LWRP/ShaderLibrary/LightweightPassLit.hlsl"

3
ScriptableRenderPipeline/LightweightPipeline/LWRP/Shaders/LightweightStandardTerrain.shader


#pragma multi_compile _ _ADDITIONAL_LIGHTS
#pragma multi_compile _ _VERTEX_LIGHTS
#pragma multi_compile _ _MIXED_LIGHTING_SUBTRACTIVE
#pragma multi_compile _ FOG_LINEAR FOG_EXP2
#pragma multi_compile _ _SHADOWS_ENABLED
#pragma multi_compile_fog
#pragma multi_compile __ _TERRAIN_NORMAL_MAP

6
build.py


unity_package_build.copy_file_to_project("CHANGELOG.md", ".", package_path, logger)
def cleanup(logger):
logger.info("Removing temporary files:")
logger.info("Reverting temporary file changes:")
# files.append(os.path.join(folder, "package.json"))
files.append(os.path.join(folder, "package.json"))
os.remove(file)
subprocess.call(["git", "checkout", file], cwd=".")
# Prepare an empty project for editor tests
def prepare_editor_test_project(repo_path, project_path, logger):

478
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/VolumetricLighting.compute


// Definitions
//--------------------------------------------------------------------------------------------------
#pragma kernel VolumetricLightingAllLights VolumetricLighting=VolumetricLightingAllLights ENABLE_REPROJECTION=0 LIGHTLOOP_SINGLE_PASS
#pragma kernel VolumetricLightingAllLightsReproj VolumetricLighting=VolumetricLightingAllLightsReproj ENABLE_REPROJECTION=1 LIGHTLOOP_SINGLE_PASS
#pragma kernel VolumetricLightingClustered VolumetricLighting=VolumetricLightingClustered ENABLE_REPROJECTION=0 LIGHTLOOP_TILE_PASS USE_CLUSTERED_LIGHTLIST
#pragma kernel VolumetricLightingClusteredReproj VolumetricLighting=VolumetricLightingClusteredReproj ENABLE_REPROJECTION=1 LIGHTLOOP_TILE_PASS USE_CLUSTERED_LIGHTLIST
#pragma kernel VolumetricLightingBruteforce VolumetricLighting=VolumetricLightingBruteforce ENABLE_REPROJECTION=0 LIGHTLOOP_SINGLE_PASS
#pragma kernel VolumetricLightingBruteforceReproj VolumetricLighting=VolumetricLightingBruteforceReproj ENABLE_REPROJECTION=1 LIGHTLOOP_SINGLE_PASS
#pragma kernel VolumetricLightingClustered VolumetricLighting=VolumetricLightingClustered ENABLE_REPROJECTION=0 LIGHTLOOP_TILE_PASS USE_CLUSTERED_LIGHTLIST
#pragma kernel VolumetricLightingClusteredReproj VolumetricLighting=VolumetricLightingClusteredReproj ENABLE_REPROJECTION=1 LIGHTLOOP_TILE_PASS USE_CLUSTERED_LIGHTLIST
#include "../../../ShaderPass/ShaderPass.cs.hlsl"
#include "../../ShaderPass/ShaderPass.cs.hlsl"
#include "../../../ShaderConfig.cs.hlsl"
#include "../../ShaderConfig.cs.hlsl"
// E.g. for 1080p: (1920/8)x(1080/8)x(128) = 4,147,200 voxels
// E.g. for 1080p: (1920/8)x(1080/8)x(64) = 2,073,600 voxels
// E.g. for 1080p: (1920/4)x(1080/4)x(256) = 33,177,600 voxels
// E.g. for 1080p: (1920/4)x(1080/4)x(128) = 16,588,800 voxels
#define VBUFFER_TILE_SIZE 4
#define VBUFFER_SLICE_COUNT 128
#endif

#define GROUP_SIZE_1D 16
#define GROUP_SIZE_2D (GROUP_SIZE_1D * GROUP_SIZE_1D)
#define GROUP_SIZE_1D 8
#if (SHADEROPTIONS_VOLUMETRIC_LIGHTING_PRESET != 0) // Switch between the full and the empty shader

#include "CoreRP/ShaderLibrary/Common.hlsl"
#include "CoreRP/ShaderLibrary/Filtering.hlsl"
#include "CoreRP/ShaderLibrary/VolumeRendering.hlsl"
#include "CoreRP/ShaderLibrary/SpaceFillingCurves.hlsl"
#include "../../../ShaderVariables.hlsl"
#include "../VolumetricLighting.cs.hlsl"
#include "../VBuffer.hlsl"
#include "../../ShaderVariables.hlsl"
#include "VolumetricLighting.cs.hlsl"
#include "VBuffer.hlsl"
#include "../../Lighting.hlsl" // Includes Material.hlsl
#include "../../LightEvaluation.hlsl"
#include "../Lighting.hlsl" // Includes Material.hlsl
#include "../LightEvaluation.hlsl"
#pragma only_renderers d3d11 ps4 xboxone vulkan metal

RW_TEXTURE3D(float4, _VBufferLightingIntegral); // RGB = radiance, A = optical depth
RW_TEXTURE3D(float4, _VBufferLightingFeedback); // RGB = radiance, A = interval length
TEXTURE3D(_VBufferLightingHistory); // RGB = radiance, A = interval length
TEXTURE3D(_VBufferDensity); // RGB = sqrt(scattering), A = sqrt(extinction)
float4 _VBufferSampleOffset; // {x, y, z}, w = rendered frame count
float _CornetteShanksConstant; // CornetteShanksPhasePartConstant(_GlobalAsymmetry)
float4 _VBufferSampleOffset; // Not used by this shader
float _CornetteShanksConstant; // Not used by this shader
uint _NumVisibleDensityVolumes;
CBUFFER_END
//--------------------------------------------------------------------------------------------------

// Multiplication by the scattering coefficient and the phase function is performed outside.
VoxelLighting EvaluateVoxelLighting(LightLoopContext context, uint featureFlags, PositionInputs posInput, float3 centerWS,
DualRay ray, float t0, float t1, float dt, float rndVal, float extinction, float asymmetry
#ifdef LIGHTLOOP_TILE_PASS
, uint clusterIndices[2], float clusterDepths[2])
#ifdef USE_CLUSTERED_LIGHTLIST
, uint lightClusters[2])
#else
)
#endif

return lighting;
#endif
#ifdef LIGHTLOOP_TILE_PASS
// Loop over 1 or 2 light clusters.
int cluster = 0;
do
if (featureFlags & LIGHTFEATUREFLAGS_PUNCTUAL)
float tMin = max(t0, ray.strataDirInvViewZ * clusterDepths[cluster]);
float tMax = t1;
#ifdef USE_CLUSTERED_LIGHTLIST
// Iterate over all lights within 2 (not necessarily unique) clusters overlapping the voxel along Z.
// We need to skip duplicates, but it's not too difficult since lights are sorted by index.
uint lightStarts[2], lightCounts[2];
if (cluster == 0 && (clusterIndices[0] != clusterIndices[1]))
for (uint k = 0; k < 2; k++)
tMax = min(t1, ray.strataDirInvViewZ * clusterDepths[1]);
GetCountAndStartCluster(posInput.tileCoord, lightClusters[k], LIGHTCATEGORY_PUNCTUAL,
lightStarts[k], lightCounts[k]);
#else
float tMin = t0;
float tMax = t1;
#endif // LIGHTLOOP_TILE_PASS
if (featureFlags & LIGHTFEATUREFLAGS_PUNCTUAL)
uint i = 0, j = 0;
if (i < lightCounts[0] || j < lightCounts[1])
uint lightCount, lightStart;
// At least one of the clusters is non-empty.
uint lightIndices[2];
#ifdef LIGHTLOOP_TILE_PASS
GetCountAndStartCluster(posInput.tileCoord, clusterIndices[cluster], LIGHTCATEGORY_PUNCTUAL,
lightStart, lightCount);
#else
lightCount = _PunctualLightCount;
lightStart = 0;
#endif // LIGHTLOOP_TILE_PASS
// Fetch two initial indices from both clusters.
lightIndices[0] = FetchIndexWithBoundsCheck(lightStarts[0], lightCounts[0], i);
lightIndices[1] = FetchIndexWithBoundsCheck(lightStarts[1], lightCounts[1], j);
if (lightCount > 0)
// Process all punctual lights except for box lights (which are technically not even punctual).
do
LightData light = FetchLight(lightStart, 0);
// Process lights in order.
uint lightIndex = min(lightIndices[0], lightIndices[1]);
uint i = 0, last = lightCount - 1;
#else // USE_CLUSTERED_LIGHTLIST
{
uint lightIndex = 0;
// Box lights require special handling (see the next while loop).
while (i <= last && light.lightType != GPULIGHTTYPE_PROJECTOR_BOX)
{
float tEntr = tMin;
float tExit = tMax;
// Process all punctual lights except for box lights (which are technically not even punctual).
for (; lightIndex < _PunctualLightCount; lightIndex++)
{
#endif // USE_CLUSTERED_LIGHTLIST
bool sampleLight = true;
LightData light = _LightDatas[lightIndex];
// Perform ray-cone intersection for pyramid and spot lights.
if (light.lightType != GPULIGHTTYPE_POINT)
{
float lenMul = 1;
// Process box lights in a separate loop.
if (light.lightType == GPULIGHTTYPE_PROJECTOR_BOX) { break; }
if (light.lightType == GPULIGHTTYPE_PROJECTOR_PYRAMID)
{
// 'light.right' and 'light.up' vectors are pre-scaled on the CPU
// s.t. if you were to place them at the distance of 1 directly in front
// of the light, they would give you the "footprint" of the light.
// For spot lights, the cone fit is exact.
// For pyramid lights, however, this is the "inscribed" cone
// (contained within the pyramid), and we want to intersect
// the "escribed" cone (which contains the pyramid).
// Therefore, we have to scale the radii by the sqrt(2).
lenMul = rsqrt(2);
}
float tEntr = t0;
float tExit = t1;
bool sampleLight = true;
float3 coneAxisX = lenMul * light.right;
float3 coneAxisY = lenMul * light.up;
// Perform ray-cone intersection for pyramid and spot lights.
if (light.lightType != GPULIGHTTYPE_POINT)
{
float lenMul = 1;
sampleLight = IntersectRayCone(ray.originWS, ray.strataDirWS,
light.positionWS, light.forward,
coneAxisX, coneAxisY,
tMin, tMax, tEntr, tExit);
if (light.lightType == GPULIGHTTYPE_PROJECTOR_PYRAMID)
{
// 'light.right' and 'light.up' vectors are pre-scaled on the CPU
// s.t. if you were to place them at the distance of 1 directly in front
// of the light, they would give you the "footprint" of the light.
// For spot lights, the cone fit is exact.
// For pyramid lights, however, this is the "inscribed" cone
// (contained within the pyramid), and we want to intersect
// the "escribed" cone (which contains the pyramid).
// Therefore, we have to scale the radii by the sqrt(2).
lenMul = rsqrt(2);
if (sampleLight)
{
// We are unable to adequately sample features larger
// than the half of the length of the integration interval
// divided by the number of temporal samples (7).
// Therefore, we apply this hack to reduce flickering.
float hackMinDistSq = Sq(dt * (0.5 / 7));
float3 coneAxisX = lenMul * light.right;
float3 coneAxisY = lenMul * light.up;
float t, distSq, rcpPdf;
ImportanceSamplePunctualLight(rndVal, light.positionWS,
ray.originWS, ray.strataDirWS,
tEntr, tExit, t, distSq, rcpPdf,
hackMinDistSq);
sampleLight = IntersectRayCone(ray.originWS, ray.strataDirWS,
light.positionWS, light.forward,
coneAxisX, coneAxisY,
t0, t1, tEntr, tExit);
}
posInput.positionWS = GetPointAtDistance(ray, t);
if (sampleLight)
{
// We are unable to adequately sample features larger
// than the half of the length of the integration interval
// divided by the number of temporal samples (7).
// Therefore, we apply this hack to reduce flickering.
float hackMinDistSq = Sq(dt * (0.5 / 7));
float3 lightToSample = posInput.positionWS - light.positionWS;
float distRcp = rsqrt(distSq);
float dist = distSq * distRcp;
float distProj = dot(lightToSample, light.forward);
float4 distances = float4(dist, distSq, distRcp, distProj);
float3 L = -lightToSample * distRcp;
float t, distSq, rcpPdf;
ImportanceSamplePunctualLight(rndVal, light.positionWS,
ray.originWS, ray.strataDirWS,
tEntr, tExit, t, distSq, rcpPdf,
hackMinDistSq);
posInput.positionWS = GetPointAtDistance(ray, t);
float3 color; float attenuation;
EvaluateLight_Punctual(context, posInput, light, unused, 0, L, lightToSample,
distances, color, attenuation);
float3 lightToSample = posInput.positionWS - light.positionWS;
float distRcp = rsqrt(distSq);
float dist = distSq * distRcp;
float distProj = dot(lightToSample, light.forward);
float4 distances = float4(dist, distSq, distRcp, distProj);
float3 L = -lightToSample * distRcp;
// Important:
// Ideally, all scattering calculations should use the stratified versions
// of the sample position and the ray direction. However, correct reprojection
// of asymmetrically scattered lighting (affected by an anisotropic phase
// function) is not possible. We work around this issue by reprojecting
// lighting not affected by the phase function. This basically removes
// the phase function from the temporal integration process. It is a hack.
// The downside is that asymmetry no longer benefits from temporal averaging,
// and any temporal instability of asymmetry causes causes visible jitter.
// In order to stabilize the image, we use the voxel center for all
// asymmetry-related calculations.
float3 centerL = light.positionWS - centerWS;
float cosTheta = dot(centerL, ray.centerDirWS) * rsqrt(dot(centerL, centerL));
float phase = CornetteShanksPhasePartVarying(asymmetry, cosTheta);
float3 color; float attenuation;
EvaluateLight_Punctual(context, posInput, light, unused, 0, L, lightToSample,
distances, color, attenuation);
float intensity = attenuation * rcpPdf;
// Important:
// Ideally, all scattering calculations should use the stratified versions
// of the sample position and the ray direction. However, correct reprojection
// of asymmetrically scattered lighting (affected by an anisotropic phase
// function) is not possible. We work around this issue by reprojecting
// lighting not affected by the phase function. This basically removes
// the phase function from the temporal integration process. It is a hack.
// The downside is that asymmetry no longer benefits from temporal averaging,
// and any temporal instability of asymmetry causes causes visible jitter.
// In order to stabilize the image, we use the voxel center for all
// asymmetry-related calculations.
float3 centerL = light.positionWS - centerWS;
float cosTheta = dot(centerL, ray.centerDirWS) * rsqrt(dot(centerL, centerL));
float phase = CornetteShanksPhasePartVarying(asymmetry, cosTheta);
// Compute transmittance from 't0' to 't'.
intensity *= TransmittanceHomogeneousMedium(extinction, t - t0);
float intensity = attenuation * rcpPdf;
// Compute the amount of in-scattered radiance.
lighting.radianceNoPhase += intensity * color;
lighting.radianceComplete += phase * intensity * color;
}
// Compute transmittance from 't0' to 't'.
intensity *= TransmittanceHomogeneousMedium(extinction, t - t0);
light = FetchLight(lightStart, min(++i, last));
// Compute the amount of in-scattered radiance.
lighting.radianceNoPhase += intensity * color;
lighting.radianceComplete += phase * intensity * color;
while (i <= last) // GPULIGHTTYPE_PROJECTOR_BOX
#ifndef USE_CLUSTERED_LIGHTLIST
}
// Process all box lights.
for (; lightIndex < _PunctualLightCount; lightIndex++)
{
#else // USE_CLUSTERED_LIGHTLIST
// Advance to the next light in one (or both at the same time) clusters.
if (lightIndex == lightIndices[0])
light = FetchLight(lightStart, min(++i, last));
light.lightType = GPULIGHTTYPE_PROJECTOR_BOX;
i++;
lightIndices[0] = FetchIndexWithBoundsCheck(lightStarts[0], lightCounts[0], i);
}
// Convert the box light from OBB to AABB.
// 'light.right' and 'light.up' vectors are pre-scaled on the CPU by (2/w) and (2/h).
float3x3 rotMat = float3x3(light.right, light.up, light.forward);
if (lightIndex == lightIndices[1])
{
j++;
lightIndices[1] = FetchIndexWithBoundsCheck(lightStarts[1], lightCounts[1], j);
}
} while (i < lightCounts[0] || j < lightCounts[1]);
float3 o = mul(rotMat, ray.originWS - light.positionWS);
float3 d = mul(rotMat, ray.strataDirWS);
// Process all box lights.
while (i < lightCounts[0] || j < lightCounts[1])
{
// Process lights in order.
uint lightIndex = min(lightIndices[0], lightIndices[1]);
float range = light.size.x;
float3 boxPt0 = float3(-1, -1, 0);
float3 boxPt1 = float3( 1, 1, range);
#endif // USE_CLUSTERED_LIGHTLIST
float tEntr, tExit;
LightData light = _LightDatas[lightIndex];
light.lightType = GPULIGHTTYPE_PROJECTOR_BOX;
if (IntersectRayAABB(o, d, boxPt0, boxPt1, tMin, tMax, tEntr, tExit))
{
float tOffset, weight;
ImportanceSampleHomogeneousMedium(rndVal, extinction, tExit - tEntr, tOffset, weight);
// Convert the box light from OBB to AABB.
// 'light.right' and 'light.up' vectors are pre-scaled on the CPU by (2/w) and (2/h).
float3x3 rotMat = float3x3(light.right, light.up, light.forward);
float t = tEntr + tOffset;
posInput.positionWS = GetPointAtDistance(ray, t);
float3 o = mul(rotMat, ray.originWS - light.positionWS);
float3 d = mul(rotMat, ray.strataDirWS);
float3 L = -light.forward;
float3 lightToSample = posInput.positionWS - light.positionWS;
float distProj = dot(lightToSample, light.forward);
float4 distances = float4(1, 1, 1, distProj);
float range = light.size.x;
float3 boxPt0 = float3(-1, -1, 0);
float3 boxPt1 = float3( 1, 1, range);
float3 color; float attenuation;
EvaluateLight_Punctual(context, posInput, light, unused, 0, L, lightToSample,
distances, color, attenuation);
float tEntr, tExit;
// Important:
// Ideally, all scattering calculations should use the stratified versions
// of the sample position and the ray direction. However, correct reprojection
// of asymmetrically scattered lighting (affected by an anisotropic phase
// function) is not possible. We work around this issue by reprojecting
// lighting not affected by the phase function. This basically removes
// the phase function from the temporal integration process. It is a hack.
// The downside is that asymmetry no longer benefits from temporal averaging,
// and any temporal instability of asymmetry causes causes visible jitter.
// In order to stabilize the image, we use the voxel center for all
// asymmetry-related calculations.
float3 centerL = light.positionWS - centerWS;
float cosTheta = dot(centerL, ray.centerDirWS) * rsqrt(dot(centerL, centerL));
float phase = CornetteShanksPhasePartVarying(asymmetry, cosTheta);
if (IntersectRayAABB(o, d, boxPt0, boxPt1, t0, t1, tEntr, tExit))
{
float tOffset, weight;
ImportanceSampleHomogeneousMedium(rndVal, extinction, tExit - tEntr, tOffset, weight);
// Note: the 'weight' accounts for transmittance from 'tEntr' to 't'.
float intensity = attenuation * weight;
float t = tEntr + tOffset;
posInput.positionWS = GetPointAtDistance(ray, t);
float3 L = -light.forward;
float3 lightToSample = posInput.positionWS - light.positionWS;
float distProj = dot(lightToSample, light.forward);
float4 distances = float4(1, 1, 1, distProj);
float3 color; float attenuation;
EvaluateLight_Punctual(context, posInput, light, unused, 0, L, lightToSample,
distances, color, attenuation);
// Compute transmittance from 't0' to 'tEntr'.
intensity *= TransmittanceHomogeneousMedium(extinction, tEntr - t0);
// Important:
// Ideally, all scattering calculations should use the stratified versions
// of the sample position and the ray direction. However, correct reprojection
// of asymmetrically scattered lighting (affected by an anisotropic phase
// function) is not possible. We work around this issue by reprojecting
// lighting not affected by the phase function. This basically removes
// the phase function from the temporal integration process. It is a hack.
// The downside is that asymmetry no longer benefits from temporal averaging,
// and any temporal instability of asymmetry causes causes visible jitter.
// In order to stabilize the image, we use the voxel center for all
// asymmetry-related calculations.
float3 centerL = light.positionWS - centerWS;
float cosTheta = dot(centerL, ray.centerDirWS) * rsqrt(dot(centerL, centerL));
float phase = CornetteShanksPhasePartVarying(asymmetry, cosTheta);
// Note: the 'weight' accounts for transmittance from 'tEntr' to 't'.
float intensity = attenuation * weight;
// Compute transmittance from 't0' to 'tEntr'.
intensity *= TransmittanceHomogeneousMedium(extinction, tEntr - t0);
// Compute the amount of in-scattered radiance.
lighting.radianceNoPhase += intensity * color;
lighting.radianceComplete += phase * intensity * color;
}
#ifdef USE_CLUSTERED_LIGHTLIST
// Advance to the next light in one (or both at the same time) clusters.
if (lightIndex == lightIndices[0])
{
i++;
lightIndices[0] = FetchIndexWithBoundsCheck(lightStarts[0], lightCounts[0], i);
}
// Compute the amount of in-scattered radiance.
lighting.radianceNoPhase += intensity * color;
lighting.radianceComplete += phase * intensity * color;
}
if (lightIndex == lightIndices[1])
{
j++;
lightIndices[1] = FetchIndexWithBoundsCheck(lightStarts[1], lightCounts[1], j);
#endif // USE_CLUSTERED_LIGHTLIST
#ifdef LIGHTLOOP_TILE_PASS
cluster++;
// Check whether the voxel is completely inside the light cluster.
} while ((cluster < 2) && (clusterIndices[0] != clusterIndices[1]));
#endif // LIGHTLOOP_TILE_PASS
}
return lighting;
}

// The contribution of the ambient probe does not depend on the position,
// only on the direction and the length of the interval.
// SampleSH9() evaluates the 3-band SH in a given direction.
// The probe is already pre-convolved with the phase function.
#ifdef LIGHTLOOP_TILE_PASS
// Our voxel is not necessarily completely inside a single light cluster.
// Note that Z-binning can solve this problem, as we can iterate over all Z-bins
// to compute min/max light indices, and then use this range for the entire slice.
uint clusterIndices[2];
float clusterDepths[2];
clusterIndices[0] = GetLightClusterIndex(posInput.tileCoord, z0);
clusterDepths[0] = GetLightClusterMinLinearDepth(posInput.tileCoord, clusterIndices[0]);
#endif // LIGHTLOOP_TILE_PASS
#ifdef USE_CLUSTERED_LIGHTLIST
// The voxel can overlap up to 2 light clusters along Z, so we have to iterate over both.
// TODO: implement Z-binning which makes Z-range queries easy.
uint lightClusters[2];
lightClusters[0] = GetLightClusterIndex(posInput.tileCoord, z0);
#endif // USE_CLUSTERED_LIGHTLIST
#if defined(SHADER_API_METAL)
[fastopt]

for (uint slice = 0; slice < sliceCountHack; slice++)
#endif
{
uint3 voxelCoord = uint3(posInput.positionSS, slice);
// Warning: this compiles, but it's nonsense. Use DecodeLogarithmicDepthGeneralized().
float z1 = DecodeLogarithmicDepth(e1, _VBufferDepthDecodingParams);
#else
float z1 = DecodeLogarithmicDepthGeneralized(e1, _VBufferDepthDecodingParams);

#ifdef LIGHTLOOP_TILE_PASS
clusterIndices[1] = GetLightClusterIndex(posInput.tileCoord, z1);
clusterDepths[1] = GetLightClusterMinLinearDepth(posInput.tileCoord, clusterIndices[1]);
#ifdef USE_CLUSTERED_LIGHTLIST
lightClusters[1] = GetLightClusterIndex(posInput.tileCoord, z1);
#endif
// Compute the -exact- position of the center of the voxel.

// Sample the participating medium at 'tc' (or 'centerWS').
// We consider it to be constant along the interval [t0, t1] (within the voxel).
// TODO: piecewise linear.
float3 scattering = _GlobalScattering;
float extinction = max(_GlobalExtinction, FLT_MIN); // Avoid NaNs
float3 scattering = LOAD_TEXTURE3D(_VBufferDensity, voxelCoord).rgb;
float extinction = LOAD_TEXTURE3D(_VBufferDensity, voxelCoord).a;
// TODO: define a function ComputeGlobalFogCoefficients(float3 centerWS),
// which allows procedural definition of extinction and scattering.
// Prevent division by 0.
extinction = max(extinction, FLT_MIN);
#if ENABLE_REPROJECTION
// This is a sequence of 7 equidistant numbers from 1/14 to 13/14.

VoxelLighting lighting = EvaluateVoxelLighting(context, featureFlags, posInput, centerWS,
ray, t0, t1, dt, rndVal, extinction, asymmetry
#ifdef LIGHTLOOP_TILE_PASS
, clusterIndices, clusterDepths);
#ifdef USE_CLUSTERED_LIGHTLIST
, lightClusters);
#else
);
#endif

// do not support reprojection and should neither read nor write to the history buffer.
// to the history buffer. This will cause them to alias, but it is the only way
// to prevent ghosting.
_VBufferLightingFeedback[uint3(posInput.positionSS, slice)] = float4(blendedRadiance, dt);
_VBufferLightingFeedback[voxelCoord] = float4(blendedRadiance, dt);
#if SUPPORT_ASYMMETRY
// Extrapolate the influence of the phase function on the results of the current frame.

#endif // SUPPORT_ASYMMETRY
#endif
#else // ENABLE_REPROJECTION
#else // ENABLE_REPROJECTION
#else // SUPPORT_ASYMMETRY
#else
#endif // SUPPORT_ASYMMETRY
#endif
#endif // ENABLE_REPROJECTION

float phase = IsotropicPhaseFunction();
#endif
float4 integral = float4(totalRadiance, opticalDepth);
// Integrate the contribution of the probe over the interval.
// Integral{a, b}{Transmittance(0, t) * L_s(t) dt} = Transmittance(0, a) * Integral{a, b}{Transmittance(0, t - a) * L_s(t) dt}.
float3 probeRadiance = probeInScatteredRadiance * TransmittanceIntegralHomogeneousMedium(extinction, dt);

opticalDepth += 0.5 * extinction * dt;
// Store the voxel data.
_VBufferLightingIntegral[uint3(posInput.positionSS, slice)] = float4(totalRadiance, opticalDepth);
_VBufferLightingIntegral[voxelCoord] = float4(totalRadiance, opticalDepth);
z0 = z1;
#ifdef LIGHTLOOP_TILE_PASS
clusterIndices[0] = clusterIndices[1];
clusterDepths[0] = clusterDepths[1];
#endif // LIGHTLOOP_TILE_PASS
#ifdef USE_CLUSTERED_LIGHTLIST
lightClusters[0] = lightClusters[1];
#endif
[numthreads(GROUP_SIZE_2D, 1, 1)]
[numthreads(GROUP_SIZE_1D, GROUP_SIZE_1D, 1)]
uint groupThreadId : SV_GroupThreadID)
uint2 groupThreadId : SV_GroupThreadID)
// Note: any factor of 64 is a suitable wave size for our algorithm.
uint waveIndex = WaveReadFirstLane(groupThreadId / 64);
uint laneIndex = groupThreadId % 64;
uint quadIndex = laneIndex / 4;
// Arrange threads in the Morton order to optimally match the memory layout of GCN tiles.
uint2 groupCoord = DecodeMorton2D(groupThreadId);
uint2 voxelCoord = groupOffset + groupCoord;
uint2 voxelCoord = groupOffset + groupThreadId;
uint2 tileCoord = voxelCoord * VBUFFER_TILE_SIZE / TILE_SIZE_CLUSTERED;
uint voxelsPerClusterTile = Sq((uint)(TILE_SIZE_CLUSTERED / VBUFFER_TILE_SIZE));

// TODO: this is a compile-time test, make sure the compiler actually scalarizes.
tileCoord = WaveReadFirstLane(tileCoord);
tileCoord = groupOffset * VBUFFER_TILE_SIZE / TILE_SIZE_CLUSTERED;
UNITY_BRANCH if (voxelCoord.x >= (uint)_VBufferResolution.x ||
voxelCoord.y >= (uint)_VBufferResolution.y)
UNITY_BRANCH
if (voxelCoord.x >= (uint)_VBufferResolution.x ||
voxelCoord.y >= (uint)_VBufferResolution.y)
float2 centerCoord = voxelCoord + 0.5;
float2 centerCoord = voxelCoord + float2(0.5, 0.5);
#if ENABLE_REPROJECTION
float2 strataCoord = centerCoord + _VBufferSampleOffset.xy;
#else

// TODO: avoid 2x matrix multiplications by precomputing the world-space offset on the Z=1 plane.
// Compute the (tile-centered) ray direction s.t. its ViewSpace(rayDirWS).z = 1.
float3 centerDirWS = mul(-float3(centerCoord, 1), (float3x3)_VBufferCoordToViewDirWS);
float centerDirLenSq = dot(centerDirWS, centerDirWS);
float centerDirLenRcp = rsqrt(centerDirLenSq);
float centerDirLen = centerDirLenSq * centerDirLenRcp;
// Compute the (tile-centered) ray direction s.t. its ViewSpace(rayDirWS).z = 1.
float3 centerDirWS = mul(-float3(centerCoord, 1), (float3x3)_VBufferCoordToViewDirWS);
float centerDirLenSq = dot(centerDirWS, centerDirWS);
float centerDirLenRcp = rsqrt(centerDirLenSq);
float centerDirLen = centerDirLenSq * centerDirLenRcp;
DualRay ray;

#else
[numthreads(GROUP_SIZE_2D, 1, 1)]
[numthreads(GROUP_SIZE_1D, GROUP_SIZE_1D, 1)]
uint groupThreadId : SV_GroupThreadID)
uint2 groupThreadId : SV_GroupThreadID)
{
// Reduce compile times if the feature is disabled.
}

303
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/VolumeVoxelization.compute


//--------------------------------------------------------------------------------------------------
// Definitions
//--------------------------------------------------------------------------------------------------
#pragma kernel VolumeVoxelizationBruteforce VolumeVoxelization=VolumeVoxelizationBruteforce LIGHTLOOP_SINGLE_PASS
#pragma kernel VolumeVoxelizationClustered VolumeVoxelization=VolumeVoxelizationClustered LIGHTLOOP_TILE_PASS USE_CLUSTERED_LIGHTLIST
// #pragma enable_d3d11_debug_symbols
#include "../../ShaderPass/ShaderPass.cs.hlsl"
#define SHADERPASS SHADERPASS_VOLUME_VOXELIZATION
#include "../../ShaderConfig.cs.hlsl"
#if (SHADEROPTIONS_VOLUMETRIC_LIGHTING_PRESET == 1)
// E.g. for 1080p: (1920/8)x(1080/8)x(64) = 2,073,600 voxels
#define VBUFFER_TILE_SIZE 8
#define VBUFFER_SLICE_COUNT 64
#else
// E.g. for 1080p: (1920/4)x(1080/4)x(128) = 16,588,800 voxels
#define VBUFFER_TILE_SIZE 4
#define VBUFFER_SLICE_COUNT 128
#endif
#define GROUP_SIZE_1D 8
#define SOFT_VOXELIZATION 1 // Hack which attempts to determine the partial coverage of the voxel
//--------------------------------------------------------------------------------------------------
// Included headers
//--------------------------------------------------------------------------------------------------
#include "CoreRP/ShaderLibrary/Common.hlsl"
#include "CoreRP/GeometryUtils.cs.hlsl"
#include "../../ShaderVariables.hlsl"
#include "VolumetricLighting.cs.hlsl"
#define UNITY_MATERIAL_VOLUMETRIC // Define before including Lighting.hlsl and Material.hlsl
#include "../Lighting.hlsl" // Includes Material.hlsl
#pragma only_renderers d3d11 ps4 xboxone vulkan metal
//--------------------------------------------------------------------------------------------------
// Inputs & outputs
//--------------------------------------------------------------------------------------------------
StructuredBuffer<OrientedBBox> _VolumeBounds;
StructuredBuffer<DensityVolumeProperties> _VolumeProperties;
RW_TEXTURE3D(float4, _VBufferDensity); // RGB = sqrt(scattering), A = sqrt(extinction)
// TODO: avoid creating another Constant Buffer...
CBUFFER_START(UnityVolumetricLighting)
float4x4 _VBufferCoordToViewDirWS; // Actually just 3x3, but Unity can only set 4x4
float4 _VBufferSampleOffset; // Not used by this shader
float _CornetteShanksConstant; // Not used by this shader
uint _NumVisibleDensityVolumes;
CBUFFER_END
//--------------------------------------------------------------------------------------------------
// Implementation
//--------------------------------------------------------------------------------------------------
void FillVolumetricDensityBuffer(PositionInputs posInput, float3 rayOriginWS, float3 rayUnDirWS,
float3 voxelAxisRight, float3 voxelAxisUp, float3 voxelAxisForward)
{
float n = _VBufferDepthDecodingParams.x + _VBufferDepthDecodingParams.z;
float z0 = n; // Start the computation from the near plane
float de = rcp(VBUFFER_SLICE_COUNT); // Log-encoded distance between slices
#ifdef USE_CLUSTERED_LIGHTLIST
// The voxel can overlap up to 2 light clusters along Z, so we have to iterate over both.
// TODO: implement Z-binning which makes Z-range queries easy.
uint volumeStarts[2], volumeCounts[2];
GetCountAndStartCluster(posInput.tileCoord, GetLightClusterIndex(posInput.tileCoord, z0),
LIGHTCATEGORY_DENSITY_VOLUME, volumeStarts[0], volumeCounts[0]);
#endif // USE_CLUSTERED_LIGHTLIST
#if defined(SHADER_API_METAL)
[fastopt]
for (uint slice = 0; slice < VBUFFER_SLICE_COUNT; slice++)
#else
uint sliceCountHack = max(VBUFFER_SLICE_COUNT, (uint)_VBufferDepthEncodingParams.w); // Prevent unrolling...
// TODO: replace 'sliceCountHack' with VBUFFER_SLICE_COUNT when the shader compiler bug is fixed.
for (uint slice = 0; slice < sliceCountHack; slice++)
#endif
{
uint3 voxelCoord = uint3(posInput.positionSS, slice);
float e1 = slice * de + de; // (slice + 1) / sliceCount
#if defined(SHADER_API_METAL)
// Warning: this compiles, but it's nonsense. Use DecodeLogarithmicDepthGeneralized().
float z1 = DecodeLogarithmicDepth(e1, _VBufferDepthDecodingParams);
#else
float z1 = DecodeLogarithmicDepthGeneralized(e1, _VBufferDepthDecodingParams);
#endif
float halfDZ = 0.5 * (z1 - z0);
float z = z0 + halfDZ;
float3 voxelCenterWS = rayOriginWS + z * rayUnDirWS; // Works due to the length of of the dir
// TODO: define a function ComputeGlobalFogCoefficients(float3 voxelCenterWS),
// which allows procedural definition of extinction and scattering.
float3 voxelScattering = _GlobalScattering;
float voxelExtinction = _GlobalExtinction;
#ifdef USE_CLUSTERED_LIGHTLIST
GetCountAndStartCluster(posInput.tileCoord, GetLightClusterIndex(posInput.tileCoord, z1),
LIGHTCATEGORY_DENSITY_VOLUME, volumeStarts[1], volumeCounts[1]);
// Iterate over all volumes within 2 (not necessarily unique) clusters overlapping the voxel along Z.
// We need to skip duplicates, but it's not too difficult since volumes are sorted by index.
uint i = 0, j = 0;
if (i < volumeCounts[0] || j < volumeCounts[1])
{
// At least one of the clusters is non-empty.
uint volumeIndices[2];
// Fetch two initial indices from both clusters.
volumeIndices[0] = FetchIndexWithBoundsCheck(volumeStarts[0], volumeCounts[0], i);
volumeIndices[1] = FetchIndexWithBoundsCheck(volumeStarts[1], volumeCounts[1], j);
do
{
// Process volumes in order.
uint volumeIndex = min(volumeIndices[0], volumeIndices[1]);
#else // USE_CLUSTERED_LIGHTLIST
{
for (uint volumeIndex = 0; volumeIndex < _NumVisibleDensityVolumes; volumeIndex++)
{
#endif // USE_CLUSTERED_LIGHTLIST
OrientedBBox obb = _VolumeBounds[volumeIndex];
float3x3 obbFrame = float3x3(obb.right, obb.up, cross(obb.up, obb.right));
float3 obbExtents = float3(obb.extentX, obb.extentY, obb.extentZ);
// Express the voxel center in the local coordinate system of the box.
float3 voxelCenterBS = mul(voxelCenterWS - obb.center, transpose(obbFrame));
float3 voxelCenterUV = voxelCenterBS / obbExtents;
#if SOFT_VOXELIZATION
// We need to determine which is the face closest to 'voxelCenterBS'.
float minFaceDist = abs(obbExtents.x - abs(voxelCenterBS.x));
// TODO: use v_cubeid_f32.
uint axisIndex; float faceDist;
faceDist = abs(obbExtents.y - abs(voxelCenterBS.y));
axisIndex = (faceDist < minFaceDist) ? 1 : 0;
minFaceDist = min(faceDist, minFaceDist);
faceDist = abs(obbExtents.z - abs(voxelCenterBS.z));
axisIndex = (faceDist < minFaceDist) ? 2 : axisIndex;
float3 N = float3(axisIndex == 0 ? 1 : 0, axisIndex == 1 ? 1 : 0, axisIndex == 2 ? 1 : 0);
// We have determined the normal of the closest face.
// We now have to construct the diagonal of the voxel with the longest extent along this normal.
float3 minDiagPointBS, maxDiagPointBS;
float3 voxelAxisRightBS = mul(voxelAxisRight, transpose(obbFrame));
float3 voxelAxisUpBS = mul(voxelAxisUp, transpose(obbFrame));
float3 voxelAxisForwardBS = mul(voxelAxisForward, transpose(obbFrame));
// Start at the center of the voxel.
minDiagPointBS = maxDiagPointBS = voxelCenterBS;
bool normalFwd = dot(voxelAxisForwardBS, N) >= 0;
float mulForward = normalFwd ? halfDZ : -halfDZ;
float mulMin = normalFwd ? z0 : z1;
float mulMax = normalFwd ? z1 : z0;
minDiagPointBS -= mulForward * voxelAxisForwardBS;
maxDiagPointBS += mulForward * voxelAxisForwardBS;
float mulUp = dot(voxelAxisUpBS, N) >= 0 ? 1 : -1;
minDiagPointBS -= (mulMin * mulUp) * voxelAxisUpBS;
maxDiagPointBS += (mulMax * mulUp) * voxelAxisUpBS;
float mulRight = dot(voxelAxisRightBS, N) >= 0 ? 1 : -1;
minDiagPointBS -= (mulMin * mulRight) * voxelAxisRightBS;
maxDiagPointBS += (mulMax * mulRight) * voxelAxisRightBS;
// We want to determine the fractional overlap of the diagonal and the box.
float3 diagOriginBS = minDiagPointBS;
float3 diagUnDirBS = maxDiagPointBS - minDiagPointBS;
float tEntr, tExit;
IntersectRayAABB(diagOriginBS, diagUnDirBS,
-obbExtents, obbExtents,
0, 1,
tEntr, tExit);
float overlapFraction = tExit - tEntr;
#else // SOFT_VOXELIZATION
bool overlap = abs(voxelCenterUV.x) <= 1 &&
abs(voxelCenterUV.y) <= 1 &&
abs(voxelCenterUV.z) <= 1;
float overlapFraction = overlap ? 1 : 0;
#endif // SOFT_VOXELIZATION
if (overlapFraction > 0)
{
// There is an overlap. Sample the 3D texture, or load the constant value.
voxelScattering += overlapFraction * _VolumeProperties[volumeIndex].scattering;
voxelExtinction += overlapFraction * _VolumeProperties[volumeIndex].extinction;
}
#ifndef USE_CLUSTERED_LIGHTLIST
}
}
#else // USE_CLUSTERED_LIGHTLIST
// Advance to the next volume in one (or both at the same time) clusters.
if (volumeIndex == volumeIndices[0])
{
i++;
volumeIndices[0] = FetchIndexWithBoundsCheck(volumeStarts[0], volumeCounts[0], i);
}
if (volumeIndex == volumeIndices[1])
{
j++;
volumeIndices[1] = FetchIndexWithBoundsCheck(volumeStarts[1], volumeCounts[1], j);
}
} while (i < volumeCounts[0] || j < volumeCounts[1]);
}
// We don't need to carry over the cluster index, only the start and the count.
volumeStarts[0] = volumeStarts[1];
volumeCounts[0] = volumeCounts[1];
#endif // USE_CLUSTERED_LIGHTLIST
_VBufferDensity[voxelCoord] = float4(voxelScattering, voxelExtinction);
z0 = z1;
}
}
[numthreads(GROUP_SIZE_1D, GROUP_SIZE_1D, 1)]
void VolumeVoxelization(uint2 groupId : SV_GroupID,
uint2 groupThreadId : SV_GroupThreadID)
{
// Perform compile-time checks.
if (!IsPower2(VBUFFER_TILE_SIZE) || !IsPower2(TILE_SIZE_CLUSTERED)) return;
uint2 groupCoord = groupThreadId;
uint2 groupOffset = groupId * GROUP_SIZE_1D;
uint2 voxelCoord = groupOffset + groupCoord;
uint2 tileCoord = voxelCoord * VBUFFER_TILE_SIZE / TILE_SIZE_CLUSTERED;
uint voxelsPerClusterTile = Sq((uint)(TILE_SIZE_CLUSTERED / VBUFFER_TILE_SIZE));
if (voxelsPerClusterTile >= 64)
{
// TODO: this is a compile-time test, make sure the compiler actually scalarizes.
tileCoord = groupOffset * VBUFFER_TILE_SIZE / TILE_SIZE_CLUSTERED;
}
UNITY_BRANCH
if (voxelCoord.x >= (uint)_VBufferResolution.x ||
voxelCoord.y >= (uint)_VBufferResolution.y)
{
return;
}
// Reminder: our voxel is a skewed pyramid frustum with square front and back faces.
// Compute 3x orthogonal directions.
float2 centerCoord = voxelCoord + float2( 0.5, 0.5);
float2 leftCoord = voxelCoord + float2(-0.5, 0.5);
float2 upCoord = voxelCoord + float2( 0.5, -0.5);
// TODO: avoid 2x matrix multiplications by precomputing the world-space offset on the vs_Z=1 plane.
// Compute 3x ray directions s.t. its ViewSpace(rayDirWS).z = 1.
float3 centerDirWS = mul(-float3(centerCoord, 1), (float3x3)_VBufferCoordToViewDirWS);
float3 leftDirWS = mul(-float3(leftCoord, 1), (float3x3)_VBufferCoordToViewDirWS);
float3 upDirWS = mul(-float3(upCoord, 1), (float3x3)_VBufferCoordToViewDirWS);
// Compute the axes of the voxel. These are not normalized, but rather computed to scale with Z.
float3 voxelAxisForward = centerDirWS;
float3 voxelAxisUp = 0.5 * (upDirWS - centerDirWS);
float3 voxelAxisRight = 0.5 * (centerDirWS - leftDirWS);
PositionInputs posInput = GetPositionInput(voxelCoord, _VBufferResolution.zw, tileCoord);
FillVolumetricDensityBuffer(posInput, GetCurrentViewPosition(), centerDirWS,
voxelAxisRight, voxelAxisUp, voxelAxisForward);
}

8
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/VolumeVoxelization.compute.meta


fileFormatVersion: 2
guid: c20b371db720da244b73830ec74a343a
ComputeShaderImporter:
externalObjects: {}
currentAPIMask: 4
userData:
assetBundleName:
assetBundleVariant:

8
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Volumetrics/VolumetricLighting.compute.meta


fileFormatVersion: 2
guid: b4901a10df2d1e24282725e9fbc77c97
ComputeShaderImporter:
externalObjects: {}
currentAPIMask: 4
userData:
assetBundleName:
assetBundleVariant:

110
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader1.png

之前 之后
宽度: 495  |  高度: 475  |  大小: 32 KiB

162
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader10.png

之前 之后
宽度: 263  |  高度: 263  |  大小: 37 KiB

6
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader11.png

之前 之后
宽度: 263  |  高度: 23  |  大小: 486 B

512
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader12.png
文件差异内容过多而无法显示
查看文件

11
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader13.png

之前 之后
宽度: 648  |  高度: 59  |  大小: 4.8 KiB

1001
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader14.png
文件差异内容过多而无法显示
查看文件

1001
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader15.png
文件差异内容过多而无法显示
查看文件

16
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader16.png

之前 之后
宽度: 646  |  高度: 41  |  大小: 4.7 KiB

175
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader17.png

之前 之后
宽度: 805  |  高度: 319  |  大小: 45 KiB

9
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader18.png

之前 之后
宽度: 651  |  高度: 21  |  大小: 2.0 KiB

1001
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader19.png
文件差异内容过多而无法显示
查看文件

546
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader2.png
文件差异内容过多而无法显示
查看文件

19
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader20.png

之前 之后
宽度: 648  |  高度: 40  |  大小: 4.3 KiB

190
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader21.png

之前 之后
宽度: 531  |  高度: 485  |  大小: 44 KiB

18
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader22.png

之前 之后
宽度: 643  |  高度: 67  |  大小: 7.2 KiB

8
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader23.png

之前 之后
宽度: 647  |  高度: 23  |  大小: 1.7 KiB

23
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader24.png

之前 之后
宽度: 648  |  高度: 65  |  大小: 6.9 KiB

27
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader25.png

之前 之后
宽度: 663  |  高度: 113  |  大小: 9.5 KiB

23
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader26.png

之前 之后
宽度: 647  |  高度: 96  |  大小: 8.0 KiB

19
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader27.png

之前 之后
宽度: 650  |  高度: 97  |  大小: 9.0 KiB

23
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader3.png

之前 之后
宽度: 648  |  高度: 68  |  大小: 8.1 KiB

15
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader4.png

之前 之后
宽度: 646  |  高度: 36  |  大小: 3.9 KiB

38
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader5.png

之前 之后
宽度: 652  |  高度: 110  |  大小: 11 KiB

50
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader6.png

之前 之后
宽度: 662  |  高度: 173  |  大小: 17 KiB

17
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader7.png

之前 之后
宽度: 650  |  高度: 36  |  大小: 4.3 KiB

26
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader8.png

之前 之后
宽度: 652  |  高度: 79  |  大小: 8.0 KiB

324
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/LitShader9.png

之前 之后
宽度: 676  |  高度: 1009  |  大小: 100 KiB

33
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/SkyAndFog1.png

之前 之后
宽度: 539  |  高度: 58  |  大小: 7.4 KiB

41
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/SkyAndFog2.png

之前 之后
宽度: 532  |  高度: 204  |  大小: 11 KiB

28
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/SkyAndFog3.png

之前 之后
宽度: 532  |  高度: 136  |  大小: 8.0 KiB

39
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/SkyAndFog4.png

之前 之后
宽度: 530  |  高度: 55  |  大小: 7.2 KiB

45
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/SkyAndFog5.png

之前 之后
宽度: 532  |  高度: 198  |  大小: 8.2 KiB

17
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/SkyAndFog7.png

之前 之后
宽度: 531  |  高度: 79  |  大小: 4.5 KiB

179
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/SkyAndFog8.png

之前 之后
宽度: 366  |  高度: 421  |  大小: 45 KiB

20
ScriptableRenderPipeline/HDRenderPipeline/Documentation/Images/SkyandFog6.png

之前 之后
宽度: 530  |  高度: 181  |  大小: 8.8 KiB

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

正在加载...
取消
保存