HDRP中获取深度值

上一篇 中试图在HDRP中使用自定义的Shader来实现贴花效果,但是在读取深度图来获取深度值时出现了问题,在HDRP中深度图的组织方式发生了改变,变成了多个lod的深度图的图集,像下图这样 。

因此使用原有的 SAMPLE_DEPTH_TEXTURE 方法获取到的深度值变的不正确了。通过在ScriptableRenderPipeline工程的源码中查找加翻阅,发现在 ShaderPassDBuffer.hlsl 中使用了 LOAD_TEXTURE2D(_CameraDepthTexture, input.positionSS.xy).x 来获取深度值,因为是hlsl代码,所以要用hlsl的方式来使用。

读取深度值

要 do it in a hlsl way, 我们需要做以下几项修改:

  1. 把 CGPROGRAM/ENDCG 修改成 HLSLPROGRAM/ENDHLSL,或 CGINCLUDE/ENDCG 修改成 HLSLINCLUDE/ENDHLSL。
  2. 在 HLSLINCLUDE/ENDHLSL 中加入#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/API/D3D11.hlsl",引用其他文件。当然还有必备的 #include "UnityCG.cginc"
  3. sampler2D _CameraDepthTexture; 修改为 TEXTURE2D(_CameraDepthTexture);,HLSL中声明采样器的方式和CG不同,需要用TEXTURE2D而不是sampler2D,在D3D11.hlsl, Metal.hlsl, GLES2.hlsl 等这些文件中都有相应的宏定义。

从源码中可以看到只有 GLES2.hlsl 中把 TEXTURE2D 定义成了 sampler2D,其余的平台则都定义成了 Texture2D 对象。这也是卡了我好几天的地方,当时怎么根据报错提示都没找到问题所在,还是在查看了一些源码后法线应该这么用。教训就是先别急着查报错提示,耐心看看代码的话可能这都不是问题,要引以为戒啊。 这也是卡了我好几天的地方,当时怎么根据报错提示都没找到问题所在,还是在查看了一些源码后法线应该这么用。教训就是先别急着查报错提示,耐心看看代码的话可能这都不是问题,要引以为戒啊。

  1. 计算屏幕坐标,而不是以前使用的纹理坐标。这里使用 ComputeScreenPos 方法的计算结果和 _ScreenParams.xy 的乘积即可获得。

做好了这些修改之后就可以使用 LOAD_TEXTURE2D 或者 LOAD_TEXTURE2D_LOD 方法,对 _CameraDepthTexture 或者 _DepthPyramidTexture 对象进行采样来获取深度值了。具体有以下四种方式:

  1. float depth = LOAD_TEXTURE2D_LOD(_CameraDepthTexture, screenPos, 0).r;
  2. float depth = LOAD_TEXTURE2D(_CameraDepthTexture, screenPos);
  3. float depth = LOAD_TEXTURE2D_LOD(_DepthPyramidTexture, TexCoordStereoOffset(screenPos), 0).r;
  4. float depth = LOAD_TEXTURE2D(_DepthPyramidTexture, screenPos).r;

现在获取到的深度值是非线性的,如果需要变换成线性的深度值则需要再加一句:
depth = Linear01Depth(depth);

_CameraDepthTexture 和 _DepthPyramidTexture

_CameraDepthTexture 图里现在是多个lod深度图的集合,而 _DepthPyramidTexture 看名字叫深度图金字塔图,感觉应该也是一个多个图片的集合。在FrameDebugger中查看渲染事件,发现 _CameraDepthTexture_DepthPyramidTexture 来起来好像没啥区别,再看一下对应的buffer名字,都是 CameraDepthBufferMipChain_960x764_RFloat,感觉应该就是同一块现存,在渲染管线中被赋值给了不同名称的图,如果有知道的同学请留言赐教哈,先感谢了。

在这里插入图片描述

在这里插入图片描述

以下是完整Shader代码:

Shader "MJ/ForwardDecal_HDRP"
{
	Properties
	{
		_MainTex ("Decal Texture", 2D) = "white" {}
	}

	HLSLINCLUDE
	#include "UnityCG.cginc"
	#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/API/D3D11.hlsl"
	ENDHLSL

	SubShader
	{
		Tags{ "Queue"="Geometry+1" }

		Pass
		{
			ZWrite Off
			Blend SrcAlpha OneMinusSrcAlpha

			HLSLPROGRAM
			#pragma target 3.0
			#pragma vertex vert
			#pragma fragment frag
			
			struct v2f
			{
				float4 pos : SV_POSITION;
				float4 screenUV : TEXCOORD0;
				float3 ray : TEXCOORD1;
			};
			
			v2f vert (appdata_base v)
			{
				v2f o;
				o.pos = UnityObjectToClipPos (v.vertex);
				o.screenUV = ComputeScreenPos (o.pos);
				o.ray = UnityObjectToViewPos(v.vertex).xyz * float3(-1,-1,1);

				return o;
			}

			sampler2D _MainTex;

			TEXTURE2D(_CameraDepthTexture);
			TEXTURE2D(_DepthPyramidTexture);
			SAMPLER(sampler_CameraDepthTexture);

			float4 frag(v2f i) : SV_Target
			{
				i.ray = i.ray * (_ProjectionParams.z / i.ray.z);
				float2 uv = i.screenUV.xy / i.screenUV.w;
				
				float2 screenPos = uint2(uv * _ScreenParams.xy);

				// // 方式1 //
				// float depth = LOAD_TEXTURE2D_LOD(_CameraDepthTexture, screenPos, 0).r;

				// // 方式2 //
				// float depth = LOAD_TEXTURE2D(_CameraDepthTexture, screenPos);

				// 方式3 //
				// float depth = LOAD_TEXTURE2D_LOD(_DepthPyramidTexture, TexCoordStereoOffset(screenPos), 0).r;

				// 方式4 //
				float depth = LOAD_TEXTURE2D(_DepthPyramidTexture, screenPos).r;
				
				depth = Linear01Depth(depth);

				float4 vpos = float4(i.ray * depth,1);
				float3 wpos = mul (unity_CameraToWorld, vpos).xyz;
				float3 opos = mul (unity_WorldToObject, float4(wpos,1)).xyz;

				clip (float3(0.5,0.5,0.5) - abs(opos.xyz));
				float2 texUV = opos.xz + 0.5;
				float4 col = tex2D(_MainTex, texUV);
				return col;
			}
			ENDHLSL
		}
	}

	Fallback Off
}
参考链接:
https://forum.unity.com/threads/camera-depth-texture-sampling-with-2018-3-and-hdrp-4-x-mip-map-issue.594160/#post-4127281
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值