using System;
using System.Collections.Generic;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Experimental.Rendering.RenderGraphModule;
using UnityEngine.Serialization;
namespace UnityEngine.Rendering.HighDefinition
{
///
/// Shadow Filtering Quality
///
public enum HDShadowFilteringQuality
{
///
/// Low Shadow Filtering Quality
///
Low = 0,
///
/// Medium Shadow Filtering Quality
///
Medium = 1,
///
/// High Shadow Filtering Quality
///
High = 2,
}
enum ShadowMapType
{
CascadedDirectional,
PunctualAtlas,
AreaLightAtlas
}
enum ShadowMapUpdateType
{
// Fully dynamic shadow maps
Dynamic = 0,
// Fully cached shadow maps (nothing is rendered unless requested)
Cached,
// Mixed, static shadow caster are cached and updated as indicated, dynamic are drawn on top.
Mixed
}
[GenerateHLSL(needAccessors = false)]
struct HDShadowData
{
public Vector3 rot0;
public Vector3 rot1;
public Vector3 rot2;
public Vector3 pos;
public Vector4 proj;
public Vector2 atlasOffset;
public float worldTexelSize;
public float normalBias;
[SurfaceDataAttributes(precision = FieldPrecision.Real)]
public Vector4 zBufferParam;
public Vector4 shadowMapSize;
public Vector4 shadowFilterParams0;
public Vector3 cacheTranslationDelta;
public float isInCachedAtlas;
public Matrix4x4 shadowToWorld;
}
// We use a different structure for directional light because these is a lot of data there
// and it will add too much useless stuff for other lights
// Note: In order to support HLSL array generation, we need to use fixed arrays and so a unsafe context for this struct
[GenerateHLSL(needAccessors = false)]
unsafe struct HDDirectionalShadowData
{
// We can't use Vector4 here because the vector4[] makes this struct non blittable
[HLSLArray(4, typeof(Vector4))]
public fixed float sphereCascades[4 * 4];
[SurfaceDataAttributes(precision = FieldPrecision.Real)]
public Vector4 cascadeDirection;
[HLSLArray(4, typeof(float))]
[SurfaceDataAttributes(precision = FieldPrecision.Real)]
public fixed float cascadeBorders[4];
}
class HDShadowRequest
{
public Matrix4x4 view;
// Use the y flipped device projection matrix as light projection matrix
public Matrix4x4 deviceProjectionYFlip;
public Matrix4x4 deviceProjection;
public Matrix4x4 projection;
public Matrix4x4 shadowToWorld;
public Vector3 position;
public Vector4 zBufferParam;
// Warning: these viewport fields are updated by ProcessShadowRequests and are invalid before
public Rect dynamicAtlasViewport;
public Rect cachedAtlasViewport;
public bool zClip;
public Vector4[] frustumPlanes;
// Store the final shadow indice in the shadow data array
// Warning: the index is computed during ProcessShadowRequest and so is invalid before calling this function
public int shadowIndex;
// Determine in which atlas the shadow will be rendered
public ShadowMapType shadowMapType = ShadowMapType.PunctualAtlas;
// TODO: Remove these field once scriptable culling is here (currently required by ScriptableRenderContext.DrawShadows)
public int lightIndex;
public ShadowSplitData splitData;
// end
public float normalBias;
public float worldTexelSize;
public float slopeBias;
// PCSS parameters
public float shadowSoftness;
public int blockerSampleCount;
public int filterSampleCount;
public float minFilterSize;
// IMS parameters
public float kernelSize;
public float lightAngle;
public float maxDepthBias;
public Vector4 evsmParams;
public bool shouldUseCachedShadowData = false;
public bool shouldRenderCachedComponent = false;
public HDShadowData cachedShadowData;
public bool isInCachedAtlas;
public bool isMixedCached = false;
}
enum DirectionalShadowAlgorithm
{
PCF5x5,
PCF7x7,
PCSS,
IMS
}
///
/// Screen Space Shadows format.
///
public enum ScreenSpaceShadowFormat
{
/// R8G8B8A8 format for fastest rendering.
R8G8B8A8 = GraphicsFormat.R8G8B8A8_UNorm,
/// R16G16B16A16 format for better quality.
R16G16B16A16 = GraphicsFormat.R16G16B16A16_SFloat
}
///
/// Shadows Global Settings.
///
[Serializable]
public struct HDShadowInitParameters
{
///
/// Shadow Atlases parameters.
///
[Serializable]
public struct HDShadowAtlasInitParams
{
/// Shadow Atlas resolution.
public int shadowAtlasResolution;
/// Shadow Atlas depth bits.
public DepthBits shadowAtlasDepthBits;
/// Enable dynamic rescale of the atlas.
public bool useDynamicViewportRescale;
internal static HDShadowAtlasInitParams GetDefault()
{
return new HDShadowAtlasInitParams()
{
shadowAtlasResolution = k_DefaultShadowAtlasResolution,
shadowAtlasDepthBits = k_DefaultShadowMapDepthBits,
useDynamicViewportRescale = true
};
}
}
internal static HDShadowInitParameters NewDefault() => new HDShadowInitParameters()
{
maxShadowRequests = k_DefaultMaxShadowRequests,
directionalShadowsDepthBits = k_DefaultShadowMapDepthBits,
punctualLightShadowAtlas = HDShadowAtlasInitParams.GetDefault(),
areaLightShadowAtlas = HDShadowAtlasInitParams.GetDefault(),
cachedPunctualLightShadowAtlas = 2048,
cachedAreaLightShadowAtlas = 1024,
shadowResolutionDirectional = new IntScalableSetting(new[] { 256, 512, 1024, 2048 }, ScalableSettingSchemaId.With4Levels),
shadowResolutionArea = new IntScalableSetting(new[] { 256, 512, 1024, 2048 }, ScalableSettingSchemaId.With4Levels),
shadowResolutionPunctual = new IntScalableSetting(new[] { 256, 512, 1024, 2048 }, ScalableSettingSchemaId.With4Levels),
shadowFilteringQuality = HDShadowFilteringQuality.Medium,
supportScreenSpaceShadows = false,
maxScreenSpaceShadowSlots = 4,
screenSpaceShadowBufferFormat = ScreenSpaceShadowFormat.R16G16B16A16,
maxDirectionalShadowMapResolution = 2048,
maxAreaShadowMapResolution = 2048,
maxPunctualShadowMapResolution = 2048,
};
internal const int k_DefaultShadowAtlasResolution = 4096;
internal const int k_DefaultMaxShadowRequests = 128;
internal const DepthBits k_DefaultShadowMapDepthBits = DepthBits.Depth32;
/// Maximum number of shadow requests at the same time.
public int maxShadowRequests;
/// Depth bits for directional shadows.
public DepthBits directionalShadowsDepthBits;
/// Shadow filtering quality.
[FormerlySerializedAs("shadowQuality")]
public HDShadowFilteringQuality shadowFilteringQuality;
/// Initialization parameters for punctual shadows atlas.
public HDShadowAtlasInitParams punctualLightShadowAtlas;
/// Initialization parameters for area shadows atlas.
public HDShadowAtlasInitParams areaLightShadowAtlas;
/// Resolution for the punctual lights cached shadow maps atlas.
public int cachedPunctualLightShadowAtlas;
/// Resolution for the area lights cached shadow maps atlas.
public int cachedAreaLightShadowAtlas;
/// Shadow scalable resolution for directional lights.
public IntScalableSetting shadowResolutionDirectional;
/// Shadow scalable resolution for point lights.
public IntScalableSetting shadowResolutionPunctual;
/// Shadow scalable resolution for area lights.
public IntScalableSetting shadowResolutionArea;
/// Maximum shadow map resolution for directional lights.
public int maxDirectionalShadowMapResolution;
/// Maximum shadow map resolution for punctual lights.
public int maxPunctualShadowMapResolution;
/// Maximum shadow map resolution for area lights.
public int maxAreaShadowMapResolution;
/// Enable support for screen space shadows.
public bool supportScreenSpaceShadows;
/// Maximum number of screen space shadows.
public int maxScreenSpaceShadowSlots;
/// Format for screen space shadows.
public ScreenSpaceShadowFormat screenSpaceShadowBufferFormat;
}
class HDShadowResolutionRequest
{
public Rect dynamicAtlasViewport;
public Rect cachedAtlasViewport;
public Vector2 resolution;
public ShadowMapType shadowMapType;
public HDShadowResolutionRequest ShallowCopy()
{
return (HDShadowResolutionRequest)this.MemberwiseClone();
}
}
partial class HDShadowManager
{
public const int k_DirectionalShadowCascadeCount = 4;
public const int k_MinShadowMapResolution = 16;
public const int k_MaxShadowMapResolution = 16384;
List m_ShadowDatas = new List();
HDShadowRequest[] m_ShadowRequests;
HDShadowResolutionRequest[] m_ShadowResolutionRequests;
HDDirectionalShadowData[] m_CachedDirectionalShadowData;
HDDirectionalShadowData m_DirectionalShadowData;
// Structured buffer of shadow datas
ComputeBuffer m_ShadowDataBuffer;
ComputeBuffer m_DirectionalShadowDataBuffer;
// The two shadowmaps atlases we uses, one for directional cascade (without resize) and the second for the rest of the shadows
HDDynamicShadowAtlas m_CascadeAtlas;
HDDynamicShadowAtlas m_Atlas;
HDDynamicShadowAtlas m_AreaLightShadowAtlas;
int m_MaxShadowRequests;
int m_ShadowRequestCount;
int m_CascadeCount;
int m_ShadowResolutionRequestCounter;
Material m_ClearShadowMaterial;
Material m_BlitShadowMaterial;
MaterialPropertyBlock m_BlitShadowPropertyBlock = new MaterialPropertyBlock();
ConstantBuffer m_GlobalShaderVariables;
public static HDCachedShadowManager cachedShadowManager { get { return HDCachedShadowManager.instance; } }
public void InitShadowManager(RenderPipelineResources renderPipelineResources, HDShadowInitParameters initParams, RenderGraph renderGraph, Shader clearShader)
{
// Even when shadows are disabled (maxShadowRequests == 0) we need to allocate compute buffers to avoid having
// resource not bound errors when dispatching a compute shader.
m_ShadowDataBuffer = new ComputeBuffer(Mathf.Max(initParams.maxShadowRequests, 1), System.Runtime.InteropServices.Marshal.SizeOf(typeof(HDShadowData)));
m_DirectionalShadowDataBuffer = new ComputeBuffer(1, System.Runtime.InteropServices.Marshal.SizeOf(typeof(HDDirectionalShadowData)));
m_MaxShadowRequests = initParams.maxShadowRequests;
m_ShadowRequestCount = 0;
if (initParams.maxShadowRequests == 0)
return;
m_ClearShadowMaterial = CoreUtils.CreateEngineMaterial(clearShader);
m_BlitShadowMaterial = CoreUtils.CreateEngineMaterial(renderPipelineResources.shaders.shadowBlitPS);
// Prevent the list from resizing their internal container when we add shadow requests
m_ShadowDatas.Capacity = Math.Max(initParams.maxShadowRequests, m_ShadowDatas.Capacity);
m_ShadowResolutionRequests = new HDShadowResolutionRequest[initParams.maxShadowRequests];
m_ShadowRequests = new HDShadowRequest[initParams.maxShadowRequests];
m_CachedDirectionalShadowData = new HDDirectionalShadowData[1]; // we only support directional light shadow
m_GlobalShaderVariables = new ConstantBuffer();
for (int i = 0; i < initParams.maxShadowRequests; i++)
{
m_ShadowResolutionRequests[i] = new HDShadowResolutionRequest();
}
HDShadowAtlas.HDShadowAtlasInitParameters punctualAtlasInitParams = new HDShadowAtlas.HDShadowAtlasInitParameters(renderPipelineResources, renderGraph, useSharedTexture: false, initParams.punctualLightShadowAtlas.shadowAtlasResolution,
initParams.punctualLightShadowAtlas.shadowAtlasResolution, HDShaderIDs._ShadowmapAtlas, m_ClearShadowMaterial, initParams.maxShadowRequests, initParams, m_GlobalShaderVariables);
punctualAtlasInitParams.name = "Shadow Map Atlas";
// The cascade atlas will be allocated only if there is a directional light
m_Atlas = new HDDynamicShadowAtlas(punctualAtlasInitParams);
// Cascade atlas render texture will only be allocated if there is a shadow casting directional light
HDShadowAtlas.BlurAlgorithm cascadeBlur = GetDirectionalShadowAlgorithm() == DirectionalShadowAlgorithm.IMS ? HDShadowAtlas.BlurAlgorithm.IM : HDShadowAtlas.BlurAlgorithm.None;
HDShadowAtlas.HDShadowAtlasInitParameters dirAtlasInitParams = punctualAtlasInitParams;
dirAtlasInitParams.useSharedTexture = false;
dirAtlasInitParams.width = 1;
dirAtlasInitParams.height = 1;
dirAtlasInitParams.atlasShaderID = HDShaderIDs._ShadowmapCascadeAtlas;
dirAtlasInitParams.blurAlgorithm = cascadeBlur;
dirAtlasInitParams.depthBufferBits = initParams.directionalShadowsDepthBits;
dirAtlasInitParams.name = "Cascade Shadow Map Atlas";
m_CascadeAtlas = new HDDynamicShadowAtlas(dirAtlasInitParams);
HDShadowAtlas.HDShadowAtlasInitParameters areaAtlasInitParams = punctualAtlasInitParams;
if (ShaderConfig.s_AreaLights == 1)
{
areaAtlasInitParams.useSharedTexture = false;
areaAtlasInitParams.width = initParams.areaLightShadowAtlas.shadowAtlasResolution;
areaAtlasInitParams.height = initParams.areaLightShadowAtlas.shadowAtlasResolution;
areaAtlasInitParams.atlasShaderID = HDShaderIDs._ShadowmapAreaAtlas;
areaAtlasInitParams.blurAlgorithm = HDShadowAtlas.BlurAlgorithm.EVSM;
areaAtlasInitParams.depthBufferBits = initParams.areaLightShadowAtlas.shadowAtlasDepthBits;
areaAtlasInitParams.name = "Area Light Shadow Map Atlas";
m_AreaLightShadowAtlas = new HDDynamicShadowAtlas(areaAtlasInitParams);
}
HDShadowAtlas.HDShadowAtlasInitParameters cachedPunctualAtlasInitParams = punctualAtlasInitParams;
cachedPunctualAtlasInitParams.useSharedTexture = true;
cachedPunctualAtlasInitParams.width = initParams.cachedPunctualLightShadowAtlas;
cachedPunctualAtlasInitParams.height = initParams.cachedPunctualLightShadowAtlas;
cachedPunctualAtlasInitParams.atlasShaderID = HDShaderIDs._CachedShadowmapAtlas;
cachedPunctualAtlasInitParams.name = "Cached Shadow Map Atlas";
cachedShadowManager.InitPunctualShadowAtlas(cachedPunctualAtlasInitParams);
if (ShaderConfig.s_AreaLights == 1)
{
HDShadowAtlas.HDShadowAtlasInitParameters cachedAreaAtlasInitParams = areaAtlasInitParams;
cachedAreaAtlasInitParams.useSharedTexture = true;
cachedAreaAtlasInitParams.width = initParams.cachedAreaLightShadowAtlas;
cachedAreaAtlasInitParams.height = initParams.cachedAreaLightShadowAtlas;
cachedAreaAtlasInitParams.atlasShaderID = HDShaderIDs._CachedAreaLightShadowmapAtlas;
cachedAreaAtlasInitParams.name = "Cached Area Light Shadow Map Atlas";
cachedShadowManager.InitAreaLightShadowAtlas(cachedAreaAtlasInitParams);
}
}
public void Cleanup(RenderGraph renderGraph)
{
m_ShadowDataBuffer.Dispose();
m_DirectionalShadowDataBuffer.Dispose();
if (m_MaxShadowRequests == 0)
return;
m_Atlas.Release(renderGraph);
if (ShaderConfig.s_AreaLights == 1)
m_AreaLightShadowAtlas.Release(renderGraph);
m_CascadeAtlas.Release(renderGraph);
CoreUtils.Destroy(m_ClearShadowMaterial);
cachedShadowManager.Cleanup(renderGraph);
m_GlobalShaderVariables.Release();
}
// Keep in sync with both HDShadowSampling.hlsl
public static DirectionalShadowAlgorithm GetDirectionalShadowAlgorithm()
{
switch (HDRenderPipeline.currentAsset.currentPlatformRenderPipelineSettings.hdShadowInitParams.shadowFilteringQuality)
{
case HDShadowFilteringQuality.Low:
{
return DirectionalShadowAlgorithm.PCF5x5;
}
case HDShadowFilteringQuality.Medium:
{
return DirectionalShadowAlgorithm.PCF7x7;
}
case HDShadowFilteringQuality.High:
{
return DirectionalShadowAlgorithm.PCSS;
}
}
;
return DirectionalShadowAlgorithm.PCF5x5;
}
public void UpdateShaderVariablesGlobalCB(ref ShaderVariablesGlobal cb)
{
if (m_MaxShadowRequests == 0)
return;
cb._CascadeShadowCount = (uint)(m_CascadeCount + 1);
cb._ShadowAtlasSize = new Vector4(m_Atlas.width, m_Atlas.height, 1.0f / m_Atlas.width, 1.0f / m_Atlas.height);
cb._CascadeShadowAtlasSize = new Vector4(m_CascadeAtlas.width, m_CascadeAtlas.height, 1.0f / m_CascadeAtlas.width, 1.0f / m_CascadeAtlas.height);
cb._CachedShadowAtlasSize = new Vector4(cachedShadowManager.punctualShadowAtlas.width, cachedShadowManager.punctualShadowAtlas.height, 1.0f / cachedShadowManager.punctualShadowAtlas.width, 1.0f / cachedShadowManager.punctualShadowAtlas.height);
if (ShaderConfig.s_AreaLights == 1)
{
cb._AreaShadowAtlasSize = new Vector4(m_AreaLightShadowAtlas.width, m_AreaLightShadowAtlas.height, 1.0f / m_AreaLightShadowAtlas.width, 1.0f / m_AreaLightShadowAtlas.height);
cb._CachedAreaShadowAtlasSize = new Vector4(cachedShadowManager.areaShadowAtlas.width, cachedShadowManager.areaShadowAtlas.height, 1.0f / cachedShadowManager.areaShadowAtlas.width, 1.0f / cachedShadowManager.areaShadowAtlas.height);
}
}
public void UpdateDirectionalShadowResolution(int resolution, int cascadeCount)
{
Vector2Int atlasResolution = new Vector2Int(resolution, resolution);
if (cascadeCount > 1)
atlasResolution.x *= 2;
if (cascadeCount > 2)
atlasResolution.y *= 2;
m_CascadeAtlas.UpdateSize(atlasResolution);
}
internal int ReserveShadowResolutions(Vector2 resolution, ShadowMapType shadowMapType, int lightID, int index, ShadowMapUpdateType updateType)
{
if (m_ShadowRequestCount >= m_MaxShadowRequests)
{
Debug.LogWarning("Max shadow requests count reached, dropping all exceeding requests. You can increase this limit by changing the max requests in the HDRP asset");
return -1;
}
m_ShadowResolutionRequests[m_ShadowResolutionRequestCounter].shadowMapType = shadowMapType;
// Note: for cached shadows we manage the resolution requests directly on the CachedShadowAtlas as they need special handling. We however keep incrementing the counter for two reasons:
// - Maintain the limit of m_MaxShadowRequests
// - Avoid to refactor other parts that the shadow manager that get requests indices from here.
if (updateType != ShadowMapUpdateType.Cached || shadowMapType == ShadowMapType.CascadedDirectional)
{
m_ShadowResolutionRequests[m_ShadowResolutionRequestCounter].resolution = resolution;
m_ShadowResolutionRequests[m_ShadowResolutionRequestCounter].dynamicAtlasViewport.width = resolution.x;
m_ShadowResolutionRequests[m_ShadowResolutionRequestCounter].dynamicAtlasViewport.height = resolution.y;
switch (shadowMapType)
{
case ShadowMapType.PunctualAtlas:
m_Atlas.ReserveResolution(m_ShadowResolutionRequests[m_ShadowResolutionRequestCounter]);
break;
case ShadowMapType.AreaLightAtlas:
m_AreaLightShadowAtlas.ReserveResolution(m_ShadowResolutionRequests[m_ShadowResolutionRequestCounter]);
break;
case ShadowMapType.CascadedDirectional:
m_CascadeAtlas.ReserveResolution(m_ShadowResolutionRequests[m_ShadowResolutionRequestCounter]);
break;
}
}
m_ShadowResolutionRequestCounter++;
m_ShadowRequestCount = m_ShadowResolutionRequestCounter;
return m_ShadowResolutionRequestCounter - 1;
}
internal HDShadowResolutionRequest GetResolutionRequest(int index)
{
if (index < 0 || index >= m_ShadowRequestCount)
return null;
return m_ShadowResolutionRequests[index];
}
public Vector2 GetReservedResolution(int index)
{
if (index < 0 || index >= m_ShadowRequestCount)
return Vector2.zero;
return m_ShadowResolutionRequests[index].resolution;
}
internal void UpdateShadowRequest(int index, HDShadowRequest shadowRequest, ShadowMapUpdateType updateType)
{
if (index >= m_ShadowRequestCount)
return;
m_ShadowRequests[index] = shadowRequest;
bool addToCached = updateType == ShadowMapUpdateType.Cached || updateType == ShadowMapUpdateType.Mixed;
bool addDynamic = updateType == ShadowMapUpdateType.Dynamic || updateType == ShadowMapUpdateType.Mixed;
switch (shadowRequest.shadowMapType)
{
case ShadowMapType.PunctualAtlas:
{
if (addToCached)
cachedShadowManager.punctualShadowAtlas.AddShadowRequest(shadowRequest);
if (addDynamic)
{
m_Atlas.AddShadowRequest(shadowRequest);
if (updateType == ShadowMapUpdateType.Mixed)
m_Atlas.AddRequestToPendingBlitFromCache(shadowRequest);
}
break;
}
case ShadowMapType.CascadedDirectional:
{
m_CascadeAtlas.AddShadowRequest(shadowRequest);
break;
}
case ShadowMapType.AreaLightAtlas:
{
if (addToCached)
{
cachedShadowManager.areaShadowAtlas.AddShadowRequest(shadowRequest);
}
if (addDynamic)
{
m_AreaLightShadowAtlas.AddShadowRequest(shadowRequest);
if (updateType == ShadowMapUpdateType.Mixed)
m_AreaLightShadowAtlas.AddRequestToPendingBlitFromCache(shadowRequest);
}
break;
}
}
;
}
public void UpdateCascade(int cascadeIndex, Vector4 cullingSphere, float border)
{
if (cullingSphere.w != float.NegativeInfinity)
{
cullingSphere.w *= cullingSphere.w;
}
m_CascadeCount = Mathf.Max(m_CascadeCount, cascadeIndex);
unsafe
{
fixed(float* sphereCascadesBuffer = m_DirectionalShadowData.sphereCascades)
((Vector4*)sphereCascadesBuffer)[cascadeIndex] = cullingSphere;
fixed(float* cascadeBorders = m_DirectionalShadowData.cascadeBorders)
cascadeBorders[cascadeIndex] = border;
}
}
HDShadowData CreateShadowData(HDShadowRequest shadowRequest, HDShadowAtlas atlas)
{
HDShadowData data = new HDShadowData();
var devProj = shadowRequest.deviceProjection;
var view = shadowRequest.view;
data.proj = new Vector4(devProj.m00, devProj.m11, devProj.m22, devProj.m23);
data.pos = shadowRequest.position;
data.rot0 = new Vector3(view.m00, view.m01, view.m02);
data.rot1 = new Vector3(view.m10, view.m11, view.m12);
data.rot2 = new Vector3(view.m20, view.m21, view.m22);
data.shadowToWorld = shadowRequest.shadowToWorld;
data.cacheTranslationDelta = new Vector3(0.0f, 0.0f, 0.0f);
var viewport = shadowRequest.isInCachedAtlas ? shadowRequest.cachedAtlasViewport : shadowRequest.dynamicAtlasViewport;
// Compute the scale and offset (between 0 and 1) for the atlas coordinates
float rWidth = 1.0f / atlas.width;
float rHeight = 1.0f / atlas.height;
data.atlasOffset = Vector2.Scale(new Vector2(rWidth, rHeight), new Vector2(viewport.x, viewport.y));
data.shadowMapSize = new Vector4(viewport.width, viewport.height, 1.0f / viewport.width, 1.0f / viewport.height);
data.normalBias = shadowRequest.normalBias;
data.worldTexelSize = shadowRequest.worldTexelSize;
data.shadowFilterParams0.x = shadowRequest.shadowSoftness;
data.shadowFilterParams0.y = HDShadowUtils.Asfloat(shadowRequest.blockerSampleCount);
data.shadowFilterParams0.z = HDShadowUtils.Asfloat(shadowRequest.filterSampleCount);
data.shadowFilterParams0.w = shadowRequest.minFilterSize;
data.zBufferParam = shadowRequest.zBufferParam;
if (atlas.HasBlurredEVSM())
{
data.shadowFilterParams0 = shadowRequest.evsmParams;
}
data.isInCachedAtlas = shadowRequest.isInCachedAtlas ? 1.0f : 0.0f;
return data;
}
unsafe Vector4 GetCascadeSphereAtIndex(int index)
{
fixed(float* sphereCascadesBuffer = m_DirectionalShadowData.sphereCascades)
{
return ((Vector4*)sphereCascadesBuffer)[index];
}
}
public void UpdateCullingParameters(ref ScriptableCullingParameters cullingParams, float maxShadowDistance)
{
cullingParams.shadowDistance = Mathf.Min(maxShadowDistance, cullingParams.shadowDistance);
}
public void LayoutShadowMaps(LightingDebugSettings lightingDebugSettings)
{
if (m_MaxShadowRequests == 0)
return;
cachedShadowManager.UpdateDebugSettings(lightingDebugSettings);
m_Atlas.UpdateDebugSettings(lightingDebugSettings);
if (m_CascadeAtlas != null)
m_CascadeAtlas.UpdateDebugSettings(lightingDebugSettings);
if (ShaderConfig.s_AreaLights == 1)
m_AreaLightShadowAtlas.UpdateDebugSettings(lightingDebugSettings);
if (lightingDebugSettings.shadowResolutionScaleFactor != 1.0f)
{
foreach (var shadowResolutionRequest in m_ShadowResolutionRequests)
{
// We don't rescale the directional shadows with the global shadow scale factor
// because there is no dynamic atlas rescale when it overflow.
if (shadowResolutionRequest.shadowMapType != ShadowMapType.CascadedDirectional)
shadowResolutionRequest.resolution *= lightingDebugSettings.shadowResolutionScaleFactor;
}
}
// Assign a position to all the shadows in the atlas, and scale shadows if needed
if (m_CascadeAtlas != null && !m_CascadeAtlas.Layout(false))
Debug.LogError("Cascade Shadow atlasing has failed, only one directional light can cast shadows at a time");
m_Atlas.Layout();
if (ShaderConfig.s_AreaLights == 1)
m_AreaLightShadowAtlas.Layout();
}
unsafe public void PrepareGPUShadowDatas(CullingResults cullResults, HDCamera camera)
{
if (m_MaxShadowRequests == 0)
return;
int shadowIndex = 0;
m_ShadowDatas.Clear();
// Create all HDShadowDatas and update them with shadow request datas
for (int i = 0; i < m_ShadowRequestCount; i++)
{
Debug.Assert(m_ShadowRequests[i] != null);
HDShadowAtlas atlas = m_Atlas;
if (m_ShadowRequests[i].isInCachedAtlas)
{
atlas = cachedShadowManager.punctualShadowAtlas;
}
if (m_ShadowRequests[i].shadowMapType == ShadowMapType.CascadedDirectional)
{
atlas = m_CascadeAtlas;
}
else if (m_ShadowRequests[i].shadowMapType == ShadowMapType.AreaLightAtlas)
{
atlas = m_AreaLightShadowAtlas;
if (m_ShadowRequests[i].isInCachedAtlas)
{
atlas = cachedShadowManager.areaShadowAtlas;
}
}
HDShadowData shadowData;
if (m_ShadowRequests[i].shouldUseCachedShadowData)
{
shadowData = m_ShadowRequests[i].cachedShadowData;
}
else
{
shadowData = CreateShadowData(m_ShadowRequests[i], atlas);
m_ShadowRequests[i].cachedShadowData = shadowData;
}
m_ShadowDatas.Add(shadowData);
m_ShadowRequests[i].shadowIndex = shadowIndex++;
}
int first = k_DirectionalShadowCascadeCount, second = k_DirectionalShadowCascadeCount;
fixed(float* sphereBuffer = m_DirectionalShadowData.sphereCascades)
{
Vector4* sphere = (Vector4*)sphereBuffer;
for (int i = 0; i < k_DirectionalShadowCascadeCount; i++)
{
first = (first == k_DirectionalShadowCascadeCount && sphere[i].w > 0.0f) ? i : first;
second = ((second == k_DirectionalShadowCascadeCount || second == first) && sphere[i].w > 0.0f) ? i : second;
}
}
// Update directional datas:
if (second != k_DirectionalShadowCascadeCount)
m_DirectionalShadowData.cascadeDirection = (GetCascadeSphereAtIndex(second) - GetCascadeSphereAtIndex(first)).normalized;
else
m_DirectionalShadowData.cascadeDirection = Vector4.zero;
m_DirectionalShadowData.cascadeDirection.w = camera.volumeStack.GetComponent().cascadeShadowSplitCount.value;
if (m_ShadowRequestCount > 0)
{
// Upload the shadow buffers to GPU
m_ShadowDataBuffer.SetData(m_ShadowDatas);
m_CachedDirectionalShadowData[0] = m_DirectionalShadowData;
m_DirectionalShadowDataBuffer.SetData(m_CachedDirectionalShadowData);
}
}
public void PushGlobalParameters(CommandBuffer cmd)
{
// This code must be in sync with HDShadowContext.hlsl
cmd.SetGlobalBuffer(HDShaderIDs._HDShadowDatas, m_ShadowDataBuffer);
cmd.SetGlobalBuffer(HDShaderIDs._HDDirectionalShadowData, m_DirectionalShadowDataBuffer);
}
public int GetShadowRequestCount()
{
return m_ShadowRequestCount;
}
public void Clear()
{
if (m_MaxShadowRequests == 0)
return;
// Clear the shadows atlas infos and requests
m_Atlas.Clear();
m_CascadeAtlas.Clear();
if (ShaderConfig.s_AreaLights == 1)
m_AreaLightShadowAtlas.Clear();
cachedShadowManager.ClearShadowRequests();
m_ShadowResolutionRequestCounter = 0;
m_ShadowRequestCount = 0;
m_CascadeCount = 0;
}
public struct ShadowDebugAtlasTextures
{
public RTHandle punctualShadowAtlas;
public RTHandle cascadeShadowAtlas;
public RTHandle areaShadowAtlas;
public RTHandle cachedPunctualShadowAtlas;
public RTHandle cachedAreaShadowAtlas;
}
// Warning: must be called after ProcessShadowRequests and RenderShadows to have valid informations
public void DisplayShadowAtlas(RTHandle atlasTexture, CommandBuffer cmd, Material debugMaterial, float screenX, float screenY, float screenSizeX, float screenSizeY, float minValue, float maxValue, MaterialPropertyBlock mpb)
{
m_Atlas.DisplayAtlas(atlasTexture, cmd, debugMaterial, new Rect(0, 0, m_Atlas.width, m_Atlas.height), screenX, screenY, screenSizeX, screenSizeY, minValue, maxValue, mpb);
}
// Warning: must be called after ProcessShadowRequests and RenderShadows to have valid informations
public void DisplayShadowCascadeAtlas(RTHandle atlasTexture, CommandBuffer cmd, Material debugMaterial, float screenX, float screenY, float screenSizeX, float screenSizeY, float minValue, float maxValue, MaterialPropertyBlock mpb)
{
m_CascadeAtlas.DisplayAtlas(atlasTexture, cmd, debugMaterial, new Rect(0, 0, m_CascadeAtlas.width, m_CascadeAtlas.height), screenX, screenY, screenSizeX, screenSizeY, minValue, maxValue, mpb);
}
// Warning: must be called after ProcessShadowRequests and RenderShadows to have valid informations
public void DisplayAreaLightShadowAtlas(RTHandle atlasTexture, CommandBuffer cmd, Material debugMaterial, float screenX, float screenY, float screenSizeX, float screenSizeY, float minValue, float maxValue, MaterialPropertyBlock mpb)
{
if (ShaderConfig.s_AreaLights == 1)
m_AreaLightShadowAtlas.DisplayAtlas(atlasTexture, cmd, debugMaterial, new Rect(0, 0, m_AreaLightShadowAtlas.width, m_AreaLightShadowAtlas.height), screenX, screenY, screenSizeX, screenSizeY, minValue, maxValue, mpb);
}
public void DisplayCachedPunctualShadowAtlas(RTHandle atlasTexture, CommandBuffer cmd, Material debugMaterial, float screenX, float screenY, float screenSizeX, float screenSizeY, float minValue, float maxValue, MaterialPropertyBlock mpb)
{
cachedShadowManager.punctualShadowAtlas.DisplayAtlas(atlasTexture, cmd, debugMaterial, new Rect(0, 0, cachedShadowManager.punctualShadowAtlas.width, cachedShadowManager.punctualShadowAtlas.height), screenX, screenY, screenSizeX, screenSizeY, minValue, maxValue, mpb);
}
public void DisplayCachedAreaShadowAtlas(RTHandle atlasTexture, CommandBuffer cmd, Material debugMaterial, float screenX, float screenY, float screenSizeX, float screenSizeY, float minValue, float maxValue, MaterialPropertyBlock mpb)
{
if (ShaderConfig.s_AreaLights == 1)
cachedShadowManager.areaShadowAtlas.DisplayAtlas(atlasTexture, cmd, debugMaterial, new Rect(0, 0, cachedShadowManager.areaShadowAtlas.width, cachedShadowManager.areaShadowAtlas.height), screenX, screenY, screenSizeX, screenSizeY, minValue, maxValue, mpb);
}
// Warning: must be called after ProcessShadowRequests and RenderShadows to have valid informations
public void DisplayShadowMap(in ShadowDebugAtlasTextures atlasTextures, int shadowIndex, CommandBuffer cmd, Material debugMaterial, float screenX, float screenY, float screenSizeX, float screenSizeY, float minValue, float maxValue, MaterialPropertyBlock mpb)
{
if (shadowIndex >= m_ShadowRequestCount)
return;
HDShadowRequest shadowRequest = m_ShadowRequests[shadowIndex];
switch (shadowRequest.shadowMapType)
{
case ShadowMapType.PunctualAtlas:
{
if (shadowRequest.isInCachedAtlas)
cachedShadowManager.punctualShadowAtlas.DisplayAtlas(atlasTextures.cachedPunctualShadowAtlas, cmd, debugMaterial, shadowRequest.cachedAtlasViewport, screenX, screenY, screenSizeX, screenSizeY, minValue, maxValue, mpb);
else
m_Atlas.DisplayAtlas(atlasTextures.punctualShadowAtlas, cmd, debugMaterial, shadowRequest.dynamicAtlasViewport, screenX, screenY, screenSizeX, screenSizeY, minValue, maxValue, mpb);
break;
}
case ShadowMapType.CascadedDirectional:
{
m_CascadeAtlas.DisplayAtlas(atlasTextures.cascadeShadowAtlas, cmd, debugMaterial, shadowRequest.dynamicAtlasViewport, screenX, screenY, screenSizeX, screenSizeY, minValue, maxValue, mpb);
break;
}
case ShadowMapType.AreaLightAtlas:
{
if (ShaderConfig.s_AreaLights == 1)
{
if (shadowRequest.isInCachedAtlas)
cachedShadowManager.areaShadowAtlas.DisplayAtlas(atlasTextures.cachedAreaShadowAtlas, cmd, debugMaterial, shadowRequest.cachedAtlasViewport, screenX, screenY, screenSizeX, screenSizeY, minValue, maxValue, mpb);
else
m_AreaLightShadowAtlas.DisplayAtlas(atlasTextures.areaShadowAtlas, cmd, debugMaterial, shadowRequest.dynamicAtlasViewport, screenX, screenY, screenSizeX, screenSizeY, minValue, maxValue, mpb);
}
break;
}
}
;
}
}
}