510 lines
26 KiB
C#
510 lines
26 KiB
C#
using System;
|
|
using UnityEngine.Experimental.Rendering;
|
|
using UnityEngine.Rendering.RenderGraphModule;
|
|
using System.Collections.Generic;
|
|
|
|
namespace UnityEngine.Rendering.Universal.Internal
|
|
{
|
|
/// <summary>
|
|
/// Renders a shadow map for the main Light.
|
|
/// </summary>
|
|
public class MainLightShadowCasterPass : ScriptableRenderPass
|
|
{
|
|
private static class MainLightShadowConstantBuffer
|
|
{
|
|
public static int _WorldToShadow;
|
|
public static int _ShadowParams;
|
|
public static int _CascadeShadowSplitSpheres0;
|
|
public static int _CascadeShadowSplitSpheres1;
|
|
public static int _CascadeShadowSplitSpheres2;
|
|
public static int _CascadeShadowSplitSpheres3;
|
|
public static int _CascadeShadowSplitSphereRadii;
|
|
public static int _ShadowOffset0;
|
|
public static int _ShadowOffset1;
|
|
public static int _ShadowmapSize;
|
|
}
|
|
|
|
const int k_MaxCascades = 4;
|
|
const int k_ShadowmapBufferBits = 16;
|
|
float m_CascadeBorder;
|
|
float m_MaxShadowDistanceSq;
|
|
int m_ShadowCasterCascadesCount;
|
|
|
|
int m_MainLightShadowmapID;
|
|
internal RTHandle m_MainLightShadowmapTexture;
|
|
private RTHandle m_EmptyMainLightShadowmapTexture;
|
|
private const int k_EmptyShadowMapDimensions = 1;
|
|
private const string k_MainLightShadowMapTextureName = "_MainLightShadowmapTexture";
|
|
private const string k_EmptyMainLightShadowMapTextureName = "_EmptyMainLightShadowmapTexture";
|
|
private static readonly Vector4 s_EmptyShadowParams = new Vector4(1, 0, 1, 0);
|
|
private static readonly Vector4 s_EmptyShadowmapSize = s_EmptyShadowmapSize = new Vector4(k_EmptyShadowMapDimensions, 1f / k_EmptyShadowMapDimensions, k_EmptyShadowMapDimensions, k_EmptyShadowMapDimensions);
|
|
|
|
Matrix4x4[] m_MainLightShadowMatrices;
|
|
ShadowSliceData[] m_CascadeSlices;
|
|
Vector4[] m_CascadeSplitDistances;
|
|
|
|
private RenderTextureDescriptor m_MainLightShadowDescriptor;
|
|
|
|
bool m_CreateEmptyShadowmap;
|
|
bool m_EmptyShadowmapNeedsClear = false;
|
|
|
|
int renderTargetWidth;
|
|
int renderTargetHeight;
|
|
|
|
ProfilingSampler m_ProfilingSetupSampler = new ProfilingSampler("Setup Main Shadowmap");
|
|
private PassData m_PassData;
|
|
/// <summary>
|
|
/// Creates a new <c>MainLightShadowCasterPass</c> instance.
|
|
/// </summary>
|
|
/// <param name="evt">The <c>RenderPassEvent</c> to use.</param>
|
|
/// <seealso cref="RenderPassEvent"/>
|
|
public MainLightShadowCasterPass(RenderPassEvent evt)
|
|
{
|
|
profilingSampler = new ProfilingSampler("Draw Main Light Shadowmap");
|
|
renderPassEvent = evt;
|
|
|
|
m_PassData = new PassData();
|
|
m_MainLightShadowMatrices = new Matrix4x4[k_MaxCascades + 1];
|
|
m_CascadeSlices = new ShadowSliceData[k_MaxCascades];
|
|
m_CascadeSplitDistances = new Vector4[k_MaxCascades];
|
|
|
|
MainLightShadowConstantBuffer._WorldToShadow = Shader.PropertyToID("_MainLightWorldToShadow");
|
|
MainLightShadowConstantBuffer._ShadowParams = Shader.PropertyToID("_MainLightShadowParams");
|
|
MainLightShadowConstantBuffer._CascadeShadowSplitSpheres0 = Shader.PropertyToID("_CascadeShadowSplitSpheres0");
|
|
MainLightShadowConstantBuffer._CascadeShadowSplitSpheres1 = Shader.PropertyToID("_CascadeShadowSplitSpheres1");
|
|
MainLightShadowConstantBuffer._CascadeShadowSplitSpheres2 = Shader.PropertyToID("_CascadeShadowSplitSpheres2");
|
|
MainLightShadowConstantBuffer._CascadeShadowSplitSpheres3 = Shader.PropertyToID("_CascadeShadowSplitSpheres3");
|
|
MainLightShadowConstantBuffer._CascadeShadowSplitSphereRadii = Shader.PropertyToID("_CascadeShadowSplitSphereRadii");
|
|
MainLightShadowConstantBuffer._ShadowOffset0 = Shader.PropertyToID("_MainLightShadowOffset0");
|
|
MainLightShadowConstantBuffer._ShadowOffset1 = Shader.PropertyToID("_MainLightShadowOffset1");
|
|
MainLightShadowConstantBuffer._ShadowmapSize = Shader.PropertyToID("_MainLightShadowmapSize");
|
|
|
|
m_MainLightShadowmapID = Shader.PropertyToID(k_MainLightShadowMapTextureName);
|
|
m_EmptyShadowmapNeedsClear = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Cleans up resources used by the pass.
|
|
/// </summary>
|
|
public void Dispose()
|
|
{
|
|
m_MainLightShadowmapTexture?.Release();
|
|
m_EmptyMainLightShadowmapTexture?.Release();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets up the pass.
|
|
/// </summary>
|
|
/// <param name="renderingData"></param>
|
|
/// <returns>True if the pass should be enqueued, otherwise false.</returns>
|
|
/// <seealso cref="RenderingData"/>
|
|
public bool Setup(ref RenderingData renderingData)
|
|
{
|
|
ContextContainer frameData = renderingData.frameData;
|
|
UniversalRenderingData universalRenderingData = frameData.Get<UniversalRenderingData>();
|
|
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
|
|
UniversalLightData lightData = frameData.Get<UniversalLightData>();
|
|
UniversalShadowData shadowData = frameData.Get<UniversalShadowData>();
|
|
return Setup(universalRenderingData, cameraData, lightData, shadowData);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets up the pass.
|
|
/// </summary>
|
|
/// <param name="renderingData">Data containing rendering settings.</param>
|
|
/// <param name="cameraData">Data containing camera settings.</param>
|
|
/// <param name="lightData">Data containing light settings.</param>
|
|
/// <param name="shadowData">Data containing shadow settings.</param>
|
|
/// <returns>True if the pass should be enqueued, otherwise false.</returns>
|
|
/// <seealso cref="RenderingData"/>
|
|
public bool Setup(UniversalRenderingData renderingData, UniversalCameraData cameraData, UniversalLightData lightData, UniversalShadowData shadowData)
|
|
{
|
|
if (!shadowData.mainLightShadowsEnabled)
|
|
return false;
|
|
|
|
#if UNITY_EDITOR
|
|
if (CoreUtils.IsSceneLightingDisabled(cameraData.camera))
|
|
return false;
|
|
#endif
|
|
|
|
using var profScope = new ProfilingScope(m_ProfilingSetupSampler);
|
|
|
|
if (!shadowData.supportsMainLightShadows)
|
|
return SetupForEmptyRendering(cameraData.renderer.stripShadowsOffVariants);
|
|
|
|
Clear();
|
|
int shadowLightIndex = lightData.mainLightIndex;
|
|
if (shadowLightIndex == -1)
|
|
return SetupForEmptyRendering(cameraData.renderer.stripShadowsOffVariants);
|
|
|
|
VisibleLight shadowLight = lightData.visibleLights[shadowLightIndex];
|
|
Light light = shadowLight.light;
|
|
if (light.shadows == LightShadows.None)
|
|
return SetupForEmptyRendering(cameraData.renderer.stripShadowsOffVariants);
|
|
|
|
if (shadowLight.lightType != LightType.Directional)
|
|
{
|
|
Debug.LogWarning("Only directional lights are supported as main light.");
|
|
}
|
|
|
|
if (!renderingData.cullResults.GetShadowCasterBounds(shadowLightIndex, out Bounds _))
|
|
return SetupForEmptyRendering(cameraData.renderer.stripShadowsOffVariants);
|
|
|
|
m_ShadowCasterCascadesCount = shadowData.mainLightShadowCascadesCount;
|
|
renderTargetWidth = shadowData.mainLightRenderTargetWidth;
|
|
renderTargetHeight = shadowData.mainLightRenderTargetHeight;
|
|
|
|
ref readonly URPLightShadowCullingInfos shadowCullingInfos = ref shadowData.visibleLightsShadowCullingInfos.UnsafeElementAt(shadowLightIndex);
|
|
|
|
for (int cascadeIndex = 0; cascadeIndex < m_ShadowCasterCascadesCount; ++cascadeIndex)
|
|
{
|
|
ref readonly ShadowSliceData sliceData = ref shadowCullingInfos.slices.UnsafeElementAt(cascadeIndex);
|
|
m_CascadeSplitDistances[cascadeIndex] = sliceData.splitData.cullingSphere;
|
|
m_CascadeSlices[cascadeIndex] = sliceData;
|
|
|
|
if (!shadowCullingInfos.IsSliceValid(cascadeIndex))
|
|
return SetupForEmptyRendering(cameraData.renderer.stripShadowsOffVariants);
|
|
}
|
|
|
|
UpdateTextureDescriptorIfNeeded();
|
|
|
|
m_MaxShadowDistanceSq = cameraData.maxShadowDistance * cameraData.maxShadowDistance;
|
|
m_CascadeBorder = shadowData.mainLightShadowCascadeBorder;
|
|
m_CreateEmptyShadowmap = false;
|
|
useNativeRenderPass = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
private void UpdateTextureDescriptorIfNeeded()
|
|
{
|
|
if ( m_MainLightShadowDescriptor.width != renderTargetWidth
|
|
|| m_MainLightShadowDescriptor.height != renderTargetHeight
|
|
|| m_MainLightShadowDescriptor.depthBufferBits != k_ShadowmapBufferBits
|
|
|| m_MainLightShadowDescriptor.colorFormat != RenderTextureFormat.Shadowmap)
|
|
{
|
|
m_MainLightShadowDescriptor = new RenderTextureDescriptor(renderTargetWidth, renderTargetHeight, RenderTextureFormat.Shadowmap, k_ShadowmapBufferBits);
|
|
}
|
|
}
|
|
|
|
bool SetupForEmptyRendering(bool stripShadowsOffVariants)
|
|
{
|
|
if (!stripShadowsOffVariants)
|
|
return false;
|
|
|
|
m_CreateEmptyShadowmap = true;
|
|
useNativeRenderPass = false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
[Obsolete(DeprecationMessage.CompatibilityScriptingAPIObsolete, false)]
|
|
public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
|
|
{
|
|
// Disable obsolete warning for internal usage
|
|
#pragma warning disable CS0618
|
|
|
|
if (m_CreateEmptyShadowmap)
|
|
{
|
|
// Required for scene view camera(URP renderer not initialized)
|
|
if (ShadowUtils.ShadowRTReAllocateIfNeeded(ref m_EmptyMainLightShadowmapTexture, k_EmptyShadowMapDimensions, k_EmptyShadowMapDimensions, k_ShadowmapBufferBits, name: k_EmptyMainLightShadowMapTextureName))
|
|
m_EmptyShadowmapNeedsClear = true;
|
|
|
|
if (!m_EmptyShadowmapNeedsClear)
|
|
{
|
|
// UUM-63146 - glClientWaitSync: Expected application to have kicked everything until job: 96089 (possibly by calling glFlush)" are thrown in the Android Player on some devices with PowerVR Rogue GE8320
|
|
// Resetting of target would clean up the color attachment buffers and depth attachment buffers, which inturn is preventing the leak in the said platform. This is likely a symptomatic fix, but is solving the problem for now.
|
|
if (Application.platform == RuntimePlatform.Android && PlatformAutoDetect.isRunningOnPowerVRGPU)
|
|
ResetTarget();
|
|
|
|
return;
|
|
}
|
|
|
|
ConfigureTarget(m_EmptyMainLightShadowmapTexture);
|
|
m_EmptyShadowmapNeedsClear = false;
|
|
}
|
|
else
|
|
{
|
|
ShadowUtils.ShadowRTReAllocateIfNeeded(ref m_MainLightShadowmapTexture, renderTargetWidth, renderTargetHeight, k_ShadowmapBufferBits, name: k_MainLightShadowMapTextureName);
|
|
ConfigureTarget(m_MainLightShadowmapTexture);
|
|
}
|
|
|
|
ConfigureClear(ClearFlag.All, Color.black);
|
|
|
|
#pragma warning restore CS0618
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
[Obsolete(DeprecationMessage.CompatibilityScriptingAPIObsolete, false)]
|
|
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
|
|
{
|
|
ContextContainer frameData = renderingData.frameData;
|
|
UniversalRenderingData universalRenderingData = frameData.Get<UniversalRenderingData>();
|
|
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
|
|
UniversalLightData lightData = frameData.Get<UniversalLightData>();
|
|
UniversalShadowData shadowData = frameData.Get<UniversalShadowData>();
|
|
|
|
if (m_CreateEmptyShadowmap)
|
|
{
|
|
SetEmptyMainLightCascadeShadowmap(CommandBufferHelpers.GetRasterCommandBuffer(universalRenderingData.commandBuffer));
|
|
universalRenderingData.commandBuffer.SetGlobalTexture(m_MainLightShadowmapID, m_EmptyMainLightShadowmapTexture.nameID);
|
|
return;
|
|
}
|
|
|
|
InitPassData(ref m_PassData, universalRenderingData, cameraData, lightData, shadowData);
|
|
InitRendererLists(ref m_PassData, context, default(RenderGraph), false);
|
|
|
|
RenderMainLightCascadeShadowmap(CommandBufferHelpers.GetRasterCommandBuffer(universalRenderingData.commandBuffer), ref m_PassData, false);
|
|
universalRenderingData.commandBuffer.SetGlobalTexture(m_MainLightShadowmapID, m_MainLightShadowmapTexture.nameID);
|
|
}
|
|
|
|
void Clear()
|
|
{
|
|
for (int i = 0; i < m_MainLightShadowMatrices.Length; ++i)
|
|
m_MainLightShadowMatrices[i] = Matrix4x4.identity;
|
|
|
|
for (int i = 0; i < m_CascadeSplitDistances.Length; ++i)
|
|
m_CascadeSplitDistances[i] = new Vector4(0.0f, 0.0f, 0.0f, 0.0f);
|
|
|
|
for (int i = 0; i < m_CascadeSlices.Length; ++i)
|
|
m_CascadeSlices[i].Clear();
|
|
}
|
|
|
|
void SetEmptyMainLightCascadeShadowmap(RasterCommandBuffer cmd)
|
|
{
|
|
cmd.EnableKeyword(ShaderGlobalKeywords.MainLightShadows);
|
|
SetEmptyMainLightShadowParams(cmd);
|
|
}
|
|
|
|
internal static void SetEmptyMainLightShadowParams(RasterCommandBuffer cmd)
|
|
{
|
|
cmd.SetGlobalVector(MainLightShadowConstantBuffer._ShadowParams, s_EmptyShadowParams);
|
|
cmd.SetGlobalVector(MainLightShadowConstantBuffer._ShadowmapSize, s_EmptyShadowmapSize);
|
|
}
|
|
|
|
void RenderMainLightCascadeShadowmap(RasterCommandBuffer cmd, ref PassData data, bool isRenderGraph)
|
|
{
|
|
var lightData = data.lightData;
|
|
|
|
int shadowLightIndex = lightData.mainLightIndex;
|
|
if (shadowLightIndex == -1)
|
|
return;
|
|
|
|
VisibleLight shadowLight = lightData.visibleLights[shadowLightIndex];
|
|
|
|
using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.MainLightShadow)))
|
|
{
|
|
// Need to start by setting the Camera position and worldToCamera Matrix as that is not set for passes executed before normal rendering
|
|
ShadowUtils.SetCameraPosition(cmd, data.cameraData.worldSpaceCameraPos);
|
|
|
|
// For non-RG, need set the worldToCamera Matrix as that is not set for passes executed before normal rendering,
|
|
// otherwise shadows will behave incorrectly when Scene and Game windows are open at the same time (UUM-63267).
|
|
if (!isRenderGraph)
|
|
ShadowUtils.SetWorldToCameraMatrix(cmd, data.cameraData.GetViewMatrix());
|
|
|
|
for (int cascadeIndex = 0; cascadeIndex < m_ShadowCasterCascadesCount; ++cascadeIndex)
|
|
{
|
|
Vector4 shadowBias = ShadowUtils.GetShadowBias(ref shadowLight, shadowLightIndex, data.shadowData, m_CascadeSlices[cascadeIndex].projectionMatrix, m_CascadeSlices[cascadeIndex].resolution);
|
|
ShadowUtils.SetupShadowCasterConstantBuffer(cmd, ref shadowLight, shadowBias);
|
|
cmd.SetKeyword(ShaderGlobalKeywords.CastingPunctualLightShadow, false);
|
|
RendererList shadowRendererList = isRenderGraph? data.shadowRendererListsHandle[cascadeIndex] : data.shadowRendererLists[cascadeIndex];
|
|
ShadowUtils.RenderShadowSlice(cmd, ref m_CascadeSlices[cascadeIndex], ref shadowRendererList, m_CascadeSlices[cascadeIndex].projectionMatrix, m_CascadeSlices[cascadeIndex].viewMatrix);
|
|
}
|
|
|
|
data.shadowData.isKeywordSoftShadowsEnabled = shadowLight.light.shadows == LightShadows.Soft && data.shadowData.supportsSoftShadows;
|
|
cmd.SetKeyword(ShaderGlobalKeywords.MainLightShadows, data.shadowData.mainLightShadowCascadesCount == 1);
|
|
cmd.SetKeyword(ShaderGlobalKeywords.MainLightShadowCascades, data.shadowData.mainLightShadowCascadesCount > 1);
|
|
ShadowUtils.SetSoftShadowQualityShaderKeywords(cmd, data.shadowData);
|
|
|
|
SetupMainLightShadowReceiverConstants(cmd, ref shadowLight, data.shadowData);
|
|
}
|
|
}
|
|
|
|
void SetupMainLightShadowReceiverConstants(RasterCommandBuffer cmd, ref VisibleLight shadowLight, UniversalShadowData shadowData)
|
|
{
|
|
Light light = shadowLight.light;
|
|
bool softShadows = shadowLight.light.shadows == LightShadows.Soft && shadowData.supportsSoftShadows;
|
|
|
|
int cascadeCount = m_ShadowCasterCascadesCount;
|
|
for (int i = 0; i < cascadeCount; ++i)
|
|
m_MainLightShadowMatrices[i] = m_CascadeSlices[i].shadowTransform;
|
|
|
|
// We setup and additional a no-op WorldToShadow matrix in the last index
|
|
// because the ComputeCascadeIndex function in Shadows.hlsl can return an index
|
|
// out of bounds. (position not inside any cascade) and we want to avoid branching
|
|
Matrix4x4 noOpShadowMatrix = Matrix4x4.zero;
|
|
noOpShadowMatrix.m22 = (SystemInfo.usesReversedZBuffer) ? 1.0f : 0.0f;
|
|
for (int i = cascadeCount; i <= k_MaxCascades; ++i)
|
|
m_MainLightShadowMatrices[i] = noOpShadowMatrix;
|
|
|
|
float invShadowAtlasWidth = 1.0f / renderTargetWidth;
|
|
float invShadowAtlasHeight = 1.0f / renderTargetHeight;
|
|
float invHalfShadowAtlasWidth = 0.5f * invShadowAtlasWidth;
|
|
float invHalfShadowAtlasHeight = 0.5f * invShadowAtlasHeight;
|
|
float softShadowsProp = ShadowUtils.SoftShadowQualityToShaderProperty(light, softShadows);
|
|
|
|
ShadowUtils.GetScaleAndBiasForLinearDistanceFade(m_MaxShadowDistanceSq, m_CascadeBorder, out float shadowFadeScale, out float shadowFadeBias);
|
|
|
|
cmd.SetGlobalMatrixArray(MainLightShadowConstantBuffer._WorldToShadow, m_MainLightShadowMatrices);
|
|
cmd.SetGlobalVector(MainLightShadowConstantBuffer._ShadowParams,
|
|
new Vector4(light.shadowStrength, softShadowsProp, shadowFadeScale, shadowFadeBias));
|
|
|
|
if (m_ShadowCasterCascadesCount > 1)
|
|
{
|
|
cmd.SetGlobalVector(MainLightShadowConstantBuffer._CascadeShadowSplitSpheres0,
|
|
m_CascadeSplitDistances[0]);
|
|
cmd.SetGlobalVector(MainLightShadowConstantBuffer._CascadeShadowSplitSpheres1,
|
|
m_CascadeSplitDistances[1]);
|
|
cmd.SetGlobalVector(MainLightShadowConstantBuffer._CascadeShadowSplitSpheres2,
|
|
m_CascadeSplitDistances[2]);
|
|
cmd.SetGlobalVector(MainLightShadowConstantBuffer._CascadeShadowSplitSpheres3,
|
|
m_CascadeSplitDistances[3]);
|
|
cmd.SetGlobalVector(MainLightShadowConstantBuffer._CascadeShadowSplitSphereRadii, new Vector4(
|
|
m_CascadeSplitDistances[0].w * m_CascadeSplitDistances[0].w,
|
|
m_CascadeSplitDistances[1].w * m_CascadeSplitDistances[1].w,
|
|
m_CascadeSplitDistances[2].w * m_CascadeSplitDistances[2].w,
|
|
m_CascadeSplitDistances[3].w * m_CascadeSplitDistances[3].w));
|
|
}
|
|
|
|
// Inside shader soft shadows are controlled through global keyword.
|
|
// If any additional light has soft shadows it will force soft shadows on main light too.
|
|
// As it is not trivial finding out which additional light has soft shadows, we will pass main light properties if soft shadows are supported.
|
|
// This workaround will be removed once we will support soft shadows per light.
|
|
if (shadowData.supportsSoftShadows)
|
|
{
|
|
cmd.SetGlobalVector(MainLightShadowConstantBuffer._ShadowOffset0,
|
|
new Vector4(-invHalfShadowAtlasWidth, -invHalfShadowAtlasHeight,
|
|
invHalfShadowAtlasWidth, -invHalfShadowAtlasHeight));
|
|
cmd.SetGlobalVector(MainLightShadowConstantBuffer._ShadowOffset1,
|
|
new Vector4(-invHalfShadowAtlasWidth, invHalfShadowAtlasHeight,
|
|
invHalfShadowAtlasWidth, invHalfShadowAtlasHeight));
|
|
|
|
cmd.SetGlobalVector(MainLightShadowConstantBuffer._ShadowmapSize, new Vector4(invShadowAtlasWidth,
|
|
invShadowAtlasHeight,
|
|
renderTargetWidth, renderTargetHeight));
|
|
}
|
|
}
|
|
|
|
private class PassData
|
|
{
|
|
internal UniversalRenderingData renderingData;
|
|
internal UniversalCameraData cameraData;
|
|
internal UniversalLightData lightData;
|
|
internal UniversalShadowData shadowData;
|
|
|
|
internal MainLightShadowCasterPass pass;
|
|
|
|
internal TextureHandle shadowmapTexture;
|
|
internal int shadowmapID;
|
|
internal bool emptyShadowmap;
|
|
|
|
internal RendererListHandle[] shadowRendererListsHandle = new RendererListHandle[k_MaxCascades];
|
|
internal RendererList[] shadowRendererLists = new RendererList[k_MaxCascades];
|
|
}
|
|
|
|
private void InitPassData(
|
|
ref PassData passData,
|
|
UniversalRenderingData renderingData,
|
|
UniversalCameraData cameraData,
|
|
UniversalLightData lightData,
|
|
UniversalShadowData shadowData)
|
|
{
|
|
passData.pass = this;
|
|
|
|
passData.emptyShadowmap = m_CreateEmptyShadowmap;
|
|
passData.shadowmapID = m_MainLightShadowmapID;
|
|
passData.renderingData = renderingData;
|
|
passData.cameraData = cameraData;
|
|
passData.lightData = lightData;
|
|
passData.shadowData = shadowData;
|
|
}
|
|
|
|
void InitEmptyPassData(
|
|
ref PassData passData,
|
|
UniversalRenderingData renderingData,
|
|
UniversalCameraData cameraData,
|
|
UniversalLightData lightData,
|
|
UniversalShadowData shadowData)
|
|
{
|
|
passData.pass = this;
|
|
|
|
passData.emptyShadowmap = m_CreateEmptyShadowmap;
|
|
passData.shadowmapID = m_MainLightShadowmapID;
|
|
passData.renderingData = renderingData;
|
|
passData.cameraData = cameraData;
|
|
passData.lightData = lightData;
|
|
passData.shadowData = shadowData;
|
|
}
|
|
|
|
private void InitRendererLists(ref PassData passData, ScriptableRenderContext context, RenderGraph renderGraph, bool useRenderGraph)
|
|
{
|
|
int shadowLightIndex = passData.lightData.mainLightIndex;
|
|
if (!m_CreateEmptyShadowmap && shadowLightIndex != -1)
|
|
{
|
|
var settings = new ShadowDrawingSettings(passData.renderingData.cullResults, shadowLightIndex);
|
|
settings.useRenderingLayerMaskTest = UniversalRenderPipeline.asset.useRenderingLayers;
|
|
for (int cascadeIndex = 0; cascadeIndex < m_ShadowCasterCascadesCount; ++cascadeIndex)
|
|
{
|
|
if (useRenderGraph)
|
|
passData.shadowRendererListsHandle[cascadeIndex] = renderGraph.CreateShadowRendererList(ref settings);
|
|
else
|
|
passData.shadowRendererLists[cascadeIndex] = context.CreateShadowRendererList(ref settings);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal TextureHandle Render(RenderGraph graph, ContextContainer frameData)
|
|
{
|
|
UniversalRenderingData renderingData = frameData.Get<UniversalRenderingData>();
|
|
UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
|
|
UniversalLightData lightData = frameData.Get<UniversalLightData>();
|
|
UniversalShadowData shadowData = frameData.Get<UniversalShadowData>();
|
|
|
|
TextureHandle shadowTexture;
|
|
|
|
using (var builder = graph.AddRasterRenderPass<PassData>(passName, out var passData, profilingSampler))
|
|
{
|
|
InitPassData(ref passData, renderingData, cameraData, lightData, shadowData);
|
|
InitRendererLists(ref passData, default(ScriptableRenderContext), graph, true);
|
|
|
|
if (!m_CreateEmptyShadowmap)
|
|
{
|
|
for (int cascadeIndex = 0; cascadeIndex < m_ShadowCasterCascadesCount; ++cascadeIndex)
|
|
{
|
|
builder.UseRendererList(passData.shadowRendererListsHandle[cascadeIndex]);
|
|
}
|
|
|
|
shadowTexture = UniversalRenderer.CreateRenderGraphTexture(graph, m_MainLightShadowDescriptor, k_MainLightShadowMapTextureName, true, ShadowUtils.m_ForceShadowPointSampling ? FilterMode.Point : FilterMode.Bilinear);
|
|
builder.SetRenderAttachmentDepth(shadowTexture, AccessFlags.Write);
|
|
}
|
|
else
|
|
{
|
|
shadowTexture = graph.defaultResources.defaultShadowTexture;
|
|
}
|
|
|
|
// Need this as shadowmap is only used as Global Texture and not a buffer, so would get culled by RG
|
|
builder.AllowPassCulling(false);
|
|
builder.AllowGlobalStateModification(true);
|
|
|
|
if (shadowTexture.IsValid())
|
|
builder.SetGlobalTextureAfterPass(shadowTexture, m_MainLightShadowmapID);
|
|
|
|
builder.SetRenderFunc((PassData data, RasterGraphContext context) =>
|
|
{
|
|
if (!data.emptyShadowmap)
|
|
{
|
|
data.pass.RenderMainLightCascadeShadowmap(context.cmd, ref data, true);
|
|
}
|
|
else
|
|
{
|
|
data.pass.SetEmptyMainLightCascadeShadowmap(context.cmd);
|
|
}
|
|
});
|
|
}
|
|
|
|
return shadowTexture;
|
|
}
|
|
};
|
|
}
|