0x00 前言

在Unity的5.6版本之前的5.x中,主要使用了Geomerics公司的Enlighten【1】来提供实时全局照明以及烘焙全局照明,在5.6之后Unity引入了新的Lightmapper——Progressive来提供烘焙全局照明并且提供了更多的混合光照模式,但是Enlighten仍然是Unity中全局照明的主要提供者。

所以,本文就来聊聊Unity5.6以及Unity2017中和Enlighten、混合光照相关的话题吧。

0x01 直接光和间接光

大家都知道在Unity中,我们可以在场景中布置方向光、点光、聚光等类型的光源。但如果只有这些光,则场景内只会受到直接光的影响,而所谓的直接光简单理解就是从光源发出的直接影响物体的光。如果只考虑直接光的影响,则会缺乏很多光影细节,导致视觉效果很“平”。而间接光则描述了光子在物体表面之间的反弹,能够用来增加细节以及真实感。



例如上图中,位于天花板灯直射光线之外的区域缺乏光照效果。表现为四壁上没有明暗细节,相反此时直接光范围之外都是均匀的黑色,而整个空间同样也显得十分平。



而增加了间接光之后进行渲染,可以看到光被物体表面反弹,彩色光从一个表面转移到另一个表面。表现为红色墙壁和绿色墙壁(在右侧和红墙相对,没在画面内)的颜色反映到了场景中的其他表面上,四壁也不再是均匀的黑色,而有了层次感。

0x02 全局照明和渲染方程

正如前文所说,在Unity中使用直接光是无法模拟光子在物体表面反弹的效果的,因此Unity使用了Enlighten所提供的全局照明(Global illumination)来提供间接光效果。

所谓的全局照明(缩写为GI)是3D计算机图形中使用的一组算法的通用名称,旨在为3D场景添加更逼真的照明。这样的算法不仅考虑直接来自光源的光(直接光),而且还考虑随后来自相同源的光线被场景中的其他表面反射的情况,即间接光。

而全局照明可以用一个称为渲染方程【2】的复杂方程来描述:

渲染方程定义了光线是如何离开表面上某个点的。但是各位也可以看到,这个积分方程太复杂以至于无法快速的计算结果。因此在具体的实现上,往往采用了一些近似的方法。

Unity中所使用的Enlighten采用的近似方法是辐射度算法,即假设存在一组有限的静态元素和仅有漫射光传输来简化计算。上面的渲染方程就可以简化为下面这样:

这样,我们就可以将积分计算变为计算求其他元素的辐射度之和。

其中Bi指的是在i点最终的光,Le是i点本身的光,而两个点之前有多少比例的光会被反弹,则有“form factor”来定义,即公式中的Fij,Lj是J点的光。而pi(输入法问题,先写成p)则是一个和i的材质属性相关的参数。

这样,这个方程就比较好理解了,同时计算相比之前的渲染方程也简单了很多。

而有了简化的方程之后,Enlighten在计算全局光照时,会将场景分组到便于并行处理的system中。接下来,每个system被切割成离散的cluster



在计算光照时,Enlighten将场景视为一组cluster。而场景内的cluster则会以一种层级关联的结构来组织,并且会对其映射的静态几何体的albedo进行采样,之后在Light Transport阶段计算cluster之间的关系以使得光在cluster之间进行传递。

这样看上去全局照明方案已经完美的解决了间接光的问题,但是预计算实时GI的代价仍然很高,针对移动平台这样相对比较低端的设备,就需要有更加优化的解决方案。所以将静态对象的光照信息烘焙到lightmap上,同时保持对动态对象使用实时光就变成了一个不错的方案。而这就是我们下文中要说的混合光照。

0x03 混合光照

使用混合光照和直接使用烘焙的lightmap有什么区别呢?简单来说,选择“混合”烘焙模式,会将标记为静态的GameObject受到的来自混合光源的光照信息保存为Lightmap。 然而,与标记为“烘焙”的灯光不同,混合光源也会为场景中的非静态(动态)GameObject提供实时的直接光照。

在Unity5.x的版本中,光源就已经有了混合模式的选择。但是直到Unity5.6版本,混合模式又变成了4种子模式。而到了Unity2017版本,则变成了3种子模式——shadowmask的两种模式的设置被放到了Quality Setting内的Shadow下。如下图所示,分别来自Unity5.5、Unity5.6以及Unity2017.3三个版本的Lighting窗口截图。



