unityshader中可以通过直接对_CameraDepthTexture采样的方式,获取Camera生成图像的深度,甚至对这个纹理的采样,都已经有了封装好的函数SampleSceneDepth,源码可见
使用SampleSceneDepth时,需要include它的源文件
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
使用样例
half4 frag(Varyings IN) : SV_Target
{
// To calculate the UV coordinates for sampling the depth buffer,
// divide the pixel location by the render target resolution
// _ScaledScreenParams.
float2 UV = IN.positionHCS.xy / _ScaledScreenParams.xy;
// Sample the depth from the Camera depth texture.
#if UNITY_REVERSED_Z
real depth = SampleSceneDepth(UV);
#else
// Adjust Z to match NDC for OpenGL ([-1, 1])
real depth = lerp(UNITY_NEAR_CLIP_VALUE, 1, SampleSceneDepth(UV));
#endif
return depth;
}
写好该采样深度的shader后,在renderfeature中使用该shader的material对相机图像进行处理,即可得到深度图
注意这里根据相机图像大小生成一张临时的texture,若直接使用固定的大小的texture,则可能只在相机的rendertarget上渲染出一小部分,并不能获取整张图像的深度图
RenderTexture temporaryRT = RenderTexture.GetTemporary(windowSize.x, windowSize.y);
cmd.Blit(source, temporaryRT, settings.blitMaterial);
cmd.Blit(temporaryRT, source);
这里采样得到的depth是(0,1)范围的值
对该深度图进行采样时,将坐标转换到NDC后,将坐标变换到(0,1)的范围
float3 pos = ndcSpacePos.xyz * 0.5 + 0.5;
然后用pos.xy作为uv,对深度图进行采样,采样后得到该点的深度值depth
若要再将该点坐标转换到其他空间,需要先将坐标值转化到ndc中(有点疑问,为什么depth不需要也变换到(-1,1),unity默认的ndc的z坐标为(0,1)吗?)
float3 ndcPos = float3(2 * pos.xy - 1, depth);
得到ndc坐标后,便可用空间变换矩阵对该点坐标进行空间变换了