US3S11L1——屏幕深度和法线纹理的使用

深度和法线纹理的使用

使用屏幕深度和法线纹理,一般分两步:

  1. 让 Unity 知道我们需要使用深度和法线纹理

    1
    2
    3
    4
    5
    6
    private void Start()
    {
    Camera.main.depthTextureMode = DepthTextureMode.Depth; // 获取一张深度纹理
    Camera.main.depthTextureMode = DepthTextureMode.DepthNormals; // 获取一张深度+法线纹理
    Camera.main.depthTextureMode = DepthTextureMode.Depth | DepthTextureMode.DepthNormals; // 获取深度纹理 和 深度+法线纹理
    }
  2. 在 Shader 当中直接声明对应变量

    • 深度纹理

      1
      sampler2D _CameraDepthTexture;
    • 深度+法线纹理:

      其中,_CameraDepthNormalsTexture.rg​ 一般存储屏幕法线消息,_CameraDepthNormalsTexture.ba​ 一般存储屏幕深度消息

      1
      sampler2D _CameraDepthNormalsTexture;

    之后直接在 Shader 中使用这两个变量便可以获取到相关信息

使用深度和法线纹理需要的内置函数

对于以下内置函数的原理,详见:US3S11L2——深度和法线纹理背后的原理

  1. 获取深度纹理的深度值

    首先需要使用 SAMPLE_DEPTH_TEXTURE()​ 宏对 _CameraDepthTexture​ 采样,此时得到的采样结果是非线性的,
    然后,使用 LinearEyeDepth()​ 将非线性的深度值转换到观察空间下,
    或者,使用 Linear01Depth()​ 将采样结果转换为 [0,1] 区间内的线性深度值(此方法不需要和 LinearEyeDepth()​ 配合使用!)

    1
    2
    3
    4
    5
    6
    fixed4 frag(v2f i) : SV_Target
    {
    float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv); // 使用基本深度纹理采样,得到的结果是非线性的
    float viewDepth = LinearEyeDepth(depth); // 将非线性的深度值转换到观察空间下
    float linearDepth = Linear01Depth(depth); // 将非线性的深度值转换为[0,1]区间内的线性深度值
    }
  2. 获取深度+法线纹理的法线消息

    其中,DecodeViewNormalStereo()​ 是 UnityCG.cginc​ 内置文件中的方法,用于同时得到深度值和法线消息
    DecodeFloatRG()​ 可以单独得到深度值,DecodeViewNormalStereo()​ 可以单独得到法线消息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    fixed4 frag(v2f i) : SV_Target
    {
    float depth; // 用于存储深度值的变量
    float3 normals; // 用于存储法线的变量
    float4 depthNormal = tex2D(_CameraDepthNormalsTexture, i.uv); // 对深度+法线纹理进行采样(xy是法线消息,zw是深度消息)
    DecodeDepthNormal(depthNormal, depth, normals); // 一次处理得到深度值和法线消息
    depth = DecodeFloatRG(depthNormal.zw); // 单独得到深度值
    normals = DecodeViewNormalStereo(depthNormal); // 单独得到法线消息
    }