type
status
date
slug
summary
tags
category
icon
password
引子:一个 overrideShader 的使用场景
在 Unity 的 SRP 中,我们可以使用统一的 Material 或 Shader 来替换 Renderer 原本绑定的材质进行渲染。
查阅 Unity 的文档你会发现,从 2019.4 开始 SRP 支持了
overrideMaterial
,而到了 2022.2,又新增了更灵活的 overrideShader
。那这两个功能到底什么时候该用哪个呢?举个我实际遇到的例子:项目里有一堆用不同 Shader 的物体,我想在某个 Pass 中让它们统一输出数值 1 到一张 RenderTexture 上,用来做屏幕空间描边。
针对这个需求,我想到的方案大概有三种:
- 给每个 Shader 单独加一个描边用的 Pass
有点麻烦,维护成本比较高。
- 用
overrideMaterial
,把它们都替换成同一个描边材质
虽然实现简单,但有个致命问题:比如原材质用了
clip()
来控制像素是否可见,而统一的材质不支持这个逻辑,那描边结果肯定不对。- 使用
overrideShader
,统一替换掉 Shader,但仍保留原来的材质
这个方法看起来最优雅,但也引出一个问题:
像
clip()
这种裁剪逻辑,很多时候我们是通过 #pragma shader_feature
控制的。那如果我用了 overrideShader
,材质中原本设置的关键字还能生效吗?overrideShader 到底干了什么?
DrawingSettings.overrideShader
的作用,是在渲染时无视每个对象原来的材质绑定,直接使用你指定的 Shader 来绘制:overrideShader
是你想统一替换用的 Shader;
overrideShaderPassIndex
是选它的第几个 Pass 来用。
听起来挺简单的,但问题来了:如果这个 Shader 里用了
multi_compile
来兼容开关 clip 功能,那 Unity 渲染时是怎么知道该用哪个变体的?关键还是得回到 Shader 编译和关键词机制上来理解。材质关键字到底起了什么作用?
我们平时在 Shader 里写的
multi_compile
或 shader_feature
,其实就是告诉 Unity 编译出一堆变体。而运行时,具体使用哪一个,是根据材质里存的关键词来决定的。也就是说,只要材质球里有记录“我需要启用 clip 功能”,Unity 就会找到带这个关键词的 Shader 变体来用。
为了验证这个机制,我打开了两个 clip 状态不同的材质球,发现它们的
.mat
文件里确实有 m_ValidKeywords
和 m_InvalidKeywords
字段,而且并没有区分是 multi_compile
还是 shader_feature
。更重要的是,启用了 clip 的材质,它的
m_ValidKeywords
里真的有那个关键字,这跟我的理解是对得上的。实际测试一下
为了更保险,我做了个实验:写了一个统一的 Shader,里面用
multi_compile _ _CLIP
控制是否启用裁剪。然后在渲染时用 overrideShader
替换掉原始 Shader。测试结果很理想:开启了 clip 的材质,裁剪逻辑生效;没开启的就完整绘制。
当然这个方案成立也有前提——比如变量名要一致,关键字名称也得对得上。不然材质球里虽然有关键词,Shader 里没定义,Unity 也找不到正确的变体。
我的总结
如果你能确保关键字和变量名的一致性,
overrideShader
是可以保留原始材质信息的,也就是说,它能做到比 overrideMaterial
更加灵活的替换。相比让每个 Shader 都手动维护额外的 Pass,或者丢失差异化逻辑的
overrideMaterial
,这个方式既省心又灵活。换句话说:Shader 是一堆变体的集合,而材质负责告诉引擎“我该用哪一个”。只要你处理好了两者的沟通方式,
overrideShader
就是个非常强大的工具。不论是做调试视图、全局替换渲染逻辑,还是构建可扩展的工具型渲染模块,它都是 SRP 开发中值得深入掌握的利器。
- 作者:应坤龙
- 链接:https://www.ykl1998.com/article/1c455cc2-cff2-80ec-948f-e9327c57dbd9
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。