void RenderDirectionalCascadeShadowmap(ref ScriptableRenderContext context, ref CullResults cullResults, ref LightData lightData, ref ShadowData shadowData) { int shadowLightIndex = lightData.mainLightIndex; if (shadowLightIndex == -1) { return; } VisibleLight shadowLight = lightData.visibleLights[shadowLightIndex]; Light light = shadowLight.light; Debug.Assert(shadowLight.lightType == LightType.Directional); if (light.shadows == LightShadows.None) { return; } Bounds bounds; if (!cullResults.GetShadowCasterBounds(shadowLightIndex, out bounds)) { return; } CommandBuffer cmd = CommandBufferPool.Get(k_RenderDirectionalShadowmapTag); using (new ProfilingSample(cmd, k_RenderDirectionalShadowmapTag)) { m_ShadowCasterCascadesCount = shadowData.directionalLightCascadeCount; int shadowResolution = LightweightShadowUtils.GetMaxTileResolutionInAtlas(shadowData.directionalShadowAtlasWidth, shadowData.directionalShadowAtlasHeight, m_ShadowCasterCascadesCount); float shadowNearPlane = light.shadowNearPlane; Matrix4x4 view, proj; var settings = new DrawShadowsSettings(cullResults, shadowLightIndex); m_DirectionalShadowmapTexture = RenderTexture.GetTemporary(shadowData.directionalShadowAtlasWidth, shadowData.directionalShadowAtlasHeight, k_ShadowmapBufferBits, m_ShadowmapFormat); m_DirectionalShadowmapTexture.filterMode = FilterMode.Bilinear; m_DirectionalShadowmapTexture.wrapMode = TextureWrapMode.Clamp; SetRenderTarget(cmd, m_DirectionalShadowmapTexture, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, ClearFlag.Depth, Color.black, TextureDimension.Tex2D); bool success = false; for (int cascadeIndex = 0; cascadeIndex < m_ShadowCasterCascadesCount; ++cascadeIndex) { success = LightweightShadowUtils.ExtractDirectionalLightMatrix(ref cullResults, ref shadowData, shadowLightIndex, cascadeIndex, shadowResolution, shadowNearPlane, out m_CascadeSplitDistances[cascadeIndex], out m_CascadeSlices[cascadeIndex], out view, out proj); if (success) { settings.splitData.cullingSphere = m_CascadeSplitDistances[cascadeIndex]; LightweightShadowUtils.SetupShadowCasterConstants(cmd, ref shadowLight, proj, shadowResolution); LightweightShadowUtils.RenderShadowSlice(cmd, ref context, ref m_CascadeSlices[cascadeIndex], ref settings, proj, view); } } if (success) { SetupDirectionalShadowReceiverConstants(cmd, ref shadowData, shadowLight); } } context.ExecuteCommandBuffer(cmd); CommandBufferPool.Release(cmd); }
void RenderLocalShadowmapAtlas(ref ScriptableRenderContext context, ref CullResults cullResults, ref LightData lightData, ref ShadowData shadowData) { List <int> localLightIndices = lightData.visibleLocalLightIndices; List <VisibleLight> visibleLights = lightData.visibleLights; int shadowCastingLightsCount = 0; int localLightsCount = localLightIndices.Count; for (int i = 0; i < localLightsCount; ++i) { VisibleLight shadowLight = visibleLights[localLightIndices[i]]; if (shadowLight.lightType == LightType.Spot && shadowLight.light.shadows != LightShadows.None) { shadowCastingLightsCount++; } } if (shadowCastingLightsCount == 0) { return; } Matrix4x4 view, proj; Bounds bounds; CommandBuffer cmd = CommandBufferPool.Get(k_RenderLocalShadows); using (new ProfilingSample(cmd, k_RenderLocalShadows)) { // 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 atlasWidth = shadowData.localShadowAtlasWidth; int atlasHeight = shadowData.localShadowAtlasHeight; int sliceResolution = LightweightShadowUtils.GetMaxTileResolutionInAtlas(atlasWidth, atlasHeight, shadowCastingLightsCount); m_LocalShadowmapTexture = RenderTexture.GetTemporary(shadowData.localShadowAtlasWidth, shadowData.localShadowAtlasHeight, k_ShadowmapBufferBits, m_LocalShadowmapFormat); m_LocalShadowmapTexture.filterMode = FilterMode.Bilinear; m_LocalShadowmapTexture.wrapMode = TextureWrapMode.Clamp; SetRenderTarget(cmd, m_LocalShadowmapTexture, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, ClearFlag.Depth, Color.black, TextureDimension.Tex2D); for (int i = 0; i < localLightsCount; ++i) { int shadowLightIndex = localLightIndices[i]; VisibleLight shadowLight = visibleLights[shadowLightIndex]; Light light = shadowLight.light; // TODO: Add support to point light shadows if (shadowLight.lightType != LightType.Spot || shadowLight.light.shadows == LightShadows.None) { continue; } if (!cullResults.GetShadowCasterBounds(shadowLightIndex, out bounds)) { continue; } Matrix4x4 shadowTransform; bool success = LightweightShadowUtils.ExtractSpotLightMatrix(ref cullResults, ref shadowData, shadowLightIndex, out shadowTransform, out view, out proj); if (success) { // 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(shadowCastingLightsCount <= 4 && shadowLight.lightType == LightType.Spot); // TODO: We need to pass bias and scale list to shader to be able to support multiple // shadow casting local lights. m_LocalLightSlices[i].offsetX = (i % 2) * sliceResolution; m_LocalLightSlices[i].offsetY = (i / 2) * sliceResolution; m_LocalLightSlices[i].resolution = sliceResolution; m_LocalLightSlices[i].shadowTransform = shadowTransform; m_LocalShadowStrength[i] = light.shadowStrength; if (shadowCastingLightsCount > 1) { LightweightShadowUtils.ApplySliceTransform(ref m_LocalLightSlices[i], atlasWidth, atlasHeight); } var settings = new DrawShadowsSettings(cullResults, shadowLightIndex); LightweightShadowUtils.SetupShadowCasterConstants(cmd, ref shadowLight, proj, sliceResolution); LightweightShadowUtils.RenderShadowSlice(cmd, ref context, ref m_LocalLightSlices[i], ref settings, proj, view); } } SetupLocalLightsShadowReceiverConstants(cmd, ref shadowData); } context.ExecuteCommandBuffer(cmd); CommandBufferPool.Release(cmd); }
void RenderDirectionalCascadeShadowmap(ref ScriptableRenderContext context, ref CullResults cullResults, ref LightData lightData, ref ShadowData shadowData) { LightShadows shadowQuality = LightShadows.None; int shadowLightIndex = lightData.mainLightIndex; if (shadowLightIndex == -1) { return; } VisibleLight shadowLight = lightData.visibleLights[shadowLightIndex]; Light light = shadowLight.light; Debug.Assert(shadowLight.lightType == LightType.Directional); if (light.shadows == LightShadows.None) { return; } Bounds bounds; if (!cullResults.GetShadowCasterBounds(shadowLightIndex, out bounds)) { return; } CommandBuffer cmd = CommandBufferPool.Get(k_RenderDirectionalShadowmapTag); using (new ProfilingSample(cmd, k_SetupRenderTargetTag)) { m_ShadowCasterCascadesCount = shadowData.directionalLightCascadeCount; int shadowResolution = LightweightShadowUtils.GetMaxTileResolutionInAtlas(shadowData.directionalShadowAtlasWidth, shadowData.directionalShadowAtlasHeight, m_ShadowCasterCascadesCount); float shadowNearPlane = light.shadowNearPlane; Matrix4x4 view, proj; var settings = new DrawShadowsSettings(cullResults, shadowLightIndex); m_DirectionalShadowmapTexture = RenderTexture.GetTemporary(shadowData.directionalShadowAtlasWidth, shadowData.directionalShadowAtlasHeight, k_ShadowmapBufferBits, m_ShadowmapFormat); m_DirectionalShadowmapTexture.filterMode = FilterMode.Bilinear; m_DirectionalShadowmapTexture.wrapMode = TextureWrapMode.Clamp; SetRenderTarget(cmd, m_DirectionalShadowmapTexture, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, ClearFlag.Depth, Color.black); bool success = false; for (int cascadeIndex = 0; cascadeIndex < m_ShadowCasterCascadesCount; ++cascadeIndex) { success = LightweightShadowUtils.ExtractDirectionalLightMatrix(ref cullResults, ref shadowData, shadowLightIndex, cascadeIndex, shadowResolution, shadowNearPlane, out m_CascadeSplitDistances[cascadeIndex], out m_CascadeSlices[cascadeIndex], out view, out proj); if (success) { LightweightShadowUtils.SetupShadowCasterConstants(cmd, ref shadowLight, proj, shadowResolution); LightweightShadowUtils.RenderShadowSlice(cmd, ref context, ref m_CascadeSlices[cascadeIndex], proj, view, settings); } } if (success) { shadowQuality = (shadowData.supportsSoftShadows) ? light.shadows : LightShadows.Hard; // In order to avoid shader variants explosion we only do hard shadows when sampling shadowmap in the lit pass. // GLES2 platform is forced to hard single cascade shadows. if (!shadowData.requiresScreenSpaceShadowResolve) { shadowQuality = LightShadows.Hard; } SetupDirectionalShadowReceiverConstants(ref context, cmd, ref shadowData, shadowLight); } } context.ExecuteCommandBuffer(cmd); CommandBufferPool.Release(cmd); // TODO: We should have RenderingData as a readonly but currently we need this to pass shadow rendering to litpass shadowData.renderedDirectionalShadowQuality = shadowQuality; }