URP camera depth query testing

Hello, I tested a way to raycast the scene from the camera without collider, using camera depth texture.
I play with Unity 6000 in URP and rendergraph with a render feature.

I would like to have advises on my work, to know if I do things right.

The render feature :

using UnityEngine.Rendering.Universal;
using UnityEngine;
using System;

public class DepthQueryRenderFeature : ScriptableRendererFeature
{
	[SerializeField] private Shader shader;
	private Material material;
	private DepthQueryRenderPass depthQueryRenderPass;

	public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
	{
		if (!renderingData.cameraData.isSceneViewCamera && !renderingData.cameraData.isPreviewCamera)
		{
			renderer.EnqueuePass(depthQueryRenderPass);
			depthQueryRenderPass.CameraNear = renderingData.cameraData.camera.nearClipPlane;
			depthQueryRenderPass.CameraFar = renderingData.cameraData.camera.farClipPlane;
		}
	}

	/// -0.5,-0.5 is viewport bottom left
	public bool Query(Vector2 position, Action<float> callback)
	{
		if (depthQueryRenderPass != null && depthQueryRenderPass.QueryCallback == null)
		{
			depthQueryRenderPass.QueryPosition = position;
			depthQueryRenderPass.QueryCallback = callback;
			depthQueryRenderPass.QueryPending = true;
			return true;
		}

		return false;
	}

	public override void Create()
	{
		if (shader == null)
		{
			return;
		}
		material = new Material(shader);

		depthQueryRenderPass = new DepthQueryRenderPass(material, 0);
		depthQueryRenderPass.renderPassEvent = RenderPassEvent.AfterRenderingOpaques;
	}
}

The render pass :

using UnityEngine.Rendering.RenderGraphModule;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using System;
using UnityEngine;
using UnityEngine.Rendering.RenderGraphModule.Util;
using Unity.Collections;

public class DepthQueryRenderPass : ScriptableRenderPass
{
	private class PassData
	{
		internal TextureHandle depth;
	}

	private Material blitMaterial;
	private int shaderPass;

	BaseRenderFunc<PassData, UnsafeGraphContext> PassExecuter;
	Action<AsyncGPUReadbackRequest> ReadbackCallback;

	public bool QueryPending;
	public Action<float> QueryCallback;
	public Vector2 QueryPosition;
	public float CameraNear;
	public float CameraFar;

	public DepthQueryRenderPass(Material blitMaterial, int shaderPass)
	{
		this.blitMaterial = blitMaterial;
		this.shaderPass = shaderPass;
		PassExecuter = ExecuteReadbackPass;
		ReadbackCallback = Readback;
	}

	public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
	{
		if (QueryPending)
		{
			QueryPending = false;
			UniversalResourceData resourceData = frameData.Get<UniversalResourceData>();

			//Readback texture
			TextureHandle readBackTexture = UniversalRenderer.CreateRenderGraphTexture(
				renderGraph
				, new RenderTextureDescriptor(1, 1, RenderTextureFormat.RFloat, 0)
				, "DepthQueryReadbackTexture"
				, false
			);
		
			//Blit camera depth to readback texture
			renderGraph.AddBlitPass(
				new RenderGraphUtils.BlitMaterialParameters(
					resourceData.cameraDepthTexture, readBackTexture
					, new Vector2(1, 1), QueryPosition
					, blitMaterial, 0
				),
				"DepthQueryBlit"
			);

			//Readback
			using (var builder = renderGraph.AddUnsafePass<PassData>("DepthQueryReadback", out var passData))
			{
				ConfigureInput(ScriptableRenderPassInput.Depth);
				passData.depth = readBackTexture;
				builder.UseTexture(passData.depth, AccessFlags.Read);
				builder.AllowPassCulling(false);
				builder.SetRenderFunc(PassExecuter);
			}
		}
	}

	void ExecuteReadbackPass(PassData passData, UnsafeGraphContext context)
	{
		CommandBuffer unsafeCommandBuffer = CommandBufferHelpers.GetNativeCommandBuffer(context.cmd);		

		var array = new NativeArray<float>(1, Allocator.Persistent);
		unsafeCommandBuffer.RequestAsyncReadbackIntoNativeArray(
			ref array,
			passData.depth, 0, 0, 1, 0, 1, 0, 1, UnityEngine.Experimental.Rendering.GraphicsFormat.R32_SFloat
			, ReadbackCallback
		);
	}

	float LinearEyeDepth(float z)
	{		
		var zpx = -1.0f + CameraFar / CameraNear;
		var zpy = 1.0f;
		var zpz = zpx / CameraFar;
		var zpw = zpy / CameraFar;

		return 1.0f / (zpz * z + zpw);
	}

	private void Readback(AsyncGPUReadbackRequest request)
	{
		if (!request.hasError)
		{			
			var array = request.GetData<float>();
			QueryCallback(LinearEyeDepth(array[0]));
			if(!QueryPending) QueryCallback = null;
			array.Dispose();
		}
	}
}

The shader :

Shader "Custom/DepthQuery"
{
    HLSLINCLUDE
    
    #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
    // The Blit.hlsl file provides the vertex shader (Vert),
    // the input structure (Attributes), and the output structure (Varyings)
    #include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
    #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"

    float4 Frag(Varyings IN) : SV_Target
    {
        #if UNITY_REVERSED_Z
            float depth = SampleSceneDepth(IN.texcoord);
        #else
            // Adjust z to match NDC for OpenGL
            float depth = lerp(UNITY_NEAR_CLIP_VALUE, 1, SampleSceneDepth(IN.texcoord));
        #endif

        return depth;
    }

ENDHLSL

    SubShader
    {
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            HLSLPROGRAM

            #pragma vertex Vert
            #pragma fragment Frag

            ENDHLSL
        }
    }
}

The raycasting behaviour :

using System;
using UnityEngine;

public class Raycaster : MonoBehaviour
{
	public Camera QueryCamera;
	public DepthQueryRenderFeature DepthQueryFeature;
	
	Action<float> queryCallback;
	Ray queryRay;
	float queryCosAngle;

	private void Start()
	{
		queryCallback = QueryCallback;
	}

	void Update()
    {
		if (Input.GetMouseButtonUp(0))
		{
			//Get the world ray from camera origin
			queryRay = QueryCamera.ScreenPointToRay(Input.mousePosition);
			queryRay.origin = QueryCamera.transform.position; //use camera origin instead of near clip plane because the query will return distance from origin plane

			//Compute the ratio between query distance (from origin plane) and real world distance from camera origin
			queryCosAngle = Vector3.Dot(queryRay.direction, QueryCamera.transform.forward);

			//Start depth query
			DepthQueryFeature.Query(
				new Vector2(Input.mousePosition.x / Screen.width - 0.5f, Input.mousePosition.y / Screen.height - 0.5f),
				queryCallback
			);
		}
	}

	private void QueryCallback(float depth)
	{
		var worldPosition = queryRay.origin + queryRay.direction * depth / queryCosAngle;		
		CreateSphere(worldPosition);
	}

	private static void CreateSphere(Vector3 worldPosition)
	{
		var go = GameObject.CreatePrimitive(PrimitiveType.Sphere);
		go.transform.position = worldPosition;
		go.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
	}
}