C for Graphic:深度图原理(一)

      前段时间玩塞尔达传说荒野之息,其中释放三大技能的场景扫描效果很实用,其中涉及到一个深度图的原理及应用,下面我们先了解一下深度图的意义。

      我们知道渲染流程中顶点变换过程,其中建模到世界到视口到裁剪到ndc这几个空间变换过程中,在视口空间就产生了z值,也就是顶点到camera的距离值,而这个z值在ndc空间中则变成了包含8bit的数值,当然我们也可以进行归一化了。而引擎一般都提供我们直接获取当前渲染场景这一帧的每个像素的深度信息,因为为了访问存储的便利性,所以和帧画幅一样创建一张名为深度图的贴图进行储存。顺便说一下,一般只适用RGBA四通道的R通道进行z值储存就行了。

       如果我们长期坚持写shader,那么我们也就知道一般shader中texture全部都是用来储存信息的,或者换句话说,shader中涉及到大量数据引用传递都会使用texture,一方面是texture根据像素分量可以储存很大的数据量(比如512*512*RGB(3byte)),另一方面tex2D这种高效率的texture采样函数可以快速方便将其中数据进行提取。所以场景深度信息使用texture进行存储和tex2D采样提取就变得非常实用。

       下面来看下unity如何进行深度图提取,c# shader代码如下:

       

using UnityEngine;

public class DepthTex : MonoBehaviour
{
    public Material mEffectMaterial;
    private Camera mMainCamera;

    void Start()
    {
        //直接可以设置camera的rt为depthtexture类型,然后进行depth贴图数据传递
        mMainCamera = GetComponent<Camera>();
        mMainCamera.depthTextureMode = DepthTextureMode.Depth;
    }

    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        Graphics.Blit(source, destination, mEffectMaterial);
    }

}

      

Shader "Unlit/DepthShader"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
				float4 uv : TEXCOORD0;
            };

            struct v2f
            {
				float4 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };
            
            //unity方便我们直接使用_CameraDepthTexture接受场景camera提供的深度图
			sampler2D _CameraDepthTexture;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
				//顶点经过mvp变换后,在计算在屏幕中的坐标参数,如xy的w化数值
				//这个计算不理解的可以查看屏幕空间相关计算
				o.uv = ComputeScreenPos(o.vertex);
                return o;
            }

			fixed4 frag (v2f i) : SV_Target
            {
                //对深度图进行采样,会发现只有R通道储存深度信息
				fixed4 col = tex2D(_CameraDepthTexture,i.uv.xy / i.uv.w);
				return col;
            }
            ENDCG
        }
    }
}

       然后运行可以观察到屏幕后期效果变成了这样,一张R通道的深度图,如下:

  

  观察framedebugger中的原始深度图也是一样,如下:

 

       这是R通道表现的图,那么我们怎么把他变成一般情况下的深度图呢?什么叫一般情况呢?就是将R通道储存的深度z转换为RGB三通道0-1区间的归一化情况。

       继续修改shader代码,进行R通道解码转化,如下:

       unitycg.cginc提供了解码深度图的函数,如下:

 

 

 然后shader代码的片段函数中进行解码转换即可,如下:

 

Shader "Unlit/DepthShader"
{
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
				float4 uv : TEXCOORD0;
            };

            struct v2f
            {
				float4 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

			sampler2D _CameraDepthTexture;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
				//顶点经过mvp变换后,在计算在屏幕中的坐标参数,如xy的w化数值
				//这个计算不理解的可以查看屏幕空间相关计算
				o.uv = ComputeScreenPos(o.vertex);
                return o;
            }

			fixed4 frag (v2f i) : SV_Target
			{
				//只需要将深度图的R通道进行Linear01Depth操作就能得到
				fixed depth = Linear01Depth(tex2D(_CameraDepthTexture,i.uv.xy / i.uv.w).r);
				return fixed4(depth, depth, depth, 1);
			}
            ENDCG
        }
    }
}

最终实现的效果图如下:

     很好理解吧,距离摄像机越近的z值越趋近于0,所以采样转换后的颜色越黑,越远则z值越趋近于1,表现效果则是越白。

     这里顺便抛出一个问题,就是为什么深度信息提取需要Linear01Depth和_ZBufferParams,原因是因为R通道的深度值并不是线性的,而是离散到从密集到稀松的,这里因为我现在办公台还没带上自动铅笔/白纸和尺规等工具,只能后面来推导一下这个计算过程的意义了。

     好,写到这里,我们大致对深度图有了一定的了解,接下来的一段时间我要在独立游戏中实现一些效果,就会使用到深度图了,后面见。

    

     

 

获取场景中各点相对于摄象机的距离是计算机视觉系统的重要任务之.场景中各点相对于摄象机的距离可以用深度图(Depth Map)来表示,即深度图中的每个像素值表示场景中某点与摄像机之间的距离.机器视觉系统获取场景深度图技术可分为被动测距传感和主动深度传感两大类.被动测距传感是指视觉系统接收来自场景发射或反射的光能量,形成有关场景光能量分布函数,即灰度图像,然后在这些图像的基础上恢复场景的深度信息.最般的方法是使用两个相隔定距离的摄像机同时获取场景图像来生成深度图.与此方法相类似的另种方法是个摄象机在不同空间位置上获取两幅或两幅以上图像,通过多幅图像的灰度信息和成象几何来生成深度图.深度信息还可以使用灰度图像的明暗特征、纹理特征、运动特征间接地估算.主动测距传感是指视觉系统首先向场景发射能量,然后接收场景对所发射能量的反射能量.主动测距传感系统也称为测距成象系统(Rangefinder).雷达测距系统和三角测距系统是两种最常用的两种主动测距传感系统.因此,主动测距传感和被动测距传感的主要区别在于视觉系统是否是通过增收自身发射的能量来测距。另外,我们还接触过两个概念:主动视觉和被动视觉。主动视觉是种理论框架,与主动测距传感完全是两回事。主动视觉主要是研究通过主动地控制摄象机位置、方向、焦距、缩放、光圈、聚散度等参数,或广义地说,通过视觉和行为的结合来获得稳定的、实时的感知。我们将在最后节介绍主动视觉。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值