using System; using Unity.Collections; using Unity.Scripting.LifecycleManagement; using UnityEngine.Rendering.RenderGraphModule; namespace UnityEngine.Rendering.Universal.Internal { // Render all tiled-based deferred lights. internal class GBufferPass : ScriptableRenderPass { // Statics private static readonly int s_CameraNormalsTextureID = Shader.PropertyToID("_CameraNormalsTexture"); private static readonly int s_CameraRenderingLayersTextureID = Shader.PropertyToID("_CameraRenderingLayersTexture"); private static readonly ShaderTagId s_ShaderTagLit = new ShaderTagId("Lit"); private static readonly ShaderTagId s_ShaderTagSimpleLit = new ShaderTagId("SimpleLit"); private static readonly ShaderTagId s_ShaderTagUnlit = new ShaderTagId("Unlit"); private static readonly ShaderTagId s_ShaderTagComplexLit = new ShaderTagId("ComplexLit"); private static readonly ShaderTagId s_ShaderTagBakedLit = new ShaderTagId("BakedLit"); private static readonly ShaderTagId s_ShaderTagUniversalGBuffer = new ShaderTagId("UniversalGBuffer"); private static readonly ShaderTagId s_ShaderTagUniversalMaterialType = new ShaderTagId("UniversalMaterialType"); DeferredLights m_DeferredLights; static readonly ShaderTagId[] s_ShaderTagValues = { s_ShaderTagLit, s_ShaderTagSimpleLit, s_ShaderTagUnlit, s_ShaderTagComplexLit, s_ShaderTagBakedLit, new ShaderTagId() // Special catch all case for materials where UniversalMaterialType is not defined or the tag value doesn't match anything we know. }; RenderStateBlock[] m_RenderStateBlocks; FilteringSettings m_FilteringSettings; RenderStateBlock m_RenderStateBlock; public GBufferPass(RenderPassEvent evt, RenderQueueRange renderQueueRange, LayerMask layerMask, StencilState stencilState, int stencilReference, DeferredLights deferredLights) { base.profilingSampler = new ProfilingSampler("Draw GBuffer"); base.renderPassEvent = evt; m_DeferredLights = deferredLights; m_FilteringSettings = new FilteringSettings(renderQueueRange, layerMask); m_RenderStateBlock = new RenderStateBlock(RenderStateMask.Nothing); m_RenderStateBlock.stencilState = stencilState; m_RenderStateBlock.stencilReference = stencilReference; m_RenderStateBlock.mask = RenderStateMask.Stencil; m_RenderStateBlocks = new RenderStateBlock[] { DeferredLights.OverwriteStencil(m_RenderStateBlock, (int)StencilUsage.MaterialMask, (int)StencilUsage.MaterialLit), DeferredLights.OverwriteStencil(m_RenderStateBlock, (int)StencilUsage.MaterialMask, (int)StencilUsage.MaterialSimpleLit), DeferredLights.OverwriteStencil(m_RenderStateBlock, (int)StencilUsage.MaterialMask, (int)StencilUsage.MaterialUnlit), DeferredLights.OverwriteStencil(m_RenderStateBlock, (int)StencilUsage.MaterialMask, (int)StencilUsage.MaterialUnlit), // Fill GBuffer, but skip lighting pass for ComplexLit DeferredLights.OverwriteStencil(m_RenderStateBlock, (int)StencilUsage.MaterialMask, (int)StencilUsage.MaterialUnlit), // Fill GBuffer, but skip lighting pass for BakedLit DeferredLights.OverwriteStencil(m_RenderStateBlock, (int)StencilUsage.MaterialMask, (int)StencilUsage.MaterialLit) }; } static void ExecutePass(RasterCommandBuffer cmd, PassData data, RendererList rendererList, RendererList errorRendererList) { bool usesRenderingLayers = data.deferredLights.UseRenderingLayers && !data.deferredLights.HasRenderingLayerPrepass; if (usesRenderingLayers) cmd.SetKeyword(ShaderGlobalKeywords.WriteRenderingLayers, true); bool useScreenSpaceIrradiance = data.screenSpaceIrradianceHdl.IsValid(); cmd.SetKeyword(ShaderGlobalKeywords.ScreenSpaceIrradiance, useScreenSpaceIrradiance); if (useScreenSpaceIrradiance) { cmd.SetGlobalTexture(ShaderPropertyId.screenSpaceIrradiance, data.screenSpaceIrradianceHdl); } #if URP_SCREEN_SPACE_REFLECTION bool useSSR = data.screenSpaceReflectionHdl.IsValid(); cmd.SetKeyword(ShaderGlobalKeywords.ScreenSpaceReflection, useSSR); if (useSSR) { cmd.SetGlobalTexture(ShaderPropertyId.screenSpaceReflection, data.screenSpaceReflectionHdl); } #endif cmd.DrawRendererList(rendererList); // Render objects that did not match any shader pass with error shader RenderingUtils.DrawRendererListObjectsWithError(cmd, ref errorRendererList); // Clean up if (usesRenderingLayers) cmd.SetKeyword(ShaderGlobalKeywords.WriteRenderingLayers, false); } /// /// Shared pass data /// private class PassData { internal DeferredLights deferredLights; internal RendererListHandle rendererListHdl; internal RendererListHandle objectsWithErrorRendererListHdl; internal TextureHandle screenSpaceIrradianceHdl; #if URP_SCREEN_SPACE_REFLECTION internal TextureHandle screenSpaceReflectionHdl; #endif } private void InitRendererLists( ref PassData passData, ScriptableRenderContext context, RenderGraph renderGraph, UniversalRenderingData renderingData, UniversalCameraData cameraData, UniversalLightData lightData, uint batchLayerMask = uint.MaxValue) { // User can stack several scriptable renderers during rendering but deferred renderer should only lit pixels added by this gbuffer pass. // If we detect we are in such case (camera is in overlay mode), we clear the highest bits of stencil we have control of and use them to // mark what pixel to shade during deferred pass. Gbuffer will always mark pixels using their material types. ShaderTagId lightModeTag = s_ShaderTagUniversalGBuffer; var drawingSettings = CreateDrawingSettings(lightModeTag, renderingData, cameraData, lightData, cameraData.defaultOpaqueSortFlags); var filterSettings = m_FilteringSettings; filterSettings.batchLayerMask = batchLayerMask; #if UNITY_EDITOR // When rendering the preview camera, we want the layer mask to be forced to Everything if (cameraData.isPreviewCamera) filterSettings.layerMask = -1; #endif NativeArray tagValues = new NativeArray(s_ShaderTagValues, Allocator.Temp); NativeArray stateBlocks = new NativeArray(m_RenderStateBlocks, Allocator.Temp); var param = new RendererListParams(renderingData.cullResults, drawingSettings, filterSettings) { tagValues = tagValues, stateBlocks = stateBlocks, tagName = s_ShaderTagUniversalMaterialType, isPassTagName = false }; passData.rendererListHdl = renderGraph.CreateRendererList(param); RenderingUtils.CreateRendererListObjectsWithError(renderGraph, ref renderingData.cullResults, cameraData.camera, filterSettings, SortingCriteria.None, ref passData.objectsWithErrorRendererListHdl); tagValues.Dispose(); stateBlocks.Dispose(); } internal void Render(RenderGraph renderGraph, ContextContainer frameData, bool setGlobalTextures, uint batchLayerMask = uint.MaxValue) { UniversalResourceData resourceData = frameData.Get(); UniversalRenderingData renderingData = frameData.Get(); UniversalCameraData cameraData = frameData.Get(); UniversalLightData lightData = frameData.Get(); using var builder = renderGraph.AddRasterRenderPass(passName, out var passData, profilingSampler); bool useCameraRenderingLayersTexture = m_DeferredLights.UseRenderingLayers && !m_DeferredLights.UseLightLayers; var cameraColor = resourceData.activeColorTexture; var cameraDepth = resourceData.activeDepthTexture; var gbuffer = resourceData.gBuffer; for (int i = 0; i < gbuffer.Length; i++) { Debug.Assert(gbuffer[i].IsValid()); builder.SetRenderAttachment(gbuffer[i], i, AccessFlags.Write); } TextureHandle irradianceTexture = resourceData.irradianceTexture; if (irradianceTexture.IsValid()) { passData.screenSpaceIrradianceHdl = irradianceTexture; builder.UseTexture(irradianceTexture, AccessFlags.Read); } #if URP_SCREEN_SPACE_REFLECTION TextureHandle ssrTexture = resourceData.ssrTexture; if (ssrTexture.IsValid()) { passData.screenSpaceReflectionHdl = ssrTexture; builder.UseTexture(ssrTexture, AccessFlags.Read); } else { passData.screenSpaceReflectionHdl = TextureHandle.nullHandle; } #endif RenderGraphUtils.UseDBufferIfValid(builder, resourceData); builder.SetRenderAttachmentDepth(cameraDepth, AccessFlags.ReadWrite); passData.deferredLights = m_DeferredLights; InitRendererLists(ref passData, default, renderGraph, renderingData, cameraData, lightData); builder.UseRendererList(passData.rendererListHdl); builder.UseRendererList(passData.objectsWithErrorRendererListHdl); if (setGlobalTextures) { builder.SetGlobalTextureAfterPass(resourceData.cameraNormalsTexture, s_CameraNormalsTextureID); if (useCameraRenderingLayersTexture) builder.SetGlobalTextureAfterPass(resourceData.renderingLayersTexture, s_CameraRenderingLayersTextureID); } builder.AllowGlobalStateModification(true); builder.SetRenderFunc(static (PassData data, RasterGraphContext context) => { ExecutePass(context.cmd, data, data.rendererListHdl, data.objectsWithErrorRendererListHdl); }); } } }