之前关于深度图的应用效果,都是基于屏幕后期处理的,也就是在camera的后期渲染深度图的基础上进行shader编写,这样的话局限性也挺大的,因为只能做后期特效,而不能和forwardbase下的场景物体进行shader层面的“交互”,后面我看到一个函数,或者说一类函数,专门用来处理forwardbase下深度图的使用,如下:
先来看看官方解释,如下:
这里我们看一看就知道主要就是使用COMPUTE_EYEDEPTH宏函数了(UNITY_TRANSFER_DEPTH已经被unity不建议使用了),在vertex顶点函数中计算视口空间的depth储存到浮点数变量o,当然了顺便说一下既然这个是计算视口空间的depth,那么我们采样camera深度图的时候就要用DECODE_EYEDEPTH也就是LinearEyeDepth函数,我们要统一空间也就是变量区间,函数如下:
这个函数也将深度图中R通道处理成线性的视口空间深度z,这里暂时立一个flag,等我五一后把我的“作业”工具带来再来推算,和Linear01Depth,起码得搞个所以然出来,这里我们暂时先用着。
当然先来通过shader了解一下COMPUTE_EYEDEPTH这个函数的作用,如下:
Shader "Unlit/DepthViewZShader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Far("Camera Far Plane",float) = 0
_Near("Camera Near Plane",float) = 0
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float viewZ : TEXCOORD1;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float _Far; /*摄像机的far*/
float _Near; /*摄像机的near*/
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
//获取视口空间中z值
COMPUTE_EYEDEPTH(o.viewZ);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
//因为viewZ是视口空间的,那么需要通过far/near转换到0-1
float depth = (i.viewZ - _Near)/(_Far - _Near);
//替换掉原来的纹理采样,进行深度信息的渲染显示
col = fixed4(depth, depth, depth, 1);
return col;
}
ENDCG
}
}
}
效果如下:
能看出来原来的纹理采样被深度信息显示覆盖了,而且正确显示。
接下来我们通过这个函数与camera后期渲染的深度信息进行“交互”,比如我在其他博客中看到的深度相交操作,就是当前物体的深度与当前camera深度图某个区域的深度约等于时,做一个“轮廓描边”,shader如下:
Shader "Unlit/DepthIntersectShader"
{
Properties
{
_MainTex("Texture",2D) = "white" {}
_IntersectColor("Intersect Color", Color) = (1,1,1,1)
_IntersectDivide("Intersect Divide Deniminator",Range(0,5)) = 0
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float4 screenPos : TEXCOORD1;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 screenPos : TEXCOORD1;
float viewZ : TEXCOORD2;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _CameraDepthTexture; /*unity传递当前场景深度图*/
float4 _IntersectColor; /*相交区域颜色*/
float _IntersectDivide; /*相交区域的除法换算分母*/
v2f vert (appdata v)
{
v2f o;
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.vertex = UnityObjectToClipPos(v.vertex);
//获取屏幕坐标用于深度图采样解码
o.screenPos = ComputeScreenPos(o.vertex);
//获取当前顶点的视口坐标z值
COMPUTE_EYEDEPTH(o.viewZ);
return o;
}
fixed4 blendColor(fixed4 col, fixed4 iCol, float wei)
{
return wei * col + (1 - wei)*iCol;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex,i.uv);
//采样深度图R通道转到视口空间,并处理成线性数值
float depthZ = LinearEyeDepth(tex2D(_CameraDepthTexture, i.screenPos.xy / i.screenPos.w).r);
//通过顶点视口z值和当前深度图视口z值的差值,再除_IntersectDivide得到一个权重值wei
//那么这个wei随着viewZ和depthZ相差越小则越趋近于0,也就是顶点视口z与当前深度图像素视口z越接近wei越小
float wei = saturate(abs(i.viewZ - depthZ) / _IntersectDivide);
//混合maintex采样颜色和_IntersectColor,wei越小则越接近_IntersectColor
//实际的场景表现效果则是顶点越接近其他深度相同的物体时,相交部分则更表现出_IntersectColor
return blendColor(col, _IntersectColor, wei);
}
ENDCG
}
}
}
效果图如下:
很容易理解,就是当物体靠近深度值相近的物体的时候,wei值越小,则_IntersectColor表现越明显,也就是越红。
好了,这篇写到这里,后面我们继续。