370 lines
17 KiB
C#
370 lines
17 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Dynamic;
|
|
using System.Runtime.ConstrainedExecution;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
using UnityEngine.Rendering.Universal;
|
|
using static UnityEngine.XR.XRDisplaySubsystem;
|
|
|
|
//GRAPH
|
|
#if UNITY_2023_3_OR_NEWER
|
|
using UnityEngine.Rendering.RenderGraphModule;
|
|
#endif
|
|
|
|
namespace Artngame.LUMINA.LimWorks.Rendering.URP.ScreenSpaceReflections
|
|
{
|
|
public class DepthPyramid : ScriptableRendererFeature
|
|
{
|
|
const int buffersize = 11;
|
|
|
|
class DepthPyramidPass : ScriptableRenderPass
|
|
{
|
|
|
|
|
|
|
|
#if UNITY_2023_3_OR_NEWER
|
|
//GRAPH
|
|
public class PassData
|
|
{
|
|
public RenderingData renderingData;
|
|
public UniversalCameraData cameraData;
|
|
public CullingResults cullResults;
|
|
public TextureHandle colorTargetHandleA;
|
|
public void Init(ContextContainer frameData, IUnsafeRenderGraphBuilder builder = null)
|
|
{
|
|
cameraData = frameData.Get<UniversalCameraData>();
|
|
cullResults = frameData.Get<UniversalRenderingData>().cullResults;
|
|
}
|
|
}
|
|
public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
|
|
{
|
|
string passName = "CameraSettingPass";
|
|
using (var builder = renderGraph.AddUnsafePass<PassData>(passName,
|
|
out var data))
|
|
{
|
|
builder.AllowPassCulling(false);
|
|
data.Init(frameData, builder);
|
|
builder.AllowGlobalStateModification(true);
|
|
UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();
|
|
data.colorTargetHandleA = resourceData.activeColorTexture;
|
|
builder.UseTexture(data.colorTargetHandleA, AccessFlags.ReadWrite);
|
|
|
|
builder.SetRenderFunc<PassData>((data, ctx) =>
|
|
{
|
|
var cmd = CommandBufferHelpers.GetNativeCommandBuffer(ctx.cmd);
|
|
OnCameraSetupA(cmd, data);
|
|
ExecutePass(cmd, data, ctx);
|
|
});
|
|
}
|
|
}
|
|
void ExecutePass(CommandBuffer command, PassData data, UnsafeGraphContext ctx)//, RasterGraphContext context)
|
|
{
|
|
CommandBuffer unsafeCmd = command;
|
|
//command.Clear();
|
|
//command.SetExecutionFlags(CommandBufferExecutionFlags.AsyncCompute);
|
|
//unsafeCmd.Clear();
|
|
//CameraData cameraData = data.cameraData;
|
|
//unsafeCmd.SetViewProjectionMatrices(data.cameraData.camera.worldToCameraMatrix, m_TaaData.projOverride);
|
|
|
|
//if (Camera.main == null)
|
|
//{
|
|
// return;
|
|
//}
|
|
//CommandBuffer cmd = unsafeCmd;// CommandBufferPool.Get(m_ProfilerTag);
|
|
RenderTextureDescriptor opaqueDesc = data.cameraData.cameraTargetDescriptor;
|
|
opaqueDesc.depthBufferBits = 0;
|
|
//v1.6
|
|
if (Camera.main != null && data.cameraData.camera == Camera.main)
|
|
{
|
|
//cmd.Blit(source, source, outlineMaterial, 0);
|
|
}
|
|
|
|
float width = data.cameraData.cameraTargetDescriptor.width;
|
|
float height = data.cameraData.cameraTargetDescriptor.height;
|
|
var cmd = command;// CommandBufferPool.Get("Init Depth Pyramid");
|
|
finalDepthPyramid = Shader.PropertyToID("_DepthPyramid");
|
|
cmd.GetTemporaryRTArray(finalDepthPyramid, (int)width, (int)height, buffersize, 0, FilterMode.Point, RenderTextureFormat.RFloat, RenderTextureReadWrite.Linear, 1, true);
|
|
cmd.SetComputeTextureParam(settings.shader, 1, "source", finalDepthPyramid);
|
|
cmd.DispatchCompute(settings.shader, 1, Mathf.CeilToInt(width / Threads), Mathf.CeilToInt(height / Threads), 1);
|
|
//context.ExecuteCommandBuffer(cmd);
|
|
//CommandBufferPool.Release(cmd);
|
|
|
|
//cmd.Clear();
|
|
//cmd = CommandBufferPool.Get("Calculate Depth Pyramid");
|
|
//cmd.SetExecutionFlags(CommandBufferExecutionFlags.AsyncCompute);
|
|
for (int i = 0; i < buffersize - 1; i++)
|
|
{
|
|
//calculate high z depth for the next scaled down buffer
|
|
SetComputeShader(cmd,
|
|
finalDepthPyramid,
|
|
tempSlices[i],
|
|
tempSlices[i + 1],
|
|
tempSlices[i].resolution.x,
|
|
tempSlices[i].resolution.y,
|
|
tempSlices[i + 1].resolution.x,
|
|
tempSlices[i + 1].resolution.y
|
|
);
|
|
|
|
int xGroup = Mathf.Max(Mathf.CeilToInt(tempSlices[i + 1].resolution.x / Threads), 1);
|
|
int yGroup = Mathf.Max(Mathf.CeilToInt(tempSlices[i + 1].resolution.y / Threads), 1);
|
|
cmd.DispatchCompute(settings.shader, 0, xGroup, yGroup, 1);
|
|
}
|
|
//context.ExecuteCommandBufferAsync(cmd, ComputeQueueType.Background);
|
|
|
|
//CommandBufferPool.Release(cmd);
|
|
|
|
#if UNITY_EDITOR
|
|
if (settings.ShowDebug)
|
|
{
|
|
cmd = command;// CommandBufferPool.Get("Debug Depth Pyramid");
|
|
int debug = Mathf.Clamp(settings.DebugSlice, 0, buffersize - 1);
|
|
|
|
//Debug.Log(tempSlices[debug].scale);
|
|
|
|
// cmd.Blit(finalDepthPyramid, colorAttachmentHandle, Vector2.one * tempSlices[debug].scale, Vector2.zero, debug, 0);
|
|
cmd.Blit(finalDepthPyramid, data.colorTargetHandleA, Vector2.one * tempSlices[debug].scale, Vector2.zero, debug, 0);
|
|
|
|
// context.ExecuteCommandBuffer(cmd);
|
|
// CommandBufferPool.Release(cmd);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
// public void OnCameraSetupA(CommandBuffer cmd, PassData renderingData)//(CommandBuffer cmd, ref UnityEngine.Rendering.Universal.RenderingData renderingData)
|
|
// {
|
|
|
|
// }
|
|
public void OnCameraSetupA(CommandBuffer cmd, PassData data)
|
|
{
|
|
|
|
RenderTextureDescriptor opaqueDesc = data.cameraData.cameraTargetDescriptor;
|
|
int rtW = opaqueDesc.width;
|
|
int rtH = opaqueDesc.height;
|
|
var renderer = data.cameraData.renderer;
|
|
//destination = renderingData.colorTargetHandleA;
|
|
//source = renderingData.colorTargetHandleA;
|
|
|
|
if (tempSlices == null)
|
|
{
|
|
tempSlices = new TargetSlice[buffersize];
|
|
//tempScale = new float2[buffersize];
|
|
//sliceScaleBuffer = new ComputeBuffer(buffersize, sizeof(float) * 2, ComputeBufferType.Constant, ComputeBufferMode.Dynamic);
|
|
}
|
|
float width = data.cameraData.cameraTargetDescriptor.width;
|
|
float height = data.cameraData.cameraTargetDescriptor.height;
|
|
|
|
for (int i = 0; i < buffersize; i++)
|
|
{
|
|
float d = Mathf.Pow(2, i);
|
|
tempSlices[i].resolution.x = Mathf.Max(MathF.Floor(width / d), 1);
|
|
tempSlices[i].resolution.y = Mathf.Max(MathF.Floor(height / d), 1);
|
|
tempSlices[i].slice = i;
|
|
tempSlices[i].scale.x = tempSlices[i].resolution.x / width;
|
|
tempSlices[i].scale.y = tempSlices[i].resolution.y / height;
|
|
|
|
//tempScale[i] = tempSlices[i].scale;
|
|
//Debug.Log(tempSlices[i].resolution + "_x" + tempSlices[i].scale);
|
|
//Debug.Log(tempSlices[i].resolution);
|
|
}
|
|
|
|
//sliceScaleBuffer.SetData(tempScale);
|
|
//Shader.SetGlobalConstantBuffer("_DepthPyramidScales", sliceScaleBuffer, 0, tempScale.Length);
|
|
|
|
/// ConfigureTarget(data.cameraData.renderer.cameraColorTargetHandle, data.cameraData.renderer.cameraColorTargetHandle);
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
internal Settings settings { get; set; }
|
|
const int Threads = 8;
|
|
struct TargetSlice
|
|
{
|
|
internal int slice;
|
|
internal Vector2 resolution;
|
|
internal Vector2 scale;
|
|
public static implicit operator int(TargetSlice target)
|
|
{
|
|
return target.slice;
|
|
}
|
|
}
|
|
|
|
int finalDepthPyramid;
|
|
|
|
TargetSlice[] tempSlices;
|
|
//float2[] tempScale;
|
|
//ComputeBuffer sliceScaleBuffer;
|
|
|
|
|
|
//public void Dispose()
|
|
//{
|
|
// sliceScaleBuffer.Release();
|
|
//}
|
|
|
|
// This method is called before executing the render pass.
|
|
// It can be used to configure render targets and their clear state. Also to create temporary render target textures.
|
|
// When empty this render pass will render to the active camera render target.
|
|
// You should never call CommandBuffer.SetRenderTarget. Instead call <c>ConfigureTarget</c> and <c>ConfigureClear</c>.
|
|
// The render pipeline will ensure target setup and clearing happens in a performant manner.
|
|
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
|
|
{
|
|
if (tempSlices == null)
|
|
{
|
|
tempSlices = new TargetSlice[buffersize];
|
|
//tempScale = new float2[buffersize];
|
|
//sliceScaleBuffer = new ComputeBuffer(buffersize, sizeof(float) * 2, ComputeBufferType.Constant, ComputeBufferMode.Dynamic);
|
|
}
|
|
float width = renderingData.cameraData.cameraTargetDescriptor.width;
|
|
float height = renderingData.cameraData.cameraTargetDescriptor.height;
|
|
|
|
for (int i = 0; i < buffersize; i++)
|
|
{
|
|
float d = Mathf.Pow(2, i);
|
|
tempSlices[i].resolution.x = Mathf.Max(MathF.Floor(width / d), 1);
|
|
tempSlices[i].resolution.y = Mathf.Max(MathF.Floor(height / d), 1);
|
|
tempSlices[i].slice = i;
|
|
tempSlices[i].scale.x = tempSlices[i].resolution.x / width;
|
|
tempSlices[i].scale.y = tempSlices[i].resolution.y / height;
|
|
|
|
//tempScale[i] = tempSlices[i].scale;
|
|
//Debug.Log(tempSlices[i].resolution + "_x" + tempSlices[i].scale);
|
|
//Debug.Log(tempSlices[i].resolution);
|
|
}
|
|
|
|
//sliceScaleBuffer.SetData(tempScale);
|
|
//Shader.SetGlobalConstantBuffer("_DepthPyramidScales", sliceScaleBuffer, 0, tempScale.Length);
|
|
#if UNITY_2022_1_OR_NEWER
|
|
ConfigureTarget(renderingData.cameraData.renderer.cameraColorTargetHandle, renderingData.cameraData.renderer.cameraColorTargetHandle);
|
|
#else
|
|
ConfigureTarget(renderingData.cameraData.renderer.cameraColorTarget, renderingData.cameraData.renderer.cameraDepthTarget);
|
|
#endif
|
|
}
|
|
void SetComputeShader(CommandBuffer cmd, RenderTargetIdentifier tArray, int sSlice, int dSlice, float sW, float sH, float dW, float dH)
|
|
{
|
|
cmd.SetComputeTextureParam(settings.shader, 0, "source", tArray);
|
|
cmd.SetComputeFloatParam(settings.shader, "sx", sW);
|
|
cmd.SetComputeFloatParam(settings.shader, "sy", sH);
|
|
cmd.SetComputeFloatParam(settings.shader, "dx", dW);
|
|
cmd.SetComputeFloatParam(settings.shader, "dy", dH);
|
|
cmd.SetComputeIntParam(settings.shader, "sSlice", sSlice);
|
|
cmd.SetComputeIntParam(settings.shader, "dSlice", dSlice);
|
|
}
|
|
|
|
// Here you can implement the rendering logic.
|
|
// Use <c>ScriptableRenderContext</c> to issue drawing commands or execute command buffers
|
|
// https://docs.unity3d.com/ScriptReference/Rendering.ScriptableRenderContext.html
|
|
// You don't have to call ScriptableRenderContext.submit, the render pipeline will call it at specific points in the pipeline.
|
|
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
|
|
{
|
|
float width = renderingData.cameraData.cameraTargetDescriptor.width;
|
|
float height = renderingData.cameraData.cameraTargetDescriptor.height;
|
|
var cmd = CommandBufferPool.Get("Init Depth Pyramid");
|
|
finalDepthPyramid = Shader.PropertyToID("_DepthPyramid");
|
|
cmd.GetTemporaryRTArray(finalDepthPyramid, (int)width, (int)height, buffersize, 0, FilterMode.Point, RenderTextureFormat.RFloat, RenderTextureReadWrite.Linear, 1, true);
|
|
cmd.SetComputeTextureParam(settings.shader, 1, "source", finalDepthPyramid);
|
|
cmd.DispatchCompute(settings.shader, 1, Mathf.CeilToInt(width / Threads), Mathf.CeilToInt(height / Threads), 1);
|
|
context.ExecuteCommandBuffer(cmd);
|
|
CommandBufferPool.Release(cmd);
|
|
|
|
cmd = CommandBufferPool.Get("Calculate Depth Pyramid");
|
|
cmd.SetExecutionFlags(CommandBufferExecutionFlags.AsyncCompute);
|
|
for (int i = 0; i < buffersize - 1; i++)
|
|
{
|
|
//calculate high z depth for the next scaled down buffer
|
|
SetComputeShader(cmd,
|
|
finalDepthPyramid,
|
|
tempSlices[i],
|
|
tempSlices[i + 1],
|
|
tempSlices[i].resolution.x,
|
|
tempSlices[i].resolution.y,
|
|
tempSlices[i + 1].resolution.x,
|
|
tempSlices[i + 1].resolution.y
|
|
);
|
|
|
|
int xGroup = Mathf.Max(Mathf.CeilToInt(tempSlices[i + 1].resolution.x / Threads), 1);
|
|
int yGroup = Mathf.Max(Mathf.CeilToInt(tempSlices[i + 1].resolution.y / Threads), 1);
|
|
cmd.DispatchCompute(settings.shader, 0, xGroup, yGroup, 1);
|
|
}
|
|
context.ExecuteCommandBufferAsync(cmd, ComputeQueueType.Background);
|
|
CommandBufferPool.Release(cmd);
|
|
|
|
#if UNITY_EDITOR
|
|
if (settings.ShowDebug)
|
|
{
|
|
cmd = CommandBufferPool.Get("Debug Depth Pyramid");
|
|
int debug = Mathf.Clamp(settings.DebugSlice, 0, buffersize - 1);
|
|
#if UNITY_2022_1_OR_NEWER
|
|
cmd.Blit(finalDepthPyramid, colorAttachmentHandle, Vector2.one * tempSlices[debug].scale, Vector2.zero, debug, 0);
|
|
#else
|
|
cmd.Blit(finalDepthPyramid, colorAttachment, Vector2.one * tempSlices[debug].scale, Vector2.zero, debug, 0);
|
|
#endif
|
|
context.ExecuteCommandBuffer(cmd);
|
|
CommandBufferPool.Release(cmd);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
public override void FrameCleanup(CommandBuffer cmd)
|
|
{
|
|
cmd.ReleaseTemporaryRT(finalDepthPyramid);
|
|
}
|
|
}
|
|
|
|
[System.Serializable]
|
|
internal struct Settings
|
|
{
|
|
[HideInInspector] internal ComputeShader shader;
|
|
[SerializeField] internal bool ShowDebug;
|
|
[Range(0, buffersize)]
|
|
[SerializeField] internal int DebugSlice;
|
|
}
|
|
|
|
|
|
[SerializeField] internal ComputeShader depthPyramidShader;
|
|
[SerializeField] Settings settings = new Settings();
|
|
DepthPyramidPass m_ScriptablePass;
|
|
|
|
/// <inheritdoc/>
|
|
public override void Create()
|
|
{
|
|
m_ScriptablePass = new DepthPyramidPass();
|
|
// Configures where the render pass should be injected.
|
|
m_ScriptablePass.renderPassEvent = RenderPassEvent.AfterRenderingGbuffer;
|
|
if (settings.ShowDebug)
|
|
{
|
|
m_ScriptablePass.renderPassEvent = RenderPassEvent.AfterRenderingTransparents;
|
|
}
|
|
}
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
//m_ScriptablePass.Dispose();
|
|
m_ScriptablePass = null;
|
|
}
|
|
|
|
// Here you can inject one or multiple render passes in the renderer.
|
|
// This method is called when setting up the renderer once per-camera.
|
|
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
|
|
{
|
|
if (!renderingData.cameraData.postProcessEnabled)
|
|
{
|
|
return;
|
|
}
|
|
settings.shader = depthPyramidShader;
|
|
m_ScriptablePass.settings = this.settings;
|
|
#if UNITY_EDITOR && UNITY_2022_1_OR_NEWER
|
|
var d = UnityEngine.Rendering.Universal.UniversalRenderPipelineDebugDisplaySettings.Instance.AreAnySettingsActive;
|
|
if (!d)
|
|
{
|
|
renderer.EnqueuePass(m_ScriptablePass);
|
|
}
|
|
#else
|
|
renderer.EnqueuePass(m_ScriptablePass);
|
|
#endif
|
|
}
|
|
}
|
|
} |