

200+篇教程总入口,欢迎收藏:
放牛的星星:[教程汇总+持续更新]Unity从入门到入坟——收藏这一篇就够了zhuanlan.zhihu.com
本文重点内容:
1、使用不同的post FX设置来渲染多个摄像机
2、使用自定义的混合来分层相机
3、支持Layer masks
4、逐相机设置灯光掩码
这是有关创建自定义脚本渲染管道的系列教程的第14部分。这次,我们重新考虑了使用多个摄像机的渲染,现在添加了post FX。
本教程是CatLikeCoding系列的一部分,原文地址见文章底部。
本教程使用Unity 2019.4.12f1制作。

1 组合相机
因为每个摄像机都执行剔除,光处理和阴影渲染等,所以最好每帧渲染尽可能少的摄像机,理想情况下只渲染一个。但是有时候我们确实需要同时渲染多个不同的观察点。示例就包括分屏多人游戏,后视镜,俯视角的小地图,游戏中的摄像头和3D人物肖像。
在第一人称游戏中,人物的手和工具如何?
无论第一人称游戏中的人物手持的是什么,由于各种原因,它所显示的视角往往与场景的其他部分不同。这可以通过另一个摄像头来完成,但也可以通过调整视图矩阵来渲染,但仍然使用同一个摄像头。
1.1 分屏
让我们首先考虑由两个并排摄像头组成的分屏方案。左摄像机的视口矩形宽度设置为0.5。右摄像机的宽度也为0.5,其X位置设置为0.5。如果我们不使用后处理功能的话,那么它将按预期工作。

但如果启用后置FX,它将失败。两台摄像机都以正确的大小渲染,但它们最终会覆盖整个摄像机目标缓冲区,只有最后一个可见。

发生这种情况是因为调用SetRenderTarget会重置视口以覆盖整个目标。要将视口应用于最终的FX Pass后,我们需要在设置目标之后且在绘制之前设置视口。通过复制PostFXStack.Draw,将其重命名为DrawFinal并在SetRenderTarget之后直接调用缓冲区的SetViewport(以相机的pixelRect作为参数)来实现。因为这是最后的Draw,所以我们可以用硬编码值替换除源参数以外的所有参数。

在DoColorGradingAndToneMapping的末尾调用新方法而不是常规Draw。


1.2 分层相机
除了渲染到单独的区域外,我们还可以使摄影机视口重叠。最简单的示例是使用覆盖整个屏幕的常规主摄像头,然后添加第二个摄像头,该摄像头稍后以相同的视图但较小的视口渲染。我将第二个视口缩小为一半,并通过将其XY位置设置为0.25居中。

如果我们不使用Post FX,则可以通过将其设置为仅清除深度来将顶部相机图层变成部分透明的叠加层。这将删除其天空盒,从而显示下面的图层。但这在使用后置FX时不起作用,因为随后我们将其强制为CameraClearFlags.Color,因此我们将改为查看相机的背景色,默认情况下为深蓝色。


为了使Post FX可以使用图层透明度,我们可以做的一件事就是更改PostFXStack着色器的最终Pass,以便它执行alpha混合,而不是默认的One Zero模式。

这需要我们总是在FinalDraw中加载目标缓冲区。

现在,将重叠式摄像机的背景色的Alpha设置为零。只要我们禁用Bloom,这似乎就可以工作。我添加了两个非常明亮的自发光对象,以使Bloom是否开启变得显而易见。


它在bloom中不起作用,因为这种效果目前不能保持透明度。我们可以通过调整最终的bloom通道来解决这个问题,这样它就可以保持高分辨率源纹理的原始透明度。我们需要同时调整BloomAddPassFragment和BloomScatterFinalPassFragment,因为它们都可以用于最终的绘制。


透明现在对bloom有效,但是bloom对透明区域的贡献不再可见。我们可以通过将最终通道切换为预乘alpha混合来保存bloom。这需要我们将相机的背景色设置为纯透明黑色,因为它将被添加到下面的图层中。


1.3 分层 Alpha
当前的分层方法仅在我们的着色器产生可用于相机图层混合的有意义的Alpha值时才有效。我们之前并不关心写入的alpha值,因为我们从未将它们用于任何用途。但是现在,如果两个具有alpha 0.5的对象最终渲染到同一纹理像素,则该纹理像素的最终alpha应该为0.25。并且当两个Alpha值之一为1时,结果应始终为1。当第二个Alpha值为零时,应保留原始Alpha。混合alpha时,使用OneOneMinusSrcAlpha可以覆盖所有这些情况。通过在颜色混合模式之后添加逗号和alpha模式,我们可以为Alpha通道与颜色分别配置着色器的混合模式。为我们的Lit和Unlit着色器的常规Pass执行此操作。