概述
在Build in渲染管线下,获取深度图、法线图很简单。但是在URP下,获取深度图很简单,但是并没有提供对获取法线图的支持。本文主要参考Build in渲染管线下获取法线图的原理,在URP下获取法线图。
一、Build in渲染管线中获取法线图
在Build in渲染管线中,获取法线图很简单,在脚本中添加如下代码,然后挂在相机上即可。这样,深度、法线信息就会存储在名为_CameraDepthNormalsTexture的图中,在Shader中可以采样该图获取深度、法线信息。
1 | Camera.main.depthTextureMode = DepthTextureMode.DepthNormals; |
使用Frame Debugger调试,可以发现,渲染法线图的Pass使用的Shader是Hidden/Internal-DepthNormalsTexture。那么,可以想到的一种方式是,模仿该Shader,在URP中添加生成法线图的Pass。
二、URP中获取法线图
从Unity官网下载一份Build in的Shader文件,解压后,上述的Shader的位置为DefaultResourcesExtra/Internal-DepthNormalsTexture.shader。先关注渲染不透明物体的SubShader,如下:
1 | SubShader |
在顶点着色器中,通过COMPUTE_VIEW_NORMAL计算出观察空间下的法线,通过COMPUTE_DEPTH_01计算出观察空间中\([0,1]\)范围内的深度值。上述两个方法的具体实现,都可以在UnityCG.cginc文件中找到:
1 | #define COMPUTE_DEPTH_01 -(UnityObjectToViewPos( v.vertex ).z * _ProjectionParams.w) |
在片元着色器中,通过EncodeDepthNormal方法将深度和法线信息渲染到一张图中,而EncodeDepthNormal的具体实现也可以在UnityCG.cginc文件中找到:
1 | inline float4 EncodeDepthNormal( float depth, float3 normal ) |
而EncodeDepthNormal里面又调用了两个内置的方法,同样可以找到:
1 | // Encoding/decoding view space normals into 2D 0..1 vector |
1 | // Encoding/decoding [0..1) floats into 8 bit/channel RG. Note that 1.0 will not be encoded properly. |
这样,我们就可以实现把Internal-DepthNormalsTexture.shader改写成符合URP的形式,代码如下。
Shader有了,怎么调用呢?这里就需要用到了Renderer Feature了。
模仿URP内置的一些Renderer Feature,我们可以实现自己的获取法线图的Renderer Feature。这里需要新建两个脚本,一个是DepthNormalsFeature.cs,另一个是DepthNormalsPass.cs。至于具体的原理,可以参考我之前的博客。
然后,在ForwardRenderer资源中添加上述DepthNormalsFeature,这样,就可以调用DepthNormalsPass了。
三、显示法线图
上面只是生成了法线图,但是如果没有其他操作的话,我们并不能看到法线图。那么怎么才能看到法线图呢?
答案是使用后处理,具体的实现可以参考练习项目(四):深度图基础及应用中的“1、渲染深度图”部分。
这里也要新建两个脚本,一个是DisplayNormalTexturePassFeature.cs,另一个是DisplayNormalTexturePass.cs。
然后,在ForwardRenderer资源中添加上述DisplayNormalTexturePassFeature,这样,就可以调用DisplayNormalTexturePass了。
最后,还要实现一个显示法线图的Shader。
1 | Varyings vert(Attributes input) |
1 | half4 frag(Varyings input): SV_Target |
在片元着色器中,DecodeViewNormalStereo方法并不是URP内置的方法,而是从Build in渲染管线中移植过来的,可以在UnityCG.cginc文件中找到具体实现:
1 | inline float3 DecodeViewNormalStereo( float4 enc4 ) |
四、总结
原本,在Build in渲染管线中,是很简单的一件事,但是在URP中,却大费周折。而且在URP的文档中,直到最新版的10.2.2都没有提供支持,以后会不会提供支持还很难说。另外,在URP中获取法线图的相关资料,在中文互联网上基本没有查到,希望本文能对后来者有帮助。
参考
- [1] outlineshader
- [2] 练习项目(四):深度图基础及应用