获取深度和法线纹理 背后的原理【Unity Shader入门精要13.1.1】

 

13.1.1背后的原理

什么是深度纹理:

实际上就是一张渲染纹理,只不过它里面储存的像素值不是颜色值,而是一个高精度的深度值,由于被储存在一张纹理中,深度纹理里的深度范围是[0,1],而且通常是 非线性分布的。

深度值来自顶点变换后得到的归一化的设备坐标(Normalized Device Coordinates,NDC)

一个模型想要最终被绘制在屏幕上,需要把它的顶点从模型空间变换到齐次裁剪坐标系下,这是通过在顶点着色器中乘以MVP变换矩阵得到的,在变换的最后一步,需要使用一个投影矩阵来变换顶点。当用的是透视投影类型的摄像机时,这个投影矩阵就是非线性的了。正交投影使用的变换矩阵是线性的。

线性关系:两个变量之间存在 一次方函数 关系

线性回归:(Linear Regression)利用线性回归方程的最小平方幻术对一个或多个自变量之间的关系进行建模的一种回归分析。

深度值对应了NDC中顶点坐标的Z分量的值,由于NDC中Z分量的范围是[0,1],为了让这些值能储存在一张图像中,需要进行映射:

映射公式:  d=0.5\cdot z_{ndc}+0.5


如何得到深度纹理:

在Unity中,深度纹理来自于:

【1】直接来自于真正的深度缓存:当使用 延迟渲染路径(包括遗留的延迟渲染路径)时,可以访问到,信息储存在G-buffer中。

【2】由一个单独的Pass渲染得到:无法直接获取深度缓存时

实现:unity使用着色器替换(Shader Replacement)技术选择渲染类型(即SubShader的RenderType标签)为Opaque的物体,判断他们使用的渲染队列是否小于等于(内置的Background,Geometry和AlphaTest渲染队列均在此范围内),如果满足条件,就把他渲染到深度和法线纹理中,因此,想让物体能够出现在深度和法线纹理中,就必须在shade中设置正确的RenderType标签。

在unity中,可以让一个摄像机生成一张深度纹理 或 一张深度纹理 + 法线纹理

一:生成一张深度纹理:

  1. unity直接获取深度缓存
  2. 用着色器替换技术,选取需要的不透明物体,并使用它投射阴影时使用的Pass(即LightMode被设置为ShadowCaster的PSS)得到深度纹理,如果Shader中不包含这样一个Pass,那这个物体就不会出现在深度纹理中(当然,它也就不能向其他物体投射阴影)
  • 深度纹理的精度通常是24位或16位,这取决于使用的深度缓存的精度

二: 一张深度纹理 + 法线纹理:

  • unity会创建一张和屏幕分辨率相同,精度为32位(每个通道为8位,四个通道)的纹理,其中观察空间下的法线信息会被编码进纹理的R和G通道,深度信息会被编码进B和A通道。

法线信息的获取在延迟渲染中是可以非常容易就得到的,unity只需要合并深度和法线缓存即可,而在向前渲染中,默认情况下是不会创建法线缓存的,因此unity底层使用了一个单独的pass把整个场景再渲染一遍来完成,


13.1.2如何获取

深度纹理的获取

1>脚本中设置摄像机的depthTexture

camera.depthTextureMode=DepthTextureMode.Depth;

2>在shader中声明_CameraDepthTexture变量来访问

获取深度加法线

1>脚本中设置摄像机的depthTexture

camera.depthTextureMode=DepthTextureMode.DepthNormals;

2>在shader中声明_CameraDepthNormalsTexture变量来访问,

同时产生一张深度 和 深度加法线纹理

1>脚本中设置摄像机的depthTexture

camera.depthTextureMode|=DepthTextureMode.Depth;
camera.depthTextureMode|=DepthTextureMode.DepthNormals;

2>在shader中声明_CameraDepthTexture变量来访问深度,声明_CameraDepthNormalsTexture变量来访问深度加法线,

可以在摄像机的Camera组件上看到当前摄像机是否需要渲染深度或深度加法线

当在shader中访问到深度纹理_CameraDepthTexture后,就可以使用当前像素的纹理坐标对它进行采样,绝大多数情况下直接使用tex2D函数采样即可,但在你某些平台上(如PS3和PSP2),需要进行一些特殊处理,用unity提供的内置宏

【SAMPLE_DEPTH_TEXTURE】宏用来处理平台差异

float d =SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv);

i.uv:float2的类型的变量,对应了当前像素的纹理坐标

......................巴拉巴拉 ...........P269

当通过纹理采样得到深度值后,这些值旺旺是非线性的,这种非线性来自于透视投影使用的裁剪矩阵。然而计算过程中通常是需要线性的深度值

猜你喜欢

转载自blog.csdn.net/ABigDeal/article/details/84072584