基于Qt的OpenGL编程(3.x以上GLSL可编程管线版)---(三十三)PBR

Vries的教程是我看过的最好的可编程管线OpenGL教程,没有之一其原地址如下,https://learnopengl-cn.github.io/07%20PBR/01%20Theory/ 关于PBR的详细知识了解请看原教程,本篇旨在对Vires基于visual studio平台的编程思想与c++代码做纯Qt平台的移植,代码移植顺序基本按照原教程顺序,并附加一些学习心得,重在记录自身学习之用

Tip1: 强烈推荐理论部分阅读Vries的原教程

Tip2: https://zhuanlan.zhihu.com/p/61962884,一个很好的知乎专栏,大致解释了BRDF公式的数学推理过程

Tip3: 移植时,Vries的中文教程翻译未及时更新,有两处错误,一为BRDF方程中的错误,二为着色器代码中正态分布函数的错误,详情见下

程序源代码链接:https://pan.baidu.com/s/1a0qOp2F1JxWbMFsNQHCHrA 提取码:dhem 

编译环境:Qt5.9.4

编译器:Desktop Qt5.9.4 MSVC2017 64bit

IDE:QtCreator

一,程序简介

  WASD控制摄像机前后左右移动,E控制上升,Q下降。鼠标左键按住不放课拖拽摄像机视线方向 

扫描二维码关注公众号,回复: 14647333 查看本文章

二,PBR理论

   这里只简单赘述,再次强烈建议看Vries原教程。PBR,Physically Based Shading,基于物理的真实渲染,简单来说,就是能量守恒,同一个强度的光束照射到一个材质球上,若该球是光滑的,则光斑半径应该小且亮,若该球是粗糙的,则光斑半径应该大且暗。光斑的半径与亮度呈负相关,他俩的关系就是一个能量守恒问题。

  这个能量守恒问题由反射率方程来表示:

  

  方程大意为对于片元P点来说,当摄像机位于W0方向时,以P点为圆心的半球所接受到的所有光束,反射到W0方向的光束强度,即求该片元的diffuse与specular颜色。

  1.   L0(p, w0)表示反射到wo方向的辐射强度
  2.   fr(p, wi, w0),为BRDF函数,双向反射分布函数,基于p点的材质(粗糙度,金属度,表面颜色)对光束的反射率进行加权
  3.   Li(p, wi)表示入射方向为wi的光束的辐射强度。

  2.1 BRDF函数

    BRDF函数,是整个反射率方程中最重要的部分,这里Vries的中文翻译教程出现了错误

    中文教程PBR“理论”的最终反射率方程为

    而英文教程的方程为:

  差别在于Ks的有无,这里因为菲涅尔函数F本身就表示反射到表面的光的比例,即ks = F,所以应在最终方程中去除ks。

(1)kd,为入射光线中折射部分所占的能量,即kd = 1-ks = 1 - F

(2) c,表示材质表面颜色

(3)Π, 除以Π 是为了保证折射光的强度不超过入射光的强度,能量守恒,推理过程见

          https://zhuanlan.zhihu.com/p/61962884

(4)D,为法线分布函数,在统计学上,近似的根据材质表面的粗糙度α,得出的微平面与中间向量h(即v+l,视线方向与光源方向的矢量和)取向一致的概率,n为片元的法线向量

这里有第二个错误,Vries在Github与learnopengl上的代码,正态分布函数如下,

这样算下来的结果是

可以很明显最左列的小球失去了光斑,正确的修改应为去掉max()函数,如下:

(5)F,菲涅尔方程,表示反射的光线占入射光的百分比

      F0表示平面的基础反射率,这里引入“金属度metalness”的概念,mix(a, b, p) = (1-p)*a + p * b,即金属度越强,F0越接近材质表面本身的颜色。

    

  (6)  G,几何遮蔽函数,表示入射光线或反射光被崎岖不平的表面遮挡后所剩余的量,

k,根据入射光线类型的不同而不同,类型为直射光或IBL全景,α为表面粗糙度

  最终的几何遮蔽函数为  

  因为光在入射与反射时都会因为微平面崎岖不平,而发生损失,所以需要计算两次遮蔽。

  (7) 4(w0·n)(wi·n),方程配平,能量守恒同理,保证只有镜面反射时,反射的强度不超过入射的强度,配平过程见同一个链接。 https://zhuanlan.zhihu.com/p/61962884

在最后的纹理映射环节,Vries加了个光源的小动画,使单个光源绕y轴旋转,这块我懒得写了。

猜你喜欢

转载自blog.csdn.net/z136411501/article/details/101176391