games101:作业7+Microfacet微平面理论+cook-torranceBRDF方程计算+作业7拓展

  • 一,作业7
    • 1.1 代码部分
    • 1.2 加入多线程
  • 二,Microfacet微平面理论
    • 2.1 BRDF==Material
    • 2.2 Lambertian漫反射部分
    • 2.3 cook-torrance镜面反射部分
      • 2.3.1 菲涅尔方程(Fresnel Rquation)
      • 2.3.2 几何函数(Geometry Function)
      • 2.3.3 法线分布函数(Normal Distribution Function)
  • 三,作业7拓展题
  • 参考资料

一,作业7

1.1 代码部分

作业7是实现路径追踪,这部分内容比较多,所以单独拿出来写一篇。

作业里的流程描述已经很详细了,如下:

  • Scene::castRay in Scene.cpp–path tracing算法,注意理解各判断条件
Vector3f Scene::shade(Intersection& hit, Vector3f wo) const
{//注意这里判断是否为光源本身,否则光源是黑色的-----作业思考题if (hit.m->hasEmission()){return hit.m->getEmission();}Vector3f p = hit.coords;Vector3f N = hit.normal;//直接光照Vector3f L_dir = {0,0,0};float pdf_light = 0.0f;Intersection inter;sampleLight(inter, pdf_light);//Get x, ws, NN, emit from interVector3f x = inter.coords;Vector3f ws = x - p;Vector3f wsdir = ws.normalized();Vector3f NN = inter.normal;Vector3f emit = inter.emit;Ray p2x(p,wsdir);Intersection IfP2xBlocked = Scene::intersect(p2x);//注意这里,有可能有交点但交点在延长线上,也就是光源比物体更近if(IfP2xBlocked.distance - ws.norm() > -EPSILON){L_dir = emit * hit.m->eval(wo, wsdir, N) * dotProduct(wsdir,N) * dotProduct(-wsdir,NN) / dotProduct(ws, ws) / pdf_light;}//间接光照Vector3f L_indir = {0,0,0};if(get_random_float() < RussianRoulette){Vector3f wi = hit.m->sample(wo,N).normalized();float pdf  = hit.m->pdf(wo,wi,N);if(pdf > EPSILON){Ray r(p,wi);Intersection r_Blocked = Scene::intersect(r);//注意这里,条件是hit&&non-emittingif (r_Blocked.happened && !r_Blocked.m->hasEmission()){L_indir = shade(r_Blocked,-wi) * hit.m->eval(wo, wi, N) * dotProduct(wi,N) / pdf / RussianRoulette;}}}return L_dir + L_indir;
}// Implementation of Path Tracing
Vector3f Scene::castRay(const Ray &ray, int depth) const
{// TO DO Implement Path Tracing Algorithm hereIntersection hit = Scene::intersect(ray);if (!hit.happened) return {};return shade(hit,-ray.direction);
}

这时发现结果图不对:

原来是上个作业里写的Bounds3::IntersectP中判断t_enter 与 t_exit关系不对,要写成:「老师说图形学不管大于还是大于等于,哼要管的!边界条件一定要注意好」

return  (t_enter <= t_exit && t_exit >= 0);

修改之后发现背景有很多黑线:

将Scene::castRay中的

if(IfP2xBlocked.distance - ws.norm() > -EPSILON)

这一句中的-EPSILON改为1e-2就可以了。为什么呢???我也不知道,参考各个网友的测试结论。注意pdf里有如下一句话


最后贴上784大小矩形下spp为32、P_RR为0.8、上述光线距离差大于-0.00005f的结果:「可以看到还有黑线,用时1h」

