SIGGRAPH)php
原做:Michal lwanickiios
本篇主要讲述 The Last of Us中用到的用到的光照技术,以及解决问题的思路,原做者wanicki是 顽皮狗的引擎工程师,同时也参与了RealTime Rendering 4th的编写。app
ppt 原文连接[http://miciwan.com/SIGGRAPH2013/Lighting%20Technology%20of%20The%20Last%20Of%20Us.pdf]函数
同时也要感谢下工做室大佬的解惑。工具
因为游戏发生在后世界末日,几乎没有电,因此没有人造光源。大部分的光线来自太阳和天空,因此大部分的环境都是由反射光照亮的。布局
有一个很是强大的艺术方向:咱们想展现这个灯光的美丽,它的柔和,它如何在不一样表面之间传播,它创造的柔和阴影。咱们想显示间接光照的镜面反射高光,并显示用普通的normal map展现细节。性能
首先展现一下咱们想要达到的效果测试
如图所见,全部的光线都很柔和,但同时表面细节也表现的很到位。优化
为了实现这样的效果,目前机器性能实时渲染是吃不消的,因此咱们使用了预计算的光照贴图。虽然光照贴图应用了这么多年,可是仍是存在一些根本性的问题。spa
接缝:在三维空间中相邻的区域,映射到UV空间中时,可能在不一样贴图的相交区域,若是沿分割线作插值的话,不彻底匹配就会产生明显的接缝。
(打个比方一个圆柱沿竖线剪开,展uv,竖线2侧在三维空间中多是连续的,可是uv空间展开以后不连续)
常看法决方法:在运行时,花费额外的开销,去减弱接缝,或者对物体在uv空间中的位置作一些限制。
为何没有用在The Last Of Us中:美术的体量不匹配,不适合当前的项目,效率低下,成本过高,没法集成到项目的管线中。
咱们发现,咱们的主要矛盾就是接缝两侧插值不匹配的问题,因此咱们经过了修改边缘纹理的强度,来让他们匹配起来
如上图所示的例子,先介绍下概念,绿色和紫色是空间中的2个mesh,红点虚线是分割边,在这个分割边上,取了不少个点,Ci0表示绿色mesh中i点相邻4个像素的 插值, 在紫色mesh中一样有一个点Ci1,若是Ci0 = Ci1 最好,咱们把同一个点在相邻mesh上的偏差定义为他们的平方差
\[\ C_{i0}= \sum_{j}^{4}{W_{0ij} * T_{0ij}}\]
\[\ C_{i1}= \sum_{j}^{4}{W_{1ij} * T_{1ij}}\]
\[E_i = (C_{i0} - C_{i1})^2 \]
整个光照贴图的偏差函数,就是各个点的偏差之和。
当有了偏差函数以后,使用最小二乘法,把纹理的值做为变量,优化过程,经过修改texel的值,确保偏差最小,为了确保最后的结果不偏离最初计算的值,引入了一个约束惩罚计算值的偏离,这个值用户能够调配。
若是你仔细观察,就会发现,最小二乘最小化,其实在其它不少地方用到过。好比游戏游戏中 3D LUT(Look Up Table,直译过来就是查找表的意思。因此LUT的本质就是输入一个特定的值转化为一个对应的输出值)管线的颜色校订,流程以下
比较的结果多是,有严重的变色,这时候偏差函数被定义为两幅图片中的平方差,经过修改volume texture 使偏差最小,会取得一个比较好的结果。
LUT扩展阅读(https://zhuanlan.zhihu.com/p/37717976)
回到灯光中,咱们但愿在没有直接光照的状况下,避免表面平坦,因此光照贴图中需要包含光照的方向信息。
咱们评估了不一样的方案,HL2(半条命)的Radiosity Normal Mapping,用6个方向的vec3来记录光照信息。(https://drivers.amd.com/developer/gdc/D3DTutorial10_Half-Life2_Shading.pdf)。
好处是相比SH(Sphere harmonic),计算量会稍微少点,可是用在曲面上,由于是插值的缘由,细节丢失的会多一点。
目前2018年UE4和unity都用上了SH。
最后选择了一个简单的方案,为每一个光照贴图 同时存储Ambient(环境光)和Directional(方向光)。
经过使用 “环境光” + ”方向光” 的方案,有几个好处
对于光照贴图的每一个texel纹理,烘焙工具会有光照发布的信息,咱们分为2个组件
咱们经过GI bake 的工具生成了SH(球谐函数sphere harmonics) lightmap,经过这样的方式(环境光+方向光)表示最终的效果。
\[I = C_{amb} + C_{dir} * max((\vec N,\vec L),0 )\]
经过这种表达方式,还能够表示表面的高光。
看看效果,感受还不错。
虽然理想很美好,可是当咱们添加了人物以后,有点蹦。
人物看起来很奇怪,为何呢,由于人物在与环境交互的时候,会产生阴影,看起来是环境的一部分,而上图却没有。
经过查阅一些资料,咱们在sh指数化的论文中获得了灵感,用一组球体来近似遮光罩,并经过将它们以一种奇特的方式相乘,结合被描述为sh向量的可见性函数。
问题是要获得满意的阴影,须要高的sh阶。斯蒂芬·希尔在《分裂细胞》中用二阶sh对AO作了相似的事情。
raytrace one week 第三本 和pbrt14.6章 都有介绍。(https://computergraphics.stackexchange.com/questions/4288/path-weight-for-direct-light-sampling)
圆锥的角度是能够调整的,可让美术来控制阴影边缘的大小,
先经过使用SPU(主机平台的一种流处理器单元)去渲染阴影到缓冲区,GPU在渲染的时候,从缓冲区中读数据,再最终渲染出结果。
4-5个角色差很少要6-7ms,可是用了这种方法,代理分割到6个SPU单元,2ms就搞定了。
这样能够很好的提升运算效率,在测试场景中,模型精度讲到1/4,计算获得的阴影基本很难看出区别,很是有效。