可以看到Unity5.6之后的版本,混合光照的模式增加了Baked IndirectDistance ShadowmaskShadowmaskSubtractive这些子模式(2017版本后Distance Shadowmask的设置放到了Quality Setting中)。

首先我们可以先来看看Subtractive模式,因为Subtractive模式也是5.6之前Unity所使用的混合光照模式。

例如在Unity5.5中,我们如果将光源设置为mixed来开启混合光照,和在5.6之后选择Subtractive模式开启混合光照是一样的。

那么现在就可以安心的使用混合光照了吗?

我们可以来看看一个在这种模式下常见的问题:

即使用点光开启mixed模式时,左下角的动态对象cube并没有产生由点光产生的实时阴影。

这个听上去并不符合预期,因为mixed光照模式下对动态对象显然要提供实时的光照效果,也就是预期应该是像下图这样产生点光造成的阴影。

那么这是为什么呢?这其实是因为在5.6之前的混合光照,以及5.6之后使用subtractive模式的混合光照只能在"只有"一个方向光(Directional light)的时候才能正常工作。

subtractive模式的另一个问题就是烘焙的结果中没有高光,这是因为这种模式不仅仅烘焙了间接光,而且它还会烘焙直接光,因此也就无法提供高光效果了。所以可以看到在上面的截图中,并没有高光的效果。

正是由于这种混合光照模式的不足,所以Unity5.6之后又引入了更多的混合光照模式,以满足大家的需求。

但是,作为开销最小的一种混合光照模式,subtractive模式仍然有被保留的必要。在一些对性能要求高过对效果的要求时,subtractive模式仍然不失为一个不错的选择。

0x04 混合光照新模式-Shadowmask

Unity的新的混合光照机制的一个重要功能便是对Shadowmask【3】的支持了。混合光照开启shadowmask模式的情况下,Unity会额外生成一套shadowmask贴图,它每个纹素的4个通道可以分别用来保存4盏不同的光源。



如图,这张shadowmask保存了2盏光源的信息,一个主方向光和一个点光。

Shadowmask的主要功能本质上十分容易理解,它解決了之前subtractive模式下无法完成的事情。Shadowmask不仅仅可以处理方向光,而且还可以正确的处理点光和聚光在混合光照条件下的表现。



可以看到左下角的动态对象cube产生了由mixed模式下的点光产生的实时阴影。

同时,由于没有对直接光进行烘焙,因此能够在运行时提供正确的高光效果。

而有些朋友如果打开Mixed Lighting的子mode选择菜单的话,在5.6版本中还会看到另一个和shadowmask类似的选项——Distance Shadowmask。



那么Distance Shadowmask和Shadowmask又有什么区别呢?

这就和阴影距离(Shadow Distance)以及混合光照下阴影是如何产生的有关了。

我们在Edit->Project Settings->Quality设置中可以找到Shadow Distance的设置,在实时光模式下,只有在Shadow Distance范围内的物体才会有阴影的影响。

而在混合光照-Shadowmask模式下,静态物体和静态物体之间的阴影是通过shadowmask贴图来产生的。而对于静态物体接收的动态物体产生的阴影,则只有在shadow distance范围内动态物体才会产生实时的shadow map阴影。而动态物体之间的阴影,同样需要在Shadow Distance范围内来产生。至于动态物体如果要接收静态物体的阴影,则需要借助light probe的帮助。



如上图所示,在静态的墙和地面之间,由shadowmask提供了阴影。

至于那三个动态物体cube,在没有light probe的情况下,左下角的cube无法接受到静态墙体的阴影。而右边的两个cube之间则有实时的shadow map阴影,并且它们也在静态墙壁上投下了实时的shadow map阴影。

而如果使用Distance Shadowmask模式的话,各位猜猜哪一种阴影产生的方式会发生变化呢?

答案其实很简单,首先肯定和Shadow Distance相关,其次肯定是和实时的shadow map和烘焙好的shadowmask之间的切换相关。嗯,答案呼之欲出——在distance shadowmask模式下,处于shadow distance范围内的静态物体也会实时的产生shadow map阴影,这一点和动态物体一样,因此无论是静态物体之间还是静态物体和动态物体之间都会产生实时的shadow map阴影。而一旦超出了shadow distance的范围,则静态物体的阴影会从shadowmask中获取。

