深度是一个很重要的概念,能用它做很多效果,比如河流的泡沫,能量球和其他物体的交互,扫描效果等等。这里只介绍深度的主要部分。
struct appdata_t { float4 vertex : POSITION; fixed4 color : COLOR; float2 texcoord : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct v2f { float4 vertex : SV_POSITION; fixed4 color : COLOR; float2 texcoord : TEXCOORD0; UNITY_FOG_COORDS(1) #ifdef SOFTPARTICLES_ON float4 projPos : TEXCOORD2; #endif UNITY_VERTEX_OUTPUT_STEREO }; v2f vert(appdata_t v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); #ifdef SOFTPARTICLES_ON //计算顶点在屏幕空间的位置(没有进行透视除法) o.projPos = ComputeScreenPos (o.vertex); //计算顶点距离相机的距离 COMPUTE_EYEDEPTH(o.projPos.z); #endif} fixed4 frag (v2f i) : SV_Target { //根据上面的屏幕空间位置,进行透视采样深度图(tex2dproj,即带有透视除法的采样,相当于tex2d(xy/w)), //SAMPLE_DEPTH_TEXTURE_PROJ得到的深度是非线性的 float sceneZ = LinearEyeDepth (SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos))); //像素点在视空间的深度 float partZ = i.projPos.z; //然后sceneZ和partZ同在视觉空间中比较大小。 }
这里主要介绍透视投影哈。假设视觉空间时顶点的坐标为P_view=(x_view,y_view,z_view,1),顶点从视觉空间转到裁剪空间后,得到P_clip=(wx,wy,wz,w),这个w=-z_view。即z_view是顶点在视觉空间中的z值,z的范围在视锥体的[near,far]之间。那这个w=-z_view怎么得的捏?直到我遇到了投影矩阵。
投影矩阵公式是(图片来自shader入门精要)

P_view左乘该投影矩阵,我们只看P_view与投影矩阵最后一行的点乘,即x_view*0+y_view*0+z_view*(-1)+1*0=-z_view,等于裁剪空间中的w,即-z_view=w.
代码里的COMPUTE_EYEDEPTH(o.projPos.z),该宏定义在UnityCG.cginc里
#define COMPUTE_EYEDEPTH(o) o=-UnityObjectToViewPos(v.vertex).z 设置o为当前顶点视空间的z值
#define DECODE_EYEDEPTH(i) LinearEyeDepth(i)
Linear01Depth和LinearEyeDepth都是从深度图的深度值去反推视觉空间的z值,是线性的。
inline float Linear01Depth(float z) { //得到的这个值是视觉空间的z值,即z_view。因为除以f(远裁剪面),所以范围就在0到1之间. return 1.0/(_ZBufferParams.x*z+_ZBufferParams.y); }
inline float LinearEyeDepth(float z) { //得到的这个值是视觉空间的z值,即z_view return 1.0/(_ZBufferParams.z*z+_ZBufferParams.w); }

浙公网安备 33010602011771号