Preface

注:鉴于很多网站随意爬取数据,可能导致内容残缺以及引用失效等问题,影响阅读,请认准原创网址:

https://www.cnblogs.com/lv-anchoret/category/1368696.html

我们这节主要讲把之前的概率密度做混合,以得到更好的效果

我们上一篇以前经常用关于cos函数的pdf,上一节用的是与光源采样相关的pdf,那么,我们把两者结合到一起,协调它们之间的比例,我们就可以得到一个有着两种概率密度模型的pdf,这往往是更贴近生活的,那么我们今天就来学习测试一下。

 Ready

这一节就是把前几篇的概率密度做混合,所以,需要的就是熟悉之前的内容。

当然,之前的框架代码也比较丑,基本都是在lerp函数里面做调整,所以,我们顺便把框架搭得更好一点

 正文

我们都知道,设计pdf的一个很重要的原则就是使得累积概率密度达到且只达到1,所以,我们先采用一种非常简单的比例协调方式混合两个pdf。

例如我们有如下的混合密度方程

pdf_mixture(direction) = 1/2 * pdf_reflection(direction) + 1/2 * pdf_light(direction)

即,两者各占一半

要实现两者,代码描述也很简单:

if ( rand01() < 0.5 )
pdf_reflection(); ...
else
pdf_light(); ...
 
但是评估pdf_mixture会稍微有点微妙。 我们需要同时评估pdf_reflection和pdf_light,因为有一些方向可以生成pdf方向。 例如,我们可以使用pdf_reflection生成朝向光的方向
 
如果我们回顾之前的内容,你会发现,这一部分主要解决两个问题:
1.此处的pdf函数值
2.按照某个随机模型产生一个随机数
 
我们抽象出这些操作之后,就可以写一个关于我们的pdf的一个基类:
///pdf.hpp

// -----------------------------------------------------
// [author] lv
// [ time ] 2019.3
// [brief ] In the Monte Carlo system, pdf acts as the
// most important element of Important-Sample
// ----------------------------------------------------- #pragma once namespace rt
{ // the basic class of pdf system
class pdf
{
public:
/*
@brief: we get the value of pdf function by this interface
@param: the direction of location
@retur: the value of the pdf function
*/
virtual rtvar value(const rtvec & direction)const = ; /*
@brief: generate a random number with a Probability model
@param: none
@retur: the Three-dimensional random vector
*/
virtual rtvec generate()const = ;
}; }//rt namespace

我们来实现关于它的一些子类

首先我们来实现关于cosine 概率密度的模型

///cosine_pdf.hpp

// -----------------------------------------------------
// [author] lv
// [ time ] 2019.3
// [brief ] one of the pdf' forms
// ----------------------------------------------------- #pragma once namespace rt
{ class cosine_pdf :public pdf
{
public:
//constructor
cosine_pdf(const rtvec& w); /*
@brief: we get the value of pdf function by this interface
@param: the direction of location
@retur: the value of the pdf function
*/
virtual rtvar value(const rtvec& direction)const; /*
@brief: generate a random number with a Probability model
@param: none
@retur: the Three-dimensional random vector
*/
virtual rtvec generate()const; private: onb _uvw;
}; inline cosine_pdf::cosine_pdf(const rtvec& w)
{
_uvw.build_from_w(w);
} rtvar cosine_pdf::value(const rtvec& direction)const
{
rtvar cosine = dot(direction.ret_unitization(), _uvw.w());
if (cosine > .)
return cosine / π;
else
return .;
} rtvec cosine_pdf::generate()const
{
return _uvw.local(random_cosine_direction());
}
}

这个模型之前细说过,cosine大于0的时候返回cosine/π,反之,则返回0。因为光线反射之后如果和表面法线的夹角为钝角的时候,违反反射规律,不以反射。生成随机数的那个之前也讲过,在上上一篇

其实这些都不是新东西,就是把之前讲的的那一套整合了一下

得到结果也就是之前的效果

我们把主函数里面的lerp()也改一下

每个像素点采样100次,取均值,即sample 为 100时

这是代码敲错了,意外得到的一张图

现在我们尝试,光源采样,即

///hit_pdf.hpp

