Net.Like.Xue.Tokyo/Assets/Plugins/Le Tai's Asset/TranslucentImage/Script/UniversalRP/Render Pass/TranslucentImageBlurSource.cs

332 lines
9.6 KiB
C#

#if !UNITY_2023_3_OR_NEWER
#define BUGGY_OVERLAY_CAM_PIXEL_RECT
#endif
#if UNITY_2022_3_OR_NEWER
#define HAS_DOUBLEBUFFER_BOTH
#endif
#if UNITY_2022_1_OR_NEWER
#define HAS_RTHANDLE
#define HAS_SETUP_OVERRIDE
#endif
#if URP12_OR_NEWER
#define HAS_RENDERORDER
#define HAS_DOUBLEBUFFER_UNIVERSAL_RENDERER
#endif
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.Scripting.APIUpdating;
using Debug = UnityEngine.Debug;
#if HAS_RTHANDLE
using RTH = UnityEngine.Rendering.RTHandle;
#else
using RTH = UnityEngine.Rendering.Universal.RenderTargetHandle;
#endif
[assembly: InternalsVisibleTo("LeTai.TranslucentImage.UniversalRP.Editor")]
namespace LeTai.Asset.TranslucentImage.UniversalRP
{
#if HAS_DOUBLEBUFFER_UNIVERSAL_RENDERER
class URPRendererInternal
{
ScriptableRenderer renderer;
Func<RTH> getBackBufferDelegate;
Func<RTH> getAfterPostColorDelegate;
public void CacheRenderer(ScriptableRenderer renderer)
{
if (this.renderer == renderer) return;
this.renderer = renderer;
void CacheBackBufferGetter(object rd)
{
#if UNITY_2022_1_OR_NEWER
const string backBufferMethodName = "PeekBackBuffer";
#else
const string backBufferMethodName = "GetBackBuffer";
#endif
// ReSharper disable once PossibleNullReferenceException
var cbs = rd.GetType()
.GetField("m_ColorBufferSystem", BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(rd);
var gbb = cbs.GetType()
.GetMethods(BindingFlags.Public | BindingFlags.Instance)
.First(m => m.Name == backBufferMethodName && m.GetParameters().Length == 0);
getBackBufferDelegate = (Func<RTH>)gbb.CreateDelegate(typeof(Func<RTH>), cbs);
}
#if HAS_DOUBLEBUFFER_BOTH
CacheBackBufferGetter(renderer);
#else
if (renderer is UniversalRenderer ur)
{
CacheBackBufferGetter(ur);
}
else
{
// ReSharper disable once PossibleNullReferenceException
getAfterPostColorDelegate =
(Func<RTH>)renderer.GetType()
.GetProperty("afterPostProcessColorHandle", BindingFlags.NonPublic | BindingFlags.Instance)
.GetGetMethod(true)
.CreateDelegate(typeof(Func<RTH>), renderer);
}
#endif
}
public RenderTargetIdentifier GetBackBuffer()
{
Debug.Assert(getBackBufferDelegate != null);
var r = getBackBufferDelegate.Invoke();
#if HAS_RTHANDLE
return r.nameID;
#else
return r.Identifier();
#endif
}
public RenderTargetIdentifier GetAfterPostColor()
{
Debug.Assert(getAfterPostColorDelegate != null);
var r = getAfterPostColorDelegate.Invoke();
#if HAS_RTHANDLE
return r.nameID;
#else
return r.Identifier();
#endif
}
}
#endif
[MovedFrom("LeTai.Asset.TranslucentImage.LWRP")]
public class TranslucentImageBlurSource : ScriptableRendererFeature
{
#if HAS_RENDERORDER
public enum RenderOrder
{
AfterPostProcessing,
BeforePostProcessing,
}
public RenderOrder renderOrder = RenderOrder.AfterPostProcessing;
#endif
public bool canvasDisappearWorkaround = false;
internal RendererType rendererType;
readonly Dictionary<Camera, TranslucentImageSource> blurSourceCache = new Dictionary<Camera, TranslucentImageSource>();
readonly Dictionary<Camera, Camera> baseCameraCache = new Dictionary<Camera, Camera>();
#if HAS_DOUBLEBUFFER_UNIVERSAL_RENDERER
URPRendererInternal urpRendererInternal;
#endif
TranslucentImageBlurRenderPass pass;
IBlurAlgorithm blurAlgorithm;
/// <summary>
/// When adding new Translucent Image Source to existing Camera at run time, the new Source must be registered here
/// </summary>
/// <param name="source"></param>
public void RegisterSource(TranslucentImageSource source)
{
blurSourceCache[source.GetComponent<Camera>()] = source;
}
public override void Create()
{
blurAlgorithm = new ScalableBlur();
#if HAS_DOUBLEBUFFER_UNIVERSAL_RENDERER
urpRendererInternal = new URPRendererInternal();
#endif
// ReSharper disable once JoinDeclarationAndInitializer
RenderPassEvent renderPassEvent;
#if HAS_RENDERORDER
renderPassEvent = renderOrder == RenderOrder.BeforePostProcessing
? RenderPassEvent.BeforeRenderingPostProcessing
: RenderPassEvent.AfterRenderingPostProcessing;
#else
renderPassEvent = RenderPassEvent.AfterRendering;
#endif
pass = new TranslucentImageBlurRenderPass(
#if HAS_DOUBLEBUFFER_UNIVERSAL_RENDERER
urpRendererInternal
#endif
) {
renderPassEvent = renderPassEvent
};
blurSourceCache.Clear();
}
void SetupSRP(ScriptableRenderer renderer)
{
#if HAS_DOUBLEBUFFER_UNIVERSAL_RENDERER
urpRendererInternal.CacheRenderer(renderer);
#endif
#if UNITY_2021_3_OR_NEWER
if (renderer is UniversalRenderer)
#else
if (renderer is ForwardRenderer)
#endif
{
rendererType = RendererType.Universal;
}
else
{
rendererType = RendererType.Renderer2D;
}
pass.SetupSRP(new TranslucentImageBlurRenderPass.SRPassData {
#if !HAS_DOUBLEBUFFER_BOTH
rendererType = rendererType,
#if HAS_RTHANDLE
cameraColorTarget = renderer.cameraColorTargetHandle,
#else
cameraColorTarget = renderer.cameraColorTarget,
#endif
#if HAS_RENDERORDER
renderOrder = renderOrder,
#endif
#endif // !HAS_DOUBLEBUFFER_BOTH
canvasDisappearWorkaround = canvasDisappearWorkaround,
});
}
#if HAS_SETUP_OVERRIDE
public override void SetupRenderPasses(ScriptableRenderer renderer, in RenderingData renderingData)
{
var cameraData = renderingData.cameraData;
var blurSource = GetBlurSource(cameraData.camera);
if (blurSource == null)
return;
SetupSRP(renderer);
}
#endif
public override void AddRenderPasses(
ScriptableRenderer renderer,
ref RenderingData renderingData
)
{
var cameraData = renderingData.cameraData;
var camera = renderingData.cameraData.camera;
var blurSource = GetBlurSource(camera);
if (blurSource == null)
return;
if (blurSource.BlurConfig == null)
return;
blurSource.CamRectOverride = Rect.zero;
#if BUGGY_OVERLAY_CAM_PIXEL_RECT
if (cameraData.renderType == CameraRenderType.Overlay)
{
var baseCam = GetBaseCamera(camera);
if (baseCam)
blurSource.CamRectOverride = baseCam.rect;
}
#endif
blurAlgorithm.Init(blurSource.BlurConfig, false);
#if UNITY_BUGGED_HAS_PASSES_AFTER_POSTPROCESS
bool applyFinalPostProcessing = renderingData.postProcessingEnabled
&& cameraData.resolveFinalTarget
&& cameraData.antialiasing == AntialiasingMode.FastApproximateAntialiasing;
pass.renderPassEvent = applyFinalPostProcessing ? RenderPassEvent.AfterRenderingPostProcessing : RenderPassEvent.AfterRendering;
#endif
pass.Setup(new TranslucentImageBlurRenderPass.PassData {
blurAlgorithm = blurAlgorithm,
blurSource = blurSource,
camPixelSize = Vector2Int.RoundToInt(GetPixelSize(cameraData).size),
shouldUpdateBlur = blurSource.ShouldUpdateBlur(),
isPreviewing = blurSource.Preview,
});
#if !HAS_SETUP_OVERRIDE
SetupSRP(renderer);
#endif
renderer.EnqueuePass(pass);
}
TranslucentImageSource GetBlurSource(Camera camera)
{
if (!blurSourceCache.ContainsKey(camera))
{
blurSourceCache.Add(camera, camera.GetComponent<TranslucentImageSource>());
}
return blurSourceCache[camera];
}
#if BUGGY_OVERLAY_CAM_PIXEL_RECT
Camera GetBaseCamera(Camera camera)
{
if (!baseCameraCache.ContainsKey(camera))
{
Camera baseCamera = null;
foreach (var uacd in Shims.FindObjectsOfType<UniversalAdditionalCameraData>())
{
if (uacd.renderType != CameraRenderType.Base) continue;
if (uacd.cameraStack == null) continue;
if (!uacd.cameraStack.Contains(camera)) continue;
baseCamera = uacd.GetComponent<Camera>();
}
baseCameraCache.Add(camera, baseCamera);
}
return baseCameraCache[camera];
}
readonly FieldInfo cameraDataPixelRectField = typeof(CameraData).GetField("pixelRect", BindingFlags.Instance | BindingFlags.NonPublic);
#endif
public Rect GetPixelSize(CameraData cameraData)
{
#if !BUGGY_OVERLAY_CAM_PIXEL_RECT
return cameraData.camera.pixelRect;
#else
if (cameraData.renderType == CameraRenderType.Base)
return cameraData.camera.pixelRect;
if (cameraDataPixelRectField == null)
Debug.LogError("CameraData.pixelRect does not exists in this version of URP. Please report a bug.");
// ReSharper disable once PossibleNullReferenceException
return (Rect)cameraDataPixelRectField.GetValue(cameraData);
#endif
}
}
}