using UnityEngine.Experimental.Rendering.Universal; using UnityEngine.Rendering.Universal.Internal; namespace UnityEngine.Rendering.Universal { internal class Renderer2D : ScriptableRenderer { // Constants #if UNITY_SWITCH internal const int k_DepthBufferBits = 24; #else internal const int k_DepthBufferBits = 32; #endif Render2DLightingPass m_Render2DLightingPass; PixelPerfectBackgroundPass m_PixelPerfectBackgroundPass; FinalBlitPass m_FinalBlitPass; Light2DCullResult m_LightCullResult; private static readonly ProfilingSampler m_ProfilingSampler = new ProfilingSampler("Create Camera Textures"); bool m_UseDepthStencilBuffer = true; bool m_CreateColorTexture; bool m_CreateDepthTexture; readonly RenderTargetHandle k_ColorTextureHandle; readonly RenderTargetHandle k_DepthTextureHandle; Material m_BlitMaterial; Material m_SamplingMaterial; Renderer2DData m_Renderer2DData; internal bool createColorTexture => m_CreateColorTexture; internal bool createDepthTexture => m_CreateDepthTexture; PostProcessPasses m_PostProcessPasses; internal ColorGradingLutPass colorGradingLutPass { get => m_PostProcessPasses.colorGradingLutPass; } internal PostProcessPass postProcessPass { get => m_PostProcessPasses.postProcessPass; } internal PostProcessPass finalPostProcessPass { get => m_PostProcessPasses.finalPostProcessPass; } internal RenderTargetHandle afterPostProcessColorHandle { get => m_PostProcessPasses.afterPostProcessColor; } internal RenderTargetHandle colorGradingLutHandle { get => m_PostProcessPasses.colorGradingLut; } /// public override int SupportedCameraStackingTypes() { return 1 << (int)CameraRenderType.Base | 1 << (int)CameraRenderType.Overlay; } public Renderer2D(Renderer2DData data) : base(data) { m_BlitMaterial = CoreUtils.CreateEngineMaterial(data.blitShader); m_SamplingMaterial = CoreUtils.CreateEngineMaterial(data.samplingShader); m_Render2DLightingPass = new Render2DLightingPass(data, m_BlitMaterial, m_SamplingMaterial); // we should determine why clearing the camera target is set so late in the events... sounds like it could be earlier m_PixelPerfectBackgroundPass = new PixelPerfectBackgroundPass(RenderPassEvent.AfterRenderingTransparents); m_FinalBlitPass = new FinalBlitPass(RenderPassEvent.AfterRendering + 1, m_BlitMaterial); m_PostProcessPasses = new PostProcessPasses(data.postProcessData, m_BlitMaterial); m_UseDepthStencilBuffer = data.useDepthStencilBuffer; // We probably should declare these names in the base class, // as they must be the same across all ScriptableRenderer types for camera stacking to work. k_ColorTextureHandle.Init("_CameraColorTexture"); k_DepthTextureHandle.Init("_CameraDepthAttachment"); m_Renderer2DData = data; supportedRenderingFeatures = new RenderingFeatures(); m_LightCullResult = new Light2DCullResult(); m_Renderer2DData.lightCullResult = m_LightCullResult; } protected override void Dispose(bool disposing) { m_PostProcessPasses.Dispose(); } public Renderer2DData GetRenderer2DData() { return m_Renderer2DData; } void CreateRenderTextures( ref CameraData cameraData, bool forceCreateColorTexture, FilterMode colorTextureFilterMode, CommandBuffer cmd, out RenderTargetHandle colorTargetHandle, out RenderTargetHandle depthTargetHandle) { ref var cameraTargetDescriptor = ref cameraData.cameraTargetDescriptor; if (cameraData.renderType == CameraRenderType.Base) { m_CreateColorTexture = forceCreateColorTexture || cameraData.postProcessEnabled || cameraData.isHdrEnabled || cameraData.isSceneViewCamera || !cameraData.isDefaultViewport || cameraData.requireSrgbConversion || !cameraData.resolveFinalTarget || m_Renderer2DData.useCameraSortingLayerTexture || !Mathf.Approximately(cameraData.renderScale, 1.0f); m_CreateDepthTexture = !cameraData.resolveFinalTarget && m_UseDepthStencilBuffer; colorTargetHandle = m_CreateColorTexture ? k_ColorTextureHandle : RenderTargetHandle.CameraTarget; depthTargetHandle = m_CreateDepthTexture ? k_DepthTextureHandle : colorTargetHandle; if (m_CreateColorTexture) { var colorDescriptor = cameraTargetDescriptor; colorDescriptor.depthBufferBits = m_CreateDepthTexture || !m_UseDepthStencilBuffer ? 0 : k_DepthBufferBits; cmd.GetTemporaryRT(k_ColorTextureHandle.id, colorDescriptor, colorTextureFilterMode); } if (m_CreateDepthTexture) { var depthDescriptor = cameraTargetDescriptor; depthDescriptor.colorFormat = RenderTextureFormat.Depth; depthDescriptor.depthBufferBits = k_DepthBufferBits; depthDescriptor.bindMS = depthDescriptor.msaaSamples > 1 && !SystemInfo.supportsMultisampleAutoResolve && (SystemInfo.supportsMultisampledTextures != 0); cmd.GetTemporaryRT(k_DepthTextureHandle.id, depthDescriptor, FilterMode.Point); } } else // Overlay camera { // These render textures are created by the base camera, but it's the responsibility of the last overlay camera's ScriptableRenderer // to release the textures in its FinishRendering(). m_CreateColorTexture = true; m_CreateDepthTexture = true; colorTargetHandle = k_ColorTextureHandle; depthTargetHandle = k_DepthTextureHandle; } } public override void Setup(ScriptableRenderContext context, ref RenderingData renderingData) { ref CameraData cameraData = ref renderingData.cameraData; ref var cameraTargetDescriptor = ref cameraData.cameraTargetDescriptor; bool stackHasPostProcess = renderingData.postProcessingEnabled; bool lastCameraInStack = cameraData.resolveFinalTarget; var colorTextureFilterMode = FilterMode.Bilinear; PixelPerfectCamera ppc = null; bool ppcUsesOffscreenRT = false; bool ppcUpscaleRT = false; if (DebugHandler != null) { #if UNITY_EDITOR UnityEditorInternal.SpriteMaskUtility.EnableDebugMode(DebugHandler.DebugDisplaySettings.MaterialSettings.DebugMaterialModeData == DebugMaterialMode.SpriteMask); #endif if (DebugHandler.AreAnySettingsActive) { stackHasPostProcess = stackHasPostProcess && DebugHandler.IsPostProcessingAllowed; } DebugHandler.Setup(context, ref cameraData); } #if UNITY_EDITOR // The scene view camera cannot be uninitialized or skybox when using the 2D renderer. if (cameraData.cameraType == CameraType.SceneView) { renderingData.cameraData.camera.clearFlags = CameraClearFlags.SolidColor; } #endif // Pixel Perfect Camera doesn't support camera stacking. if (cameraData.renderType == CameraRenderType.Base && lastCameraInStack) { cameraData.camera.TryGetComponent(out ppc); if (ppc != null && ppc.enabled) { if (ppc.offscreenRTSize != Vector2Int.zero) { ppcUsesOffscreenRT = true; // Pixel Perfect Camera may request a different RT size than camera VP size. // In that case we need to modify cameraTargetDescriptor here so that all the passes would use the same size. cameraTargetDescriptor.width = ppc.offscreenRTSize.x; cameraTargetDescriptor.height = ppc.offscreenRTSize.y; } colorTextureFilterMode = ppc.finalBlitFilterMode; ppcUpscaleRT = ppc.gridSnapping == PixelPerfectCamera.GridSnapping.UpscaleRenderTexture; } } RenderTargetHandle colorTargetHandle; RenderTargetHandle depthTargetHandle; CommandBuffer cmd = CommandBufferPool.Get(); using (new ProfilingScope(cmd, m_ProfilingSampler)) { CreateRenderTextures(ref cameraData, ppcUsesOffscreenRT, colorTextureFilterMode, cmd, out colorTargetHandle, out depthTargetHandle); } context.ExecuteCommandBuffer(cmd); CommandBufferPool.Release(cmd); ConfigureCameraTarget(colorTargetHandle.Identifier(), depthTargetHandle.Identifier()); // Add passes from Renderer Features. - NOTE: This should be reexamined in the future. Please see feedback from this PR https://github.com/Unity-Technologies/Graphics/pull/3147/files isCameraColorTargetValid = true; // This is to make it possible to call ScriptableRenderer.cameraColorTarget in the custom passes. AddRenderPasses(ref renderingData); isCameraColorTargetValid = false; // We generate color LUT in the base camera only. This allows us to not break render pass execution for overlay cameras. if (stackHasPostProcess && cameraData.renderType == CameraRenderType.Base && m_PostProcessPasses.isCreated) { colorGradingLutPass.Setup(colorGradingLutHandle); EnqueuePass(colorGradingLutPass); } var needsDepth = m_CreateDepthTexture || (!m_CreateColorTexture && m_UseDepthStencilBuffer); m_Render2DLightingPass.Setup(needsDepth); m_Render2DLightingPass.ConfigureTarget(colorTargetHandle.Identifier(), depthTargetHandle.Identifier()); EnqueuePass(m_Render2DLightingPass); // When using Upscale Render Texture on a Pixel Perfect Camera, we want all post-processing effects done with a low-res RT, // and only upscale the low-res RT to fullscreen when blitting it to camera target. Also, final post processing pass is not run in this case, // so FXAA is not supported (you don't want to apply FXAA when everything is intentionally pixelated). bool requireFinalPostProcessPass = lastCameraInStack && !ppcUpscaleRT && stackHasPostProcess && cameraData.antialiasing == AntialiasingMode.FastApproximateAntialiasing; bool hasPassesAfterPostProcessing = activeRenderPassQueue.Find(x => x.renderPassEvent == RenderPassEvent.AfterRenderingPostProcessing) != null; if (stackHasPostProcess && m_PostProcessPasses.isCreated) { RenderTargetHandle postProcessDestHandle = lastCameraInStack && !ppcUpscaleRT && !requireFinalPostProcessPass ? RenderTargetHandle.CameraTarget : afterPostProcessColorHandle; postProcessPass.Setup( cameraTargetDescriptor, colorTargetHandle, postProcessDestHandle, depthTargetHandle, colorGradingLutHandle, requireFinalPostProcessPass, postProcessDestHandle == RenderTargetHandle.CameraTarget); EnqueuePass(postProcessPass); colorTargetHandle = postProcessDestHandle; } if (ppc != null && ppc.enabled && (ppc.cropFrame == PixelPerfectCamera.CropFrame.Pillarbox || ppc.cropFrame == PixelPerfectCamera.CropFrame.Letterbox || ppc.cropFrame == PixelPerfectCamera.CropFrame.Windowbox || ppc.cropFrame == PixelPerfectCamera.CropFrame.StretchFill)) { EnqueuePass(m_PixelPerfectBackgroundPass); } if (requireFinalPostProcessPass && m_PostProcessPasses.isCreated) { finalPostProcessPass.SetupFinalPass(colorTargetHandle, hasPassesAfterPostProcessing); EnqueuePass(finalPostProcessPass); } else if (lastCameraInStack && colorTargetHandle != RenderTargetHandle.CameraTarget) { m_FinalBlitPass.Setup(cameraTargetDescriptor, colorTargetHandle); EnqueuePass(m_FinalBlitPass); } } public override void SetupCullingParameters(ref ScriptableCullingParameters cullingParameters, ref CameraData cameraData) { cullingParameters.cullingOptions = CullingOptions.None; cullingParameters.isOrthographic = cameraData.camera.orthographic; cullingParameters.shadowDistance = 0.0f; m_LightCullResult.SetupCulling(ref cullingParameters, cameraData.camera); } public override void FinishRendering(CommandBuffer cmd) { if (m_CreateColorTexture) cmd.ReleaseTemporaryRT(k_ColorTextureHandle.id); if (m_CreateDepthTexture) cmd.ReleaseTemporaryRT(k_DepthTextureHandle.id); } } }