深度是一个很重要的概念,能用它做很多效果,比如河流的泡沫,能量球和其他物体的交互,扫描效果等等。这里只介绍深度的主要部分。

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); 
}

posted on 2021-05-02 11:50  魔域大道  阅读(1635)  评论(0)    收藏  举报