|
|
|
|
|
|
|
|
|
|
private static readonly int kMaxVertexLights = 4; |
|
|
|
|
|
|
|
// We have no good approach exposed to skip shader variants, e.g, ideally we would like to skip _CASCADE for all punctual lights
|
|
|
|
// We combine light and shadow classification keywords to reduce the amount of shader variants.
|
|
|
|
// Lightweight shader library declares defines based on these keywords to avoid having to check them in the shaders
|
|
|
|
// Core.hlsl defines _MAIN_LIGHT_DIRECTIONAL and _MAIN_LIGHT_SPOT (point lights can't be main light)
|
|
|
|
// Shadow.hlsl defines _SHADOWS_ENABLED, _SHADOWS_SOFT, _SHADOWS_CASCADE, _SHADOWS_PERSPECTIVE
|
|
|
|
private static readonly string[] kMainLightKeywords = |
|
|
|
{ |
|
|
|
"_MAIN_LIGHT_DIRECTIONAL_SHADOW", |
|
|
|
"_MAIN_LIGHT_DIRECTIONAL_SHADOW_CASCADE", |
|
|
|
"_MAIN_LIGHT_DIRECTIONAL_SHADOW_SOFT", |
|
|
|
"_MAIN_LIGHT_DIRECTIONAL_SHADOW_CASCADE_SOFT", |
|
|
|
|
|
|
|
"_MAIN_LIGHT_SPOT_SHADOW", |
|
|
|
"_MAIN_LIGHT_SPOT_SHADOW_SOFT" |
|
|
|
}; |
|
|
|
|
|
|
|
private StringBuilder m_MainLightKeywordString = new StringBuilder(43); |
|
|
|
|
|
|
|
private bool m_IsOffscreenCamera; |
|
|
|
|
|
|
|
private Vector4[] m_LightPositions = new Vector4[kMaxVisibleLights]; |
|
|
|
|
|
|
private const int kMaxCascades = 4; |
|
|
|
private int m_ShadowCasterCascadesCount; |
|
|
|
private int m_ShadowMapRTID; |
|
|
|
private Matrix4x4[] m_ShadowMatrices = new Matrix4x4[kMaxCascades + 1]; |
|
|
|
private RenderTargetIdentifier m_CurrCameraColorRT; |
|
|
|
private RenderTargetIdentifier m_ShadowMapRT; |
|
|
|
private RenderTargetIdentifier m_ColorRT; |
|
|
|
|
|
|
private PostProcessLayer m_CameraPostProcessLayer; |
|
|
|
|
|
|
|
private CameraComparer m_CameraComparer = new CameraComparer(); |
|
|
|
private LightComparer m_LightCompararer = new LightComparer(); |
|
|
|
private LightComparer m_LightComparer = new LightComparer(); |
|
|
|
private Dictionary<VisibleLight, int> m_VisibleLightsIDMap = new Dictionary<VisibleLight, int>(new LightEqualityComparer()); |
|
|
|
|
|
|
|
private Mesh m_BlitQuad; |
|
|
|
private Material m_BlitMaterial; |
|
|
|
private Material m_CopyDepthMaterial; |
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
CullResults.Cull(ref cullingParameters, context, ref m_CullResults); |
|
|
|
VisibleLight[] visibleLights = m_CullResults.visibleLights.ToArray(); |
|
|
|
List<VisibleLight> visibleLights = m_CullResults.visibleLights; |
|
|
|
|
|
|
|
LightData lightData; |
|
|
|
InitializeLightData(visibleLights, out lightData); |
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private void ShadowPass(VisibleLight[] visibleLights, ref ScriptableRenderContext context, ref LightData lightData) |
|
|
|
private void ShadowPass(List<VisibleLight> visibleLights, ref ScriptableRenderContext context, ref LightData lightData) |
|
|
|
{ |
|
|
|
if (m_Asset.AreShadowsEnabled() && lightData.mainLightIndex != -1) |
|
|
|
{ |
|
|
|
|
|
|
context.DrawRenderers(m_CullResults.visibleRenderers, ref opaqueDrawSettings, opaqueFilterSettings); |
|
|
|
} |
|
|
|
|
|
|
|
private void ForwardPass(VisibleLight[] visibleLights, FrameRenderingConfiguration frameRenderingConfiguration, ref ScriptableRenderContext context, ref LightData lightData, bool stereoEnabled) |
|
|
|
private void ForwardPass(List<VisibleLight> visibleLights, FrameRenderingConfiguration frameRenderingConfiguration, ref ScriptableRenderContext context, ref LightData lightData, bool stereoEnabled) |
|
|
|
{ |
|
|
|
SetupShaderConstants(visibleLights, ref context, ref lightData); |
|
|
|
|
|
|
|
|
|
|
cmd.GetTemporaryRT(CameraRenderTargetID.color, rtDesc, FilterMode.Bilinear); |
|
|
|
} |
|
|
|
|
|
|
|
private void SetupShaderConstants(VisibleLight[] visibleLights, ref ScriptableRenderContext context, ref LightData lightData) |
|
|
|
private void SetupShaderConstants(List<VisibleLight> visibleLights, ref ScriptableRenderContext context, ref LightData lightData) |
|
|
|
{ |
|
|
|
CommandBuffer cmd = CommandBufferPool.Get("SetupShaderConstants"); |
|
|
|
SetupShaderLightConstants(cmd, visibleLights, ref lightData); |
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
private void InitializeLightData(VisibleLight[] visibleLights, out LightData lightData) |
|
|
|
private void InitializeLightData(List<VisibleLight> visibleLights, out LightData lightData) |
|
|
|
int visibleLightsCount = Math.Min(visibleLights.Length, m_Asset.MaxPixelLights); |
|
|
|
int visibleLightsCount = Math.Min(visibleLights.Count, m_Asset.MaxPixelLights); |
|
|
|
m_SortedLightIndexMap.Clear(); |
|
|
|
|
|
|
|
lightData.shadowMapSampleType = LightShadows.None; |
|
|
|
|
|
|
// If we have a main light we don't shade it in the per-object light loop. We also remove it from the per-object cull list
|
|
|
|
int mainLightPresent = (lightData.mainLightIndex >= 0) ? 1 : 0; |
|
|
|
int additionalPixelLightsCount = visibleLightsCount - mainLightPresent; |
|
|
|
int vertexLightCount = (m_Asset.SupportsVertexLight) ? Math.Min(visibleLights.Length, kMaxPerObjectLights) - additionalPixelLightsCount : 0; |
|
|
|
int vertexLightCount = (m_Asset.SupportsVertexLight) ? Math.Min(visibleLights.Count, kMaxPerObjectLights) - additionalPixelLightsCount : 0; |
|
|
|
vertexLightCount = Math.Min(vertexLightCount, kMaxVertexLights); |
|
|
|
|
|
|
|
lightData.pixelAdditionalLightsCount = additionalPixelLightsCount; |
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
private int SortLights(VisibleLight[] visibleLights) |
|
|
|
private int SortLights(List<VisibleLight> visibleLights) |
|
|
|
int totalVisibleLights = visibleLights.Length; |
|
|
|
int totalVisibleLights = visibleLights.Count; |
|
|
|
Dictionary<int, int> visibleLightsIDMap = new Dictionary<int, int>(); |
|
|
|
m_VisibleLightsIDMap.Clear(); |
|
|
|
visibleLightsIDMap.Add(visibleLights[i].GetHashCode(), i); |
|
|
|
m_VisibleLightsIDMap.Add(visibleLights[i], i); |
|
|
|
m_LightCompararer.CurrCamera = m_CurrCamera; |
|
|
|
Array.Sort(visibleLights, m_LightCompararer); |
|
|
|
m_LightComparer.CurrCamera = m_CurrCamera; |
|
|
|
visibleLights.Sort(m_LightComparer); |
|
|
|
m_SortedLightIndexMap.Add(visibleLightsIDMap[visibleLights[i].GetHashCode()]); |
|
|
|
m_SortedLightIndexMap.Add(m_VisibleLightsIDMap[visibleLights[i]]); |
|
|
|
|
|
|
|
return GetMainLight(visibleLights); |
|
|
|
} |
|
|
|
|
|
|
// Otherwise directional lights have priority based on cookie support and intensity
|
|
|
|
private int GetMainLight(VisibleLight[] visibleLights) |
|
|
|
private int GetMainLight(List<VisibleLight> visibleLights) |
|
|
|
int totalVisibleLights = visibleLights.Length; |
|
|
|
int totalVisibleLights = visibleLights.Count; |
|
|
|
bool shadowsEnabled = m_Asset.AreShadowsEnabled(); |
|
|
|
|
|
|
|
if (totalVisibleLights == 0 || m_Asset.MaxPixelLights == 0) |
|
|
|
|
|
|
return brighestDirectionalIndex; |
|
|
|
} |
|
|
|
|
|
|
|
private void InitializeLightConstants(VisibleLight[] lights, int lightIndex, out Vector4 lightPos, out Vector4 lightColor, out Vector4 lightDistanceAttenuation, out Vector4 lightSpotDir, |
|
|
|
private void InitializeLightConstants(List<VisibleLight> lights, int lightIndex, out Vector4 lightPos, out Vector4 lightColor, out Vector4 lightDistanceAttenuation, out Vector4 lightSpotDir, |
|
|
|
out Vector4 lightSpotAttenuation) |
|
|
|
{ |
|
|
|
float directContributionNotBaked = 1.0f; |
|
|
|
|
|
|
Shader.SetGlobalVector(PerFrameBuffer._SubtractiveShadowColor, CoreUtils.ConvertSRGBToActiveColorSpace(RenderSettings.subtractiveShadowColor)); |
|
|
|
} |
|
|
|
|
|
|
|
private void SetupShaderLightConstants(CommandBuffer cmd, VisibleLight[] lights, ref LightData lightData) |
|
|
|
private void SetupShaderLightConstants(CommandBuffer cmd, List<VisibleLight> lights, ref LightData lightData) |
|
|
|
SetupShadowReceiverConstants(cmd, ref lights[lightData.mainLightIndex]); |
|
|
|
SetupShadowReceiverConstants(cmd, lights[lightData.mainLightIndex]); |
|
|
|
private void SetupMainLightConstants(CommandBuffer cmd, VisibleLight[] lights, int lightIndex) |
|
|
|
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); |
|
|
|
|
|
|
cmd.SetGlobalVector(PerCameraBuffer._MainLightSpotAttenuation, lightSpotAttenuation); |
|
|
|
} |
|
|
|
|
|
|
|
private void SetupAdditionalListConstants(CommandBuffer cmd, VisibleLight[] lights, ref LightData lightData) |
|
|
|
private void SetupAdditionalListConstants(CommandBuffer cmd, List<VisibleLight> lights, ref LightData lightData) |
|
|
|
{ |
|
|
|
int additionalLightIndex = 0; |
|
|
|
|
|
|
|
|
|
|
int[] perObjectLightIndexMap = m_CullResults.GetLightIndexMap(); |
|
|
|
for (int i = 0; i < lights.Length; ++i) |
|
|
|
for (int i = 0; i < lights.Count; ++i) |
|
|
|
for (int i = 0; i < lights.Length && additionalLightIndex < kMaxVisibleLights; ++i) |
|
|
|
for (int i = 0; i < lights.Count && additionalLightIndex < kMaxVisibleLights; ++i) |
|
|
|
{ |
|
|
|
if (i != lightData.mainLightIndex) |
|
|
|
{ |
|
|
|
|
|
|
cmd.SetGlobalVector("_LightDirection", new Vector4(lightDirection.x, lightDirection.y, lightDirection.z, 0.0f)); |
|
|
|
} |
|
|
|
|
|
|
|
private void SetupShadowReceiverConstants(CommandBuffer cmd, ref VisibleLight shadowLight) |
|
|
|
private void SetupShadowReceiverConstants(CommandBuffer cmd, VisibleLight shadowLight) |
|
|
|
Matrix4x4[] shadowMatrices = new Matrix4x4[kMaxCascades + 1]; |
|
|
|
shadowMatrices[i] = (cascadeCount >= i) ? m_ShadowSlices[i].shadowTransform : Matrix4x4.identity; |
|
|
|
m_ShadowMatrices[i] = (cascadeCount >= i) ? m_ShadowSlices[i].shadowTransform : Matrix4x4.identity; |
|
|
|
|
|
|
|
// We setup and additional a no-op WorldToShadow matrix in the last index
|
|
|
|
// because the ComputeCascadeIndex function in Shadows.hlsl can return an index
|
|
|
|
|
|
|
shadowMatrices[kMaxCascades] = noOpShadowMatrix; |
|
|
|
m_ShadowMatrices[kMaxCascades] = noOpShadowMatrix; |
|
|
|
cmd.SetGlobalMatrixArray("_WorldToShadow", shadowMatrices); |
|
|
|
cmd.SetGlobalMatrixArray("_WorldToShadow", m_ShadowMatrices); |
|
|
|
cmd.SetGlobalVector("_ShadowData", new Vector4(light.shadowStrength, 0.0f, 0.0f, 0.0f)); |
|
|
|
cmd.SetGlobalVectorArray("_DirShadowSplitSpheres", m_DirectionalShadowSplitDistances); |
|
|
|
cmd.SetGlobalVector("_DirShadowSplitSphereRadii", m_DirectionalShadowSplitRadii); |
|
|
|
|
|
|
cmd.SetGlobalVector("_ShadowOffset3", new Vector4(invShadowResolution, invShadowResolution, 0.0f, 0.0f)); |
|
|
|
} |
|
|
|
|
|
|
|
private void SetShaderKeywords(CommandBuffer cmd, ref LightData lightData, VisibleLight[] visibleLights) |
|
|
|
private void SetShaderKeywords(CommandBuffer cmd, ref LightData lightData, List<VisibleLight> visibleLights) |
|
|
|
// We have no good approach exposed to skip shader variants, e.g, ideally we would like to skip _CASCADE for all punctual lights
|
|
|
|
// We combine light and shadow classification keywords to reduce the amount of shader variants.
|
|
|
|
// Lightweight shader library declares defines based on these keywords to avoid having to check them in the shaders
|
|
|
|
// Core.hlsl defines _MAIN_LIGHT_DIRECTIONAL and _MAIN_LIGHT_SPOT (point lights can't be main light)
|
|
|
|
// Shadow.hlsl defines _SHADOWS_ENABLED, _SHADOWS_SOFT, _SHADOWS_CASCADE, _SHADOWS_PERSPECTIVE
|
|
|
|
string[] mainLightKeywords = |
|
|
|
{ |
|
|
|
"_MAIN_LIGHT_DIRECTIONAL_SHADOW", |
|
|
|
"_MAIN_LIGHT_DIRECTIONAL_SHADOW_CASCADE", |
|
|
|
"_MAIN_LIGHT_DIRECTIONAL_SHADOW_SOFT", |
|
|
|
"_MAIN_LIGHT_DIRECTIONAL_SHADOW_CASCADE_SOFT", |
|
|
|
|
|
|
|
"_MAIN_LIGHT_SPOT_SHADOW", |
|
|
|
"_MAIN_LIGHT_SPOT_SHADOW_SOFT" |
|
|
|
}; |
|
|
|
|
|
|
|
for (int i = 0; i < mainLightKeywords.Length; ++i) |
|
|
|
cmd.DisableShaderKeyword(mainLightKeywords[i]); |
|
|
|
for (int i = 0; i < kMainLightKeywords.Length; ++i) |
|
|
|
cmd.DisableShaderKeyword(kMainLightKeywords[i]); |
|
|
|
StringBuilder keywordString = new StringBuilder("_MAIN_LIGHT"); |
|
|
|
m_MainLightKeywordString.Length = 0; |
|
|
|
m_MainLightKeywordString.Append("_MAIN_LIGHT"); |
|
|
|
keywordString.Append("_DIRECTIONAL_SHADOW"); |
|
|
|
m_MainLightKeywordString.Append("_DIRECTIONAL_SHADOW"); |
|
|
|
keywordString.Append("_CASCADE"); |
|
|
|
m_MainLightKeywordString.Append("_CASCADE"); |
|
|
|
keywordString.Append("_SPOT_SHADOW"); |
|
|
|
m_MainLightKeywordString.Append("_SPOT_SHADOW"); |
|
|
|
keywordString.Append("_SOFT"); |
|
|
|
string keyword = keywordString.ToString(); |
|
|
|
m_MainLightKeywordString.Append("_SOFT"); |
|
|
|
string keyword = m_MainLightKeywordString.ToString(); |
|
|
|
cmd.EnableShaderKeyword(keyword); |
|
|
|
} |
|
|
|
|
|
|
|