如上图所示,可以看到静态的墙和地面之间的阴影边缘锐利了,不像之前从Shadowmask获取的阴影,由于分辨率的原因可能会更加模糊,此时已经是实时的Shadow Map阴影了,因此边缘更加清晰锐利。而且左下角的cube已经可以接受到静态墙体的实时阴影了。

不过正如我刚才提到的,Distance Shadowmask和Shadow Distance以及两种阴影产生的方式有关,那么就有可能会出现一种瑕疵~即在Shadow Distance的内外,会有两种不同的阴影,而Shadowmask产生的阴影由于分辨率的原因往往更加模糊,例如下面这样:



可以看到墙壁产生了两种不同的阴影。因此这个问题各位在开发过程中可能也要关注一下。

另外,Distance Shadowmask和Shadowmask相比,性能上的开销显然要更大一些,这也不难想象,毕竟还有很多静态物体也会产生实时阴影嘛。那么我们可以简单的对比一下两者在Draw Call上的开销:



可以看到,右侧的Distance Shadowmask的drawcall开销要远远高于shadowmask。因此,在移动设备上采用shadowmask而不是开销更高的Distance Shadowmask对于追求性能的情况更加适用。当然,Unity2017之后,Distance Shadowmask和Shadowmask的设置已经移到了Quality Setting中了,这意味着我们可以在运行时动态的切换这两种模式了。

void OnTriggerEnter(Collider other)
{
if(QualitySettings.shadowmaskMode == ShadowmaskMode.Shadowmask)
{
QualitySettings.shadowmaskMode = ShadowmaskMode.DistanceShadowmask;
}else
{
QualitySettings.shadowmaskMode = ShadowmaskMode.Shadowmask;
}
}

当然,无论是Distance Shadowmask还是Shadowmask,它们都可以在Shadow Distance之外提供来自Shadowmask的阴影,虽然较之实时阴影要模糊一些。因此,对于需要远方也要产生阴影效果的项目,Shadowmask模式是一个很好的选择。

0x05 混合光照新模式-Baked Indirect

下面还剩下最后一个混合光照模式——Baked Indirect【4】。事实上这个混合模式的名字就已经十分直白了——它只烘焙间接光,其他的全部是实时的。Shadowmask贴图?不存在的。

因此我们有了实时光、实时阴影等等。所以,在Shadow Distance的范围之内和实时光下效果一样,阴影是实时的shadow map,并且在shadow distance之外不会有阴影产生——哪怕是分辨率比较低的模糊阴影也没有。

可以看到在Shadow Distance范围内的墙的阴影十分清晰,但是在范围之外则已经没有阴影了。同时,这种混合模式的开销也很大,因为它只烘焙了间接光,其他的全部是实时的。

0x06 总结

ok,让我们对这几种混合模式做一个小的总结吧~可以简单的归纳为下面这个表格【5】。

Ref

【1】https://www.siliconstudio.co.jp/middleware/enlighten/en/

【2】https://en.wikipedia.org/wiki/Rendering_equation

【3】https://docs.unity3d.com/Manual/LightMode-Mixed-BakedIndirect.html

【4】https://docs.unity3d.com/Manual/LightMode-Mixed-Shadowmask.html

【5】https://docs.google.com/spreadsheets/d/18R663xpccuyRns1kOvGAiqj0qU9QFMbbXyrOCQMsU5w/edit#gid=1748986211