// -----------------------------------------------------
// [author] lv
// [ time ] 2019.3
// [brief ] toward to the hitable
// ----------------------------------------------------- #pragma once namespace rt
{ class hit_pdf :public pdf
{
public: /*
@param: info -> Geometry information
origion -> the point of intersection
*/
hit_pdf(intersect* info, const rtvec& origion)
:_intersectp(info)
,_o(origion)
{
} /*
@brief: we get the value of pdf function by this interface
@param: the direction of location
@retur: the value of the pdf function
*/
virtual rtvar value(const rtvec& direction)const
{
return _intersectp->pdf_value(_o, direction);
} /*
@brief: generate a random number with a Probability model
@param: none
@retur: the Three-dimensional random vector
*/
virtual rtvec generate()const
{
return _intersectp->random(_o);
} private: rtvec _o; intersect * _intersectp;
}; }// rt namespace

对应的intersect类也要改一下

/// intersect.hpp
//https://www.cnblogs.com/lv-anchoret/p/10190092.html
// -----------------------------------------------------
// [author] lv
// [begin ] 2018.12
// [refre ] 2019.3
// [brief ] the intersect-class for the ray-tracing project
// from the 《ray tracing in one week》
// ----------------------------------------------------- #pragma once #include "E:\OpenGL\光线追踪\code\ray tracing 1-3\ray tracing 1-3\ray.hpp" namespace rt
{
class material;
class aabb; // the infomation of intersection point struct hitInfo
{
lvgm::precision _t; //ray 中的系数t
rtvec _p; //相交点、撞击点
rtvec _n; //_p点的表面法线
material* _materialp; //材质
rtvar _u; //texture-u
rtvar _v; //texture-v
}; // the statement of intersect class class intersect
{
public: /*
@brief: 撞击函数,求取撞击点相关记录信息
@param: sight->视线
系数t的上下界->筛选撞击点
info->返回撞击点信息
@retur: 是否存在合法撞击点
*/
virtual bool hit(const ray& sight, rtvar t_min, rtvar t_max, hitInfo& info)const = ; /*
@brief: get the box of Geometry
*/
virtual aabb getbox()const = ; /*
Get the value of pdf function
*/
virtual rtvar pdf_value(const rtvec& o, const rtvec& v)const
{
return .;
} /*
generate the random number
*/
virtual rtvec random(const rtvec& o)const
{
return rtvec(, , );
} }; }// rt namespace

因为我们现在只是拿区域光源做实验,并不是所有的几何体派生类都要继承pdf相关的方法,所以,它们两个以虚函数的形式存在即可。

那么就剩下xz长方形了

rtvar xz_rect::pdf_value(const rtvec& o, const rtvec& v)const
{
hitInfo rec;
if (this->hit(ray(o, v), 1e-, rt::rtInf(), rec))
{
rtvar area = (_x2 - _x1)*(_z2 - _z1);
rtvar distance_squared = rec._t * rec._t * v.squar();
rtvar cosine = fabs(dot(v, rec._n) / v.normal());
return distance_squared / (cosine*area);
}
else
return .;
} rtvec xz_rect::random(const rtvec& o)const
{
rtvec random_point = rtvec(_x1 + lvgm::rand01() * (_x2 - _x1), _other, _z1 + lvgm::rand01()*(_z2 - _z1));
return random_point - o;
}

把上一篇写在lerp函数里面的一大堆东西整合到类里面

那么我们的lerp就统一化了:

我们取sample为10,即可得到很好的效果:

现在我们将写一个关于混合概率密度的类:

///mixture_pdf.hpp

// -----------------------------------------------------
// [author] lv
// [ time ] 2019.3
// [brief ] mixture pdfs
// ----------------------------------------------------- #pragma once namespace rt
{ class mixture_pdf :public pdf
{
public: mixture_pdf(pdf * p1, pdf* p2)
{
_p[] = p1;
_p[1] = p2;
} /*
@brief: we get the value of pdf function by this interface
@param: the direction of location
@retur: the value of the pdf function
*/
virtual rtvar value(const rtvec& direction)const
{
return 0.5*_p[]->value(direction) + 0.5*_p[]->value(direction);
} /*
@brief: generate a random number with a Probability model
@param: none
@retur: the Three-dimensional random vector
*/
virtual rtvec generate()const
{
if (lvgm::rand01() < 0.5)
return _p[]->generate();
else
return _p[]->generate();
} private: pdf* _p[]; }; }// rt namespace

我们的lerp函数如下:

我们采样10次得到:

但是觉得效果不是很理想,我们来做一些测试

1. pdf 方程修改为 mixture_pdf = 1/3 * hit_pdf + 2/3  * cosine_pdf

