Unity Shader更复杂光照学习笔记(个人向)

一个场景中一般不可能只有一个光照,在多个光照的情况下,如果我们像之前一样处理光照的话可能就会出错,那么Unity如何处理多个光照呢?

Unity的渲染路径

渲染路径决定了光照是如何应用到Unity Shader中的,如果我们要和光源打交道,就要为每个pass指定它使用的渲染路径。

大多数情况下,一个项目只使用一种渲染路径;如果当前显卡不支持所选的渲染路径,Unity会自动使用更低一级的渲染路径。

渲染路径的指示:通过pass中的LightMode实现。

前向渲染路径的原理

每进行一次完整的前向渲染,我们需要渲染该对象的渲染图元,并计算两个缓冲区的信息:

一个是颜色缓冲区,一个是深度缓冲区。

我们利用深度缓冲区决定一个片元是否可见,如果可见就更新颜色缓冲区中的颜色值;对于每个逐像素光源,我们就要执行多个pass,每个pass计算一个逐像素光源的关照结果,然后在帧缓冲区中把这些光照结果混合起来得到最终的颜色值。

事实上,一个pass不仅仅可以计算逐像素光照,它也可以用来计算逐顶点等其他光照(取决于光照计算所处的流水线阶段以及计算时使用的光照模型);

前向渲染路径有三种处理光照的方式:逐顶点处理、逐像素处理、球谐函数处理;

决定一个光源使用哪种方式处理取决于它的类型和渲染模式

光源类型指的是该光源是平行光还是其他类型的光源

而光源的渲染模式指的是该光源是否是重要的

在前向渲染中,当我们渲染一个物体时,Unity会根据场景中个光源的设置及这些光源对物体的影响程度对这些光源进行一个重要度排序,一定数目的光源会按照逐像素的方式处理,最多4个按照逐顶点,剩下的按照SH方式处理。

判断规则:

最亮的平行光总是按逐像素处理;

Not Important安装逐顶点或者SH;

Important安装逐像素;

当根据上述规则得到的逐像素处理光源数目小于Quality Setting中设置的数目,那么会有更多的光源按照逐像素处理。

Base Pass与Additional Pass

 在 Base Pass 中处理了场景中的最重要的平行光。如果场景中包含了多个平行光, Unity 会选择最亮的平行光传递给 Base Pass进行逐 像素处理, 其他平行光会按照逐顶点或在 Additional Pass 中按逐像素的方式处理

 Additional Pass 处理的光源类型可能是平行光、点光源或是聚光灯 , 因此在计算光源 的 5 个属性一位置、 方向、颜色、强度以及衰减时,颜色和强度我们仍然可以使用_LightColorO 来得到,但对于位移、 方向和衰减属性, 我们就需要根据光源类型分别计算。

在Base渲染设置中,一般会使用#pragma multi_compile_fwdbase编译指令,这样的编译指令会保证Unity可以为相应的Pass生成所有需要的Shader变种,这些变种会处理不同条件下的渲染逻辑,同时Unity也会在背后声明相关的内置变量并传递到Shader中。

Tip:Unity Shader变种:在unity中我们可以通过使用#pragma multi_compile或#pragma shader_feature指令来为shader创建多个稍微有点区别的shader变体。这个Shader被称为宏着色器(mega shader)或者超着色器(uber shader)。实现原理:根据不同的情况,使用不同的预处理器指令,来多次编译Shader代码。
在运行时,Unity从Material宏Material.EnableKeyword和Shader.DisableKeyword或全局着色器宏Shader.EnableKeyword和Shader.DisableKeyword中选择适当的着色器变体。如果这两个宏都未启用,则Unity使用第一个宏。

默认情况下,Additional Pass中渲染的光源是没有阴影效果的,即使我们在它的Light组件中设置了有阴影的Shadow Type。但是我们可以使用#pragma multi_compile_fwdadd_fullshadows代替#pragma multi_compile_fwdadd。

环境光和自发光在Base Pass中计算,以为我们只希望计算一次环境光和自发光;

