|
大家如果看见任何错误请使劲喷! 我随后改正, 我们一起成长学习
在开始学习图形学的时候, 看到兰伯特, blinnPhong 这些小可爱.
内心就会想,也不过就是这样嘛.
Easy
直到慢慢看到BRDF,
然后我就产生了这种感觉:
但是到现在我自己手撸了一个BRDF的材质后,
我觉得这并不是我的错,从工程的角度看问题,可能比物理的角度切入会更好理解
在工程上完全理解了BRDF,你再去看物理原理和数学,至少比较舒服一点?
如果你和之前的我有同样的感觉, 希望这篇文章可以帮到你
BRDF到底是什么?
我们先看小可爱们
兰伯特+BlinnPhong 其实就是 漫反射+高光
只要你能看懂上面这句话,我保证你可以看懂下面的内容了,
但是你要看不懂上面这段,你需要先去学一下基本光照模型.
而BRDF可以分为两种实现: 直接光照和间接光照
直接光照和间接光照的实现又同时都包含两部分: 漫反射和高光(镜面高光)
这里我们先无视间接光,直接看直接光照
我们把那一坨劝退公式拿出来:
童靴们不要被他吓到, 其实他的意思是这样的:
其实大家只要明白, 漫反射+高光 就等于结果就行了,当然严谨的讲,实际上是反射,不过我们先无视这个
而兰伯特其他的部分 都是为了这两项服务的,为了让大家不晕,我在最后在解释其他细节
而间接光和直接光的不同就在于漫反射和高光(镜面反射)的计算方式不同,本质还是漫反射+高光
于是我做了这个表格来像大家展示BRDF的本质:
看到这里,大家应该理解了BRDF就是漫反射+高光(镜面反射)这件事吧!
BRDF为什么是漫反射+高光?
这里我们先慢慢聊直接光的实现
我们还是小可爱镇楼, Lambert漫反射:
翻译一下:
BlinnPhong:
翻译一下:
这里讲下h, 其实h就是半角向量
普通的Phong不是这样的么:
r是反射方向,而实际上r是要算出来的, r的位置是:
公式是:
带入到Phong里:
一看就很复杂,对不对?
所以大佬们用了一个手段,引入一个V和L之间的向量, 我们叫他半角向量:
h等于:
所以用h点积n 代替了r点积l,这样可以避免计算r,
h就是这样来的啦,
我们接下来看他们产生的结果就是相加:
上面的公式等于下面这个:
如果上面这一坨你能看懂, 下面这一坨应该也可以了
BRDF直接光漫反射:
在这里C实际上就是albedo
就是这么简单
高光 (其实这里是镜面反射,我们在下一部分介绍DGF这三个东西):
最后还是加一起
是不是顿时感觉也不过如此?
此时加上两个参数ks和kd在看这个公式:.
这时我们知道 这里已经基本齐了
不知道大家注意到没? 在漫反射项和高光项前面
有两个 Kd 和 Ks分别是什么,?
我们要从菲涅尔讲起, 菲涅尔的公式是:
这个F0 实际上就是菲涅尔系数,unity里用的是0.04,
其他材料的F0:
这样我们就容易解释ks了 ks就是F:
kd实际上是为了保证能量守恒的一个
而Ks就是F 所以实际使用中我们就省略了, 所以最后我们得到这东西了:
然后我们全部再乘上Li:
我们把Li写成人能看懂的东西:
最后因为kd和ks太长了 我们还是把kd,ks代入方程再看一遍这个劝退公式正经有效的部分:
注意: ks 在这里和F重了, 实际上是不需要额外乘一次F的
而外面那个积分,我给大家说,所有的积分就是加一起
那个积分其实抽出来看长这样:
后你但凡看见积分就当成加好,不要被他吓到了
我们以Forward为例
例如在基础光照中, 就要算一个平行光的+间接光
之后Forward Add 就一次pass添加一个光源 等于是累加一次
所以大家会发现这里实际上就是求和 ,所以根本不要被积分符号吓到,不就是加一起吗!
来和我一起念: 积分就是加一起!
至于更多的细节大家可以参考这篇文章:
Unity中BRDF直接光照部分的DGF
但是你经过上面一长串的洗礼,估计已经对BRDF有了一个初步的理解
此时我们就要聊另外一个问题,就是 镜面反射
BRDF公式中有 DGF三个字母
分别代表三种属性:
D - 正太分布函数(也有人喜欢法线分布函数),说人话就是-高光反射
G - 几何函数, 其实就是粗糙度,来确定表面散射量
F - 菲尼尔, 菲涅尔就是菲涅尔反射了,请大家自行百度,这个概念太清晰了
这三个的公式我就不列了,只要大家可以认为这三个加一起就是求高光反射就好了,
在实际使用中, 直接光是没办法实现镜面反射的
所以如果我们只考虑直接光, 这三个东西得到的结果,还真就是高光而已
D决定你高光的强度和大小
G决定表面的粗糙度,会影响漫反射的效果和高光的效果,这个值等于1的时候,就等于极其粗糙了
F就是叠加一个菲涅尔反射
直接光照中的BRDF就是为了体现物体自身被光照之后的表现
积分是为了在多光照(复杂光照就是环境光了)情况下保持一个正确的物理叠加
Unity - BRDF中间接光照部分的DGF
实际上直接光照的BRDF非常简单,易懂,但是其实BRDF真正的意义在于间接光
如果只看直接光其实用不用BRDF都还差不多,间接光其实就是如何正确的镜面透射周围的环境
而间接光照是BRDF中最核心也是最复杂的部分,
因为太复杂,我就不放公式了,我主要讲下间接光到底是怎么回事
也有好多文章讲各种公式证明什么的,大家感兴趣就自行搜索吧
而间接光照中,分为
球谐函数 - 其实就是漫反射
IBL - 镜面反射的核心
球谐:
简单的说这就是为了算在环境光下的漫反射,所为环境光实际上就是环境贴图
球谐是根据这个环境贴图,生成一个对应的漫反射,这一步是烘焙的时候预计算的
你可以在下面看IBL的解释
unity里给我们提供了一个方法来计算球谐: ShadeSH9(float4(i.normal, 1));
如果这个不能满足你的话可以去看这篇文章(反正我是没看懂):
IBL实现高光反射:
我们之前说过的镜面反射,就是利用IBL技术实现的
菲涅尔还是我们熟悉的菲涅尔,不同的是
D和G都不一样了
而间接光的DG计算都需要预积分和积分查找表(LUT)参与
我们先介绍下什么是IBL (image-based lighting)
镜面反射说白了,就是和镜子一样反射周围的环境
众所周知,实时渲染里根本不可能真的像光线追踪那样让光线弹来弹去
那这里很自然的,我们把周围的环境预先烘焙到一个贴图上
类似这样:
为什么要这么多张呢...因为G嘛, 粗糙度不一样, 而金属度影响的是菲涅尔
不同的光滑程度,就直接插值出当前结果了
镜面反射就是这样实现的,大家可以看看效果:
右下角还写错了...右下角是两者都为0
嗯 图上右下角还写错了...右下角是两者都为0
横轴是光滑度下降的球体,纵轴是金属度下降的球体
左上角和右上角的环境采样纹理肯定不一样
但是左上角和左下角确实一样的, 所以这个只和粗糙度有关系
金属度决定的是反射量
所以简单的理解的话,就是把不同的照片映射到物体身上产生镜面效果
反射球,光照探针基本都是这个原理
这里最大的坑在于
我们如何生成这个图片,
以及因为每片元收到环境光影响的贡献度是不同的,所以如何积分如何采样就成了关键
但是这两块是在太复杂,大家可以去这里挑战:
不过我们也可以大致看下代码理解下:
const float MAX_REFLECTION_LOD = 4.0;
//根据粗糙度和反射向量生成lod级别对贴图进行采样
vec3 R = reflect(-V, N);
vec3 prefilteredColor = textureLod(prefilterMap, R, roughness * MAX_REFLECTION_LOD).rgb;
//从Lut中获取预计算
vec2 envBRDF = texture(brdfLUT, vec2(max(dot(N, V), 0.0), roughness)).rg;
vec3 specular = prefilteredColor * (F * envBRDF.x + envBRDF.y);
最后
谢谢你看到这里, 如果有问题请使劲喷,我也在不断学习
如果可以的话请友情三连: 点赞收藏关注 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|