2. pdf 方程修改为 mixture_pdf = 2/3 * hit_pdf + 1/3  * cosine_pdf

3. random修改  2/3 取 hit_pdf产生的随机值, 1/3 取 cosine_pdf 产生的随机值

4. random修改  1/3 取 hit_pdf产生的随机值, 2/3 取 cosine_pdf 产生的随机值

我们去上述方案的3、1,即:

得到图:

这张图显然比均分的效果要好

这里我们看不出到底是random起作用还是value,我们不妨取2、3组合

3把2的彩色噪声消除了些,但是这张图和原始的均分图差不多一样

所以结论,random和value的比例交叉比较好

我们采样1000次得到:

渲染中。。。。(就是清晰了点)

/***********************************************************************************/

跑了一晚上爬起来发现除零错误了,又抽空跑完了

/************************************************************************************/

本书第九章(下一章)介绍了一些关于当前渲染器的看法

作者在描述阴影光线和混合密度设计时,作者个人更偏向于混合密度设计,所以并没有在渲染器中采用阴影光线

作者描述了关于lerp函数中内存问题以及编码的不足

作者描述了关于玻璃材质和镜面的一些处理方法

作者还描述了关于HDR的0~1浮点表示以及RGB分组的0~255表示,还说明了这个渲染器是RGB的且基于物理的,还有一种是基于光谱的,以及两者结合的,但做起来很难,所以我们坚持RGB且基于物理的渲染器。

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

【RAY TRACING THE REST OF YOUR LIFE 超详解】 光线追踪 3-7 混合概率密度的更多相关文章

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

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

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

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

  3. 【RAY TRACING THE REST OF YOUR LIFE 超详解】 光线追踪 3-6 直接光源采样

    Chapter7 Sample Lights Directly  Preface 今天我们来讲这个还算牛逼的技术——直接光源采样 之前我们提到过,在2-7 前两篇我们也提到要减少噪点,就是图片上的黑点 ...

  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. geeksforgeeks-Array-Rotation and deletion

      As usual Babul is again back with his problem and now with numbers. He thought of an array of numb ...

  2. python 历险记(一)— python 的String,集合(List,元组,Dict)

    目录 引言 String 有哪些有用的方法? 如何拼接字符串? 如何分隔字符串? 如何获取字符串长度 如何将 list 拼接成字符串? 如何替换字符串? 如何去除字符串中的空格? 如何子字符串是否包含 ...

  3. OA协同办公软件

    OA协同办公软件: 泛微软件. 九思软件. 华天动力. 万户OA.:北京万户网络技术有限公司创立于1998年2月,是北京华宇软件股份有限公司(股票简称:“华宇软件”,股票代码:300271)的全资子公 ...

  4. openstack swift节点安装手册3-最后的安装配置及验证

    以下步骤都在controller节点上执行 1.远程获取/etc/swift/swift.conf文件: curl -o /etc/swift/swift.conf https://git.opens ...

  5. linux下ssh远程连接工具SecureCRT和xshell编码设置

    默认的编码有时候显示乱码,需要切换到utf-8 xshell的设置 多个会话窗口执行同样命令 中文界面:

  6. Jmeter接口测试参数化实例图文示例

    在实际测试中,不可能查询值测试一个输入值,还有其他测试数据,故引入参数化的概念,让一条用例循环执行,直到所有测试数据均测试完成,如下示例: Jmeter参数化有4种方法,本例仅介绍最普遍及简单的1个方 ...

  7. LeetCode(49): 字母异位词分组

    Medium! 题目描述: 给定一个字符串数组,将字母异位词组合在一起.字母异位词指字母相同,但排列不同的字符串. 示例: 输入: ["eat", "tea", ...

  8. 目标检测-ssd

    intro: ECCV 2016 Oral arxiv: http://arxiv.org/abs/1512.02325 paper: http://www.cs.unc.edu/~wliu/pape ...

  9. python+selenium十二:一个输入框双层input标签

    先点击第一个,再对第二个进行操作,否则操作失败 driver.find_element_by_css_selector(".pwd").click()driver.find_ele ...

  10. 内连接,外链接(左连接、右连接、全连接),交叉连接大总结+附SQL JOINS图解[转]

    1.什么是连接查询呢? 概念:根据两个表或多个表的列之间的关系,从这些表中查询数据. 目的:实现多个表查询操作. 2.分类: 首先划分一下,连接分为三种:内连接.外连接.交叉连接 内连接(INNER ...