在Add的设渲染置中,我们开启和设置了混合模式,使得Add可以与上次的光照结果在帧缓存中进行叠加(帧缓存区也叫做帧缓存,是用于存放一帧中数据信息的容器),否则计算出的光照结果会覆盖之前的计算结果。

Q:Additional Pass只执行逐像素处理吗?

顶点照明渲染

顶点照明渲染路径是对硬件配置要求最少,运算性能最高,但同时也是得到的效果最差的一种类型,它不支持那些逐像素才能得到的效果,例如阴影、法线映射、高精度的高光反射等。实际上它仅仅是前向渲染路径的一个子集,也就是说所有可以在顶点照明渲染路径实现的功能都可以在前向渲染路径中完成,顶点照明路径只是使用了逐顶点的方式来计算光照。但如果选择使用顶点照明渲染路径,那么unity会只填充那些逐顶点相关的光源变量,意味着我们不可以使用一些逐像素光照变量。


延迟渲染路径

前向渲染的问题是:当场景中包含大量实时光源时,前向渲染的性能会急速下降。例如:如果我们在场景的某一块区域放置了多个光源,这些光源的影响的区域互相重叠。那么为了得到最终的光照效果,我们就需要为该区域内的每个物体执行多个Pass来计算不同光源对该物体的光照结果,然后在颜色缓存中把这些结果混合起来得到最终的光照。然而每执行一个pass我们都需要重新渲染一遍物体,但很多计算实际上是重复的。

延迟渲染是一种更古老的渲染方法,除了前向渲染中使用的颜色缓冲和深度缓冲外,延迟渲染还好利用额外的缓冲区,这些缓冲区也被称为G缓冲(G-buffer),G缓冲区存储了我们所关心的表面(通常指的是离摄像机最近的表面)的其他信息,例如该表面的法线、位置、用于光照计算的材质属性等。

1.延迟渲染的原理
延迟渲染主要包含了两个Pass,再第一个pass中,我们不进行任何光照计算,而是仅仅计算哪些片元的可见的,是通过深度缓冲计算实现的,当发现一个片元是可见的,欧美就把它的相关信息存储到G缓冲区中,然后在第二个Pass中,我们利用G缓冲区的各个片元信息,例如表面的法线、视角方向、漫反射系数等,进行真正的光照计算。

可以看出延迟渲染使用的Pass数目通常就是两个,这跟场景中包含的光源数目是没有关系的。换句话说,延迟渲染的效率不依赖于场景的复杂度,而是和我们使用的屏幕空间的大小有关。这是因为,我们需要的信息都存储在缓冲区中,而这些缓冲区可以理解成是一张张2D图像,我们的计算实际上就是在这些图像空间中进行的。

2.Unity中的延迟渲染
如果游戏中使用了大量的实时光照。我们可能希望选择延迟渲染路径,但这种路径需要一定的硬件支持。延迟渲染路径中的每个光源都可以按照逐像素的方式处理。

但是延迟渲染也有缺点:

不支持真正的抗锯齿功能。

不能处理半透明物体。

对显卡有一定要求。

当使用延迟渲染时,unity要求我们提供两个pass。

(1)第一个pass用于渲染G缓冲。在这个pass中,我们会把物体的漫反射颜色、高光反射颜色、平滑度、法线、自发光和深度等信息渲染到屏幕空间的G缓冲区中,对于每个物体来说,这个pass仅会执行一次。

(2)第二个pass用于计算真正的光照模型,这个pass会使用上一个pass中渲染的数据来计算最终的光照颜色,再存储到帧缓冲中。

默认的G缓冲区包含了以下几个渲染纹理:(注意Unity版本不同可能储存内容会不同)
RT0:格式是ARGB32,RGB通道用于存储漫反射颜色,A通道没有被使用。
RT1:格式是ARGB32,RGB通道用于存储高光反射颜色,A通道用于存储高光反射的指数部分。
RT2:格式是ARGB2101010,RGB通道用于存储法线,A通道没有被使用。
RT3:格式是ARGB32(非HDR)或ARGBHalf(HDR),用于存储自发光+lightmap+反射探针。
深度缓冲和模板缓冲。
在第二个Pass中计算光照时,默认情况下只可以使用Unity内置的Standard光照模型。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值