Shader学习的基础知识(二十四)深度纹理和法线纹理

版权声明:版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ww1351646544/article/details/88571129

原理

Unity里取深度和法线很简单,但是我们还是要知道一下它的原理。
深度纹理记录的是不是像素值,而是深度值0~1之间,而且是非线性分布的。深度值来自于变换后得到的归一化的设备坐标。如果一个模型要想显示在屏幕上,要把它的顶点从模型空间变到齐次空间下,当我们使用透视摄像机时这个投影就是非线性的。

深度纹理可以直接来自于真正的深度缓存,也可以由一个单独的Pass渲染得到。unity会把标签RenderType为Opaque的物体且它使用队列小于2500的,就把它的深度和法线渲染出来,存在深度纹理和法线纹理中。我们可以让一个摄像机生成一张深度纹理或是一张深度+法线纹理。

着色器替换技术,选取需要的不透明的使用它投射使用的Pass(即LightMode为ShadowCaster得来到深度纹理。如果Shader中不包含这种Pass,则不会有深度纹理)

深度纹理通常有24或16位,如果深度+法线纹理则为32位,法线信息会写进R和G通道,深度则是B和A通道。

如何获取

通过以下代码即可获取:

camera.depthTextureMode=DepthTextureMode.Depth;

一旦设置好上面的摄像机模式后,我们就可以在Shader中通过CmaeraDepthNormalsTexture来访问了

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

访问_CameraDepthTexture后就可以对纹理坐标进行采样。绝大多数情况下使用tex2D即可。
SAMPLE_DEPTH_TEXTURE用来处理平台差异问题。

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

i.uv是一个float2对应了当前像素的纹理坐标。类似的还有
SAMPEL_DEPTH_TEXTURE_PROJ:接受两个参数深度纹理和一个float3和float4类型的纹理坐标,内部使用了tex2Dproj进行投影纹理采样,通常用于阴影的实现。
SAMPLE_DEPTH_TEXTURE_LOD:第二个参数通常是由顶点着色器输出插值而得的屏幕坐标,例如:

float d = SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture,UNITY_PROJ_COORD(i.scrPos));

i.scrPos就顶点着色器中能过调用ComputeScreenPos(o.pos)得到的屏幕坐标。

常用的辅助函数

LinearEyeDepth:负责把深度纹理的采样转到视角空间下的深度值。
Linear01Depth:返回一个0~1的线性深度值 。
如果需要得到深度+法线纹理,可以直接使用tex2D对_CameraDepthNormalsTexture进行采样。
DecodeDepthNormal:的第一个参数是对深度+法线采样的结果0~1;
也可以通过DecodeFloatRG和DecodeViewNormalStereo来解码深度+法线纹理中的深度法线信息。

查看深度和法线纹理

可以用帧调试器Freame Debugger来查看,如果发现几乎全白的可以把远截面调小即可。
一般显示出线性空间下的信息或解码后的法线方向 会更加有用。
我们可以利用下面代码输出线性深度值:

float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv);
float linearDepth=Linear01Depth(depth);
return fixed4(linearDepth,linearDepth,linearDepth,1.0);

或是输出法线方向:

fixed3 normal=DecodeViewNormalStereo(tex2D(_CameraDepthNormalsTexture,i.uv).xy);
return fixed4(normal*0.5+0.5,1);

基础说到这,后面开始讲实例。

猜你喜欢

转载自blog.csdn.net/ww1351646544/article/details/88571129