Chapter7 Sample Lights Directly

 Preface

今天我们来讲这个还算牛逼的技术——直接光源采样

之前我们提到过,在2-7

前两篇我们也提到要减少噪点,就是图片上的黑点点,所以,所有的矛头都指向了这一篇。

简单说一下为什么会有那么多小点点,就是因为光线路径中没有触碰到光源,路径计算之后就会是黑色的点,可以通过发射大量的光线,比如计算每个像素点的时候发射8k~1w条采样光线进行路径计算;也可以路径计算方面做文章,比如加深路径计算递归深度;等等诸如此类。但是上述方法都是暴力解决法,相当耗时,我们可以运用数学对其进行优化,从而实现画质和效率的双面提升,这就是我们今天要讲的——直接光源采样!

 Ready

可能您需要以下基础:

1.微分

2.立体角 (蒙特卡罗(三))

没了,剩下全靠想象

 content

简明扼要。

我们朝光源方向发送光线或者生成朝向光源的随机方向都是很容易实现的,但是我们需要知道的是,pdf(direction)是什么呢?

引用书上一张图:

对于一个光源区域A,如果我们均匀采样该区域,那么这个pdf就等于1/A,意思就是每个点的概率均等

但是和我们的单位球体结合在一起的话,就比较麻烦了,见上图

?为什么老是提到单位球体呢??

因为我们的光线和物体表面的交点,会作为下一个eye,然后新的视线方向是表面单位球随机产生的方向,具体见1-5中的diagram7-3

好了,渊源就是酱紫,我们继续

如果那个小的微分区域dA的采样概率为

  p_q(q)*dA(采样比例乘以微分区域),也就是dA/A

而对应到单位球体表面的很小的区域,即我们所述的方位角。方位角微分dΩ对应的采样概率为

  p(direction)*dΩ

这里有一个用来描述dΩ 和 dA 的表达式:

