您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
251 行
13 KiB
251 行
13 KiB
using System;
|
|
|
|
namespace UnityEngine.Rendering.Universal
|
|
{
|
|
internal 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 _ShadowOffset2;
|
|
public static int _ShadowOffset3;
|
|
public static int _ShadowmapSize;
|
|
}
|
|
|
|
const int k_MaxCascades = 4;
|
|
const int k_ShadowmapBufferBits = 16;
|
|
int m_ShadowmapWidth;
|
|
int m_ShadowmapHeight;
|
|
int m_ShadowCasterCascadesCount;
|
|
bool m_SupportsBoxFilterForShadows;
|
|
|
|
RenderTargetHandle m_MainLightShadowmap;
|
|
RenderTexture m_MainLightShadowmapTexture;
|
|
|
|
Matrix4x4[] m_MainLightShadowMatrices;
|
|
ShadowSliceData[] m_CascadeSlices;
|
|
Vector4[] m_CascadeSplitDistances;
|
|
|
|
const string m_ProfilerTag = "Render Main Shadowmap";
|
|
|
|
public MainLightShadowCasterPass(RenderPassEvent evt)
|
|
{
|
|
renderPassEvent = evt;
|
|
|
|
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._ShadowOffset2 = Shader.PropertyToID("_MainLightShadowOffset2");
|
|
MainLightShadowConstantBuffer._ShadowOffset3 = Shader.PropertyToID("_MainLightShadowOffset3");
|
|
MainLightShadowConstantBuffer._ShadowmapSize = Shader.PropertyToID("_MainLightShadowmapSize");
|
|
|
|
m_MainLightShadowmap.Init("_MainLightShadowmapTexture");
|
|
m_SupportsBoxFilterForShadows = Application.isMobilePlatform || SystemInfo.graphicsDeviceType == GraphicsDeviceType.Switch;
|
|
}
|
|
|
|
public bool Setup(ref RenderingData renderingData)
|
|
{
|
|
if (!renderingData.shadowData.supportsMainLightShadows)
|
|
return false;
|
|
|
|
Clear();
|
|
int shadowLightIndex = renderingData.lightData.mainLightIndex;
|
|
if (shadowLightIndex == -1)
|
|
return false;
|
|
|
|
VisibleLight shadowLight = renderingData.lightData.visibleLights[shadowLightIndex];
|
|
Light light = shadowLight.light;
|
|
if (light.shadows == LightShadows.None)
|
|
return false;
|
|
|
|
if (shadowLight.lightType != LightType.Directional)
|
|
{
|
|
Debug.LogWarning("Only directional lights are supported as main light.");
|
|
}
|
|
|
|
Bounds bounds;
|
|
if (!renderingData.cullResults.GetShadowCasterBounds(shadowLightIndex, out bounds))
|
|
return false;
|
|
|
|
m_ShadowCasterCascadesCount = renderingData.shadowData.mainLightShadowCascadesCount;
|
|
|
|
int shadowResolution = ShadowUtils.GetMaxTileResolutionInAtlas(renderingData.shadowData.mainLightShadowmapWidth,
|
|
renderingData.shadowData.mainLightShadowmapHeight, m_ShadowCasterCascadesCount);
|
|
m_ShadowmapWidth = renderingData.shadowData.mainLightShadowmapWidth;
|
|
m_ShadowmapHeight = (m_ShadowCasterCascadesCount == 2) ?
|
|
renderingData.shadowData.mainLightShadowmapHeight >> 1 :
|
|
renderingData.shadowData.mainLightShadowmapHeight;
|
|
|
|
for (int cascadeIndex = 0; cascadeIndex < m_ShadowCasterCascadesCount; ++cascadeIndex)
|
|
{
|
|
bool success = ShadowUtils.ExtractDirectionalLightMatrix(ref renderingData.cullResults, ref renderingData.shadowData,
|
|
shadowLightIndex, cascadeIndex, m_ShadowmapWidth, m_ShadowmapHeight, shadowResolution, light.shadowNearPlane,
|
|
out m_CascadeSplitDistances[cascadeIndex], out m_CascadeSlices[cascadeIndex], out m_CascadeSlices[cascadeIndex].viewMatrix, out m_CascadeSlices[cascadeIndex].projectionMatrix);
|
|
|
|
if (!success)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
|
|
{
|
|
m_MainLightShadowmapTexture = ShadowUtils.GetTemporaryShadowTexture(m_ShadowmapWidth,
|
|
m_ShadowmapHeight, k_ShadowmapBufferBits);
|
|
ConfigureTarget(new RenderTargetIdentifier(m_MainLightShadowmapTexture));
|
|
ConfigureClear(ClearFlag.All, Color.black);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
|
|
{
|
|
RenderMainLightCascadeShadowmap(ref context, ref renderingData.cullResults, ref renderingData.lightData, ref renderingData.shadowData);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override void FrameCleanup(CommandBuffer cmd)
|
|
{
|
|
if (cmd == null)
|
|
throw new ArgumentNullException("cmd");
|
|
|
|
if (m_MainLightShadowmapTexture)
|
|
{
|
|
RenderTexture.ReleaseTemporary(m_MainLightShadowmapTexture);
|
|
m_MainLightShadowmapTexture = null;
|
|
}
|
|
}
|
|
|
|
void Clear()
|
|
{
|
|
m_MainLightShadowmapTexture = null;
|
|
|
|
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 RenderMainLightCascadeShadowmap(ref ScriptableRenderContext context, ref CullingResults cullResults, ref LightData lightData, ref ShadowData shadowData)
|
|
{
|
|
int shadowLightIndex = lightData.mainLightIndex;
|
|
if (shadowLightIndex == -1)
|
|
return;
|
|
|
|
VisibleLight shadowLight = lightData.visibleLights[shadowLightIndex];
|
|
|
|
CommandBuffer cmd = CommandBufferPool.Get(m_ProfilerTag);
|
|
using (new ProfilingSample(cmd, m_ProfilerTag))
|
|
{
|
|
var settings = new ShadowDrawingSettings(cullResults, shadowLightIndex);
|
|
|
|
for (int cascadeIndex = 0; cascadeIndex < m_ShadowCasterCascadesCount; ++cascadeIndex)
|
|
{
|
|
var splitData = settings.splitData;
|
|
splitData.cullingSphere = m_CascadeSplitDistances[cascadeIndex];
|
|
settings.splitData = splitData;
|
|
Vector4 shadowBias = ShadowUtils.GetShadowBias(ref shadowLight, shadowLightIndex, ref shadowData, m_CascadeSlices[cascadeIndex].projectionMatrix, m_CascadeSlices[cascadeIndex].resolution);
|
|
ShadowUtils.SetupShadowCasterConstantBuffer(cmd, ref shadowLight, shadowBias);
|
|
ShadowUtils.RenderShadowSlice(cmd, ref context, ref m_CascadeSlices[cascadeIndex],
|
|
ref settings, m_CascadeSlices[cascadeIndex].projectionMatrix, m_CascadeSlices[cascadeIndex].viewMatrix);
|
|
}
|
|
|
|
bool softShadows = shadowLight.light.shadows == LightShadows.Soft && shadowData.supportsSoftShadows;
|
|
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadows, true);
|
|
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadowCascades, shadowData.mainLightShadowCascadesCount > 1);
|
|
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.SoftShadows, softShadows);
|
|
|
|
SetupMainLightShadowReceiverConstants(cmd, shadowLight, softShadows);
|
|
}
|
|
|
|
context.ExecuteCommandBuffer(cmd);
|
|
CommandBufferPool.Release(cmd);
|
|
}
|
|
|
|
void SetupMainLightShadowReceiverConstants(CommandBuffer cmd, VisibleLight shadowLight, bool softShadows)
|
|
{
|
|
Light light = shadowLight.light;
|
|
|
|
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 / m_ShadowmapWidth;
|
|
float invShadowAtlasHeight = 1.0f / m_ShadowmapHeight;
|
|
float invHalfShadowAtlasWidth = 0.5f * invShadowAtlasWidth;
|
|
float invHalfShadowAtlasHeight = 0.5f * invShadowAtlasHeight;
|
|
float softShadowsProp = softShadows ? 1.0f : 0.0f;
|
|
cmd.SetGlobalTexture(m_MainLightShadowmap.id, m_MainLightShadowmapTexture);
|
|
cmd.SetGlobalMatrixArray(MainLightShadowConstantBuffer._WorldToShadow, m_MainLightShadowMatrices);
|
|
cmd.SetGlobalVector(MainLightShadowConstantBuffer._ShadowParams, new Vector4(light.shadowStrength, softShadowsProp, 0.0f, 0.0f));
|
|
|
|
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));
|
|
}
|
|
|
|
if (softShadows)
|
|
{
|
|
if (m_SupportsBoxFilterForShadows)
|
|
{
|
|
cmd.SetGlobalVector(MainLightShadowConstantBuffer._ShadowOffset0,
|
|
new Vector4(-invHalfShadowAtlasWidth, -invHalfShadowAtlasHeight, 0.0f, 0.0f));
|
|
cmd.SetGlobalVector(MainLightShadowConstantBuffer._ShadowOffset1,
|
|
new Vector4(invHalfShadowAtlasWidth, -invHalfShadowAtlasHeight, 0.0f, 0.0f));
|
|
cmd.SetGlobalVector(MainLightShadowConstantBuffer._ShadowOffset2,
|
|
new Vector4(-invHalfShadowAtlasWidth, invHalfShadowAtlasHeight, 0.0f, 0.0f));
|
|
cmd.SetGlobalVector(MainLightShadowConstantBuffer._ShadowOffset3,
|
|
new Vector4(invHalfShadowAtlasWidth, invHalfShadowAtlasHeight, 0.0f, 0.0f));
|
|
}
|
|
|
|
// Currently only used when !SHADER_API_MOBILE but risky to not set them as it's generic
|
|
// enough so custom shaders might use it.
|
|
cmd.SetGlobalVector(MainLightShadowConstantBuffer._ShadowmapSize, new Vector4(invShadowAtlasWidth,
|
|
invShadowAtlasHeight,
|
|
m_ShadowmapWidth, m_ShadowmapHeight));
|
|
}
|
|
}
|
|
};
|
|
}
|