浅析Unity中的Enlighten与混合光照的更多相关文章

  1. unity中使用自定义shader进行光照贴图烘培无法出现透明度的坑爹问题

    最近开发中在对场景进行光照贴图烘焙时发现一个坑爹问题,在使用自定义shader的时候,shader命名中必须包含Transparent路径,否则烘焙的时候不对alpha通道进行计算,烘焙出来都是狗皮膏 ...

  2. Unity 5.6中的混合光照(下)

    https://mp.weixin.qq.com/s/DNQFsWpZm-ybIlF3DTAk2A 在<Unity 5.6中的混合光照(上)>中,我们介绍了混合模式,以及Subtracti ...

  3. Unity 5.6中的混合光照(上)

    https://mp.weixin.qq.com/s/AbWM21sihHw5pFdMzENDPg 在Unity 5中,光照得到了很大的改进.现在,创建高度逼真的游戏已成为可能.但是,出于对性能的考虑 ...

  4. 解读Unity中的CG编写Shader系列七(不透明度与混合)

    转自http://www.itnose.net/detail/6098539.html 1.不透明度 当我们要将两个半透的纹理贴图到一个材质球上的时候就遇到混合的问题,由于前面的知识我们已经知道了片段 ...

  5. 关于Unity中的光照(七)

    全局光照 GI 这里所说的反射就是,一个红色的物体,当太阳照射它的时候,它周围的物体也会变得有点红. 1:Realtime每帧都会计算光照,实时光照是不会反射的,所以它的光影显得单调;2:Baked ...

  6. [转]解读Unity中的CG编写Shader系列6——不透明度与混合

    1.不透明度当我们要将两个半透的纹理贴图到一个材质球上的时候就遇到混合的问题,由于前面的知识我们已经知道了片段着色器以及后面的环节的主要工作是输出颜色与深度到帧缓存中,所以两个纹理在每个像素上的颜色到 ...

  7. Unity Shader入门精要学习笔记 - 第6章 开始 Unity 中的基础光照

    转自冯乐乐的<Unity Shader入门精要> 通常来讲,我们要模拟真实的光照环境来生成一张图像,需要考虑3种物理现象. 首先,光线从光源中被发射出来. 然后,光线和场景中的一些物体相交 ...

  8. 第五章 Unity中的基础光照(2)

    目录 1. Unity中的环境光和自发光 2. 在UnityShader中实现漫反射光照模型 2.1 实践:逐顶点光照 2.2 实践:逐像素光照 2.3 半兰伯特模型 1. Unity中的环境光和自发 ...

  9. Unite 2018 | 《崩坏3》:在Unity中实现高品质的卡通渲染(下)

    http://forum.china.unity3d.com/thread-32273-1-1.html 今天我们继续分享米哈游技术总监贺甲在Unite Beijing 2018大会上的演讲<在 ...

随机推荐

  1. JSP的几种跳转方式的异同

    1 <jsp:foward page="url" /> 服务端跳转,立即跳转,后续语句不会执行: 2 <% response.sendRedirect(" ...

  2. mysql之mysql_config_editor

    本文来自我的github pages博客http://galengao.github.io/ 即www.gaohuirong.cn mysql_config_editor允许你把登录的身份验证信息存储 ...

  3. CentOS6.9安装mysql5.7

    1.查看系统版本 uname -a 2.卸载old mysql rpm -qa|grep -i mysql rpm -ev MySQL-client-5.5.25a-1.rhel5 如果提示依赖错误, ...

  4. C# 使用 SmtpClient 发送邮件注意项

    最近有邮件发送需求,使用 C#  SmtpClient 对象发送邮件 , 报异常, 如下错误代码: 调整代码顺序后,发送邮件成功! 注意:一定要先设置 EnableSsl和UseDefaultCred ...

  5. C++11 左值、右值、右值引用详解

    C++11 左值.右值.右值引用详解 左值.右值 在C++11中所有的值必属于左值.右值两者之一,右值又可以细分为纯右值.将亡值. 在C++11中可以取地址的.有名字的就是左值,反之,不能取地址的.没 ...

  6. springmvc 对 jsonp 的支持

    在与前端开发人员合作过程中,经常遇到跨域名访问的问题,通常我们是通过jsonp调用方式来解决.jsop百科:http://baike.baidu.com/link?url=JKlwoETqx2uuKe ...

  7. Ubuntu14.04上安装Composer

    1,查看机子上有没有安装php 2,下载Composer的安装包 3,安装Composer 4,设置Composer全局可访问

  8. 两种实现方式mycat多租户,枚举分片,注解拦截

    第一种: 优点:支持进一步分片 缺点:schema配置繁琐 注解式  /*!mycat:schema=[schemaName] */   注意:这在navicat 里面是会报错的,请用命令行登陆myc ...

  9. MyCat 枚举分片设计思考,查询命中条件

    Mycat多租户实现的两种方式 MyCat,各种分片规则,仅保证插入的时候分片.表关联,join,查询怎么命中分片条件,还是需要设计. 今天稍微测了一下. ER 分片,此方式,插入的时候能分片,但是查 ...

  10. Qt Creator 整合 python 解释器教程

    目录 1. 前言 2.前提条件 3.步骤 3.1 新建 python文件 3.2 编写 python 代码 3.3 配置 python 解释器 3.4 执行 python file 1. 前言 Pyt ...