2026-03-18 20:09:32 +03:00

175 lines
5.2 KiB
C#

using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
public class DepthRenderPassFeature : ScriptableRendererFeature
{
class DepthRenderPass : ScriptableRenderPass
{
public static Queue<bool> Requests;
public static Queue<float[]> Answers;
ProfilingSampler m_ProfilingSampler = new ProfilingSampler("ColorBlit");
private Material material;
private RTHandle rtHandle;
private bool depth = false;
private ComputeBuffer computeBuffer;
public DepthRenderPass(Material material)
{
this.material = material;
Requests = new Queue<bool>();
Answers = new Queue<float[]>();
}
public void SetTarget(RTHandle handle, bool depth)
{
rtHandle = handle;
this.depth = depth;
if (computeBuffer != null) DestroyComputeBuffer();
RenderTexture rt = rtHandle.rt;
computeBuffer = new ComputeBuffer(rt.width * rt.height, 1 * sizeof(float));
if(material != null)
{
material.SetBuffer("distBuffer", computeBuffer);
material.SetFloat("res", rt.height);
}
}
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
ConfigureTarget(rtHandle);
}
// 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)
{
if (!depth) return;
CommandBuffer cmd = CommandBufferPool.Get();
//RTHandle rt = renderingData.cameraData.renderer.cameraColorTargetHandle;
using (new ProfilingScope(cmd, m_ProfilingSampler))
{
Blitter.BlitCameraTexture(cmd, rtHandle, rtHandle, material, 0);
if(Requests.Count > 0)
{
Requests.Dequeue();
float[] resultArray = new float[computeBuffer.count];
computeBuffer.GetData(resultArray);
Answers.Enqueue(resultArray);
}
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
// Cleanup any allocated resources that were created during the execution of this render pass.
public override void OnCameraCleanup(CommandBuffer cmd)
{
}
public void Dispose()
{
#if UNITY_EDITOR
if (EditorApplication.isPlaying)
{
Destroy(material);
}
else
{
DestroyImmediate(material);
}
#else
Destroy(material);
#endif
if (rtHandle != null) rtHandle.Release();
if (computeBuffer != null)
{
DestroyComputeBuffer();
}
if (Requests != null)
{
Requests.Clear();
Requests = null;
}
if (Answers != null)
{
Answers.Clear();
Answers = null;
}
}
public void DestroyComputeBuffer()
{
computeBuffer.Release();
computeBuffer = null;
}
}
[SerializeField] Shader shader;
[SerializeField] bool Depth = false;
DepthRenderPass m_ScriptablePass;
Material material;
/// <inheritdoc/>
public override void Create()
{
if(shader == null) shader = TexturesSettings.Instance.DepthShader;
material = CoreUtils.CreateEngineMaterial(shader);
m_ScriptablePass = new DepthRenderPass(material);
// Configures where the render pass should be injected.
m_ScriptablePass.renderPassEvent = RenderPassEvent.AfterRenderingOpaques;
}
// 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.camera.tag == "Eye")
{
renderer.EnqueuePass(m_ScriptablePass);
}
}
public override void SetupRenderPasses(ScriptableRenderer renderer, in RenderingData renderingData)
{
m_ScriptablePass.ConfigureInput(ScriptableRenderPassInput.Color);
m_ScriptablePass.SetTarget(renderer.cameraColorTargetHandle, Depth);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
#if UNITY_EDITOR
if (EditorApplication.isPlaying)
{
Destroy(material);
}
else
{
DestroyImmediate(material);
}
#else
Destroy(material);
#endif
m_ScriptablePass.Dispose();
}
}