球谐光照

一.原理

球谐光照实际上是一种对光照的简化,对于空间上的一点,受到的光照在各个方向上是不同的,也即各向异性,所以空间上一点如果要完全还原光照情况,那就需要记录周围球面上所有方向的光照。注意这里考虑的周围环境往往是复杂的情况,而不是几个简单的光源,如果是那样的话,直接用光源的光照模型求和就可以了。

如果环境光照可以用简单函数表示,那自然直接求点周围球面上的积分就可以了。但是通常光照不会那么简单,并且用函数表示光照也不方便,所以经常用的方法是使用环境光贴图,比如像这样的:

img

 

上面的图是立方体展开得到的,这种贴图也就是cubemap,需要注意的是一般的cubemap是从里往外看的。

考虑一个简单场景中有个点,他周围的各个方向上的环境光照就是上面的cubemap呈现的,假如我想知道这个点各个方向的光照情况,那么就必须在cubemap对应的各个方向进行采样。对于一个大的场景来说,每个位置点的环境光都有可能不同,如果把每个点的环境光贴图储存起来,并且每次获取光照都从相应的贴图里面采样,可想而知这样的方法是非常昂贵的。

利用球谐函数就可以很好的解决这个问题,球谐函数的主要作用就是用简单的系数表示复杂的球面函数。关于球谐函数的理论推导与解释可以参考wiki( https://en.wikipedia.org/wiki/Spherical_harmonics )。如果只是要应用和实现球谐光照,不会涉及到推导过程,不过球谐基函数却是关键的内容,球谐基函数已经有人在wiki上列好了表格,参考( https://en.wikipedia.org/wiki/Table_of_spherical_harmonics ),前3阶的球谐基函数如下:

img

这里值得注意的是很多资料用这张图来描述球谐基函数:

img

我刚开始看到这张图的时候简直觉得莫名其妙,实际上这里面每个曲面都是用球坐标系表示的,球谐基都是定义在球坐标系上的函数,r(也就是离中心的距离)表示的就是这个球谐基在这个方向分量的重要程度。我是用类比傅里叶变换的方法来理解的,其实球谐函数本身就是拉普拉斯变换在球坐标系下的表示,这里的每个球谐基可以类比成傅里叶变换中频域的各个离散的频率,各个球谐基乘以对应的系数就可以还原出原来的球面函数。一个复杂的波形可以用简单的谐波和相应系数表示,同样的,一个复杂的球面上的函数也可以用简单的球谐基和相应的系数表示。

由于球谐基函数阶数是无限的,所以只能取前面几组基来近似,一般在光照中大都取3阶(Unity中就取3阶),也即9个球谐系数。这里讲一下我自己认为比较核心的几个点的理解:

1、蒙特卡洛积分: 
将计算机尤其是GPU上非常难以计算的积分简化为了加法,这是球谐光照的前提 
2、投影: 
球谐光照的实质就是将复杂的光照信号投影到基函数上存储,然后在使用的时候再将基函数上的数据加起来重建光照信号 
3、伴随勒让德多项式 
想比如正弦信号,伴随勒让德多项式作为基函数不仅是正交的,而且是归一化的, 这意味着其具有旋转不变性,适用于动态物体

综合说来球谐光照的基本框架如下所述:
连续的光照方程 -> 离散的光照方程 -> 分解后的光照方程 -> 球谐变换得到球谐系数 -> 利用球谐系数还原光照方程

二.实验

我们先考虑简单的情况,比如说定义一个光照函数:

img

在球坐标系下,将该函数的值当做光照强度值,可以画出光照在球面上的分布情况:

img

 不过由于这种方式可视化方式对于亮度变换不是很敏感,所以我们把强度当成球坐标系的r,画出来是这个样子:

img

 现在要将这个函数转换成球谐系数表示,首先要做的就是对其进行采样,采样的目标是确定在某个球谐基方向上强度的大小,也即求得每个球谐基Yi对应的系数ci。具体的采样方法如下:

img

 其中N为采样次数。也就是说在计算某个球谐系数ci的时候,首先在球面上采许多点,然后把这些点的光照强度和球谐基相乘(在那个方向上,球谐基函数的分量或者说重要程度就是Yi(xi)),通过这些采样点,从而得到了在每个球谐基函数上光照的分布情况。由于某个球谐基只能大致代表它那个方向上的光照强度,所以需要组合很多个球谐基函数才能近似还原出原光照。需要注意的是:采样时必须要在球面上均匀采样,如果在CubeMap的每个图像上面逐像素采样,将会导致每个面边角亮度提高,中心亮度降低。关于如何在球面上均匀采样方法有很多,比如用正态分布随机生成x,y,z,然后归一化成单位向量。

还原的过程比较简单,通过球谐基与对应的系数相乘得到:

img

这里L’是还原后的光照,s是球面上的一点(也可以看成某个方向),n是球谐函数的阶数,n^2也即球谐系数的个数。

值得注意的是采样和计算ci是预先进行的,比如说复杂场景中,某个位置预先用光线跟踪方法计算环境光,从而采样出ci,这样这个位置的光照信息就压缩成几个ci表示了。但是重建光照的过程是在运行时实时进行的,从重建光照的过程中可以看出该式非常简单,其中Yi的计算从球谐基函数的表中就可以看出只涉及到简单的乘法和加法,完全可以在shader中实现(球谐基函数中的r一般默认都设置成1)。所以如果给我们一个点的球谐系数,利用上面的公式马上就等得到每个方向上的光照强度。

  计算好了球谐系数之后,我们就可以利用这些系数来还原原光照了,利用第二个公式还原之后的效果如下:

 

从左至右分别是原光照、0~2阶球谐光照、0~5阶球谐光照,从中可以看出到第5阶球谐光照与原光照已经很接近了,只是有小部分的高频信息不同。说明球谐系数越多,还原的效果越好,同时还原光照时能够较好地保留低频部分,而高频信息则丢失得比较多。不过对于光照来说,一般都是比较低频的信息,所以3阶,也就是到l=2时就已经足够了。

抛开简单的函数,如果是复杂的环境光贴图,过程也是一样的,比如对于一个这样的环境光:

img

 对它进行采样并还原之后,得到了这样的结果:

img

效果还不错,只是高频丢失了很多。不过这是对光照的还原,因此丢失了高频信息关系也不大。

如果把这两个光照投射到球面上进行可视化,就是这个样子:

三.实现

参照该文章 https://lianera.github.io/post/2017/sh-lighting-apply/

四.Unity中实际使用

Unity中,不管是预计算GI与烘培GI,都不会对非静态模型计算间接反射,光探头(LightProbe)的加入,可以使非静态模型得到周围静态模型的幅射光,主要技术原理就是使用的球谐光照的技术,注意light probe一般不会对静态模型有影响,你看到的影响,只是因为非静态模型的颜色变化大造成的反差。

Unity通过烘培时的光线追踪计算出其光照原始信号,然后投影到基函数并存储其系数,Unity 使用了三阶的伴随勒让德多项式作为基函数,我们在Shader中可通过 ShadeSH9 函数获取重建信号,ShadeSH9 实现在 UnityCG.cginc 文件中,具体代码如下:

// normal should be normalized, w=1.0
half3 SHEvalLinearL0L1 (half4 normal) {half3 x;// Linear (L1) + constant (L0) polynomial termsx.r = dot(unity_SHAr,normal);x.g = dot(unity_SHAg,normal);x.b = dot(unity_SHAb,normal);return x;
}// normal should be normalized, w=1.0
half3 SHEvalLinearL2 (half4 normal) {half3 x1, x2;// 4 of the quadratic (L2) polynomialshalf4 vB = normal.xyzz * normal.yzzx;x1.r = dot(unity_SHBr,vB);x1.g = dot(unity_SHBg,vB);x1.b = dot(unity_SHBb,vB);// Final (5th) quadratic (L2) polynomialhalf vC = normal.x * normal.x - normal.y * normal.y;x2 = unity_SHC.rgb * vC;return x1 + x2;
}// normal should be normalized, w=1.0
// output in active color space
half3 ShadeSH9 (half4 normal) {// Linear + constant polynomial termshalf3 res = SHEvalLinearL0L1(normal);// Quadratic polynomialsres += SHEvalLinearL2(normal);if (IsGammaSpace())res = LinearToGammaSpace(res);return res;
}

三阶的基函数系数分别用了两个子函数来读取,其中

   // SH lighting environmenthalf4 unity_SHAr;half4 unity_SHAg;half4 unity_SHAb;half4 unity_SHBr;half4 unity_SHBg;half4 unity_SHBb;half4 unity_SHC;

 是 UnityShaderVariables.cginc 中的内置变量,用来存放存储的系数,在实际使用中,我们直接调用 ShadeSH9,配合LightProbe 即可读取到 precompute bake 生成的自发光信息 

五.应用与局限

球谐光照最早出现应该是在2002年的Siggraph上,距今还是有些时间了,而且关于其的研究也还有不少学者在做。 最近高调发布的BattleField3所使用的Frostbite2引擎中使用了Enlighten实时GI解决方案,其效果令人印象深刻,其中若干部分就用到了球谐光照的技术。但是观察其它的主流引擎却较少使用该技术(这里是指直接对全部场景做SH来代替LM的模式,不过在生成Light Probe等操作时SH的应用却是必需的),应该说其还是有不少局限的:

  1. 由于球谐变换需要在光照方程中的函数上进行,故而一些需要进行变换的信息首先需要进行参数化,然后再投影并得到SH系数,这就涉及到整个引擎中材质、光源的存储、表述等诸多问题;
  2. 当前对于球谐参数的存储多是逐顶点进行的,因而对于整个场景要想得到较为平滑、细腻的着色效果需要对场景进行较细粒度的细分。
  3. 虽然球谐系数的变换是在预处理阶段生成,但是对于较多的离散采样点、较细的场景细分粒度(对应较多的顶点数)整个预处理的时间代价还是很大的。因这其中涉及到光线跟踪等高密度计算,甚至在使用GPU进行加速之后仍是重量级的时间耗费。
  4. 要想在光照方程重建时获得较高的质量就需要存储较多的SH系数,而这些额外的空间无论是对于传输的带宽,还是设备存储的占用均是劣势所在。

 

参考文章链接:

https://lianera.github.io/lianera.github.io/post/2016/sh-lighting-exp/(本文多摘录于此,感谢前人写这么好的文章)

https://lianera.github.io/post/2017/sh-lighting-apply/

https://gameinstitute.qq.com/community/detail/101099

https://blog.csdn.net/NotMz/article/details/78339913

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/246270.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

图像色调,饱和度,对比度等相关定义

RGB颜色模型 RGB颜色模型也就是我们最常用的三原色,红绿蓝。RGB颜色模型在混色时属于加法混色,RGB中每种颜色数值越高,色彩越明亮。RBG为(0,0,0)时为黑色,RGB为(255,255,255)时为白…

各Rendering Path技术以及其在Unity中的实现

Rendering Path其实指的就是渲染场景中光照的方式。由于场景中的光源可能很多,甚至是动态的光源。所以怎么在速度和效果上达到一个最好的结果确实很困难。以当今的显卡发展为契机,人们才衍生出了这么多的Rendering Path来处理各种光照。 一. 正向渲染Fo…

GPU Gems2 - 3 几何体实例化的内幕(Inside Geometry Instancing)

文章部分内容摘自 https://zhuanlan.zhihu.com/p/38411575 【章节概览】 本章讨论了在Direct3D中渲染一个几何体的许多独特实例(Instance)的技术细节问题,对几何体实例(Geometry Instancing)的技术内幕进行了分析。 【…

GPU Gems2 - 4 分段缓冲(Segment Buffering)

文章参照该文 https://zhuanlan.zhihu.com/p/38411575 【章节概览】 本章介绍了一项可以明显减少一个显示帧中渲染的批次数目的技术——分段缓冲(segment buffering),以及其改进。 【核心要点】 分段缓冲(segment buffering&…

GPU Gems2 - 6 用多流来优化资源管理(Optimizing Resource Management with Multistreaming)

本文摘自https://zhuanlan.zhihu.com/p/38411575 【章节概览】 现代实时图形应用程序最困难的问题之一是必须处理庞大的数据。复杂的场景结合多通道的渲染,渲染起来往往会较为昂贵。 首先,多流(Multistreaming)技术由微软在Dire…

GameObject数组逐渐消失

GameObject数组逐渐消失 我做了10个物体需要每隔俩秒消失一个。 我是这样做的: 我先梳理出大概我需要怎么做的,第一步先引用预制体然后再创建一个数组最后是代码主体。 在start里先把起始时间设好,然后再看Nos方法time是让他时间自己在加&am…

Unity SRP自定义渲染管线 -- 1.Custom Pipeline

该篇是对Catlike Coding这篇文章的概要总结,本人能力有限,如果有不正确的地方欢迎指正 https://catlikecoding.com/unity/tutorials/scriptable-render-pipeline/custom-pipeline/ 通过这篇文章,你将学习到 Create a pipeline asset and i…

GPU Gems2 - 7 带位移映射的细分表面自适应镶嵌

文章参照该文 https://zhuanlan.zhihu.com/p/38411575 【章节概览】 这章介绍了如何使用可选的位移贴图(Displacement Mapping)执行Catmull-Clark细分曲面(Catmull-Clark Subdivision Surfaces)的视图相关的自适应镶嵌&#xff0…

GPU Gems2 - 8 使用距离函数的逐像素位移贴图

【章节概览】 距离贴图(distance map)是一种在像素着色器中给对象添加小范围位移映射的技术。这章中详细介绍了使用距离函数的逐像素位移贴图(Per-Pixel Displacement Mapping with Distance Functions)技术。 【核心要点】 这章中…

GPU Gems2 - 9 S.T.A.L.K.E.R.中的延迟着色(Deferred Shading in S.T.A.L.K.E.R.)

关于延迟着色的详细技术及最新渲染管线技术可以参考我的这篇文章: https://blog.csdn.net/yinfourever/article/details/90263638 【章节概览】 本章是对《S.T.A.L.K.E.R.》中所用渲染器的几乎两年的研究和开发的事后剖析。该渲染器完全基于延迟着色(De…

GPU Gems2 - 10 动态辐照度环境映射实时计算

【章节概览】 环境映射(Environment Maps)是常用的基于图像的渲染技术,用来表现以空间上不变的球面函数。本章描述了一种完全GPU加速的方法,来生成一个环境映射在图形上特别有趣的类型——辐照度环境映射(Irradiance …

GPU Gems2 - 11 近似的双向纹理函数(Approximate Bidirectional Texture Functions)

【章节概览】 本章介绍的内容关于如何较容易地采集和渲染的真实材质,如布料、羊毛和皮革等的技术。这些材质难以用早先的技术渲染,它们基本来与兼得的纹理映射。本章的目标是在采集上花费少量的努力,在渲染上花费少量的技术,但是仍…

GPU Gems2 - 12 基于贴面的纹理映射(Tile-Based Texture Mapping)

本文内容摘自https://zhuanlan.zhihu.com/p/38411575 【章节概览】 这章介绍了一个基于贴面的纹理映射(Tile-Based Texture Mapping)系统,用来从一组贴面生成一个大的虚拟纹理。 【核心要点】 使用纹理贴面(Texture Tiling&#…

一些图形学中的数学应用

包围体是一个简单的几何空间,里面包含着复杂形状的物体。为物体添加包围体的目的是快速的进行碰撞检测或者进行精确的碰撞检测之前进行过滤(即当包围体碰撞,才进行精确碰撞检测和处理)。包围体类型包括球体、轴对齐包围盒&#xf…

GPU Gems2 - 13 动态环境光遮蔽与间接光照(Dynamic Ambient Occlusion and Indirect Lighting)

本文摘自https://zhuanlan.zhihu.com/p/38411575 【章节概览】 这章在讲大家很熟知的环境光遮蔽(Ambient Occlusion , AO)。 文中的描述是,介绍了一种用于计算散射光传递的新技术,并演示如何用它来计算运动场景中的全局光照。主要…

解析Monte-Carlo算法(基本原理,理论基础,应用实践)

转载自https://www.cnblogs.com/leoo2sk/archive/2009/05/29/1491526.html 引言 最近在和同学讨论研究Six Sigma(六西格玛)软件开发方法及CMMI相关问题时,遇到了需要使用Monte-Carlo算法模拟分布未知的多元一次概率密度分布问题。于是花了几天…

Unity SRP自定义渲染管线 -- 3.Lights

Lights Single-Pass Forward Rendering 实现 diffuse shading.支持 directional(方向光), point(点光源), and spotlights(聚光灯).每帧可允许最多16个可见光参与渲染每个物体可以最多由4个像素光和4个顶…

Faceware 面部捕捉在Unity中的应用

官网软件下载:https://www.facewaretech.com/ 官网教程:http://support.facewaretech.com/ 官网素材下载:https://www.facewaretech.com/learn/free-assets Faceware Analyzer Faceware Retargeter(Maya) Unity 真…

Tone mapping进化论

转载自 https://zhuanlan.zhihu.com/p/21983679 这几年,随着拍摄设备、渲染方法和显示设备的发展,HDR慢慢会成为标配。照相机和摄像机可以捕捉到HDR的影响,渲染过程中可以产生HDR的画面。这些内容如果需要显示到LDR的设备上,就需…

坐标变换过程(vertex transformation)

原文:https://blog.csdn.net/wangdingqiaoit/article/details/51594408 在上面的图中,注意,OpenGL只定义了裁剪坐标系、规范化设备坐标系和屏幕坐标系,而局部坐标系(模型坐标系)、世界坐标系和照相机坐标系都是为了方便用户设计而…