《Unity的URP项目中使用自定义shader导致材质消失的解决办法》

        在Unity中使用URP时,会有需求使用自定义的一些shader来实现特殊效果,这时如果我们直接使用新建材质与无光照着色器(Unlit shader),可能会发生一个对于新手而言意料之外的问题——物体!消失了!

解决办法:

        打开你正在使用的的通用渲染器(Universal Renderer Data),找到渲染(Rendering)->深度引动模式(Depth Priming Mode),将其从默认的“自动”修改为“已禁用”。


如果你的问题解决了并且想知道为什么的话,请接着往下阅读。

        什么是深度引动模式?深度引动技术是Unity2021.2中URP管线的新增功能。在Unity的文档中是这样解释的:“The feature uses a depth prepass to determine which pixel shader invocations Unity can skip”,通过使用一种用于预处理深度信息的Pass来帮助Unity跳过对部分片元的渲染。而在使用Unity2021默认的URP项目时,其自动生成的通用渲染器文件(Universal Renderer Data)会默认开启这一项技术,而这也是问题的根源。

        为什么深度引动模式会导致我们的物体消失?首先必须澄清的是,这并不是Unity的什么Bug,而是很典型的新手效应事件,对不熟悉技术的使用导致了意料之外的错误。深度引动模式需要使用一种LightMode为DepthOnly的特殊Pass来生成场景中不透明物体的深度图,而我们所创建的无光照着色器是不具有该类型Pass的(因为压根就没写这东西),这就导致在开启了该技术的渲染流程中,这些使用了“不具备DepthOnlyPass的shader”的物体无法生成深度信息从而被Unity过早剔除无法进行后续的渲染,造成了物体的消失。

        因此若想在URP项目中同时使用深度引动技术与自定义shader,则务必注意需要在自定义shader中向Unity声明DepthOnlyPass用于执行深度引导。幸运的是Unity在Universal Render Pipeline内置的Unlit shader中已经实现了该Pass,在自定义shader中使用以下语句即可直接使用。

UsePass "Universal Render Pipeline/Unlit/DepthOnly

对比使用前后:

       左侧未使用DepthOnlyPass,右侧则添加了DepthOnlyPass,两者均在前向渲染的情况下开启了深度引动模式。可见在使用了DepthOnlyPass的情况下,Unity通过DepthPrepass记录了我们Sphere的深度信息,从而保证了后续DrawOpaqueObjects的正确执行。

Tips:

  • 深度引动模式只工作在前向渲染的情况下,因此在通用渲染器中为你的项目选择延迟渲染路径的话就能绕过这个问题。
  • 深度引动模式只针对不透明物体进行优化,因此如果你将物体的渲染队列设置为“透明”,那么即使不添加DepthOnlyPass也能正常渲染,不过代价是什么呢?
  • 更多参考资料可以查看官方文档,以及Unity工程师NicoLeyman在论坛中的一些回答

"The more you know, the more you know you don't know."

——Daniel Kahneman