Environment Mapping
Shading From Environment Lighting
环境光照:用一张图来记录在场景中往任何一个方向看的光照
Image-Based Lighting (IBL)
基于物理的渲染:
- 基于微平面理论
- 使用基于物理的BRDF(Blinn-Phong光照模型也被认为是一个BRDF。然而由于Blinn-Phong模型并没有遵循能量守恒定律,因此它不被认为是基于物理的渲染)
- 保证能量守恒
在基于物理的渲染方法之中,想要计算间接光照, 需要分析光线的传播(光线追踪、光子映射)等方法, 但在实时渲染中计算量太大. 实时渲染中最常用的是基于图像照明(IBL)计算间接光照,把天空盒环境贴图上的颜色信息当做环境光源,通过对反射方程的近似计算,从而生成采样贴图,最终计算光照能量时仅仅需要去对这个贴图进行采样再加以计算即可,相比于完整的全局光照减轻了计算代价,同时也带来了不错的渲染质量的提升
IBL的情况下,通常解渲染方程-蒙特卡洛积分-需要采样 每个shadingpoint采样太慢
通常只要shader中有sampling就不能用在实时渲染(但近几年技术的提升 在实时渲染使用sampling有了可行性)
不考虑visibility
rendering equation就只有brdf和lighting相乘再积分
brdf是glossy时,在球面上的覆盖范围很小
brdf是diffuse时,覆盖范围大,且足够平滑
此时可以用$\int_\Omega f(x)g(x) dx \approx \frac{\int_\Omega f(x) dx}{\int_\Omega dx} \cdot \int_\Omega g(x) dx$ 近似
1. light
把light单独拆出来,并normalize,相当于把ibl表示的图给模糊了
把light拆出来,其实就定义了一种操作filtering,可以去滤波环境光。滤波的核取多大取决于BRDF占多大,BRDF的区域越大,最后取得的图也就越模糊
Prefiltering就是提前把滤波环境光生成,提前将不同卷积核的滤波核的环境光生成(和mipmap相似)即把环境贴图在render前就模糊,当需要时进行查询即可,其他尺寸的图则可以经过这些已生成的通过三线性插值得到(要取一片区域的近似可以先近似好再取)
用brdf来计算shading point时,左图要根据glosness来以一定立体角的范围内进行采样再加权平均来得到 右图从镜面反射方向望去在pre-filtering的图上进行查询 进行一次查询就等价于左图的操作,并且不需要采样
Prefiltering + single query = no filtering + multiple queries
到此解决了拆分后的前半部分积分采样的问题,接下来处理BRDF项采样的问题
2. brdf
要解决积分就要通过预计算,直接把brdf进行预计算需要打一个五维的表格,这样就会导致爆炸的存储量。想要进行预计算,就要把预计算的参数维度压到二维
主要想法:降维,减少依赖变量,拆开菲尼尔项
brdf 详解:
- 近似F(Fresnel)和D(NDF)项 spilt sum:
- 此时暂时不考虑阴影
- Frenel term可以近似成一个基础反射率R0和入射角度的指数函数
- 法线分布函数(NDF)是一个一维的分布,其中有两个变量,一个变量定义是diffuse还是gloosy,另一个是half vector和法线中间的夹角,可以近似成入射角度相关的数,这样就变成了3维的预计算
- 再把Frenel的近似公式带入到brdf里,R0拆到积分的外面去,这样需要积分的变量只有roughnes和入射角度,这样就可以预计算存成一个二维的数组,就不用采样了
工业界用求和
将预计算后的结果存入一个2D的纹理texture中 使用时查询即可
Shadow from environment lighting
very difficult
- many-light problem 把环境光照认为成很多光源的光照 每个光源都要有个shadowmap 开销大
- sampling problem 在任何一个shading point采样各个方向的光照的Visibility项很复杂 需要大量采样的样本 brdf可能是非常高频的glossy 不容易把brdf给拆分开来 很难从环境中分离出V项
工业界主流方法 只用一个主要光源生成阴影
生成阴影相关研究:
Imperfect shadow maps 全局光照部分产生的shadow
Light cuts 离线渲染 把反射物当成小光源,把所有的小光源做归类并近似出照射的结果
RTRT 可能是最终解决方案
PRT ✔
preKnowledge:
两种函数相乘的积分可以认为成一个卷积操作。其中只要有一个函数是低频的,得到的结果也是低频, 相当于做了低通滤波,积分之后的频率取决于积分前最低的频率 低频也就是smooth
基函数(Basis Functions)把一个函数可以描绘成其他函数(基函数)的线性组合 傅里叶变化就是基函数
Spherical Harmonics (SH)
定义在球面上的一系列二维函数组成的基函数
类似一维里的傅里叶级数 存在不同频率的函数,不同频率的函数个数也不同。第l阶的SH有2l+1个二维函数 每个基函数都有一个比较复杂的数学表示,对应一个legendre多项式
一个函数f由一系列基函数B和系数c的线性组合表示,通过投影操作确定基函数前面的系数c
空间中想描述一个向量,可以xyz三个坐标来表达,就可以这么理解,把xyz轴当做三个基函数,把向量投影到,xyz轴上,得到三个系数就是三个坐标
球面函数变cos sin再傅里叶展开可能会有缝 所以用Spherical Harmonics 适用于直接分析球面上的函数
重建:已经知道基函数对应的系数,就能恢复原来的函数。基函数的l可以是无限个的,可以只用前几阶来恢复原来的函数,取的阶数的个数越多,越能还原原来函数的细节
rendering equation在计算shading的情况下就只有lighting和brdf
brdf如果是diffuse材质,就会像一个低通滤波器,只有低频的信息,非常smooth
因为brdf是低频的,那么Lighting和brdf两个函数相乘的积分也是低频的
由于环境光是来自于四面八方且都有值,所以环境光照就是一个球面函数,可以把它投影到任何一个SH basis上,可以投影很多阶,但是只需要取前三阶的SH去恢复环境光就可以恢复出最低频的细节 这样SH只要用前三阶就能还原shading的结果
以上仍然还是shading
SH 实现: https://zhuanlan.zhihu.com/p/362460950
Precomputed Radiance Transfer (PRT)
解决shadows和global illumination
在rendering equation中把lighting,visbility,brdf项可以描述成三个二维的球面函数,在环境光照中,需要大量的采样,开销很大
PRT会假设在一个环境中,就光照变化,其他不变
把渲染方程看作lighting 和 light transport(brdf和visibility)
- lighting是一个球面函数,可用基函数表示,预计算阶段计算出lighting
- light transport 只和当前shading point相关(只有light发生变化时) 可以认为是shading point自己的性质 写成基函数形式预计算出 (brdf只有一个变量,即入射光线,出射光线不随相机变化而改变,只要有入射光线,出射光线的值就是确定的)
diffuse:
brdf是一个常值,可以从积分里拿出来。把lighting写成一个用基函数来描述的函数,这样就能把Lighting从积分从拿出来
积分里剩下来的就是light transport(brdf和visibility)乘一个基函数,这就成了lighting transport投影到一个基函数的系数,就能进行预计算,这样就只要算一个点乘就好了。
代价就是场景里的物体就不能动(light transport预计算,visibility当成常量),而且在光源可以旋转的环境就处理不了
旋转一个基函数之后,得到的函数就不再是一个基函数(因为基函数有严格的朝向等限制),但是旋转球谐函数等价于同阶基函数的线性组合 预计算的光照可以旋转 可以立刻得出旋转后的sh基函数新的线性组合
可以把Bi理解为lighting,也就是说每个basis所描述的环境光去照亮这个物体从而得到照亮之后的结果,预计算就是把每个basis照亮得到的结果生成
最终在任意一个shading point点(几何形体上的vertex)求得的shading result,在实际计算时只是lighting项投影到sh基函数上求得的li系数组成的vector和Light transport项投影到SH基函数上求得的Ti系数组成的vector做了个点乘
在实际运算时,对每个顶点预计算出它的shading result,三角形内部任一点则通过插值得到它的shading result,叫做per vertex shading.
或者在三角形内部先插值好lighting的vector和light transport的vector,然后再去计算pixel上的shading result,叫做per pixel shading.
另一种思路把light transport和lighting一样也描述成基函数,再在积分中把lighting 和light transport合并,变成一个双重求和,因为SH的正交性,虽然结果是O($n^2$),但和O(n)没区别
glossy:
diffuse的brdf是常数,glossy的不是
像diffuse一样把light transport投影的到SH,这样light transport包含v又包含brdf,brdf是四维函数(2维的输入方向,2维的输出方向)
对于diffuse,brdf与摄像机位置无关,存储小,而glossy与摄像机有关,摄像机方向是无限可能的无法存储
即使light transport即使投影到了i方向上的基函数,所得到的仍然是一个关于O的函数而不是系数
light transpoert投影到SH就成了关于o的二维函数,把投影的结果再投影到SH上去,这样一来就得到一个矩阵。diffuse的情况下SH会用到三阶的basis function,glossy的情况用四阶,五阶,甚至更高阶数
上面的积分已经计算了全部入射光线关于一个固定的出射光线的值,换一个出射光线,就又要积分一次,所以T变成了T(O)
结果就从原来的向量点乘变为了一个向量和一个矩阵的乘法
light transport上就不认为得到的是向量,而是矩阵,即对任意一个O都会得到一串VECTOR,把所有不同O得到的VECTOR摆在一起,就形成了一个矩阵多次反射当作lighttransport的一部分 不管中间boucne几次,只需要预计算出Light transport就能得出最后的shading result
可以把任意复杂的light transport给预计算出来,只是light transport越复杂在预计算时花费的时间多而实际跑时候是很快的
预计算是一个独立的程序,会有存储和读取的过程
PRT使用要求: 静态场景、动态光源 低频的情况
Wavelet 小波函数
SH只适合低频的情况,不太适合描述高频的情况,需要非常高的阶数才能才能还原一个比较高频场景。SH是用预计算的方式,只能在固定场景中使用,在场景中也不能动态改变物体的材质
其他不同basis functions - wavelet
sh是定义在球面上,小波是定义在一个图像块 SH通过截断前几阶的SH来压缩,小波是任何一个函数也能投影到各个不同的小波对应的基函数上,投影在基函数之后会发现很多基函数对应的系数是接近0的,这样就能通过保留非接近0或者保留最大的几个来近似地描述原始的函数 支持全频率的描述,高低频都能描述
定义在平面上 用球面函数描述2D会出现一个缝,用cubemap来描述
对任何一张cubemap做小波变换,都把高频信息留出来,把稍微低频的信息留下,再对低频的信息进行小波变换,不断进行小波变换就能进行很好的压缩。jpeg的格式就用了类似的方式来压缩。但是小波不像SH能支持旋转