前言
上章讲到,我们可以用替换渲染的方法来渲染所有场景的物体,并介绍了替换渲染用到的shader。为了告诉我们的相机,我们需要使用替换渲染的方法,我们需要给相机添加一份C#代码,并且对所有适合的物体进行渲染,如下:
[ExecuteInEditMode]
public class ReplacementShaderEffect : MonoBehaviour
{
public Shader ReplacementShader;
private void OnEnable()
{
if (ReplacementShader != null)
GetComponent<Camera>().SetReplacementShader(ReplacementShader, "RenderType");
}
private void OnDisable()
{
GetComponent<Camera>().ResetReplacementShader();
}
}
同样ExecuteInEditMode是为了在edit mode下观察变化。首先需要一个shader属性,接下来在OnEnable里面,我们做一个非空检查,如果控制面板上有将shader拖入赋值,那么就将现在的相机的替换渲染着色器设置我们写好的shader,第二个参数表示的是我们希望使用哪一个渲染类型的子着色器进行渲染。
流程大概是这样的:
相机:嘿,你用的哪个shader做替换渲染啊?
我们:帅气地把ReplacementShader的引用丢出
相机:收到!哇这个shader有很多个SubShader哦
我们(大吼):明明只写了一个相机你眼睛花了吗?
相机:这不是先假设一下嘛。哎,每个SubShader的渲染类型应该是不一样,有些是渲染透明物体,有些则不是透明物体,是用哪个渲染类型啊?
我们:现在还想不到,所有东西都渲染一遍啦(RenderType就是所有类型的意思)
而一旦替换渲染的着色器被设定了之后,直到我们取消之前都会保持运行,所以在OnDisable中就简单设定一下重设的方法。
正文
为了展示本章的内容,我将场景做了一些更改
将C#代码拖到相机上,并将上一章的shader代入赋值。如果没有反应只需要将C#代码的组件禁用再启用就可以,OnDisable方法会被触发重新设定替换渲染着色器。得到以下渲染效果:
回想以下我们这个shader的目的,它需要是将屏幕上的像素深度作为颜色输出,越远的像素越深色,距离相机越近的像素越浅色。那么理论上来说,远处的像素应该是黑色才对,很明显,渲染效果是错误的,为什么呢?
原因是相机远裁剪平面太远了,上一章提到的_ProjectionParams.w,这个参数表示的是远裁剪平面到相机的距离,在这里是1000,这个数值太大了,导致整个场景都被看作“离相机很近”的像素,因此渲染成了白色。只需要将远裁剪平面的值调小就可以得到正确效果
自问自答
能一次将所有的物体统一渲染的确很方便,但是物体本身的颜色信息丢失了,这是替换渲染的缺点嘛?
不是哦,颜色、纹理还有高光细节等等都是在相机的替换渲染着色器中被统一管理的,比如我们可以试着在shader中加入一个_Color属性
Properties{
_Color("Color", Color) = (1,1,1,1)
}
初始值是多少没有关系,替换渲染着色器会帮我们搞定每个像素的颜色的了。(如果没有用_Color这个属性名,替换渲染着色器就没有办法做事情了)
接下来,在frag函数中将颜色与深度颜色相乘。
half4 _Color;
float4 frag(v2f i) : SV_Target
{
float invert = 1- i.depth;
return float4(invert, invert, invert, 1) * _Color;
}
得到效果:
下一章:
当场景中有使用不同渲染类型的物体,比如有透明物体,有不透明物体,该怎么将他们统一使用一个替换渲染着色器来渲染呢?
俊銘:Shader从入门到跑路(9):替换渲染(下)zhuanlan.zhihu.com