2026-02-02 15:26:23 +08:00

170 lines
6.3 KiB
C#

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();
}
}
}