![在这里插入图片描述](https://img-blog.csdnimg.cn/c984292dc9ea49f49f48710e8a0fbd3e.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5oiR6KaB5ZCQ5rOh5rOh5LqG5ZOm,size_20,color_FFFFFF,t_70,g_se,x_16# =784 × 784)

1.2 加入多线程

  • Renderer::Render in Renderer.cpp–调用castRay函数的地方,将整个场景分为多块,每块为一个线程,多线程处理。修改部分的代码如下:
// change the spp value to change sample ammount
int spp = 32;
std::cout << "SPP: " << spp << "\n";int process = 0;
auto MultiThreading = [&](uint32_t lx, uint32_t rx, uint32_t uy, uint32_t dy)
{for (uint32_t j = uy; j < dy; ++j) {int m = j * scene.width + lx;for (uint32_t i = lx; i < rx; ++i) {// generate primary ray directionfloat x = (2 * (i + 0.5) / (float)scene.width - 1) *imageAspectRatio * scale;float y = (1 - 2 * (j + 0.5) / (float)scene.height) * scale;Vector3f dir = normalize(Vector3f(-x, y, 1));for (int k = 0; k < spp; k++) {framebuffer[m] += scene.castRay(Ray(eye_pos, dir), 0) / spp;}m++;process++;}// 互斥锁,用于打印处理进程std::lock_guard<std::mutex> g1(mutex_ins);UpdateProgress(1.0*process / scene.width / scene.height);}
};int bx = 5, by = 5;
std::thread th[bx * by];int strideX = (scene.width + bx-1) / bx;
int strideY = (scene.height + by-1) / by;// 多线程分块计算
int id = 0;
for (int i = 0; i < scene.height; i += strideY)
{for (int j = 0; j < scene.width; j += strideX){th[id] = std::thread(MultiThreading, i, std::min(i + strideY, scene.height), j, std::min(j + strideX, scene.width));id++;}
}for (int i = 0; i < bx*by; i++) th[i].join();
UpdateProgress(1.f);

以下为400大小矩形下spp为32、P_RR为0.8、上述光线距离差大于-0.001f的结果:「用时10min」

二,Microfacet微平面理论

老师在这块讲的我没太捋顺逻辑,在此感谢论坛里的各位大佬和知乎、CSDN里的各位大佬的分享。

2.1 BRDF==Material

BRDF(广义)最常用在实时渲染管线中的是Cook-Torrance 模型,其中兼顾了漫反射和镜面反射2个部分:
f r = k d f l a m b e r t + k s f c o o k − t o r r a n c e fr = k_df_{lambert} + k_sf_{cook-torrance} fr=kd​flambert​+ks​fcook−torrance​

  1. 其中 k d k_d kd​是入射光线中被折射部分的能量占比, k s k_s ks​是被反射部分的能量占比(后文的菲涅尔项反映的就是反射能量占比,因此 k s k_s ks​为菲涅尔项,再根据能量守恒 k d = 1 − k s k_d = 1 -k_s kd​=1−ks​)。
  2. f l a m b e r t f_{lambert} flambert​是Lambertian漫反射(理想散射-朗伯散射)BRDF部分, f c o o k − t o r r a n c e f_{cook-torrance} fcook−torrance​是镜面反射BRDF部分

2.2 Lambertian漫反射部分

我们知道理想漫反射的反射光线是均匀散布在各个方向的(半球),因此漫反射的BRDF值一定是个常数。假设入射光均匀且布满整个半球,可以得到如下推导:「半球对cos积分结果为π」

假设物体不吸收能量,由能量守恒得到入射irradiance和出射一定是一样的( L i = L o L_i = L_o Li​=Lo​),因此得到 f r = 1 π f_r = \frac{1}{π} fr​=π1​;考虑到物体吸收能量的损失后,
f l a m b e r t = ρ π f_{lambert} = \frac{ρ}{π} flambert​=πρ​
其中ρ为反射率或rgb光谱

2.3 cook-torrance镜面反射部分

微表面模型细看有很多凹凸细节,这些细节可看作微小的镜面,远看就像是完全的平面,只能感受到微小平面对整体的作用。现实生活中就算是纯金属表面也有划痕、磨砂等,因此微表面模型能表示非常多实际物体。

  • 核心是用反射的法线分布来表示材质粗糙程度

  • f c o o k − t o r r a n c e = F ( i , h ) G ( i , o , h ) D ( h ) 4 ( n , i ) ( n , o ) f_{cook-torrance}= \frac {F(i,h)G(i,o,h)D(h)}{4(n,i)(n,o)} fcook−torrance​=4(n,i)(n,o)F(i,h)G(i,o,h)D(h)​

    1. F为菲涅尔方程(Fresnel Rquation),考虑不同入射角下反射光所占比例的区别(角度越大,反射越多)----[0.1]
    2. G为几何函数(Geometry Function)(也叫Masking-Shadowing项),描述各个微小表面之间的相互遮挡的属性,相互遮挡如上图(光线入射角大时更容易遮挡)----[0.1]
    3. D为法线分布函数(Normal Distribution Function),如上图所示,参数是h为微平面法向「n是宏观平面法向」
    4. 分母4(n,i)(n,o)为校正因子(correctionfactor),是局部微观和整体宏观表面变换的矫正。
  • tips:

    1. 分母的点积要避免负值和0值,通常通过clamp或者绝对值后加上微小正值实现。
    2. 微表面模型里所假设的微小镜面都是镜面反射。
    3. Microfacet Cook-Torrance BRDF只是最常用的模型,但它仅仅建模了单层微表面,多次散射、多层材质、衍射等都没考虑,具体这些可看闫老师的头发建模论文学习。

2.3.1 菲涅尔方程(Fresnel Rquation)

现实中在不同的角度看物体,明显看到反射率不同(看玻璃也是)

如下图所示,绝缘体上入射角越大反射率越高,而金属的反射率一直很高(所以被拿来做镜子),图中的S、P表示极化性质,与光线的波动性有关,一般渲染器不考虑。

绝缘体反射率和角度关系 金属反射率和角度关系

菲涅尔项计算方法和简化计算:「其中n是折射率」

  • 作业中fresnel项计算函数已经给出

2.3.2 几何函数(Geometry Function)

几何函数模型有很多,其中Smith联合遮蔽阴影函数(Smith Joint Masking-Shadowing Function)中的分离遮蔽阴影(Separable Masking and Shadowing Function)最常用。这种同时对光线与视线方向使用相同的分布函数的思想与法线分布函数NDF结合,形成的新Schlick-GGX几何项是目前ue4使用的方案。
G S c h l i c k G G X ( v ) = n ⋅ v ( n ⋅ v ) ( 1 − k ) + k G_{SchlickGGX}(v)= \frac{n \cdot v}{(n \cdot v)(1-k)+k} GSchlickGGX​(v)=(n⋅v)(1−k)+kn⋅v​
k = ( α + 1 ) 2 8 k = \frac{(α+1)^2}{8} k=8(α+1)2​
G ( i , o , h ) = G S c h l i c k G G X ( i ) G S c h l i c k G G X ( o ) G(i,o,h)= G_{SchlickGGX}(i)G_{SchlickGGX}(o) G(i,o,h)=GSchlickGGX​(i)GSchlickGGX​(o)

  • 其中 α α α表示粗糙度,粗糙度低时更聚光,粗糙度高时更磨砂。

2.3.3 法线分布函数(Normal Distribution Function)

业界较为主流的法线分布函数是GGX(Trowbridge-Reitz):
D G G X ( h ) = α 2 π ( ( n ⋅ h ) 2 ( α 2 − 1 ) + 1 ) 2 D_{GGX}(h) = \frac{α^2}{π((n \cdot h)^2(α^2 - 1)+1)^2} DGGX​(h)=π((n⋅h)2(α2−1)+1)2α2​

  • α α α同几何函数。

三,作业7拓展题

拓展题是将原代码里只描述了Diffuse的sample, eval, pdf三个函数改为支持Microfacet 模型的函数。其他sample 与 pdf 计算可以与Diffuse一致。

  • DGF函数计算 in Material.hpp「F已有」
float Dfunc_GGX(const Vector3f &N,const  Vector3f &H, float a)
{float a2     = a*a;float NdotH  = clamp(0.0 , 1.0 , dotProduct(N, H));float NdotH2 = NdotH*NdotH;float denom  = (NdotH2 * (a2 - 1.0) + 1.0);denom = M_PI * denom * denom;return a2 / denom;
}float Gfunc_1(float NdotV, float a)
{float r = (a + 1.0);float k = (r*r) / 8.0;float nom   = NdotV;float denom = NdotV * (1.0 - k) + k;return nom / denom;
}float Gfunc_SchlickGGX(const Vector3f &N, const Vector3f &I, const Vector3f &O, float a)
{float NdotI = clamp(0.0 , 1.0 , dotProduct(N, I));float NdotO = clamp(0.0 , 1.0 , dotProduct(N, O));float ggx1 = Gfunc_1(NdotI, a);float ggx2 = Gfunc_1(NdotO, a);return ggx1 * ggx2;
}
  • Material::eval in Material.hpp
Vector3f Material::eval(const Vector3f &wi, const Vector3f &wo, const Vector3f &N){switch(m_type){case DIFFUSE:{// calculate the contribution of Microfacet modelfloat cosalpha = dotProduct(N, wo);if (cosalpha > 0.0f) {Vector3f diffuse = Kd / M_PI;return diffuse;}elsereturn Vector3f(0.0f);break;}case COOKTORRANCE:{float cosalpha = dotProduct(N, wo);if (cosalpha > 0.0f) {float roughness = 0.35f;Vector3f H = (wo+wi).normalized();float D = Dfunc_GGX(N, H, roughness);float G = Gfunc_SchlickGGX(N, wi, wo, roughness);float F = 0.0f;fresnel(-wi, N, ior, F);float nominator    = D * G * F;float denominator = 4.0 * clamp(0.0 , 1.0 , dotProduct(N, wi)) * clamp(0.0 , 1.0 , dotProduct(N, wo)) + 0.001;float specular =  nominator / denominator;float diffuse = 1.0f / M_PI;Vector3f ks_ = Vector3f(F);Vector3f kd_ = Vector3f(clamp(0.0 , 1.0 , 1.0-F));//ks_已经在specular里有体现,所以这里只用kd_即可return Kd * kd_ * diffuse + Ks * specular;}elsereturn Vector3f(0.0f);break;}}
}

然后再在main.cpp增加一个球体,设置好ior等参数即可。开始设置ior为一点多,但渲染效果高光不明显(右边为DIFFUSE,左边为COOKTORRANCE):

将ior设置为20后效果变明显,但不符合物理规律:

后分析这现象应该是由于公式里的fresnel项计算的是绝缘体系数(类似木头等),而不是我们想要的金属,金属的fresnel系数一直很高(见2.3.1附图),因此将ior设置为20相当于放大了绝缘体的fresnel系数使之更接近金属了。

参考资料

http://games-cn.org/forums/topic/zuoye7detigaoticaideyixiekengmangengzhong/
https://zhuanlan.zhihu.com/p/60977923(怀念大神)
https://learnopengl-cn.github.io/07%20PBR/02%20Lighting/
https://blog.csdn.net/qq_36242312/article/details/116307626?spm=1001.2014.3001.5501

games101:作业7+Microfacet微平面理论+cook-torranceBRDF方程计算+作业7拓展相关推荐

  1. 基于微平面理论的BRDF模型(PBR材质、Cook-Torrance、GGX)

    前言   因为前边讲了在Unity中如何实现一个BRDF--简单来说就是把公式抄到Shader里,于是这篇文章则主要从原理角度来讲一讲基于物理的BRDF公式为什么长那个样子.本篇文章主要是整理一下去年 ...

  2. 20、计算机图形学——微平面理论和Cook-Torrance BRDF

    一.微平面理论 如下图中的海面,从远处看,就像镜子一样平整,反光很强烈 但是从近处看,却能法线,海平面是有微小的凹凸不平.可以认为,海平面是由无数个微小的镜面组成,而每个微小的镜面都有法线 如果法线的 ...

  3. 光线追踪渲染实战(四):微平面理论与迪士尼 BRDF,严格遵循物理!

    项目代码仓库: GitHub:https://github.com/AKGWSB/EzRT gitee:https://gitee.com/AKGWSB/EzRT 目录 前言 0. 前情回顾 1. 微 ...

  4. 20秋PHP作业1,南开17秋学期(清考)《电子商务理论与实践》在线作业1

    17秋学期(清考)<电子商务理论与实践>在线作业 试卷总分:100 得分:100 一.单选题 (共 25 道试题,共 50 分) 1. "Spider"就是由搜索引擎来 ...

  5. 微服务理论与实践[1]-什么是微服务

    微服务理论与实践[1]-什么是微服务 什么是微服务 微服务 (Microservices) 是一种软件架构风格,将应用程序构造为围绕业务的小型自治服务的集合 微服务以专注于单一责任与功能的小型功能区块 ...

  6. GAMES101作业6及课程总结(重点解决SAH扩展作业)

    这次作业相对于作业5会麻烦一点点,而且框架相较于作业五的也麻烦了一点,当然作业的难点其实主要还是在扩展作业SAH那块. 目录 课程总结与理解(光线追踪) 框架梳理 作业一:光线生成 作业二:光线-三角 ...

  7. c++大作业迷宫游戏 规定时间内完成_开卷有益 | 小学生做作业磨蹭的7个原因及对策!太准了~不得不为孩子收藏!...

    很多小学生家长一提到孩子写作业就头疼,因为作业总是磨磨蹭蹭,从来没有痛写完的时候,往往很简单的家庭作业总要拖沓到半夜才完成,那么,究竟是什么原因导致小学生作业磨蹭呢? 01 学习没方法,不知道先做什么 ...

  8. 计算机作业有相似度,抄袭检测系统对计算机类电子作业的影响分析

    摘要: 计算机类课程的电子作业存在普遍的抄袭现象,给老师批改作业和评定分数带来了难题.针对计算机类课程的作业特点,利用作业检测系统对学生计算机类课程的电子作业进行了抄袭检测并进行深入分析. Abstr ...

  9. 智能计算作业——差分进化算法求解函数最值

    下面是智能计算作业,哎呀,你们快来抄我作业呀╭(╯^╰)╮ 问题描述: 算法理论我省略了,你们自己去百科上抄吧╭(╯^╰)╮ 求解步骤: (这个好像也是百科上的╭(╯^╰)╮我根据自己的需要改了一下) ...

最新文章

  1. 对称密码算法Rijndael解析—加密
  2. UA MATH571B 试验设计VI 随机效应与混合效应3 嵌套设计
  3. ITK:从二进制图像中的对象计算距离图
  4. 下载 | 9G火爆的Python爬虫教程+ 520页《图解机器学习》
  5. 1321. Robot
  6. jpa调用mysql函数_Spring data jpa 调用存储过程处理返回参数及结果集(示例代码)
  7. 如何去掉UITableViewController中的分隔线setSeparatorStyle
  8. Ubuntu 14.04 jdk安装与配置
  9. 机器人仿真软件小汇总
  10. 云端软件关闭的原因是什么?
  11. 基于Python的股票红利预测
  12. vc excel编程
  13. Log4j 日志配置及初始化
  14. k8s单节点无法启动pod
  15. 软件开发外包:你有什么选择
  16. C++:替换文本文件中的某些字符
  17. spark专业术语解释
  18. microbit开发环境搭建
  19. 超详细宝塔面板搭建和安装wordpress网站图文教程(附案例)
  20. 「老文补发」写在GitBubble上线之后

热门文章

  1. 如何破解Excel密码保护?
  2. 安装Ubuntu系统教程(图文结合-详细步骤)
  3. Visual Studio高效调试手段与技巧总结(经验分享)
  4. 数字签名的签名与验证
  5. idea无法创建java文件
  6. 我fork的110+star的newbee-mall商城V2.2.0发布啦
  7. 开源项目新蜂商城在Linux上部署,mysql+nginx
  8. 深入探索 Android 网络优化(二、网络优化基础篇)下
  9. halcon 二值形态学 计算小颗粒数目例子
  10. 深度学习项目(二)对话机器人