using System; using UnityEngine; using UnityEngine.Experimental.Rendering; using UnityEngine.Experimental.Rendering.Universal; using UnityEngine.Rendering; using UnityEngine.Rendering.RendererUtils; using UnityEngine.Rendering.Universal; [DisallowMultipleRendererFeature("Weighted Blended Order-Independent Transparency")] public class WBOITFeature : ScriptableRendererFeature { [Serializable] public class FilterSettings { public RenderQueueType RenderQueueType; public LayerMask LayerMask; public FilterSettings() { RenderQueueType = RenderQueueType.Transparent; LayerMask = 0; } } [Serializable] public class OITSettings { public RenderPassEvent RenderPassEvent = RenderPassEvent.AfterRenderingOpaques; public FilterSettings FilterSettings = new FilterSettings(); public Shader BlendShader; } [SerializeField] OITSettings settings; OITRenderPass pass; public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) { var cam = renderingData.cameraData; if (cam.cameraType != CameraType.Game && cam.cameraType != CameraType.SceneView) { return; } renderer.EnqueuePass(pass); } public override void Create() { pass = new OITRenderPass(settings); } protected override void Dispose(bool disposing) { base.Dispose(disposing); pass.Dispose(); } class OITRenderPass : ScriptableRenderPass, IDisposable { private ProfilingSampler profiler; private CommandBuffer commandBuffer; private OITSettings settings; private Material blendMaterial; static readonly int accumTexID = Shader.PropertyToID("_AccumTex"); static readonly int revealageTexID = Shader.PropertyToID("_RevealageTex"); static readonly int cameraColorTexID = Shader.PropertyToID("_CameraColorTex"); RTHandle[] oitRTs = new RTHandle[2]; RenderTargetIdentifier[] oitRtIds = new RenderTargetIdentifier[2]; private ShaderTagId shaderTagId = new ShaderTagId("WBOIT"); public OITRenderPass(OITSettings settings) { this.settings = settings; profiler = new(nameof(OITRenderPass)); commandBuffer = new CommandBuffer(); commandBuffer.name = profiler.name; renderPassEvent = settings.RenderPassEvent; blendMaterial = new Material(settings.BlendShader); } public void Dispose() { oitRTs[0]?.Release(); oitRTs[1]?.Release(); commandBuffer.Release(); GameObject.DestroyImmediate(blendMaterial); } RTHandle destinationRT; public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) { var cmd = commandBuffer; using var scp = new ProfilingScope(cmd, profiler); var rdr = renderingData.cameraData.renderer; var desc = renderingData.cameraData.cameraTargetDescriptor; desc.depthBufferBits = 0; desc.sRGB = false; RenderingUtils.ReAllocateIfNeeded(ref destinationRT, desc, filterMode: FilterMode.Bilinear); desc.graphicsFormat = GraphicsFormat.R16G16B16A16_SFloat; RenderingUtils.ReAllocateIfNeeded(ref oitRTs[0], desc, filterMode: FilterMode.Bilinear, name: "_AccumTex"); cmd.SetRenderTarget(oitRTs[0]); cmd.ClearRenderTarget(false, true, new Color(0.0f, 0.0f, 0.0f, 0.0f)); desc.graphicsFormat = SystemInfo.IsFormatSupported(GraphicsFormat.R16_SFloat, FormatUsage.Render) ? GraphicsFormat.R16_SFloat : GraphicsFormat.R32_SFloat; RenderingUtils.ReAllocateIfNeeded(ref oitRTs[1], desc, filterMode: FilterMode.Bilinear, name: "_RevealageTex"); cmd.SetRenderTarget(oitRTs[1]); cmd.ClearRenderTarget(false, true, new Color(1.0f, 1.0f, 1.0f, 1.0f)); oitRtIds[0] = oitRTs[0]; oitRtIds[1] = oitRTs[1]; RenderQueueRange renderQueueRange = (settings.FilterSettings.RenderQueueType == RenderQueueType.Transparent) ? RenderQueueRange.transparent : RenderQueueRange.opaque; var renderStateBlock = new RenderStateBlock(RenderStateMask.Nothing); SortingCriteria sortingCriteria = (renderQueueRange == RenderQueueRange.transparent) ? SortingCriteria.CommonTransparent : renderingData.cameraData.defaultOpaqueSortFlags; DrawingSettings drawSettings = CreateDrawingSettings(shaderTagId, ref renderingData, sortingCriteria); #region Draw Weighted Blended Order-Independent Transparency cmd.SetRenderTarget(oitRtIds, rdr.cameraDepthTargetHandle); RendererList rendererList = context.CreateRendererList(new RendererListDesc(shaderTagId, renderingData.cullResults, renderingData.cameraData.camera) { renderQueueRange = renderQueueRange, sortingCriteria = sortingCriteria, rendererConfiguration = renderingData.perObjectData, layerMask = settings.FilterSettings.LayerMask, stateBlock = renderStateBlock, }); cmd.DrawRendererList(rendererList); #endregion #region Blend cmd.BeginSample("Blend"); cmd.SetGlobalTexture(accumTexID, oitRTs[0]); cmd.SetGlobalTexture(revealageTexID, oitRTs[1]); cmd.SetGlobalTexture(cameraColorTexID, rdr.cameraColorTargetHandle); cmd.SetRenderTarget(destinationRT, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare); cmd.DrawProcedural(Matrix4x4.identity, blendMaterial, 0, MeshTopology.Triangles, 3); if (SystemInfo.copyTextureSupport != CopyTextureSupport.None) { cmd.CopyTexture(destinationRT, rdr.cameraColorTargetHandle); } else { Blit(cmd, destinationRT, rdr.cameraColorTargetHandle); } cmd.EndSample("Blend"); #endregion context.ExecuteCommandBuffer(cmd); cmd.Clear(); } } }