1148 lines
72 KiB
C#
1148 lines
72 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.CompilerServices;
|
|
using Unity.Collections;
|
|
using Unity.Collections.LowLevel.Unsafe;
|
|
using Unity.Profiling;
|
|
using Unity.Mathematics;
|
|
using Unity.Jobs;
|
|
|
|
namespace UnityEngine.Rendering.HighDefinition
|
|
{
|
|
internal partial class HDGpuLightsBuilder
|
|
{
|
|
#region internal HDRP API
|
|
|
|
//Preallocates number of lights for bounds arrays and resets all internal counters. Must be called once per frame per view always.
|
|
public void NewFrame(HDCamera hdCamera, int maxLightCount)
|
|
{
|
|
int viewCounts = hdCamera.viewCount;
|
|
if (viewCounts > m_LighsPerViewCapacity)
|
|
{
|
|
m_LighsPerViewCapacity = viewCounts;
|
|
m_LightsPerView.ResizeArray(m_LighsPerViewCapacity);
|
|
}
|
|
|
|
m_LightsPerViewCount = viewCounts;
|
|
|
|
int totalBoundsCount = maxLightCount * viewCounts;
|
|
int requestedBoundsCount = Math.Max(totalBoundsCount, 1);
|
|
if (requestedBoundsCount > m_LightBoundsCapacity)
|
|
{
|
|
m_LightBoundsCapacity = Math.Max(Math.Max(m_LightBoundsCapacity * 2, requestedBoundsCount), ArrayCapacity);
|
|
m_LightBounds.ResizeArray(m_LightBoundsCapacity);
|
|
m_LightVolumes.ResizeArray(m_LightBoundsCapacity);
|
|
}
|
|
m_LightBoundsCount = totalBoundsCount;
|
|
|
|
m_BoundsEyeDataOffset = maxLightCount;
|
|
|
|
for (int viewId = 0; viewId < viewCounts; ++viewId)
|
|
{
|
|
m_LightsPerView[viewId] = new LightsPerView()
|
|
{
|
|
worldToView = HDRenderPipeline.GetWorldToViewMatrix(hdCamera, viewId),
|
|
boundsOffset = viewId * m_BoundsEyeDataOffset,
|
|
boundsCount = 0
|
|
};
|
|
}
|
|
|
|
if (!m_LightTypeCounters.IsCreated)
|
|
m_LightTypeCounters.ResizeArray(Enum.GetValues(typeof(GPULightTypeCountSlots)).Length);
|
|
|
|
m_LightCount = 0;
|
|
m_ContactShadowIndex = 0;
|
|
m_ScreenSpaceShadowIndex = 0;
|
|
m_ScreenSpaceShadowChannelSlot = 0;
|
|
m_ScreenSpaceShadowsUnion.Clear();
|
|
|
|
m_CurrentShadowSortedSunLightIndex = -1;
|
|
m_CurrentSunShadowMapFlags = HDProcessedVisibleLightsBuilder.ShadowMapFlags.None;
|
|
|
|
m_DebugSelectedLightShadowIndex = -1;
|
|
m_DebugSelectedLightShadowCount = 0;
|
|
|
|
for (int i = 0; i < m_Asset.currentPlatformRenderPipelineSettings.hdShadowInitParams.maxScreenSpaceShadowSlots; ++i)
|
|
{
|
|
m_CurrentScreenSpaceShadowData[i].additionalLightData = null;
|
|
m_CurrentScreenSpaceShadowData[i].lightDataIndex = -1;
|
|
m_CurrentScreenSpaceShadowData[i].valid = false;
|
|
}
|
|
|
|
for (int i = 0; i < m_LightTypeCounters.Length; ++i)
|
|
m_LightTypeCounters[i] = 0;
|
|
}
|
|
|
|
//Builds the GPU light list.
|
|
public void Build(
|
|
CommandBuffer cmd,
|
|
HDCamera hdCamera,
|
|
in CullingResults cullingResult,
|
|
HDProcessedVisibleLightsBuilder visibleLights,
|
|
HDLightRenderDatabase lightEntities,
|
|
in HDShadowInitParameters shadowInitParams,
|
|
DebugDisplaySettings debugDisplaySettings)
|
|
{
|
|
// Using the same pattern than shadowmaps, light have requested space in the atlas for their
|
|
// cookies and now we can layout the atlas (re-insert all entries by order of size) if needed
|
|
m_TextureCaches.lightCookieManager.LayoutIfNeeded();
|
|
|
|
int totalLightsCount = visibleLights.sortedLightCounts;
|
|
int lightsCount = visibleLights.sortedNonDirectionalLightCounts;
|
|
int directionalCount = visibleLights.sortedDirectionalLightCounts;
|
|
AllocateLightData(lightsCount, directionalCount);
|
|
|
|
// TODO: Refactor shadow management
|
|
// The good way of managing shadow:
|
|
// Here we sort everyone and we decide which light is important or not (this is the responsibility of the lightloop)
|
|
// we allocate shadow slot based on maximum shadow allowed on screen and attribute slot by bigger solid angle
|
|
// THEN we ask to the ShadowRender to render the shadow, not the reverse as it is today (i.e render shadow than expect they
|
|
// will be use...)
|
|
// The lightLoop is in charge, not the shadow pass.
|
|
// For now we will still apply the maximum of shadow here but we don't apply the sorting by priority + slot allocation yet
|
|
|
|
if (totalLightsCount > 0)
|
|
{
|
|
for (int viewId = 0; viewId < hdCamera.viewCount; ++viewId)
|
|
{
|
|
var viewInfo = m_LightsPerView[viewId];
|
|
viewInfo.boundsCount += lightsCount;
|
|
m_LightsPerView[viewId] = viewInfo;
|
|
}
|
|
|
|
var hdShadowSettings = hdCamera.volumeStack.GetComponent<HDShadowSettings>();
|
|
StartCreateGpuLightDataJob(hdCamera, cullingResult, hdShadowSettings, visibleLights, lightEntities);
|
|
CompleteGpuLightDataJob();
|
|
CalculateAllLightDataTextureInfo(cmd, hdCamera, cullingResult, visibleLights, lightEntities, hdShadowSettings, shadowInitParams, debugDisplaySettings);
|
|
}
|
|
|
|
//Sanity check
|
|
Debug.Assert(m_DirectionalLightCount == directionalLightCount, "Mismatch in Directional gpu lights processed. Lights should not be culled in this loop.");
|
|
Debug.Assert(m_LightCount == areaLightCount + punctualLightCount, "Mismatch in Area and Punctual gpu lights processed. Lights should not be culled in this loop.");
|
|
}
|
|
|
|
//Calculates a shadow type for a light and sets the shadow index information into the LightData.
|
|
public void ProcessLightDataShadowIndex(
|
|
CommandBuffer cmd,
|
|
in HDShadowInitParameters shadowInitParams,
|
|
LightType lightType,
|
|
Light lightComponent,
|
|
HDAdditionalLightData additionalLightData,
|
|
int shadowIndex,
|
|
ref LightData lightData)
|
|
{
|
|
if (lightData.lightType == GPULightType.ProjectorBox && shadowIndex >= 0)
|
|
{
|
|
// We subtract a bit from the safe extent depending on shadow resolution
|
|
float shadowRes = additionalLightData.shadowResolution.Value(shadowInitParams.shadowResolutionPunctual);
|
|
shadowRes = Mathf.Clamp(shadowRes, 128.0f, 2048.0f); // Clamp in a somewhat plausible range.
|
|
// The idea is to subtract as much as 0.05 for small resolutions.
|
|
float shadowResFactor = Mathf.Lerp(0.05f, 0.01f, Mathf.Max(shadowRes / 2048.0f, 0.0f));
|
|
lightData.boxLightSafeExtent = 1.0f - shadowResFactor;
|
|
}
|
|
|
|
if (lightComponent != null &&
|
|
(
|
|
(lightType.IsSpot() && (lightComponent.cookie != null || additionalLightData.IESPoint != null)) ||
|
|
((lightType.IsArea() && (lightData.lightType == GPULightType.Rectangle || lightData.lightType == GPULightType.Disc)) && (lightComponent.cookie != null || additionalLightData.IESSpot != null)) ||
|
|
(lightType == LightType.Point && (lightComponent.cookie != null || additionalLightData.IESPoint != null))
|
|
)
|
|
)
|
|
{
|
|
switch (lightType)
|
|
{
|
|
case LightType.Spot:
|
|
case LightType.Pyramid:
|
|
case LightType.Box:
|
|
lightData.cookieMode = (lightComponent.cookie?.wrapMode == TextureWrapMode.Repeat) ? CookieMode.Repeat : CookieMode.Clamp;
|
|
if (additionalLightData.IESSpot != null && lightComponent.cookie != null && additionalLightData.IESSpot != lightComponent.cookie)
|
|
lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.Fetch2DCookie(cmd, lightComponent.cookie, additionalLightData.IESSpot);
|
|
else if (lightComponent.cookie != null)
|
|
lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.Fetch2DCookie(cmd, lightComponent.cookie);
|
|
else if (additionalLightData.IESSpot != null)
|
|
lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.Fetch2DCookie(cmd, additionalLightData.IESSpot);
|
|
else
|
|
lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.Fetch2DCookie(cmd, Texture2D.whiteTexture);
|
|
break;
|
|
case LightType.Point:
|
|
lightData.cookieMode = CookieMode.Repeat;
|
|
if (additionalLightData.IESPoint != null && lightComponent.cookie != null && additionalLightData.IESPoint != lightComponent.cookie)
|
|
lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.FetchCubeCookie(cmd, lightComponent.cookie, additionalLightData.IESPoint);
|
|
else if (lightComponent.cookie != null)
|
|
lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.FetchCubeCookie(cmd, lightComponent.cookie);
|
|
else if (additionalLightData.IESPoint != null)
|
|
lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.FetchCubeCookie(cmd, additionalLightData.IESPoint);
|
|
break;
|
|
case LightType.Rectangle:
|
|
case LightType.Tube:
|
|
case LightType.Disc:
|
|
lightData.cookieMode = CookieMode.Clamp;
|
|
if (additionalLightData.areaLightCookie != null && additionalLightData.IESSpot != null && additionalLightData.areaLightCookie != additionalLightData.IESSpot)
|
|
lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.FetchAreaCookie(cmd, additionalLightData.areaLightCookie, additionalLightData.IESSpot);
|
|
else if (additionalLightData.IESSpot != null)
|
|
lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.FetchAreaCookie(cmd, additionalLightData.IESSpot);
|
|
else if (additionalLightData.areaLightCookie != null)
|
|
lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.FetchAreaCookie(cmd, additionalLightData.areaLightCookie);
|
|
break;
|
|
}
|
|
}
|
|
else if (lightType == LightType.Pyramid || lightType == LightType.Box)
|
|
{
|
|
// Projectors lights must always have a cookie texture.
|
|
// As long as the cache is a texture array and not an atlas, the 4x4 white texture will be rescaled to 128
|
|
lightData.cookieMode = CookieMode.Clamp;
|
|
lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.Fetch2DCookie(cmd, Texture2D.whiteTexture);
|
|
}
|
|
else if (lightData.lightType == GPULightType.Rectangle || lightData.lightType == GPULightType.Disc)
|
|
{
|
|
if (additionalLightData.areaLightCookie != null || additionalLightData.IESPoint != null)
|
|
{
|
|
lightData.cookieMode = CookieMode.Clamp;
|
|
if (additionalLightData.areaLightCookie != null && additionalLightData.IESSpot != null && additionalLightData.areaLightCookie != additionalLightData.IESSpot)
|
|
lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.FetchAreaCookie(cmd, additionalLightData.areaLightCookie, additionalLightData.IESSpot);
|
|
else if (additionalLightData.IESSpot != null)
|
|
lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.FetchAreaCookie(cmd, additionalLightData.IESSpot);
|
|
else if (additionalLightData.areaLightCookie != null)
|
|
lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.FetchAreaCookie(cmd, additionalLightData.areaLightCookie);
|
|
}
|
|
}
|
|
|
|
lightData.shadowIndex = shadowIndex;
|
|
additionalLightData.shadowIndex = shadowIndex;
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
// The first rendered 24 lights that have contact shadow enabled have a mask used to select the bit that contains
|
|
// the contact shadow shadowed information (occluded or not). Otherwise -1 is written
|
|
private void GetContactShadowMask(HDAdditionalLightData hdAdditionalLightData, BoolScalableSetting contactShadowEnabled, HDCamera hdCamera, ref int contactShadowMask, ref float rayTracingShadowFlag)
|
|
{
|
|
contactShadowMask = 0;
|
|
rayTracingShadowFlag = 0.0f;
|
|
// If contact shadows are not enabled or we already reached the manimal number of contact shadows
|
|
// or this is not rasterization
|
|
if ((!hdAdditionalLightData.useContactShadow.Value(contactShadowEnabled))
|
|
|| m_ContactShadowIndex >= LightDefinitions.s_ContactShadowMaskMask)
|
|
return;
|
|
|
|
// Evaluate the contact shadow index of this light
|
|
contactShadowMask = 1 << m_ContactShadowIndex;
|
|
m_ContactShadowIndex++; // Update the index for next light that will need to cast contact shadows.
|
|
|
|
// If this light has ray traced contact shadow
|
|
if (hdCamera.frameSettings.IsEnabled(FrameSettingsField.RayTracing) && hdAdditionalLightData.rayTraceContactShadow)
|
|
rayTracingShadowFlag = 1.0f;
|
|
}
|
|
|
|
private bool EnoughScreenSpaceShadowSlots(GPULightType gpuLightType, int screenSpaceChannelSlot)
|
|
{
|
|
if (gpuLightType == GPULightType.Rectangle)
|
|
{
|
|
// Area lights require two shadow slots
|
|
return (screenSpaceChannelSlot + 1) < m_Asset.currentPlatformRenderPipelineSettings.hdShadowInitParams.maxScreenSpaceShadowSlots;
|
|
}
|
|
else
|
|
{
|
|
return screenSpaceChannelSlot < m_Asset.currentPlatformRenderPipelineSettings.hdShadowInitParams.maxScreenSpaceShadowSlots;
|
|
}
|
|
}
|
|
|
|
private void CalculateDirectionalLightDataTextureInfo(
|
|
ref DirectionalLightData lightData, CommandBuffer cmd, in VisibleLight light, in Light lightComponent, in HDAdditionalLightData additionalLightData,
|
|
HDCamera hdCamera, HDProcessedVisibleLightsBuilder.ShadowMapFlags shadowFlags, int lightDataIndex, int shadowIndex)
|
|
{
|
|
if (shadowIndex != -1)
|
|
{
|
|
if ((shadowFlags & HDProcessedVisibleLightsBuilder.ShadowMapFlags.WillRenderScreenSpaceShadow) != 0)
|
|
{
|
|
lightData.screenSpaceShadowIndex = m_ScreenSpaceShadowChannelSlot;
|
|
bool willRenderRtShadows = (shadowFlags & HDProcessedVisibleLightsBuilder.ShadowMapFlags.WillRenderRayTracedShadow) != 0;
|
|
if (additionalLightData.colorShadow && willRenderRtShadows)
|
|
{
|
|
m_ScreenSpaceShadowChannelSlot += 3;
|
|
lightData.screenSpaceShadowIndex |= (int)LightDefinitions.s_ScreenSpaceColorShadowFlag;
|
|
}
|
|
else
|
|
{
|
|
m_ScreenSpaceShadowChannelSlot++;
|
|
}
|
|
|
|
// Raise the ray tracing flag in case the light is ray traced
|
|
if (willRenderRtShadows)
|
|
lightData.screenSpaceShadowIndex |= (int)LightDefinitions.s_RayTracedScreenSpaceShadowFlag;
|
|
|
|
// increment the number of screen space shadows
|
|
m_ScreenSpaceShadowIndex++;
|
|
|
|
m_ScreenSpaceShadowsUnion.Add(additionalLightData);
|
|
}
|
|
m_CurrentSunLightDirectionalLightData = lightData;
|
|
m_CurrentShadowSortedSunLightIndex = lightDataIndex;
|
|
m_CurrentSunShadowMapFlags = shadowFlags;
|
|
}
|
|
|
|
// Get correct light cookie in case it is overriden by a volume
|
|
CookieParameters cookieParams = new CookieParameters()
|
|
{
|
|
texture = lightComponent?.cookie,
|
|
size = new Vector2(additionalLightData.shapeWidth, additionalLightData.shapeHeight),
|
|
position = light.GetPosition()
|
|
};
|
|
|
|
if (lightComponent == HDRenderPipeline.currentPipeline.GetMainLight())
|
|
{
|
|
if (HDRenderPipeline.currentPipeline.skyManager.TryGetCloudSettings(hdCamera, out var cloudSettings, out var cloudRenderer))
|
|
{
|
|
if (cloudRenderer.GetSunLightCookieParameters(cloudSettings, ref cookieParams))
|
|
{
|
|
var builtinParams = new BuiltinSunCookieParameters
|
|
{
|
|
cloudSettings = cloudSettings,
|
|
sunLight = lightComponent,
|
|
hdCamera = hdCamera,
|
|
commandBuffer = cmd
|
|
};
|
|
cloudRenderer.RenderSunLightCookie(builtinParams);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cookieParams.texture)
|
|
{
|
|
lightData.cookieMode = cookieParams.texture.wrapMode == TextureWrapMode.Repeat ? CookieMode.Repeat : CookieMode.Clamp;
|
|
lightData.cookieScaleOffset = m_TextureCaches.lightCookieManager.Fetch2DCookie(cmd, cookieParams.texture);
|
|
}
|
|
else
|
|
{
|
|
lightData.cookieMode = CookieMode.None;
|
|
}
|
|
|
|
lightData.right = light.GetRight() * 2 / Mathf.Max(cookieParams.size.x, 0.001f);
|
|
lightData.up = light.GetUp() * 2 / Mathf.Max(cookieParams.size.y, 0.001f);
|
|
|
|
// Apply precomputed atmospheric attenuation on light
|
|
if (ShaderConfig.s_PrecomputedAtmosphericAttenuation != 0 && additionalLightData.interactsWithSky)
|
|
{
|
|
var skySettings = SkyManager.GetSkySetting(hdCamera.volumeStack);
|
|
if (skySettings)
|
|
{
|
|
Vector3 transm = skySettings.EvaluateAtmosphericAttenuation(-lightData.forward, hdCamera.camera.transform.position);
|
|
lightData.color.x *= transm.x;
|
|
lightData.color.y *= transm.y;
|
|
lightData.color.z *= transm.z;
|
|
}
|
|
}
|
|
|
|
GetContactShadowMask(additionalLightData, HDAdditionalLightData.ScalableSettings.UseContactShadow(m_Asset), hdCamera, ref lightData.contactShadowMask, ref lightData.isRayTracedContactShadow);
|
|
|
|
lightData.shadowIndex = shadowIndex;
|
|
additionalLightData.shadowIndex = shadowIndex;
|
|
}
|
|
|
|
private void CalculateLightDataTextureInfo(
|
|
ref LightData lightData, CommandBuffer cmd, in Light lightComponent, HDAdditionalLightData additionalLightData, in HDShadowInitParameters shadowInitParams,
|
|
in HDCamera hdCamera, BoolScalableSetting contactShadowScalableSetting,
|
|
LightType lightType, HDProcessedVisibleLightsBuilder.ShadowMapFlags shadowFlags, bool rayTracingEnabled, int lightDataIndex, int shadowIndex)
|
|
{
|
|
ProcessLightDataShadowIndex(
|
|
cmd,
|
|
shadowInitParams,
|
|
lightType,
|
|
lightComponent,
|
|
additionalLightData,
|
|
shadowIndex,
|
|
ref lightData);
|
|
|
|
GetContactShadowMask(additionalLightData, contactShadowScalableSetting, hdCamera, ref lightData.contactShadowMask, ref lightData.isRayTracedContactShadow);
|
|
|
|
// If there is still a free slot in the screen space shadow array and this needs to render a screen space shadow
|
|
if (rayTracingEnabled
|
|
&& EnoughScreenSpaceShadowSlots(lightData.lightType, m_ScreenSpaceShadowChannelSlot)
|
|
&& (shadowFlags & HDProcessedVisibleLightsBuilder.ShadowMapFlags.WillRenderScreenSpaceShadow) != 0)
|
|
{
|
|
if (lightData.lightType == GPULightType.Rectangle)
|
|
{
|
|
// Rectangle area lights require 2 consecutive slots.
|
|
// Meaning if (screenSpaceChannelSlot % 4 ==3), we'll need to skip a slot
|
|
// so that the area shadow gets the first two slots of the next following texture
|
|
if (m_ScreenSpaceShadowChannelSlot % 4 == 3)
|
|
{
|
|
m_ScreenSpaceShadowChannelSlot++;
|
|
}
|
|
}
|
|
|
|
// Bind the next available slot to the light
|
|
lightData.screenSpaceShadowIndex = m_ScreenSpaceShadowChannelSlot;
|
|
|
|
// Keep track of the screen space shadow data
|
|
m_CurrentScreenSpaceShadowData[m_ScreenSpaceShadowIndex].additionalLightData = additionalLightData;
|
|
m_CurrentScreenSpaceShadowData[m_ScreenSpaceShadowIndex].lightDataIndex = lightDataIndex;
|
|
m_CurrentScreenSpaceShadowData[m_ScreenSpaceShadowIndex].valid = true;
|
|
m_ScreenSpaceShadowsUnion.Add(additionalLightData);
|
|
|
|
// increment the number of screen space shadows
|
|
m_ScreenSpaceShadowIndex++;
|
|
|
|
// Based on the light type, increment the slot usage
|
|
if (lightData.lightType == GPULightType.Rectangle)
|
|
m_ScreenSpaceShadowChannelSlot += 2;
|
|
else
|
|
m_ScreenSpaceShadowChannelSlot++;
|
|
}
|
|
}
|
|
|
|
private unsafe void CalculateAllLightDataTextureInfo(
|
|
CommandBuffer cmd,
|
|
HDCamera hdCamera,
|
|
in CullingResults cullResults,
|
|
HDProcessedVisibleLightsBuilder visibleLights,
|
|
HDLightRenderDatabase lightEntities,
|
|
HDShadowSettings hdShadowSettings,
|
|
in HDShadowInitParameters shadowInitParams,
|
|
DebugDisplaySettings debugDisplaySettings)
|
|
{
|
|
BoolScalableSetting contactShadowScalableSetting = HDAdditionalLightData.ScalableSettings.UseContactShadow(m_Asset);
|
|
bool rayTracingEnabled = hdCamera.frameSettings.IsEnabled(FrameSettingsField.RayTracing);
|
|
HDProcessedVisibleLight* processedLightArrayPtr = (HDProcessedVisibleLight*)visibleLights.processedEntities.GetUnsafePtr<HDProcessedVisibleLight>();
|
|
LightData* lightArrayPtr = (LightData*)m_Lights.GetUnsafePtr<LightData>();
|
|
DirectionalLightData* directionalLightArrayPtr = (DirectionalLightData*)m_DirectionalLights.GetUnsafePtr<DirectionalLightData>();
|
|
VisibleLight* visibleLightsArrayPtr = (VisibleLight*)cullResults.visibleLights.GetUnsafePtr<VisibleLight>();
|
|
|
|
int directionalLightCount = visibleLights.sortedDirectionalLightCounts;
|
|
int lightCounts = visibleLights.sortedLightCounts;
|
|
EnsureScratchpadCapacity(lightCounts);
|
|
|
|
NativeArray<int> shadowIndexResults = m_ShadowIndicesScratchpadArray;
|
|
UpdateShadowRequestsAndCalculateShadowIndices(hdCamera, in cullResults, visibleLights, lightEntities, hdShadowSettings, debugDisplaySettings,
|
|
m_ShadowManager, m_Asset, shadowIndexResults, ref m_DebugSelectedLightShadowIndex, ref m_DebugSelectedLightShadowCount);
|
|
|
|
using (new ProfilingScope(ProfilingSampler.Get(HDProfileId.CalculateLightDataTextureInfo)))
|
|
{
|
|
for (int sortKeyIndex = 0; sortKeyIndex < lightCounts; ++sortKeyIndex)
|
|
{
|
|
uint sortKey = visibleLights.sortKeys[sortKeyIndex];
|
|
HDGpuLightsBuilder.UnpackLightSortKey(sortKey, out var lightCategory, out var gpuLightType, out var lightVolumeType, out var lightIndex, out var offscreen);
|
|
|
|
// We don't need offscreen lights on the GPU
|
|
if (offscreen)
|
|
continue;
|
|
|
|
int dataIndex = visibleLights.visibleLightEntityDataIndices[lightIndex];
|
|
if (dataIndex == HDLightRenderDatabase.InvalidDataIndex)
|
|
continue;
|
|
|
|
HDAdditionalLightData additionalLightData = lightEntities.hdAdditionalLightData[dataIndex];
|
|
if (additionalLightData == null)
|
|
continue;
|
|
|
|
//We utilize a raw light data pointer to avoid copying the entire structure
|
|
HDProcessedVisibleLight* processedEntityPtr = processedLightArrayPtr + lightIndex;
|
|
ref HDProcessedVisibleLight processedEntity = ref UnsafeUtility.AsRef<HDProcessedVisibleLight>(processedEntityPtr);
|
|
LightType lightType = processedEntity.lightType;
|
|
|
|
Light lightComponent = additionalLightData.legacyLight;
|
|
|
|
int shadowIndex = shadowIndexResults[sortKeyIndex];
|
|
if (gpuLightType == GPULightType.Directional)
|
|
{
|
|
VisibleLight* visibleLightPtr = visibleLightsArrayPtr + lightIndex;
|
|
ref VisibleLight light = ref UnsafeUtility.AsRef<VisibleLight>(visibleLightPtr);
|
|
int directionalLightDataIndex = sortKeyIndex;
|
|
DirectionalLightData* lightDataPtr = directionalLightArrayPtr + directionalLightDataIndex;
|
|
ref DirectionalLightData lightData = ref UnsafeUtility.AsRef<DirectionalLightData>(lightDataPtr);
|
|
CalculateDirectionalLightDataTextureInfo(
|
|
ref lightData, cmd, light, lightComponent, additionalLightData,
|
|
hdCamera, processedEntity.shadowMapFlags, directionalLightDataIndex, shadowIndex);
|
|
}
|
|
else
|
|
{
|
|
int lightDataIndex = sortKeyIndex - directionalLightCount;
|
|
LightData* lightDataPtr = lightArrayPtr + lightDataIndex;
|
|
ref LightData lightData = ref UnsafeUtility.AsRef<LightData>(lightDataPtr);
|
|
CalculateLightDataTextureInfo(
|
|
ref lightData, cmd, lightComponent, additionalLightData, shadowInitParams,
|
|
hdCamera, contactShadowScalableSetting,
|
|
lightType, processedEntity.shadowMapFlags, rayTracingEnabled, lightDataIndex, shadowIndex);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
internal unsafe void UpdateShadowRequestsAndCalculateShadowIndices(
|
|
HDCamera hdCamera,
|
|
in CullingResults cullResults,
|
|
HDProcessedVisibleLightsBuilder visibleLights,
|
|
HDLightRenderDatabase lightEntities,
|
|
HDShadowSettings hdShadowSettings,
|
|
DebugDisplaySettings debugDisplaySettings,
|
|
HDShadowManager shadowManager, HDRenderPipelineAsset renderPipelineAsset,
|
|
NativeArray<int> shadowIndices,
|
|
ref int debugSelectedLightShadowIndex, ref int debugSelectedLightShadowCount)
|
|
{
|
|
using (new ProfilingScope(ProfilingSampler.Get(HDProfileId.CalculateShadowIndices)))
|
|
{
|
|
var punctualShadowFilteringQuality = renderPipelineAsset.currentPlatformRenderPipelineSettings.hdShadowInitParams.punctualShadowFilteringQuality;
|
|
var directionalShadowFilteringQuality = renderPipelineAsset.currentPlatformRenderPipelineSettings.hdShadowInitParams.directionalShadowFilteringQuality;
|
|
int lightCounts = visibleLights.sortedLightCounts;
|
|
NativeBitArray shadowRequestValidityArray = visibleLights.shadowRequestValidityArray;
|
|
|
|
HDShadowManagerDataForShadowRequestUpateJob shadowManagerData = default;
|
|
shadowManager.GetUnmanageDataForShadowRequestJobs(ref shadowManagerData);
|
|
|
|
bool usesReversedZBuffer = SystemInfo.usesReversedZBuffer;
|
|
Vector3 worldSpaceCameraPos = hdCamera.mainViewConstants.worldSpaceCameraPos;
|
|
|
|
HDShadowRequestDatabase shadowRequestsDatabase = lightEntities.shadowRequests;
|
|
shadowRequestsDatabase.EnsureNativeListsAreCreated();
|
|
#if UNITY_EDITOR
|
|
NativeArray<int> shadowRequestCounts = m_ShadowRequestCountsScratchpad;
|
|
#endif
|
|
NativeList<Vector3> cachedViewPositionsStorage = shadowRequestsDatabase.cachedViewPositionsStorage;
|
|
NativeList<HDShadowRequest> requestStorage = shadowRequestsDatabase.hdShadowRequestStorage;
|
|
ref UnsafeList<HDShadowRequest> requestStorageUnsafe = ref *requestStorage.GetUnsafeList();
|
|
NativeList<int> requestIndicesStorage = shadowRequestsDatabase.hdShadowRequestIndicesStorage;
|
|
NativeArray<HDAdditionalLightDataUpdateInfo> additionalLightDataUpdateInfos = lightEntities.additionalLightDataUpdateInfos;
|
|
int shadowSettingsCascadeShadowSplitCount = hdShadowSettings.cascadeShadowSplitCount.value;
|
|
|
|
HDShadowRequestUpdateJob shadowRequestsAndIndicesJob = new HDShadowRequestUpdateJob
|
|
{
|
|
shadowManager = shadowManagerData,
|
|
|
|
shadowRequestValidityArray = shadowRequestValidityArray,
|
|
sortKeys = visibleLights.sortKeys,
|
|
visibleLightEntityDataIndices = visibleLights.visibleLightEntityDataIndices,
|
|
processedEntities = visibleLights.processedEntities,
|
|
visibleLights = cullResults.visibleLights,
|
|
additionalLightDataUpdateInfos = additionalLightDataUpdateInfos,
|
|
requestIndicesStorage = requestIndicesStorage,
|
|
cachedViewPositionsStorage = cachedViewPositionsStorage,
|
|
|
|
requestStorage = requestStorage,
|
|
cachedPointUpdateInfos = m_CachedPointUpdateInfos,
|
|
cachedSpotUpdateInfos = m_CachedSpotUpdateInfos,
|
|
cachedAreaRectangleUpdateInfos = m_CachedAreaRectangleUpdateInfos,
|
|
cachedDirectionalUpdateInfos = m_CachedDirectionalUpdateInfos,
|
|
dynamicPointUpdateInfos = m_DynamicPointUpdateInfos,
|
|
dynamicSpotUpdateInfos = m_DynamicSpotUpdateInfos,
|
|
dynamicAreaRectangleUpdateInfos = m_DynamicAreaRectangleUpdateInfos,
|
|
dynamicDirectionalUpdateInfos = m_DynamicDirectionalUpdateInfos,
|
|
frustumPlanesStorage = shadowRequestsDatabase.frustumPlanesStorage,
|
|
|
|
shadowIndices = shadowIndices,
|
|
#if UNITY_EDITOR
|
|
shadowRequestCounts = shadowRequestCounts,
|
|
#endif
|
|
visibleLightsAndIndicesBuffer = visibleLights.visibleLightsAndIndicesBuffer,
|
|
|
|
cachedPointVisibleLightsAndIndices = visibleLights.cachedPointVisibleLightsAndIndices,
|
|
cachedSpotVisibleLightsAndIndices = visibleLights.cachedSpotVisibleLightsAndIndices,
|
|
cachedAreaRectangleVisibleLightsAndIndices = visibleLights.cachedAreaRectangleVisibleLightsAndIndices,
|
|
cachedDirectionalVisibleLightsAndIndices = visibleLights.cachedDirectionalVisibleLightsAndIndices,
|
|
dynamicPointVisibleLightsAndIndices = visibleLights.dynamicPointVisibleLightsAndIndices,
|
|
dynamicSpotVisibleLightsAndIndices = visibleLights.dynamicSpotVisibleLightsAndIndices,
|
|
dynamicAreaRectangleVisibleLightsAndIndices = visibleLights.dynamicAreaRectangleVisibleLightsAndIndices,
|
|
dynamicDirectionalVisibleLightsAndIndices = visibleLights.dynamicDirectionalVisibleLightsAndIndices,
|
|
|
|
cachedPointHDSplits = visibleLights.cachedPointHDSplits,
|
|
cachedSpotHDSplits = visibleLights.cachedSpotHDSplits,
|
|
cachedAreaRectangleHDSplits = visibleLights.cachedAreaRectangleHDSplits,
|
|
cachedDirectionalHDSplits = visibleLights.cachedDirectionalHDSplits,
|
|
dynamicPointHDSplits = visibleLights.dynamicPointHDSplits,
|
|
dynamicSpotHDSplits = visibleLights.dynamicSpotHDSplits,
|
|
dynamicAreaRectangleHDSplits = visibleLights.dynamicAreaRectangleHDSplits,
|
|
dynamicDirectionalHDSplits = visibleLights.dynamicDirectionalHDSplits,
|
|
|
|
lightCounts = lightCounts,
|
|
shadowSettingsCascadeShadowSplitCount = shadowSettingsCascadeShadowSplitCount,
|
|
worldSpaceCameraPos = worldSpaceCameraPos,
|
|
shaderConfigCameraRelativeRendering = ShaderConfig.s_CameraRelativeRendering,
|
|
shadowRequestCount = shadowManager.GetShadowRequestCount(),
|
|
punctualShadowFilteringQuality = punctualShadowFilteringQuality,
|
|
directionalShadowFilteringQuality = directionalShadowFilteringQuality,
|
|
usesReversedZBuffer = usesReversedZBuffer,
|
|
|
|
cachedDirectionalRequestsMarker = ShadowRequestUpdateProfiling.cachedDirectionalRequestsMarker,
|
|
cachedSpotRequestsMarker = ShadowRequestUpdateProfiling.cachedSpotRequestsMarker,
|
|
cachedPointRequestsMarker = ShadowRequestUpdateProfiling.cachedPointRequestsMarker,
|
|
cachedAreaRectangleRequestsMarker = ShadowRequestUpdateProfiling.cachedAreaRectangleRequestsMarker,
|
|
dynamicDirectionalRequestsMarker = ShadowRequestUpdateProfiling.dynamicDirectionalRequestsMarker,
|
|
dynamicSpotRequestsMarker = ShadowRequestUpdateProfiling.dynamicSpotRequestsMarker,
|
|
dynamicPointRequestsMarker = ShadowRequestUpdateProfiling.dynamicPointRequestsMarker,
|
|
dynamicAreaRectangleRequestsMarker = ShadowRequestUpdateProfiling.dynamicAreaRectangleRequestsMarker,
|
|
};
|
|
|
|
shadowRequestsAndIndicesJob.Run();
|
|
|
|
ref UnsafeList<ShadowRequestIntermediateUpdateData> cachedDirectionalUpdateInfos = ref *(m_CachedDirectionalUpdateInfos.GetUnsafeList());
|
|
int cachedDirectionalCount = cachedDirectionalUpdateInfos.Length;
|
|
ref UnsafeList<ShadowRequestIntermediateUpdateData> dynamicDirectionalUpdateInfos = ref *(m_DynamicDirectionalUpdateInfos.GetUnsafeList());
|
|
int dynamicDirectionalCount = dynamicDirectionalUpdateInfos.Length;
|
|
|
|
HDAdditionalLightDataUpdateInfo* updateInfosUnsafePtr = (HDAdditionalLightDataUpdateInfo*)additionalLightDataUpdateInfos.GetUnsafePtr();
|
|
|
|
int shaderConfigCameraRelativeRendering = ShaderConfig.s_CameraRelativeRendering;
|
|
NativeList<float4> frustumPlanesStorage = shadowRequestsDatabase.frustumPlanesStorage;
|
|
HDProcessedVisibleLight* processedLightArrayPtr = (HDProcessedVisibleLight*)visibleLights.processedEntities.GetUnsafePtr<HDProcessedVisibleLight>();
|
|
VisibleLight* visibleLightsArrayPtr = (VisibleLight*)cullResults.visibleLights.GetUnsafePtr<VisibleLight>();
|
|
|
|
// Do all the directional light work we couldn't do inside the job.
|
|
|
|
using (new ProfilingScope(ProfilingSampler.Get(HDProfileId.UpdateDirectionalShadowData)))
|
|
{
|
|
for (int i = 0; i < cachedDirectionalCount; i++)
|
|
{
|
|
ref ShadowRequestIntermediateUpdateData directionalUpdateInfo = ref cachedDirectionalUpdateInfos.ElementAt(i);
|
|
ref HDShadowCullingSplit newCullingSplit = ref visibleLights.cachedDirectionalHDSplits.ElementAt(i);
|
|
bool needToUpdateCachedContent = directionalUpdateInfo.states[ShadowRequestIntermediateUpdateData.k_NeedToUpdateCachedContent];
|
|
HDShadowRequestHandle shadowRequestHandle = directionalUpdateInfo.shadowRequestHandle;
|
|
ref HDShadowRequest shadowRequest = ref requestStorageUnsafe.ElementAt(shadowRequestHandle.storageIndexForRequestIndex);
|
|
int additionalLightDataIndex = directionalUpdateInfo.additionalLightDataIndex;
|
|
int lightIndex = directionalUpdateInfo.lightIndex;
|
|
Vector2 viewportSize = directionalUpdateInfo.viewportSize;
|
|
VisibleLight* visibleLightPtr = visibleLightsArrayPtr + lightIndex;
|
|
ref VisibleLight visibleLight = ref UnsafeUtility.AsRef<VisibleLight>(visibleLightPtr);
|
|
|
|
//We utilize a raw light data pointer to avoid copying the entire structure
|
|
HDProcessedVisibleLight* processedEntityPtr = processedLightArrayPtr + lightIndex;
|
|
ref HDProcessedVisibleLight processedEntity = ref UnsafeUtility.AsRef<HDProcessedVisibleLight>(processedEntityPtr);
|
|
ref HDAdditionalLightDataUpdateInfo updateInfo = ref UnsafeUtility.AsRef<HDAdditionalLightDataUpdateInfo>(updateInfosUnsafePtr + additionalLightDataIndex);
|
|
|
|
if (needToUpdateCachedContent)
|
|
{
|
|
cachedViewPositionsStorage[shadowRequestHandle.storageIndexForCachedViewPosition] = worldSpaceCameraPos;
|
|
shadowRequest.cachedShadowData.cacheTranslationDelta = new Vector3(0.0f, 0.0f, 0.0f);
|
|
|
|
// Write per light type matrices, splitDatas and culling parameters
|
|
UpdateDirectionalShadowRequest(shadowManager, hdShadowSettings, shadowRequestHandle.offset, worldSpaceCameraPos, ref shadowRequest, newCullingSplit);
|
|
|
|
SetDirectionalRequestSettings(ref shadowRequest, shadowRequestHandle, visibleLight, worldSpaceCameraPos,
|
|
shadowRequest.cullingSplit.invViewProjection, shadowRequest.cullingSplit.projection, shadowRequest.cullingSplit.deviceProjectionMatrix, viewportSize,
|
|
lightIndex, directionalShadowFilteringQuality, updateInfo, shaderConfigCameraRelativeRendering, frustumPlanesStorage);
|
|
|
|
shadowRequest.shouldUseCachedShadowData = false;
|
|
shadowRequest.shouldRenderCachedComponent = true;
|
|
}
|
|
else
|
|
{
|
|
shadowRequest.cachedShadowData.cacheTranslationDelta = worldSpaceCameraPos - cachedViewPositionsStorage[shadowRequestHandle.storageIndexForCachedViewPosition];
|
|
shadowRequest.shouldUseCachedShadowData = true;
|
|
shadowRequest.shouldRenderCachedComponent = false;
|
|
|
|
var _ViewMatrix = shadowRequest.cullingSplit.view;
|
|
var _ProjMatrix = shadowRequest.cullingSplit.deviceProjectionYFlip;
|
|
|
|
// We still need to calculate the split data for directional.
|
|
UpdateDirectionalShadowRequest(shadowManager, hdShadowSettings, shadowRequestHandle.offset, worldSpaceCameraPos, ref shadowRequest, newCullingSplit);
|
|
|
|
shadowRequest.cullingSplit.view = _ViewMatrix;
|
|
shadowRequest.cullingSplit.deviceProjectionYFlip = _ProjMatrix;
|
|
}
|
|
|
|
int dataIndex = visibleLights.visibleLightEntityDataIndices[lightIndex];
|
|
HDAdditionalLightData additionalLightData = lightEntities.hdAdditionalLightData[dataIndex];
|
|
if (needToUpdateCachedContent && hdCamera.camera.cameraType != CameraType.Reflection)
|
|
{
|
|
HDCachedShadowManager.instance.MarkDirectionalShadowAsRendered(additionalLightData.lightIdxForCachedShadows + directionalUpdateInfo.shadowRequestHandle.offset);
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < dynamicDirectionalCount; i++)
|
|
{
|
|
ref ShadowRequestIntermediateUpdateData directionalUpdateInfo = ref dynamicDirectionalUpdateInfos.ElementAt(i);
|
|
ref HDShadowCullingSplit newCullingSplit = ref visibleLights.dynamicDirectionalHDSplits.ElementAt(i);
|
|
HDShadowRequestHandle shadowRequestHandle = directionalUpdateInfo.shadowRequestHandle;
|
|
ref HDShadowRequest shadowRequest = ref requestStorageUnsafe.ElementAt(shadowRequestHandle.storageIndexForRequestIndex);
|
|
int additionalLightDataIndex = directionalUpdateInfo.additionalLightDataIndex;
|
|
int lightIndex = directionalUpdateInfo.lightIndex;
|
|
Vector2 viewportSize = directionalUpdateInfo.viewportSize;
|
|
VisibleLight* visibleLightPtr = visibleLightsArrayPtr + lightIndex;
|
|
ref VisibleLight visibleLight = ref UnsafeUtility.AsRef<VisibleLight>(visibleLightPtr);
|
|
ref HDAdditionalLightDataUpdateInfo updateInfo = ref UnsafeUtility.AsRef<HDAdditionalLightDataUpdateInfo>(updateInfosUnsafePtr + additionalLightDataIndex);
|
|
|
|
shadowRequest.shouldUseCachedShadowData = false;
|
|
shadowRequest.cachedShadowData.cacheTranslationDelta = new Vector3(0.0f, 0.0f, 0.0f);
|
|
|
|
// Write per light type matrices, splitDatas and culling parameters
|
|
UpdateDirectionalShadowRequest(shadowManager, hdShadowSettings, shadowRequestHandle.offset, worldSpaceCameraPos, ref shadowRequest, newCullingSplit);
|
|
|
|
SetDirectionalRequestSettings(ref shadowRequest, shadowRequestHandle, visibleLight, worldSpaceCameraPos,
|
|
shadowRequest.cullingSplit.invViewProjection, shadowRequest.cullingSplit.projection, shadowRequest.cullingSplit.deviceProjectionMatrix, viewportSize,
|
|
lightIndex, directionalShadowFilteringQuality, updateInfo, shaderConfigCameraRelativeRendering, frustumPlanesStorage);
|
|
}
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
using (new ProfilingScope(ProfilingSampler.Get(HDProfileId.EditorOnlyDebugSelectedLightShadow)))
|
|
{
|
|
for (int sortKeyIndex = 0; sortKeyIndex < lightCounts; sortKeyIndex++)
|
|
{
|
|
if (!shadowRequestValidityArray.IsSet(sortKeyIndex))
|
|
continue;
|
|
|
|
int shadowIndex = shadowIndices[sortKeyIndex];
|
|
if (shadowIndex < 0)
|
|
continue;
|
|
|
|
uint sortKey = visibleLights.sortKeys[sortKeyIndex];
|
|
int lightIndex = (int)(sortKey & 0xFFFF);
|
|
int dataIndex = visibleLights.visibleLightEntityDataIndices[lightIndex];
|
|
Light lightComponent = lightEntities.hdAdditionalLightData[dataIndex].legacyLight;
|
|
|
|
if (lightComponent != null)
|
|
{
|
|
LightingDebugSettings debugSettings = debugDisplaySettings.data.lightingDebugSettings;
|
|
|
|
if ((debugSettings.shadowDebugUseSelection || debugSettings.shadowDebugMode == ShadowMapDebugMode.SingleShadow)
|
|
&& UnityEditor.Selection.activeGameObject == lightComponent.gameObject)
|
|
{
|
|
debugSelectedLightShadowIndex = shadowIndex;
|
|
debugSelectedLightShadowCount = shadowRequestCounts[sortKeyIndex];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Unfortunately we have to redo a lot of shadow update calculations for lights with custom view callbacks.
|
|
// Since they are managed delegates, they can't be part of a Burst compiled job.
|
|
// We do what we can to minimize extra cost for the common case here,
|
|
// but if a user has many spot lights with custom view callbacks then their loop will be much more expensive.
|
|
|
|
if (lightEntities.validCustomViewCallbackEvents > 0)
|
|
{
|
|
DynamicArray<HDLightRenderDatabase.SpotLightCallbackData> callbacks = lightEntities.customViewCallbackEvents;
|
|
|
|
UpdateCachedSpotShadowRequestsAndResolutionRequests(visibleLights, callbacks, m_CachedSpotUpdateInfos,
|
|
shadowRequestsDatabase.hdShadowRequestStorage, shadowRequestsDatabase.cachedViewPositionsStorage,
|
|
lightEntities.additionalLightDataUpdateInfos, punctualShadowFilteringQuality,
|
|
shadowRequestsDatabase.frustumPlanesStorage, shaderConfigCameraRelativeRendering, worldSpaceCameraPos,
|
|
usesReversedZBuffer);
|
|
|
|
UpdateDynamicSpotShadowRequestsAndResolutionRequests(visibleLights, callbacks, m_DynamicSpotUpdateInfos,
|
|
shadowRequestsDatabase.hdShadowRequestStorage,
|
|
lightEntities.additionalLightDataUpdateInfos, punctualShadowFilteringQuality,
|
|
shadowRequestsDatabase.frustumPlanesStorage, shaderConfigCameraRelativeRendering, worldSpaceCameraPos,
|
|
usesReversedZBuffer);
|
|
}
|
|
|
|
// Reset our scratchpad arrays.
|
|
m_CachedPointUpdateInfos.ResizeUninitialized(0);
|
|
m_CachedSpotUpdateInfos.ResizeUninitialized(0);
|
|
m_CachedAreaRectangleUpdateInfos.ResizeUninitialized(0);
|
|
m_CachedDirectionalUpdateInfos.ResizeUninitialized(0);
|
|
m_DynamicPointUpdateInfos.ResizeUninitialized(0);
|
|
m_DynamicSpotUpdateInfos.ResizeUninitialized(0);
|
|
m_DynamicAreaRectangleUpdateInfos.ResizeUninitialized(0);
|
|
m_DynamicDirectionalUpdateInfos.ResizeUninitialized(0);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A duplicate of the function of the same name inside HDShadowRequestUpdateJob.cs
|
|
/// Duplicated to support the expensive managed callback per spot light, without sacrificing performance in the Burst compiled job.
|
|
/// Any changes made here should be duplicated in the other function and vice versa.
|
|
/// </summary>
|
|
internal static unsafe void UpdateCachedSpotShadowRequestsAndResolutionRequests(HDProcessedVisibleLightsBuilder visibleLights, DynamicArray<HDLightRenderDatabase.SpotLightCallbackData> callbacks, NativeList<ShadowRequestIntermediateUpdateData> cachedSpotUpdateInfos, NativeList<HDShadowRequest> requestStorage,
|
|
NativeList<Vector3> cachedViewPositionsStorage, NativeArray<HDAdditionalLightDataUpdateInfo> additionalLightDataUpdateInfos, HDShadowFilteringQuality shadowFilteringQuality, NativeList<float4> frustumPlanesStorage,
|
|
int shaderConfigCameraRelativeRendering, Vector3 worldSpaceCameraPos, bool usesReversedZBuffer)
|
|
{
|
|
int spotCount = cachedSpotUpdateInfos.Length;
|
|
|
|
ref UnsafeList<ShadowRequestIntermediateUpdateData> updateDataUnsafe = ref *cachedSpotUpdateInfos.GetUnsafeList();
|
|
|
|
for (int i = 0; i < spotCount; i++)
|
|
{
|
|
ref ShadowRequestIntermediateUpdateData spotUpdateInfo = ref updateDataUnsafe.ElementAt(i);
|
|
ref HDShadowCullingSplit newCullingSplit = ref visibleLights.cachedSpotHDSplits.ElementAt(i);
|
|
int additionalLightDataIndex = spotUpdateInfo.additionalLightDataIndex;
|
|
ref HDLightRenderDatabase.SpotLightCallbackData callbackData = ref callbacks[additionalLightDataIndex];
|
|
|
|
if (callbackData.isAnythingRegistered)
|
|
{
|
|
bool needToUpdateCachedContent = spotUpdateInfo.states[ShadowRequestIntermediateUpdateData.k_NeedToUpdateCachedContent];
|
|
HDShadowRequestHandle shadowRequestHandle = spotUpdateInfo.shadowRequestHandle;
|
|
ref HDShadowRequest shadowRequest = ref requestStorage.ElementAt(shadowRequestHandle.storageIndexForRequestIndex);
|
|
int lightIndex = spotUpdateInfo.lightIndex;
|
|
Vector2 viewportSize = spotUpdateInfo.viewportSize;
|
|
ShadowMapUpdateType updateType = spotUpdateInfo.updateType;
|
|
bool isSampledFromCache = (updateType == ShadowMapUpdateType.Cached);
|
|
bool needToUpdateDynamicContent = !isSampledFromCache;
|
|
HDAdditionalLightDataUpdateInfo updateInfo = additionalLightDataUpdateInfos[additionalLightDataIndex];
|
|
|
|
bool hasUpdatedRequestData = false;
|
|
|
|
if (needToUpdateCachedContent)
|
|
{
|
|
cachedViewPositionsStorage[shadowRequestHandle.storageIndexForCachedViewPosition] = worldSpaceCameraPos;
|
|
shadowRequest.cachedShadowData.cacheTranslationDelta = new Vector3(0.0f, 0.0f, 0.0f);
|
|
shadowRequest.cullingSplit = newCullingSplit;
|
|
|
|
if (callbackData.callback != null)
|
|
{
|
|
shadowRequest.cullingSplit.view = callbackData.callback(spotUpdateInfo.visibleLight.localToWorldMatrix);
|
|
}
|
|
|
|
SetSpotRequestSettings(ref shadowRequest, shadowRequestHandle, spotUpdateInfo.visibleLight, 0f, worldSpaceCameraPos,
|
|
shadowRequest.cullingSplit.invViewProjection, shadowRequest.cullingSplit.projection, viewportSize,
|
|
lightIndex, shadowFilteringQuality, updateInfo, shaderConfigCameraRelativeRendering, frustumPlanesStorage);
|
|
|
|
hasUpdatedRequestData = true;
|
|
shadowRequest.shouldUseCachedShadowData = false;
|
|
shadowRequest.shouldRenderCachedComponent = true;
|
|
}
|
|
else
|
|
{
|
|
shadowRequest.cachedShadowData.cacheTranslationDelta = worldSpaceCameraPos - cachedViewPositionsStorage[shadowRequestHandle.storageIndexForCachedViewPosition];
|
|
shadowRequest.shouldUseCachedShadowData = true;
|
|
shadowRequest.shouldRenderCachedComponent = false;
|
|
}
|
|
|
|
if (needToUpdateDynamicContent && !hasUpdatedRequestData)
|
|
{
|
|
shadowRequest.shouldUseCachedShadowData = false;
|
|
shadowRequest.cachedShadowData.cacheTranslationDelta = new Vector3(0.0f, 0.0f, 0.0f);
|
|
shadowRequest.cullingSplit = newCullingSplit;
|
|
|
|
if (callbackData.callback != null)
|
|
{
|
|
shadowRequest.cullingSplit.view = callbackData.callback(spotUpdateInfo.visibleLight.localToWorldMatrix);
|
|
}
|
|
|
|
SetSpotRequestSettings(ref shadowRequest, shadowRequestHandle, spotUpdateInfo.visibleLight, 0f, worldSpaceCameraPos,
|
|
shadowRequest.cullingSplit.invViewProjection, shadowRequest.cullingSplit.projection, viewportSize,
|
|
lightIndex, shadowFilteringQuality, updateInfo, shaderConfigCameraRelativeRendering, frustumPlanesStorage);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
internal static unsafe void UpdateDynamicSpotShadowRequestsAndResolutionRequests(HDProcessedVisibleLightsBuilder visibleLights, DynamicArray<HDLightRenderDatabase.SpotLightCallbackData> callbacks, NativeList<ShadowRequestIntermediateUpdateData> dynamicSpotUpdateInfos, NativeList<HDShadowRequest> requestStorage,
|
|
NativeArray<HDAdditionalLightDataUpdateInfo> additionalLightDataUpdateInfos, HDShadowFilteringQuality shadowFilteringQuality, NativeList<float4> frustumPlanesStorage,
|
|
int shaderConfigCameraRelativeRendering, Vector3 worldSpaceCameraPos, bool usesReversedZBuffer)
|
|
{
|
|
int spotCount = dynamicSpotUpdateInfos.Length;
|
|
|
|
ref UnsafeList<ShadowRequestIntermediateUpdateData> updateDataUnsafe = ref *dynamicSpotUpdateInfos.GetUnsafeList();
|
|
|
|
for (int i = 0; i < spotCount; i++)
|
|
{
|
|
ref ShadowRequestIntermediateUpdateData spotUpdateInfo = ref updateDataUnsafe.ElementAt(i);
|
|
ref HDShadowCullingSplit newCullingSplit = ref visibleLights.dynamicSpotHDSplits.ElementAt(i);
|
|
int additionalLightDataIndex = spotUpdateInfo.additionalLightDataIndex;
|
|
ref HDLightRenderDatabase.SpotLightCallbackData callbackData = ref callbacks[additionalLightDataIndex];
|
|
|
|
if (callbackData.isAnythingRegistered)
|
|
{
|
|
HDShadowRequestHandle shadowRequestHandle = spotUpdateInfo.shadowRequestHandle;
|
|
ref HDShadowRequest shadowRequest = ref requestStorage.ElementAt(shadowRequestHandle.storageIndexForRequestIndex);
|
|
int lightIndex = spotUpdateInfo.lightIndex;
|
|
Vector2 viewportSize = spotUpdateInfo.viewportSize;
|
|
|
|
HDAdditionalLightDataUpdateInfo updateInfo = additionalLightDataUpdateInfos[additionalLightDataIndex];
|
|
|
|
shadowRequest.shouldUseCachedShadowData = false;
|
|
shadowRequest.cachedShadowData.cacheTranslationDelta = new Vector3(0.0f, 0.0f, 0.0f);
|
|
shadowRequest.cullingSplit = newCullingSplit;
|
|
|
|
if (callbackData.callback != null)
|
|
{
|
|
shadowRequest.cullingSplit.view = callbackData.callback(spotUpdateInfo.visibleLight.localToWorldMatrix);
|
|
}
|
|
|
|
SetSpotRequestSettings(ref shadowRequest, shadowRequestHandle, spotUpdateInfo.visibleLight, 0f, worldSpaceCameraPos,
|
|
shadowRequest.cullingSplit.invViewProjection, shadowRequest.cullingSplit.projection, viewportSize,
|
|
lightIndex, shadowFilteringQuality, updateInfo, shaderConfigCameraRelativeRendering, frustumPlanesStorage);
|
|
}
|
|
}
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
internal static float4 GetZBufferParam(in VisibleLight visibleLight, float nearPlaneForZBufferParam)
|
|
{
|
|
// zBuffer param to reconstruct depth position (for transmission)
|
|
float f = visibleLight.range;
|
|
float n = nearPlaneForZBufferParam;
|
|
return new float4((f-n)/n, 1.0f, (f-n)/(n*f), 1.0f/f);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
internal static float4 GetDirectionalZBufferParam(in VisibleLight visibleLight, float nearPlaneForZBufferParam, float rangeScale)
|
|
{
|
|
float4 zBufferParam = GetZBufferParam(visibleLight, nearPlaneForZBufferParam);
|
|
zBufferParam.x = rangeScale;
|
|
return zBufferParam;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
internal static void MakeViewAndViewProjectionCameraRelative(ref HDShadowRequest shadowRequest, ref Matrix4x4 invViewProjection, int shaderConfigCameraRelativeRendering, Vector3 cameraPos)
|
|
{
|
|
// Make light position camera relative:
|
|
// TODO: think about VR (use different camera position for each eye)
|
|
if (shaderConfigCameraRelativeRendering != 0)
|
|
{
|
|
CoreMatrixUtils.MatrixTimesTranslation(ref shadowRequest.cullingSplit.view, cameraPos);
|
|
CoreMatrixUtils.TranslationTimesMatrix(ref invViewProjection, -cameraPos);
|
|
}
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
internal static float2 GetDirectionalLightSoftnessAndRangeScale(in HDShadowRequest shadowRequest, in HDAdditionalLightDataUpdateInfo additionalLightData, Matrix4x4 devProj)
|
|
{
|
|
float frustumExtentZ = Vector4.Dot(new Vector4(devProj.m32, -devProj.m32, -devProj.m22, devProj.m22), new Vector4(devProj.m22, devProj.m32, devProj.m23, devProj.m33)) /
|
|
(devProj.m22 * (devProj.m22 - devProj.m32));
|
|
|
|
// We use the light view frustum derived from view projection matrix and angular diameter to work out a filter size in
|
|
// shadow map space, essentially figuring out the footprint of the cone subtended by the light on the shadow map
|
|
float halfAngleTan = Mathf.Tan(0.5f * Mathf.Deg2Rad * (additionalLightData.softnessScale * additionalLightData.angularDiameter) / 2);
|
|
float softness = Mathf.Abs(halfAngleTan * frustumExtentZ / (2.0f * shadowRequest.cullingSplit.cullingSphere.w));
|
|
float range = 2.0f * (1.0f / devProj.m22);
|
|
float rangeScale = Mathf.Abs(range) / 100.0f;
|
|
|
|
var viewportWidth = shadowRequest.isInCachedAtlas ? shadowRequest.cachedAtlasViewport.width : shadowRequest.dynamicAtlasViewport.width;
|
|
softness *= (viewportWidth / 512); // Make it resolution independent whereas the baseline is 512
|
|
|
|
return new float2(softness, rangeScale);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
internal static float GetNonDirectionalSoftness(in HDShadowRequest shadowRequest, in HDAdditionalLightDataUpdateInfo additionalLightData)
|
|
{
|
|
// This derivation has been fitted with quartic regression checking against raytracing reference and with a resolution of 512
|
|
float x = additionalLightData.shapeRadius * additionalLightData.softnessScale;
|
|
float x2 = x * x;
|
|
float softness = 0.02403461f + 3.452916f * x - 1.362672f * x2 + 0.6700115f * x2 * x + 0.2159474f * x2 * x2;
|
|
softness /= 100.0f;
|
|
|
|
var viewportWidth = shadowRequest.isInCachedAtlas ? shadowRequest.cachedAtlasViewport.width : shadowRequest.dynamicAtlasViewport.width;
|
|
softness *= (viewportWidth / 512); // Make it resolution independent whereas the baseline is 512
|
|
|
|
return softness;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
internal static float GetBaseBias(bool isHighQuality, float softness)
|
|
{
|
|
// Bias
|
|
// This base bias is a good value if we expose a [0..1] since values within [0..5] are empirically shown to be sensible for the slope-scale bias with the width of our PCF.
|
|
float baseBias = 5.0f;
|
|
// If we are PCSS, the blur radius can be quite big, hence we need to tweak up the slope bias
|
|
if (isHighQuality && softness > 0.01f)
|
|
{
|
|
// maxBaseBias is an empirically set value, also the lerp stops at a shadow softness of 0.05, then is clamped.
|
|
float maxBaseBias = 18.0f;
|
|
baseBias = Mathf.Lerp(baseBias, maxBaseBias, Mathf.Min(1.0f, (softness * 100) / 5));
|
|
}
|
|
|
|
return baseBias;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
internal static Vector3 GetPositionFromView(in Matrix4x4 view)
|
|
{
|
|
return new Vector3(view.m03, view.m13, view.m23);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
internal static Vector3 GetPositionFromVisibleLight(in VisibleLight visibleLight, Vector3 cameraPos, float forwardOffset, int shaderConfigCameraRelativeRendering)
|
|
{
|
|
var lightAxisAndPosition = visibleLight.GetAxisAndPosition();
|
|
Vector3 position = lightAxisAndPosition.Position + lightAxisAndPosition.Forward * forwardOffset;
|
|
if (shaderConfigCameraRelativeRendering != 0)
|
|
position -= cameraPos;
|
|
|
|
return position;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
internal static void SetDirectionalRequestSettings(ref HDShadowRequest shadowRequest,
|
|
HDShadowRequestHandle shadowRequestHandle, in VisibleLight visibleLight, Vector3 cameraPos,
|
|
Matrix4x4 invViewProjection, in Matrix4x4 projection, in Matrix4x4 devProjMatrix, Vector2 viewportSize, int lightIndex, HDShadowFilteringQuality filteringQuality,
|
|
in HDAdditionalLightDataUpdateInfo additionalLightData, int shaderConfigCameraRelativeRendering, NativeList<float4> frustumPlanesStorage)
|
|
{
|
|
MakeViewAndViewProjectionCameraRelative(ref shadowRequest, ref invViewProjection, shaderConfigCameraRelativeRendering, cameraPos);
|
|
|
|
float nearPlane = Mathf.Max(additionalLightData.shadowNearPlane, HDShadowUtils.k_MinShadowNearPlane);
|
|
float2 softnessAndRangeScale = GetDirectionalLightSoftnessAndRangeScale(shadowRequest, additionalLightData, devProjMatrix);
|
|
float4 zBufferParam = GetDirectionalZBufferParam(visibleLight, nearPlane, softnessAndRangeScale.y);
|
|
Vector3 position = new Vector3(shadowRequest.cullingSplit.view.m03, shadowRequest.cullingSplit.view.m13, shadowRequest.cullingSplit.view.m23);
|
|
|
|
// New directional light PCSS implementation no longer requires boosting base bias
|
|
float baseBias = GetBaseBias(filteringQuality == HDShadowFilteringQuality.High, 0.0f);
|
|
|
|
SetCommonShadowRequestSettings(ref shadowRequest, shadowRequestHandle, cameraPos, invViewProjection, projection,
|
|
viewportSize, lightIndex, additionalLightData, shaderConfigCameraRelativeRendering, frustumPlanesStorage,
|
|
ShadowMapType.CascadedDirectional, zBufferParam, softnessAndRangeScale.x, position, baseBias,
|
|
true, false);
|
|
|
|
// Directional light PCSS parameters
|
|
if(filteringQuality == HDShadowFilteringQuality.High)
|
|
{
|
|
float lightAngularDiameter = additionalLightData.softnessScale * additionalLightData.angularDiameter;
|
|
float halfAngularDiameterTangent = Mathf.Tan(0.5f * Mathf.Deg2Rad * lightAngularDiameter);
|
|
float shadowMapDepth2RadialScale = Mathf.Abs(devProjMatrix.m00 / devProjMatrix.m22);
|
|
shadowRequest.dirLightPCSSDepth2RadialScale = halfAngularDiameterTangent * shadowMapDepth2RadialScale;
|
|
shadowRequest.dirLightPCSSRadial2DepthScale = 1.0f / shadowRequest.dirLightPCSSDepth2RadialScale;
|
|
shadowRequest.dirLightPCSSMaxBlockerDistance = additionalLightData.dirLightPCSSMaxPenumbraSize / (2.0f * halfAngularDiameterTangent);
|
|
shadowRequest.dirLightPCSSMaxSamplingDistance = additionalLightData.dirLightPCSSMaxSamplingDistance;
|
|
shadowRequest.dirLightPCSSMinFilterSizeTexels = additionalLightData.dirLightPCSSMinFilterSizeTexels;
|
|
// Ensure min filter angular diameter covers blocker search angular diameter
|
|
float minFilterAngularDiameter = Mathf.Max(additionalLightData.dirLightPCSSBlockerSearchAngularDiameter,
|
|
additionalLightData.dirLightPCSSMinFilterMaxAngularDiameter);
|
|
float halfMinFilterAngularDiameterTangent = Mathf.Tan(0.5f * Mathf.Deg2Rad * Mathf.Max(minFilterAngularDiameter, lightAngularDiameter));
|
|
shadowRequest.dirLightPCSSMinFilterRadial2DepthScale = 1.0f / (halfMinFilterAngularDiameterTangent * shadowMapDepth2RadialScale);
|
|
float halfBlockerSearchAngularDiameterTangent = Mathf.Tan(0.5f * Mathf.Deg2Rad * Mathf.Max(additionalLightData.dirLightPCSSBlockerSearchAngularDiameter, lightAngularDiameter));
|
|
shadowRequest.dirLightPCSSBlockerRadial2DepthScale = 1.0f / (halfBlockerSearchAngularDiameterTangent * shadowMapDepth2RadialScale);
|
|
// Uniform distribution is sqrt of linear range, so we remap the exponent to the [0.5, 3.0] range
|
|
shadowRequest.dirLightPCSSBlockerSamplingClumpExponent = 0.5f * additionalLightData.dirLightPCSSBlockerSamplingClumpExponent;
|
|
shadowRequest.blockerSampleCount = (byte)additionalLightData.dirLightPCSSBlockerSampleCount;
|
|
shadowRequest.filterSampleCount = (byte)additionalLightData.dirLightPCSSFilterSampleCount;
|
|
}
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
internal static void SetAreaRequestSettings(ref HDShadowRequest shadowRequest,
|
|
HDShadowRequestHandle shadowRequestHandle, in VisibleLight visibleLight, float forwardOffset,
|
|
Vector3 cameraPos, Matrix4x4 invViewProjection, Matrix4x4 projection, Vector2 viewportSize, int lightIndex,
|
|
HDAreaShadowFilteringQuality areaFilteringQuality,
|
|
in HDAdditionalLightDataUpdateInfo additionalLightData, int shaderConfigCameraRelativeRendering,
|
|
NativeList<float4> frustumPlanesStorage)
|
|
{
|
|
MakeViewAndViewProjectionCameraRelative(ref shadowRequest, ref invViewProjection, shaderConfigCameraRelativeRendering, cameraPos);
|
|
|
|
float nearPlane = additionalLightData.shadowNearPlane;
|
|
float4 zBufferParam = GetZBufferParam(visibleLight, nearPlane);
|
|
|
|
Vector3 position = GetPositionFromVisibleLight(visibleLight, cameraPos, forwardOffset, shaderConfigCameraRelativeRendering);
|
|
float softness = GetNonDirectionalSoftness(shadowRequest, additionalLightData);
|
|
float baseBias = GetBaseBias(areaFilteringQuality == HDAreaShadowFilteringQuality.High, softness);
|
|
|
|
SetCommonShadowRequestSettings(ref shadowRequest, shadowRequestHandle, cameraPos, invViewProjection, projection,
|
|
viewportSize, lightIndex, additionalLightData, shaderConfigCameraRelativeRendering, frustumPlanesStorage,
|
|
ShadowMapType.AreaLightAtlas, zBufferParam, softness, position, baseBias,
|
|
false, true);
|
|
|
|
// We transform it to base two for faster computation.
|
|
// So e^x = 2^y where y = x * log2 (e)
|
|
const float log2e = 1.44269504089f;
|
|
shadowRequest.evsmParams.x = additionalLightData.evsmExponent * log2e;
|
|
shadowRequest.evsmParams.y = additionalLightData.evsmLightLeakBias;
|
|
shadowRequest.evsmParams.z = additionalLightData.evsmVarianceBias;
|
|
shadowRequest.evsmParams.w = additionalLightData.evsmBlurPasses;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
internal static void SetSpotRequestSettings(ref HDShadowRequest shadowRequest,
|
|
HDShadowRequestHandle shadowRequestHandle, in VisibleLight visibleLight, float forwardOffset,
|
|
Vector3 cameraPos, Matrix4x4 invViewProjection, Matrix4x4 projection, Vector2 viewportSize, int lightIndex,
|
|
HDShadowFilteringQuality filteringQuality,
|
|
in HDAdditionalLightDataUpdateInfo additionalLightData, int shaderConfigCameraRelativeRendering,
|
|
NativeList<float4> frustumPlanesStorage)
|
|
{
|
|
MakeViewAndViewProjectionCameraRelative(ref shadowRequest, ref invViewProjection, shaderConfigCameraRelativeRendering, cameraPos);
|
|
|
|
bool isBoxShape = visibleLight.lightType == LightType.Box;
|
|
float nearPlane = additionalLightData.shadowNearPlane;
|
|
float minimumConeAndPyramidNearPlane = Mathf.Max(nearPlane, HDShadowUtils.k_MinShadowNearPlane);
|
|
nearPlane = isBoxShape ? nearPlane : minimumConeAndPyramidNearPlane;
|
|
float4 zBufferParam = GetZBufferParam(visibleLight, nearPlane);
|
|
bool hasOrthoMatrix = isBoxShape;
|
|
|
|
Vector3 position = GetPositionFromVisibleLight(visibleLight, cameraPos, forwardOffset, shaderConfigCameraRelativeRendering);
|
|
|
|
if (isBoxShape)
|
|
{
|
|
position = GetPositionFromView(shadowRequest.cullingSplit.view);
|
|
}
|
|
|
|
float softness = GetNonDirectionalSoftness(shadowRequest, additionalLightData);
|
|
float baseBias = GetBaseBias(filteringQuality == HDShadowFilteringQuality.High, softness);
|
|
|
|
SetCommonShadowRequestSettings(ref shadowRequest, shadowRequestHandle, cameraPos, invViewProjection, projection,
|
|
viewportSize, lightIndex, additionalLightData, shaderConfigCameraRelativeRendering, frustumPlanesStorage,
|
|
ShadowMapType.PunctualAtlas, zBufferParam, softness, position, baseBias,
|
|
hasOrthoMatrix, true);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
internal static void SetPointRequestSettings(ref HDShadowRequest shadowRequest,
|
|
HDShadowRequestHandle shadowRequestHandle, in VisibleLight visibleLight,
|
|
Vector3 cameraPos, Matrix4x4 invViewProjection, Matrix4x4 projection, Vector2 viewportSize, int lightIndex,
|
|
HDShadowFilteringQuality filteringQuality,
|
|
in HDAdditionalLightDataUpdateInfo additionalLightData, int shaderConfigCameraRelativeRendering,
|
|
NativeList<float4> frustumPlanesStorage)
|
|
{
|
|
MakeViewAndViewProjectionCameraRelative(ref shadowRequest, ref invViewProjection, shaderConfigCameraRelativeRendering, cameraPos);
|
|
|
|
float nearPlane = Mathf.Max(additionalLightData.shadowNearPlane, HDShadowUtils.k_MinShadowNearPlane);
|
|
float4 zBufferParam = GetZBufferParam(visibleLight, nearPlane);
|
|
Vector3 position = GetPositionFromVisibleLight(visibleLight, cameraPos, 0f, shaderConfigCameraRelativeRendering);
|
|
float softness = GetNonDirectionalSoftness(shadowRequest, additionalLightData);
|
|
float baseBias = GetBaseBias(filteringQuality == HDShadowFilteringQuality.High, softness);
|
|
|
|
SetCommonShadowRequestSettings(ref shadowRequest, shadowRequestHandle, cameraPos, invViewProjection, projection,
|
|
viewportSize, lightIndex, additionalLightData, shaderConfigCameraRelativeRendering, frustumPlanesStorage,
|
|
ShadowMapType.PunctualAtlas, zBufferParam, softness, position, baseBias,
|
|
false, true);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
internal static void SetCommonShadowRequestSettings(ref HDShadowRequest shadowRequest,
|
|
HDShadowRequestHandle shadowRequestHandle, Vector3 cameraPos, Matrix4x4 invViewProjection, Matrix4x4 projection, Vector2 viewportSize, int lightIndex,
|
|
in HDAdditionalLightDataUpdateInfo additionalLightData, int shaderConfigCameraRelativeRendering,
|
|
NativeList<float4> frustumPlanesStorage, ShadowMapType shadowMapType, float4 zBufferParam, float softness, Vector3 position, float baseBias, bool hasOrthoMatrix, bool zClip)
|
|
{
|
|
shadowRequest.zBufferParam = zBufferParam;
|
|
shadowRequest.worldTexelSize = 2.0f / shadowRequest.cullingSplit.deviceProjectionYFlip.m00 / viewportSize.x * Mathf.Sqrt(2.0f);
|
|
shadowRequest.normalBias = additionalLightData.normalBias;
|
|
|
|
shadowRequest.position = position;
|
|
|
|
shadowRequest.shadowToWorld = invViewProjection.transpose;
|
|
shadowRequest.zClip = zClip;
|
|
shadowRequest.lightIndex = lightIndex;
|
|
// We don't allow shadow resize for directional cascade shadow
|
|
shadowRequest.shadowMapType = shadowMapType;
|
|
|
|
Matrix4x4 finalMatrix = CoreMatrixUtils.MultiplyProjectionMatrix(projection, shadowRequest.cullingSplit.view, hasOrthoMatrix);
|
|
|
|
ref float4 frustumPlanesLeft = ref frustumPlanesStorage.ElementAt(shadowRequestHandle.storageIndexForFrustumPlanes);
|
|
ref float4 frustumPlanesRight = ref frustumPlanesStorage.ElementAt(shadowRequestHandle.storageIndexForFrustumPlanes + 1);
|
|
ref float4 frustumPlanesBottom = ref frustumPlanesStorage.ElementAt(shadowRequestHandle.storageIndexForFrustumPlanes + 2);
|
|
ref float4 frustumPlanesTop = ref frustumPlanesStorage.ElementAt(shadowRequestHandle.storageIndexForFrustumPlanes + 3);
|
|
ref float4 frustumPlanesNear = ref frustumPlanesStorage.ElementAt(shadowRequestHandle.storageIndexForFrustumPlanes + 4);
|
|
ref float4 frustumPlanesFar = ref frustumPlanesStorage.ElementAt(shadowRequestHandle.storageIndexForFrustumPlanes + 5);
|
|
|
|
// shadow clip planes (used for tessellation clipping)
|
|
HDShadowUtils.CalculateFrustumPlanes(finalMatrix, out frustumPlanesLeft, out frustumPlanesRight, out frustumPlanesBottom, out frustumPlanesTop, out frustumPlanesNear, out frustumPlanesFar);
|
|
|
|
shadowRequest.slopeBias = HDShadowUtils.GetSlopeBias(baseBias, additionalLightData.slopeBias);
|
|
|
|
// Shadow algorithm parameters
|
|
shadowRequest.shadowSoftness = softness;
|
|
shadowRequest.blockerSampleCount = additionalLightData.blockerSampleCount;
|
|
shadowRequest.filterSampleCount = additionalLightData.filterSampleCount;
|
|
shadowRequest.minFilterSize = additionalLightData.minFilterSize * 0.001f; // This divide by 1000 is here to have a range [0...1] exposed to user
|
|
|
|
shadowRequest.kernelSize = (uint)additionalLightData.kernelSize;
|
|
}
|
|
|
|
private static void UpdateDirectionalShadowRequest(HDShadowManager manager, HDShadowSettings shadowSettings, int requestIndex, Vector3 cameraPos, ref HDShadowRequest shadowRequest, in HDShadowCullingSplit newCullingSplit)
|
|
{
|
|
Vector4 cullingSphere = newCullingSplit.cullingSphere;
|
|
|
|
// Camera relative for directional light culling sphere
|
|
if (ShaderConfig.s_CameraRelativeRendering != 0)
|
|
{
|
|
cullingSphere.x -= cameraPos.x;
|
|
cullingSphere.y -= cameraPos.y;
|
|
cullingSphere.z -= cameraPos.z;
|
|
}
|
|
|
|
manager.UpdateCascade(requestIndex, cullingSphere, shadowSettings.cascadeShadowBorders[requestIndex]);
|
|
shadowRequest.cullingSplit = newCullingSplit;
|
|
}
|
|
}
|
|
}
|