八、D3D12学习笔记——光照

龙书中对光照作用的表述有一句话非常经典:我们在视觉上对世界的感知依靠的是光照及其与材质的交互。所谓渲染,不过是材质与光交互的结果。

一、光照的分类

一般光栅化使用的都是局部光照模型:仅考虑精确光源的直接光照,不考虑场景中其他物体的反射光叠加效果。与之对应的就是全局光照模型:不仅考虑精确光源的直接光照,还要考虑场景物体的间接反射光照

二、光照模型

根据光照细节层次,我们可以简单把光照模型划分在顶点级(逐顶点光照)和像素级(逐像素光照or Phong光照模型)。这对效率的影响是比较大的,比如在Unity中只有重要光源是逐像素的以节省开销。

三、法向量

求解法向量的基本逻辑是叉积,一般先求解逐顶点法向,再插值得到逐像素法线。对于我们在场景中的变换,也应将模型空间法线进行变换,对于等比例缩放和旋转这种变换,其变换矩阵是正交矩阵(矩阵的转置=矩阵的逆),则法线变换矩阵与坐标点变换矩阵一致,否则要使用逆转置矩阵进行求解。

四、参与光照计算关键向量

1.光向量:

常规意义上指由光源指向计算点P,为了与指向观察表面外侧的法线进行边侧夹角计算,一般会以从P到光源表示光向量L;

2.观察向量:

常规意义上指从眼睛(视点)到计算点P,但是出于同样的考虑,一般我们会以从P到视点表示观察向量V

3.反射向量:

光从界面法线一侧入射后,从另一侧镜像射出的向量,计算反射向量r要使用下式:
r=I-2(dot(n,I))n(图形学入门:计算反射向量 - 知乎 (zhihu.com));注意这个地方使用的光向量I=-L

五、常用光照计算表达

1.兰伯特余弦(漫反射)

兰伯特描述了一束光照射到观察点,使观察点在半圆面内呈现出的辐照度(色彩),已经得到了半圆面的均分,不管你去不去看,光就在那里,只要把眼睛放在半圆面的某个方向就能接收。

兰伯特的投射是根据照射面积均分的,因此投影面积非常重要,其公式如下:
Cd=max(dot(L,n),0)XBLXMd

max(dot(L,n),0)XBL表示光线经过投射后到达观察点,均分后反射的实际光量,与材质经过Md漫反射率进行交互得到最终的色彩。只是我们在使用中很多时候BL使用了(1,1,1,1),才可能忽略光本身的影响。

2.环境光照

为了不让不接受光照的部分什么都看不见,往往会给一个很暗的亮度展现一些模型的边界,以达到立体的效果,虽然不准确,但是效率非常高:

Ca=ALXMd

AL指环境光的亮度,这个值往往很小,再经过一轮与材质的交互,Md漫反射率,就是我们需要的环境光照。

3.镜面光照

在很多地方高光反射都是Phong或者Blinn-Phong高光反射,D3D12在这里实际使用了snell效应,并根据材质表面粗糙度进行。

Phong或Blinn-Phong高光

两种高光反射的原理一致,只是对于是否计算反射向量r存在差异

Phong看上去更加接近我们在高中建立的光线传播原理,即光经过界面反射之后,入射光线与反射光线关于法线对称。如果此时我们将眼睛放到反射光线指示方向,即V=r,那么此时反射光线会全部进入眼睛,我们会看到最亮的效果,但是你同时可以考虑光是波,他的传播方向并不是一成不变,在空间中波具有衍射等行为,因此只要V与r偏差不大,在一定范围内都是可以看到光的,据此Phong提出了他的高光计算模型;

Cs=BLXMsXpow(max(dot(V,r),0),gloss);

BLXMs表示观察点在光照颜色BL以及高光反射率Ms交互后的出射光量,然后依据观察向量与反射向量的夹角dot(V,r),对其进行衰减。Blinn-Phong模型的不同之处在于不用计算r,改为计算一个半角向量h:

Cs=BLXMsXpow(max(dot(h,n),0),gloss);

但是我们不禁产生这样一种疑问,谁是正确的。答案是都不准确,这里笔者就抛出自己所理解的不合理之处:

1).BLXMs怎么就能表示光经过反射的出射量呢,他不考虑像兰珀特那样的投射吗,那么是不是说我们可以改成这样:max(dot(L,n),0)XBLXMs?还是说Ms自带了?Ms肯定不能自带,他是一个材质点属性,与角度是无关的;

2).使用半角向量与法向量比较,避免了计算反射向量的开销,看上去是一个不错的加速方法,但是这肯定不满足常规的物理逻辑,但是实际上有的时候效果确不错,甚至超过Phong,那也从客观说明了Phong的不准确性。

为了解决上述问题,我们不得不考虑D3D12中介绍的基于snell的一种高光反射,他不仅与材质表面相关,还与观察角度相关,也就是我们常听说的PBS,基于物理的渲染。

Snell效应

 Snell效应展示了一个现象,从不同的角度观察一个表面反射光量是不同的,即描述了不同角度观察,光的反射率不同(对应上述问题1,观察角度的不同反射率是不同的)。那么我们也就经常使用菲涅尔方程求解入射光线被反射的百分比,常用公式为石里克近似:

Rf(a)=Rf(0)+(1-Rf(0))*pow(1-cos(a),5);

可以看出这个公式以Rf(0)为基础,得到的数值是在Rf(0)上增加,可以看一下常见的曲线:

其中Rf(0)是材质属性的一种,有专门的实验进行测定,如果要准确就去查表,这里提供一种近似计算:

Rf(0)=pow((n1-n2)/(n1+n2),2);

这个公式是我在RayTraceOneWeek里看到的,他是根据光反射界面两侧介质折射率计算出来的。

表面粗糙度

是否反光与表面光滑,或粗糙程度相关,当然这里我们也只是基于微平面的模型来进行估计,这是近似的,真的要了解粗糙度的影响,我们后边会出一篇有关BRDF的介绍,从表面几何角度来分析这个问题。

记一下结论:

1).定义一种归一化分布函数,描述观察点P周围微观层面微平面法线h与宏观平面法线n的偏离dot(h,n)情况,期望在偏移为0时取得最大值,看一下D3D12的描述:

 

2.根据上述函数,m越大,函数值越小,偏离越远,表面越粗糙;

3.上述函数存在一个问题,最大值就是1,其函数图像如下:

不难看出图像面积差异很大,客观代表了光能量的大小,但是我们期望光反射的能量是入射光与反射率的乘积,和粗糙度无关,因此我们要保证光能量的守恒,需让函数图像面积大致一致,给出如下方法:

这里增加了一个系数,其图像如图: 

 

 确实,能量守恒了,但是都大于1。这难道不会导致反射能量被放大吗???

基于Snell的高光

这里给出计算方程

Cs=max(dot(n,L),0)*BLXRf(a)*(8+m)pow(dot(n,h),m)/8;

 max(dot(n,L),0)*BL:观察点P接收到的光线投射辐照度;

Rf(a):根据Snell从观察角度定义的反射率;

(8+m)pow(dot(n,h),m)/8:由于表面粗糙导致的光线散射衰减。

六、完整光照模型

LitColor=环境光照+兰伯特漫反射+高光反射

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值