#if UNITY_PIPELINE_URP
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using com.zibra.liquid.Solver;
using com.zibra.liquid.Bridge;
namespace com.zibra.liquid
{
///
/// Component responsible for rendering liquid in case of URP.
///
///
/// This is not used in case liquid's
/// ZibraLiquid.CurrentRenderingMode
/// is set to Unity Render.
///
public class LiquidURPRenderComponent : ScriptableRendererFeature
{
#region Public Interface
///
/// URP specific liquid rendering settings.
///
[System.Serializable]
public class LiquidURPRenderSettings
{
///
/// Globally defines whether liquid renders in URP.
///
public bool IsEnabled = true;
///
/// Injection point where we will insert liquid rendering.
///
///
/// In case of URP, this parameter will be used instead of
/// ZibraLiquid.CurrentInjectionPoint.
///
public RenderPassEvent InjectionPoint = RenderPassEvent.AfterRenderingSkybox;
}
///
/// See .
///
// Must be called exactly "settings" so Unity shows this as render feature settings in editor
public LiquidURPRenderSettings settings = new LiquidURPRenderSettings();
///
/// Creates URP ScriptableRendererFeature.
///
public override void Create()
{
handleSystem.Initialize(0, 0);
}
///
/// Adds scriptable render passes.
///
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
if (!settings.IsEnabled)
{
return;
}
if (renderingData.cameraData.cameraType != CameraType.Game &&
renderingData.cameraData.cameraType != CameraType.SceneView)
{
return;
}
Camera camera = renderingData.cameraData.camera;
camera.depthTextureMode = DepthTextureMode.Depth;
int liquidsToRenderCount = 0;
int backgroundsToCopyCount = 0;
int liquidsToVisualizeSDFCount = 0;
int liquidsToUpscaleCount = 0;
foreach (var liquid in ZibraLiquid.AllFluids)
{
if (liquid != null && liquid.Initialized)
{
liquidsToRenderCount++;
if (liquid.EnableDownscale)
{
liquidsToUpscaleCount++;
}
if (liquid.IsBackgroundCopyNeeded(camera))
{
backgroundsToCopyCount++;
}
if (liquid.VisualizeSceneSDF)
{
liquidsToVisualizeSDFCount++;
}
}
}
if (copyPasses == null || copyPasses.Length != backgroundsToCopyCount)
{
copyPasses = new CopyBackgroundURPRenderPass[backgroundsToCopyCount];
for (int i = 0; i < backgroundsToCopyCount; ++i)
{
copyPasses[i] = new CopyBackgroundURPRenderPass(settings.InjectionPoint);
}
}
if (liquidNativePasses == null || liquidNativePasses.Length != liquidsToRenderCount)
{
liquidNativePasses = new LiquidNativeRenderPass[liquidsToRenderCount];
for (int i = 0; i < liquidsToRenderCount; ++i)
{
liquidNativePasses[i] = new LiquidNativeRenderPass(settings.InjectionPoint);
}
}
if (liquidURPPasses == null || liquidURPPasses.Length != liquidsToRenderCount)
{
liquidURPPasses = new LiquidURPRenderPass[liquidsToRenderCount];
for (int i = 0; i < liquidsToRenderCount; ++i)
{
liquidURPPasses[i] = new LiquidURPRenderPass(settings.InjectionPoint);
}
}
if (liquidVisualizeSDFPasses == null || liquidVisualizeSDFPasses.Length != liquidsToVisualizeSDFCount)
{
liquidVisualizeSDFPasses = new LiquidVisualizeSDFPass[liquidsToVisualizeSDFCount];
for (int i = 0; i < liquidsToVisualizeSDFCount; ++i)
{
liquidVisualizeSDFPasses[i] = new LiquidVisualizeSDFPass(settings.InjectionPoint);
}
}
if (upscalePasses == null || upscalePasses.Length != liquidsToUpscaleCount)
{
upscalePasses = new LiquidUpscaleURPRenderPass[liquidsToUpscaleCount];
for (int i = 0; i < liquidsToUpscaleCount; ++i)
{
upscalePasses[i] = new LiquidUpscaleURPRenderPass(settings.InjectionPoint);
}
}
int currentCopyPass = 0;
int currentLiquidPass = 0;
int currentVisualizeSDFPass = 0;
int currentUpscalePass = 0;
foreach (var liquid in ZibraLiquid.AllFluids)
{
if (liquid != null && liquid.IsRenderingEnabled() &&
((camera.cullingMask & (1 << liquid.gameObject.layer)) != 0))
{
if (liquid.IsBackgroundCopyNeeded(camera))
{
copyPasses[currentCopyPass].liquid = liquid;
copyPasses[currentCopyPass].handleSystem = handleSystem;
copyPasses[currentCopyPass].ConfigureInput(ScriptableRenderPassInput.Color |
ScriptableRenderPassInput.Depth);
copyPasses[currentCopyPass].renderPassEvent = settings.InjectionPoint;
renderer.EnqueuePass(copyPasses[currentCopyPass]);
currentCopyPass++;
}
liquidNativePasses[currentLiquidPass].liquid = liquid;
liquidNativePasses[currentLiquidPass].handleSystem = handleSystem;
liquidNativePasses[currentLiquidPass].renderPassEvent = settings.InjectionPoint;
renderer.EnqueuePass(liquidNativePasses[currentLiquidPass]);
liquidURPPasses[currentLiquidPass].liquid = liquid;
liquidURPPasses[currentLiquidPass].handleSystem = handleSystem;
liquidURPPasses[currentLiquidPass].ConfigureInput(ScriptableRenderPassInput.Color |
ScriptableRenderPassInput.Depth);
liquidURPPasses[currentLiquidPass].renderPassEvent = settings.InjectionPoint;
renderer.EnqueuePass(liquidURPPasses[currentLiquidPass]);
currentLiquidPass++;
if (liquid.VisualizeSceneSDF)
{
liquidVisualizeSDFPasses[currentVisualizeSDFPass].ConfigureInput(
ScriptableRenderPassInput.Color | ScriptableRenderPassInput.Depth);
liquidVisualizeSDFPasses[currentVisualizeSDFPass].liquid = liquid;
liquidVisualizeSDFPasses[currentVisualizeSDFPass].handleSystem = handleSystem;
liquidVisualizeSDFPasses[currentVisualizeSDFPass].renderPassEvent = settings.InjectionPoint;
renderer.EnqueuePass(liquidVisualizeSDFPasses[currentVisualizeSDFPass]);
currentVisualizeSDFPass++;
}
if (liquid.EnableDownscale)
{
upscalePasses[currentUpscalePass].liquid = liquid;
upscalePasses[currentUpscalePass].handleSystem = handleSystem;
upscalePasses[currentUpscalePass].renderPassEvent = settings.InjectionPoint;
renderer.EnqueuePass(upscalePasses[currentUpscalePass]);
currentUpscalePass++;
}
}
}
}
#endregion
#region Implementation details
private class CopyBackgroundURPRenderPass : ScriptableRenderPass
{
public ZibraLiquid liquid;
public RTHandleSystem handleSystem;
RTHandle cameraColorTarget;
public CopyBackgroundURPRenderPass(RenderPassEvent injectionPoint)
{
renderPassEvent = injectionPoint;
}
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
#if UNITY_PIPELINE_URP_13_1_OR_HIGHER
cameraColorTarget = renderingData.cameraData.renderer.cameraColorTargetHandle;
#else
cameraColorTarget = handleSystem.Alloc(renderingData.cameraData.renderer.cameraColorTarget);
#endif
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
Camera camera = renderingData.cameraData.camera;
CommandBuffer cmd = CommandBufferPool.Get("ZibraLiquid.Render");
if (liquid.CameraResourcesMap.ContainsKey(camera))
{
RTHandle background = handleSystem.Alloc(liquid.CameraResourcesMap[camera].Background);
Blit(cmd, cameraColorTarget, background);
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
}
private class LiquidNativeRenderPass : ScriptableRenderPass
{
public ZibraLiquid liquid;
public RTHandleSystem handleSystem;
public LiquidNativeRenderPass(RenderPassEvent injectionPoint)
{
renderPassEvent = injectionPoint;
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
Camera camera = renderingData.cameraData.camera;
camera.depthTextureMode = DepthTextureMode.Depth;
CommandBuffer cmd = CommandBufferPool.Get("ZibraLiquid.Render");
liquid.RenderCallBack(renderingData.cameraData.camera, renderingData.cameraData.renderScale);
// set initial parameters in the native plugin
LiquidBridge.SubmitInstanceEvent(cmd, liquid.CurrentInstanceID, LiquidBridge.EventID.SetCameraParams,
liquid.CamNativeParams[camera]);
if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.Vulkan)
{
cmd.SetRenderTarget(liquid.Color0, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store,
liquid.Depth, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store);
cmd.ClearRenderTarget(true, true, Color.clear);
}
liquid.RenderLiquidNative(cmd, renderingData.cameraData.camera);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
}
private class LiquidURPRenderPass : ScriptableRenderPass
{
public ZibraLiquid liquid;
public RTHandleSystem handleSystem;
RTHandle cameraColorTarget;
static int UpscaleColorTextureID = Shader.PropertyToID("ZibraLiquid_LiquidTempColorTexture");
static int UpscaleDepthTextureID = Shader.PropertyToID("ZibraLiquid_LiquidTempDepthTexture");
RTHandle UpscaleColorTexture;
RTHandle UpscaleDepthTexture;
public LiquidURPRenderPass(RenderPassEvent injectionPoint)
{
renderPassEvent = injectionPoint;
}
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
#if UNITY_PIPELINE_URP_13_1_OR_HIGHER
cameraColorTarget = renderingData.cameraData.renderer.cameraColorTargetHandle;
#else
cameraColorTarget = handleSystem.Alloc(renderingData.cameraData.renderer.cameraColorTarget);
#endif
}
public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
{
if (liquid.EnableDownscale)
{
RenderTextureDescriptor descriptor = cameraTextureDescriptor;
Vector2Int dimensions = new Vector2Int(descriptor.width, descriptor.height);
dimensions = liquid.ApplyDownscaleFactor(dimensions);
descriptor.width = dimensions.x;
descriptor.height = dimensions.y;
descriptor.msaaSamples = 1;
descriptor.colorFormat = RenderTextureFormat.ARGBHalf;
descriptor.depthBufferBits = 0;
cmd.GetTemporaryRT(UpscaleColorTextureID, descriptor, FilterMode.Bilinear);
descriptor.colorFormat = RenderTextureFormat.Depth;
descriptor.depthBufferBits = 32;
cmd.GetTemporaryRT(UpscaleDepthTextureID, descriptor, FilterMode.Bilinear);
UpscaleColorTexture = handleSystem.Alloc(new RenderTargetIdentifier(UpscaleColorTextureID));
UpscaleDepthTexture = handleSystem.Alloc(new RenderTargetIdentifier(UpscaleDepthTextureID));
ConfigureTarget(UpscaleColorTexture, UpscaleDepthTexture);
ConfigureClear(ClearFlag.All, new Color(0, 0, 0, 0));
}
else
{
ConfigureTarget(cameraColorTarget);
// ConfigureClear seems to be persistent, so need to reset it
ConfigureClear(ClearFlag.None, new Color(0, 0, 0, 0));
}
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
Camera camera = renderingData.cameraData.camera;
camera.depthTextureMode = DepthTextureMode.Depth;
CommandBuffer cmd = CommandBufferPool.Get("ZibraLiquid.Render");
if (!liquid.EnableDownscale)
{
cmd.SetRenderTarget(cameraColorTarget);
}
liquid.RenderLiquidMain(cmd, camera);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
public override void OnCameraCleanup(CommandBuffer cmd)
{
if (liquid.EnableDownscale)
{
cmd.ReleaseTemporaryRT(UpscaleColorTextureID);
cmd.ReleaseTemporaryRT(UpscaleDepthTextureID);
}
}
}
private class LiquidVisualizeSDFPass : ScriptableRenderPass
{
public ZibraLiquid liquid;
public RTHandleSystem handleSystem;
RTHandle cameraColorTarget;
static int UpscaleColorTextureID = Shader.PropertyToID("ZibraLiquid_LiquidTempColorTexture");
static int UpscaleDepthTextureID = Shader.PropertyToID("ZibraLiquid_LiquidTempDepthTexture");
RTHandle UpscaleColorTexture;
RTHandle UpscaleDepthTexture;
public LiquidVisualizeSDFPass(RenderPassEvent injectionPoint)
{
renderPassEvent = injectionPoint;
}
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
#if UNITY_PIPELINE_URP_13_1_OR_HIGHER
cameraColorTarget = renderingData.cameraData.renderer.cameraColorTargetHandle;
#else
cameraColorTarget = handleSystem.Alloc(renderingData.cameraData.renderer.cameraColorTarget);
#endif
}
public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
{
if (liquid.EnableDownscale)
{
UpscaleColorTexture = handleSystem.Alloc(new RenderTargetIdentifier(UpscaleColorTextureID));
UpscaleDepthTexture = handleSystem.Alloc(new RenderTargetIdentifier(UpscaleDepthTextureID));
ConfigureTarget(UpscaleColorTexture, UpscaleDepthTexture);
}
else
{
ConfigureTarget(cameraColorTarget);
}
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
Camera camera = renderingData.cameraData.camera;
camera.depthTextureMode = DepthTextureMode.Depth;
CommandBuffer cmd = CommandBufferPool.Get("ZibraLiquid.Render");
LiquidBridge.SubmitInstanceEvent(cmd, liquid.CurrentInstanceID, LiquidBridge.EventID.RenderSDF);
if (liquid.EnableDownscale)
{
cmd.SetRenderTarget(UpscaleColorTexture, UpscaleDepthTexture);
}
else
{
cmd.SetRenderTarget(cameraColorTarget);
}
liquid.RenderSDFVisualization(cmd, camera);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
}
private class LiquidUpscaleURPRenderPass : ScriptableRenderPass
{
public ZibraLiquid liquid;
public RTHandleSystem handleSystem;
static int UpscaleColorTextureID = Shader.PropertyToID("ZibraLiquid_LiquidTempColorTexture");
static int UpscaleDepthTextureID = Shader.PropertyToID("ZibraLiquid_LiquidTempDepthTexture");
RTHandle UpscaleColorTexture;
RTHandle UpscaleDepthTexture;
public LiquidUpscaleURPRenderPass(RenderPassEvent injectionPoint)
{
renderPassEvent = injectionPoint;
}
public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
{
UpscaleColorTexture = handleSystem.Alloc(new RenderTargetIdentifier(UpscaleColorTextureID));
UpscaleDepthTexture = handleSystem.Alloc(new RenderTargetIdentifier(UpscaleDepthTextureID));
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
Camera camera = renderingData.cameraData.camera;
camera.depthTextureMode = DepthTextureMode.Depth;
CommandBuffer cmd = CommandBufferPool.Get("ZibraLiquid.Render");
liquid.UpscaleLiquidDirect(cmd, camera, UpscaleColorTexture, UpscaleDepthTexture);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
}
RTHandleSystem handleSystem = new RTHandleSystem();
// 1 pass per rendered liquid that requires background copy
CopyBackgroundURPRenderPass[] copyPasses;
// 1 pass per rendered liquid
LiquidNativeRenderPass[] liquidNativePasses;
// 1 pass per rendered liquid
LiquidURPRenderPass[] liquidURPPasses;
// 1 pass per rendered liquid with VisualizeSceneSDF enabled
LiquidVisualizeSDFPass[] liquidVisualizeSDFPasses;
// 1 pass per rendered liquid that have downscale enabled
LiquidUpscaleURPRenderPass[] upscalePasses;
#endregion
}
}
#endif // UNITY_PIPELINE_URP