= dA cosα / (distance(p,q^2)

即:方位角微分区域:光源微分区域分成(球心到A中心距离平方)份,取其中的cosα代表的份额数

因为这个dA 和 dΩ的概率是相同的,所以就有如下等式

p(direction) * cosα * dA / (distance(p,q)^2) = p_q(q) * dA = dA / A

所以

p(direction) = distance(p,q)^2 / (cosα * A)

我们接下来就检验一下这个数学公式是否正确

但是代码可能非常丑

我们需要之前的光源的区域参数

    list[cnt++] = new xz_rect(, , , , , light);

所以我们有以下的代码

rtvec lerp(const ray& sight, intersect* world, int depth)
{
hitInfo info;
if (world->hit(sight, (rtvar)0.001, rtInf(), info))
{
ray scattered;
rtvec emitted = info._materialp->emitted(info._u, info._v, info._p);
rtvar pdf;
rtvec albedo;
if (depth < && info._materialp->scatter(sight, info, albedo, scattered, pdf))
{
rtvec on_light = rtvec( + lvgm::rand01() * ( - ), , + lvgm::rand01() * ( - ));
rtvec to_light = on_light - info._p;
double distance_squared = to_light.squar();
to_light.self_unitization();
if (dot(to_light, info._n) < )
return emitted;
double light_area = ( - )*( - );
double light_cosine = fabs(to_light.y());
if (light_cosine < 1e-)
return emitted;
pdf = distance_squared / (light_cosine*light_area);
scattered = ray(info._p, to_light, sight.time());
return emitted + albedo *info._materialp->scatter_pdf(sight, info, scattered)*lerp(scattered, world, depth + ) / pdf;
}
else
return emitted;
}
else
return rtvec();
}

如下图:

因为我们一路做测试,做图形分析对比,所以我们上图是sample为250时候的效果

据说,sample为10时,效果依旧很好

所以又超快速运行了一个sample为10的

不管怎样,我们的图形噪点已经做到了比较不错的境地了,sample为10!!!

再看看之前的sample为250的图形效果

简直噪出天际线

关于本篇的那个图

天花板上灯光周围的噪声是由于灯光是双面的,灯光和天花板之间有一个狭窄空间。

我们可以通过将灯光法向量调至垂直向下来解决这一问题,同时让我们的灯光发射函数也做相应的处理

    virtual rtvec emitted(const ray& rIn, const hitInfo& info, const rtvar u, rtvar v, const rtvec& p)const
{
if(dot(info._n,rIn.direction())<.)
return _emit->value(u, v, p);
else
return rtvec();
}

记得一起改了material基类,以及lerp的emit函数调用根据上述参数描述

所以我们又得到了一个sample为10的新图

没什么大的变化

只是灯光周围的噪点少了,解释:

因为灯光的法向量垂直向下,而我们的反射光线与反射之后与法向量的夹角为锐角的时候才进行纹理计算

而来自屋顶上面的光线与灯光区域碰撞反射的方向与法向量呈钝角(注意是反射之后的新方向不是入射光方向)则不计算返回黑色,默认光无法到达

感谢您的阅读,生活愉快~

【RAY TRACING THE REST OF YOUR LIFE 超详解】 光线追踪 3-6 直接光源采样的更多相关文章

  1. 【RAY TRACING THE REST OF YOUR LIFE 超详解】 光线追踪 3-7 混合概率密度

     Preface 注:鉴于很多网站随意爬取数据,可能导致内容残缺以及引用失效等问题,影响阅读,请认准原创网址: https://www.cnblogs.com/lv-anchoret/category ...

  2. 【RAY TRACING THE REST OF YOUR LIFE 超详解】 光线追踪 3-5 random direction & ONB

     Preface 往后看了几章,对这本书有了新的理解 上一篇,我们第一次尝试把MC积分运用到了Lambertian材质中,当然,第一次尝试是失败的,作者发现它的渲染效果和现实有些出入,所以结尾处声明要 ...

  3. 【RAY TRACING THE REST OF YOUR LIFE 超详解】 光线追踪 3-4 基于重要性采样的材质初探

     Preface 我们今天来把第三本书从开局到现在讲的一大堆理论运用到我们的框架中,那么今天我们首先将原始的材质改为基于重要性采样原理的材质 这一篇是代码工程中进行MC理论应用的初步尝试篇  Read ...

  4. 【RAY TRACING THE REST OF YOUR LIFE 超详解】 光线追踪 3-3 蒙特卡罗 (三)

    开学人倍忙,趁着第二周周末,我们继续图形相关的博客  Preface 今天我们来介绍一些理论方面的东西,为Monte Carlo 应用到我们的光线追踪器做铺垫 我们今天会介绍两章的东西,因为有一章内容 ...

  5. 【RAY TRACING THE REST OF YOUR LIFE 超详解】 光线追踪 3-2 蒙特卡罗(二) 重要性采样

    书本内容:见相册 preface 还记的我们上一篇说的Monte Carlo 维度诅咒吗 上一篇算是二维的例子吧,大家看了之后是否想着写一个一维的Monte Carlo模拟积分?(我想了,没写出来) ...

  6. 【RAY TRACING THE REST OF YOUR LIFE 超详解】 光线追踪 3-1 蒙特卡罗 (一)

    今天起,我们就开始学习第三本书了 这本书主要讲的是蒙特卡罗渲染,以及相关的数学.术语概念等 这本书相较于前面两本有着什么不同,承担着什么样的任务,尚涉书未深,姑妄言之: 第一本书,带领我们初探光线追踪 ...

  7. html5的float属性超详解(display,position, float)(文本流)

    html5的float属性超详解(display,position, float)(文本流) 一.总结 1.文本流: 2.float和绝对定位都不占文本流的位置 3.普通流是默认定位方式,就是依次按照 ...

  8. HTML中DOM核心知识有哪些(带实例超详解)

    HTML中DOM核心知识有哪些(带实例超详解) 一.总结: 1.先取html元素,然后再对他进行操作,取的话可以getElementById等 2.操作的话,可以是innerHtml,value等等 ...

  9. Mysql超详解

    Mysql超详解 一.命令框基本操作及连接Mysql 找到Mysql安装路径,查看版本 同时按快捷键win+R会弹出一个框,在框中输入cmd 点击确定后会出现一个黑框,这是命令框,我们的操作要在这命令 ...

随机推荐

  1. nginx实践(五)之代理服务(正向代理与反向代理介绍)

    正向代理 正向代理代理是为客户端服务,代理负责DNS解析域名到对应ip,并进行访问服务端,返回响应给客户端 反向代理 客户端自己负责请求DNS解析域名到对应ip,服务端通过代理分发流量,进行负载均衡 ...

  2. Android adb from work ---three

    转接from work --two 0.查看Android的物理存储空间df adb shell df -h 表示以MB单位查看存储使用情况 1.在Android设备中创建指定大小的文件(也能测试其I ...

  3. python Requests 的一些高级特性

    会话对象 会话对象让你能够跨请求保持某些参数.它也会在同一个 Session 实例发出的所有请求之间保持 cookie, 期间使用 urllib3 的 connection pooling 功能.所以 ...

  4. java多线程快速入门(二十二)

    线程池的好处: 避免我们过多的去new线程,new是占资源的(GC主要堆内存) 提高效率 避免浪费资源 提高响应速度 作用:会把之前执行某个线程完毕的线程不会释放掉会留到线程池中给下一个调用的线程直接 ...

  5. laravel 频率限制throttle

    在 Laravel 5.6 中,还引入了频率限制功能.所谓频率限制,指的是在指定时间单个用户对某个路由的访问次数限制,该功能有两个使用场景,一个是在某些需要验证/认证的页面限制用户失败尝试次数,提高系 ...

  6. 安装mysql后在/var/log/mysqld.log 中找不到临时密码

    centos7通过yum装完mysql,使用grep 'temporary password' /var/log/mysqld.log找不到root密码打开mysqld.log中根本没有tempora ...

  7. python调用PHP方法

    PHP代码如下:<?php $method = $argv[1]; $param1 = $argv[2]; $param2 = $argv[3]; if(isset($method) & ...

  8. 论文阅读笔记七:Structure Inference Network:Object Detection Using Scene-Level Context and Instance-Level Relationships(CVPR2018)

    结构推理网络:基于场景级与实例级目标检测 原文链接:https://arxiv.org/abs/1807.00119 代码链接:https://github.com/choasup/SIN Yong ...

  9. 步步为营-84-数字转化为金额的Js+enter键取消页面刷新

    说明:来不及细说了,老铁快上车 function fmoney(s, n) { console.log(s); n = n > && n <= ? n : ; s = pa ...

  10. Liunx 特殊权限 suid sgid t

    suid 在passwd 中体现,在执行命令的时候普通用户拥有管理员的权限 [root@test_android_client_download ~]# ll /usr/bin/passwd -rws ...