|
|
|
|
|
|
using System; |
|
|
|
using System.Collections.Generic; |
|
|
|
using System.Diagnostics; |
|
|
|
using System.Text; |
|
|
|
using UnityEngine.Assertions; |
|
|
|
#if UNITY_EDITOR
|
|
|
|
using UnityEditor.Experimental.Rendering.LightweightPipeline; |
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
// Lights are culled per-object. This holds the maximum amount of lights that can be shaded per-object.
|
|
|
|
// The engine fills in the lights indices per-object in unity4_LightIndices0 and unity_4LightIndices1
|
|
|
|
private static readonly int kMaxPerObjectLights = 4; |
|
|
|
private static readonly int kMaxPerObjectLights = 8; |
|
|
|
private static readonly int kMaxLocalPixelLightPerPass = 4; |
|
|
|
|
|
|
|
private static readonly int kMaxVertexLights = 4; |
|
|
|
|
|
|
|
|
|
|
private int m_AdditionalShadowmapRTID; |
|
|
|
private int m_ScreenSpaceShadowMapRTID; |
|
|
|
private Matrix4x4[] m_ShadowMatrices = new Matrix4x4[kMaxCascades + 1]; |
|
|
|
private Matrix4x4[] m_LocalLightShadowMatrices = new Matrix4x4[4]; |
|
|
|
private Matrix4x4[] m_LocalLightShadowMatrices = new Matrix4x4[kMaxLocalPixelLightPerPass]; |
|
|
|
private RenderTargetIdentifier m_CurrCameraColorRT; |
|
|
|
private RenderTexture m_DirectionalShadowmapRT; |
|
|
|
private RenderTexture m_AdditionalShadowmapRT; |
|
|
|
|
|
|
|
|
|
|
private ShadowSettings m_ShadowSettings = ShadowSettings.Default; |
|
|
|
private ShadowSliceData[] m_ShadowCascadeSlices = new ShadowSliceData[kMaxCascades]; |
|
|
|
private ShadowSliceData[] m_AddtionalShadowSlices = new ShadowSliceData[kMaxPerObjectLights]; |
|
|
|
private ShadowSliceData[] m_LocalLightShadowSlices = new ShadowSliceData[kMaxPerObjectLights]; |
|
|
|
private List<int> m_LocalShadowLightIndices = new List<int>(kMaxLocalPixelLightPerPass); |
|
|
|
private float[] m_LocalShadowStrength = new float[kMaxLocalPixelLightPerPass]; |
|
|
|
private int m_LocalLightShadowResolution = 512; |
|
|
|
private int m_LocalLightShadowIndex; |
|
|
|
private int m_LocalLightShadowAtlasResolution = 512; |
|
|
|
|
|
|
|
// Pipeline pass names
|
|
|
|
private static readonly ShaderPassName m_DepthPrepass = new ShaderPassName("DepthOnly"); |
|
|
|
|
|
|
DepthPass(ref context, frameRenderingConfiguration); |
|
|
|
|
|
|
|
if (screenspaceShadows) |
|
|
|
ShadowCollectPass(visibleLights, ref context, ref lightData, frameRenderingConfiguration); |
|
|
|
ShadowCollectPass(frameRenderingConfiguration, ref context); |
|
|
|
|
|
|
|
ForwardPass(visibleLights, frameRenderingConfiguration, ref context, ref lightData, stereoEnabled); |
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private bool ShadowPass(List<VisibleLight> visibleLights, ref ScriptableRenderContext context, ref LightData lightData) |
|
|
|
private void InitializeShadowPass() |
|
|
|
m_LocalLightShadowIndex = -1; |
|
|
|
m_LocalShadowLightIndices.Clear(); |
|
|
|
for (int i = 0; i < kMaxLocalPixelLightPerPass; ++i) |
|
|
|
m_LocalShadowStrength[i] = 0.0f; |
|
|
|
} |
|
|
|
|
|
|
|
private bool ShadowPass(List<VisibleLight> visibleLights, ref ScriptableRenderContext context, ref LightData lightData) |
|
|
|
{ |
|
|
|
InitializeShadowPass(); |
|
|
|
|
|
|
|
bool directionalShadowmapRendered = false; |
|
|
|
if (m_Asset.AreShadowsEnabled()) |
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (lightData.pixelAdditionalLightsCount > 0) |
|
|
|
RenderAdditionalShadowmapAtlas(visibleLights, ref context); |
|
|
|
RenderLocalShadowmapAtlas(visibleLights, ref context); |
|
|
|
private void ShadowCollectPass(List<VisibleLight> visibleLights, ref ScriptableRenderContext context, ref LightData lightData, FrameRenderingConfiguration frameRenderingConfiguration) |
|
|
|
private void ShadowCollectPass(FrameRenderingConfiguration frameRenderingConfiguration, ref ScriptableRenderContext context) |
|
|
|
SetShadowCollectPassKeywords(cmd, visibleLights[lightData.mainLightIndex], ref lightData); |
|
|
|
SetShadowCollectPassKeywords(cmd); |
|
|
|
|
|
|
|
// TODO: Support RenderScale for the SSSM target. Should probably move allocation elsewhere, or at
|
|
|
|
// least propogate RenderTextureDescriptor generation
|
|
|
|
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
private void InitializeLightConstants(List<VisibleLight> lights, int lightIndex, out Vector4 lightPos, out Vector4 lightColor, out Vector4 lightDistanceAttenuation, out Vector4 lightSpotDir, |
|
|
|
private void InitializeLightConstants(List<VisibleLight> lights, int lightIndex, bool castShadows, out Vector4 lightPos, out Vector4 lightColor, out Vector4 lightDistanceAttenuation, out Vector4 lightSpotDir, |
|
|
|
out Vector4 lightSpotAttenuation) |
|
|
|
{ |
|
|
|
lightPos = kDefaultLightPosition; |
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
VisibleLight lightData = lights[lightIndex]; |
|
|
|
float castShadowsProp = castShadows ? 1.0f : 0.0f; |
|
|
|
lightPos = new Vector4(dir.x, dir.y, dir.z, 0.0f); |
|
|
|
lightPos = new Vector4(dir.x, dir.y, dir.z, castShadowsProp); |
|
|
|
lightPos = new Vector4(pos.x, pos.y, pos.z, 1.0f); |
|
|
|
lightPos = new Vector4(pos.x, pos.y, pos.z, castShadowsProp); |
|
|
|
} |
|
|
|
|
|
|
|
// VisibleLight.finalColor already returns color in active color space
|
|
|
|
|
|
|
private void SetupMainLightConstants(CommandBuffer cmd, List<VisibleLight> lights, int lightIndex) |
|
|
|
{ |
|
|
|
Vector4 lightPos, lightColor, lightDistanceAttenuation, lightSpotDir, lightSpotAttenuation; |
|
|
|
InitializeLightConstants(lights, lightIndex, out lightPos, out lightColor, out lightDistanceAttenuation, out lightSpotDir, out lightSpotAttenuation); |
|
|
|
InitializeLightConstants(lights, lightIndex, m_ShadowSampling != LightShadows.None, out lightPos, out lightColor, out lightDistanceAttenuation, out lightSpotDir, out lightSpotAttenuation); |
|
|
|
|
|
|
|
if (lightIndex >= 0) |
|
|
|
{ |
|
|
|
|
|
|
else |
|
|
|
{ |
|
|
|
perObjectLightIndexMap[i] -= directionalLightCount; |
|
|
|
InitializeLightConstants(lights, i, out m_LightPositions[localLights], |
|
|
|
InitializeLightConstants(lights, i, m_LocalShadowLightIndices.Contains(i), out m_LightPositions[localLights], |
|
|
|
out m_LightColors[localLights], |
|
|
|
out m_LightDistanceAttenuations[localLights], |
|
|
|
out m_LightSpotDirections[localLights], |
|
|
|
|
|
|
|
|
|
|
// Clear to default all light constant data
|
|
|
|
for (int i = 0; i < kMaxVisibleLights; ++i) |
|
|
|
InitializeLightConstants(lights, -1, out m_LightPositions[i], |
|
|
|
InitializeLightConstants(lights, -1, false, out m_LightPositions[i], |
|
|
|
out m_LightColors[i], |
|
|
|
out m_LightDistanceAttenuations[i], |
|
|
|
out m_LightSpotDirections[i], |
|
|
|
|
|
|
|
|
|
|
private void SetupLocalLightsShadowReceiverConstants(CommandBuffer cmd, List<VisibleLight> visibleLights, ref ScriptableRenderContext context) |
|
|
|
{ |
|
|
|
VisibleLight shadowLight = visibleLights[m_LocalLightShadowIndex]; |
|
|
|
|
|
|
|
m_LocalLightShadowMatrices[0] = m_AddtionalShadowSlices[0].shadowTransform; |
|
|
|
m_LocalLightShadowMatrices[1] = Matrix4x4.identity; |
|
|
|
m_LocalLightShadowMatrices[2] = Matrix4x4.identity; |
|
|
|
m_LocalLightShadowMatrices[3] = Matrix4x4.identity; |
|
|
|
for (int i = 0; i < kMaxLocalPixelLightPerPass; ++i) |
|
|
|
m_LocalLightShadowMatrices[i] = m_LocalLightShadowSlices[i].shadowTransform; |
|
|
|
float invShadowResolution = 1.0f / m_LocalLightShadowResolution; |
|
|
|
float invShadowResolution = 1.0f / m_LocalLightShadowAtlasResolution; |
|
|
|
cmd.SetGlobalVector(LocalShadowConstantBuffer._LocalShadowData, new Vector4(shadowLight.light.shadowStrength, 0.0f, 0.0f, 0.0f)); |
|
|
|
cmd.SetGlobalVector(LocalShadowConstantBuffer._LocalShadowData, new Vector4(m_LocalShadowStrength[0], m_LocalShadowStrength[1], m_LocalShadowStrength[2], m_LocalShadowStrength[3])); |
|
|
|
cmd.SetGlobalVector(LocalShadowConstantBuffer._LocalShadowmapSize, new Vector4(invShadowResolution, invShadowResolution, m_LocalLightShadowResolution, m_LocalLightShadowResolution)); |
|
|
|
cmd.SetGlobalVector(LocalShadowConstantBuffer._LocalShadowmapSize, new Vector4(invShadowResolution, invShadowResolution, m_LocalLightShadowAtlasResolution, m_LocalLightShadowAtlasResolution)); |
|
|
|
context.ExecuteCommandBuffer(cmd); |
|
|
|
cmd.Clear(); |
|
|
|
} |
|
|
|
|
|
|
CoreUtils.SetKeyword(cmd, "SOFTPARTICLES_ON", m_RequireDepthTexture && m_Asset.RequireSoftParticles); |
|
|
|
} |
|
|
|
|
|
|
|
private void SetShadowCollectPassKeywords(CommandBuffer cmd, VisibleLight shadowLight, ref LightData lightData) |
|
|
|
private void SetShadowCollectPassKeywords(CommandBuffer cmd) |
|
|
|
{ |
|
|
|
CoreUtils.SetKeyword(cmd, "_SHADOWS_SOFT", m_ShadowSampling == LightShadows.Soft); |
|
|
|
CoreUtils.SetKeyword(cmd, "_SHADOWS_CASCADE", m_Asset.CascadeCount > 1); |
|
|
|
|
|
|
return success; |
|
|
|
} |
|
|
|
|
|
|
|
private bool RenderAdditionalShadowmapAtlas(List<VisibleLight> visibleLights, ref ScriptableRenderContext context) |
|
|
|
private void RenderLocalShadowmapAtlas(List<VisibleLight> visibleLights, ref ScriptableRenderContext context) |
|
|
|
int shadowResolution = m_LocalLightShadowResolution; |
|
|
|
|
|
|
|
// TODO: Add support to point light shadows. We make a simplification here that only works
|
|
|
|
// for spot lights and with max spot shadows per pass.
|
|
|
|
int sliceResolution = GetMaxTileResolutionInAtlas(m_LocalLightShadowAtlasResolution, m_LocalLightShadowAtlasResolution, kMaxLocalPixelLightPerPass); |
|
|
|
RenderTextureDescriptor shadowmapDescriptor = new RenderTextureDescriptor(shadowResolution, shadowResolution, m_ShadowSettings.shadowmapTextureFormat, kShadowBufferBits); |
|
|
|
RenderTextureDescriptor shadowmapDescriptor = new RenderTextureDescriptor(m_LocalLightShadowAtlasResolution, m_LocalLightShadowAtlasResolution, m_ShadowSettings.shadowmapTextureFormat, kShadowBufferBits); |
|
|
|
shadowmapDescriptor.shadowSamplingMode = ShadowSamplingMode.CompareDepths; |
|
|
|
m_AdditionalShadowmapRT = RenderTexture.GetTemporary(shadowmapDescriptor); |
|
|
|
m_AdditionalShadowmapRT.filterMode = FilterMode.Bilinear; |
|
|
|
|
|
|
CoreUtils.SetRenderTarget(cmd, m_AdditionalShadowmapRT, ClearFlag.Depth, CoreUtils.ConvertSRGBToActiveColorSpace(m_CurrCamera.backgroundColor)); |
|
|
|
|
|
|
|
int shadowSliceIndex = 0; |
|
|
|
Light light = shadowLight.light; |
|
|
|
if (shadowLight.lightType != LightType.Spot) |
|
|
|
if (m_LocalShadowLightIndices.Count >= kMaxLocalPixelLightPerPass) |
|
|
|
break; |
|
|
|
|
|
|
|
if (shadowLight.lightType != LightType.Spot || light.shadows == LightShadows.None) |
|
|
|
continue; |
|
|
|
|
|
|
|
if (!m_CullResults.GetShadowCasterBounds(i, out bounds)) |
|
|
|
|
|
|
success = m_CullResults.ComputeSpotShadowMatricesAndCullingPrimitives(i, out view, out proj, out settings.splitData); |
|
|
|
if (success) |
|
|
|
{ |
|
|
|
Rect shadowSliceRect = new Rect(0.0f, 0.0f, shadowResolution, shadowResolution); |
|
|
|
SetupShadowCasterConstants(cmd, ref shadowLight, proj, shadowResolution); |
|
|
|
SetupShadowSliceTransform(ref shadowSliceRect, shadowResolution, proj, view, out m_AddtionalShadowSlices[0]); |
|
|
|
RenderShadowSlice(cmd, ref context, ref m_AddtionalShadowSlices[0], proj, view, settings); |
|
|
|
m_LocalLightShadowIndex = i; |
|
|
|
shadowSampling = Math.Max(shadowSampling, (int)shadowLight.light.shadows); |
|
|
|
break; |
|
|
|
// This way of computing the shadow slice only work for spots and with most 4 shadow casting lights per pass
|
|
|
|
// Change this when point lights are supported.
|
|
|
|
Debug.Assert(kMaxLocalPixelLightPerPass == 4 && shadowLight.lightType == LightType.Spot); |
|
|
|
int atlasX = (shadowSliceIndex % 2) * sliceResolution; |
|
|
|
int atlasY = (shadowSliceIndex / 2) * sliceResolution; |
|
|
|
float atlasWidth = (float)m_LocalLightShadowAtlasResolution; |
|
|
|
float atlasHeight = (float)m_LocalLightShadowAtlasResolution; |
|
|
|
|
|
|
|
Rect shadowSliceRect = new Rect(atlasX, atlasY, atlasWidth, atlasHeight); |
|
|
|
SetupShadowCasterConstants(cmd, ref shadowLight, proj, sliceResolution); |
|
|
|
SetupShadowSliceTransform(ref shadowSliceRect, sliceResolution, proj, view, out m_LocalLightShadowSlices[shadowSliceIndex]); |
|
|
|
RenderShadowSlice(cmd, ref context, ref m_LocalLightShadowSlices[shadowSliceIndex], proj, view, settings); |
|
|
|
m_LocalShadowStrength[shadowSliceIndex] = light.shadowStrength; |
|
|
|
m_LocalShadowLightIndices.Add(i); |
|
|
|
shadowSampling = Math.Max(shadowSampling, (int)light.shadows); |
|
|
|
shadowSliceIndex++; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
m_LocalLightShadowSampling = (LightShadows)Math.Min(shadowSampling, (int)m_Asset.ShadowSetting); |
|
|
|
context.ExecuteCommandBuffer(cmd); |
|
|
|
cmd.Clear(); |
|
|
|
return success; |
|
|
|
} |
|
|
|
|
|
|
|
private void SetupShadowSliceTransform(ref Rect shadowSliceRect, int shadowResolution, Matrix4x4 proj, Matrix4x4 view, out ShadowSliceData shadowSliceData) |
|
|
|