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


今天起,咱们就开始学习第三本书了ios

  

 

 

这本书主要讲的是蒙特卡罗渲染,以及相关的数学、术语概念等ide

这本书相较于前面两本有着什么不一样,承担着什么样的任务,尚涉书未深,姑妄言之:学习

第一本书,带领咱们初探光线追踪技术,感觉一下测试

第二本书,篇幅页目最多,带着咱们一步一步,构建了一个“真正”的光线追踪器,这里真正指的是,第二本书的内容较广,涉及纹理、光照、烟雾,随机初步等,所谓麻雀虽小,五脏俱全,此所谓“真正”优化

第三本书,让咱们更加走进了实际的光线追踪器,偏向工业级的,因此,做者前言即讲到,若是你想要从事光线追踪相关的行业,这本书为你准备。学过第二本书,咱们知道,越日后面,渲染效果越不尽人意,这里指的是若是采样点过少(例如几百),根本没法渲染出真实的效果,好比光照相关的Cornell box例子就有不少噪声干扰,这些,玩玩还能够,可是,离专业还有距离,也就是它只是一个五脏俱全的劣质品,并不能称得上是真正的光线追踪器。spa

而这本书承担的任务只有一个,就是利用Monte Carlo(MC)方法优化咱们第二本书中的渲染效果,也就是为第二本书中的光线追踪机器装一个高端的引擎驱动内核零件,让它更好。code

 

咱们先来一个简单的开胃菜blog

 

chapter 1:A Simple Monte Carlo Program图片

蒙特卡罗方法(MC)是一种统计模拟方法,是一类很重要的数值计算方法,它是一种使用随机数解决好不少实际问题的方法。ci

先来看一个很简单的例子:估计π

有不少经典的方法,其中之一是

假设你扔了不少随机的点到方框中,那么有一部分在圆内,其中圆内点和方框点的比例应该就是圆的面积和方框面积的比例,由此:

比例 = (π * R * R)/((2R)*(2R)) = π/4

因此上式和R无关,咱们任意取R = 1,圆心位于原点,则

#include <iostream>
#include <lvgm\randfunc.hpp>
#define stds std::
using namespace lvgm;

void estimate_π(const size_t points)
{
    int inside = 0;
    for (int i = 0; i < points; ++i)
    {
        double x = 2 * rand01() - 1;
        double y = 2 * rand01() - 1;
        if (x*x + y*y < 1)
            inside++;
    }
    stds cout << "Estimate of π by" << points << "test points is " << 4 * double(inside) / points << stds endl;
}

int main()
{
  estimate_π(1000);
  estimate_π(10000);
  estimate_π(100000);
  estimate_π(1000000);
  estimate_π(10000000);
  estimate_π(10000000 / 2);
}

 

模拟结果为

 

 

 固然咱们能够利用下面的程序使结果迅速逼近π

void lawDiminishingReturns()
{
    int inside = 0;
    int runs = 0;
    while (true)
    {
        runs++;
        double x = 2 * rand01() - 1;
        double y = 2 * rand01() - 1;
        if (x*x + y*y < 1)
            inside++;
        if(runs % 10000 == 0)
            stds cout << "Estimate of π by" << runs << "test points is " << 4 * double(inside) / runs << stds endl;
    }
}

结果:

.

 

一开始很是快速的逼近π,以后变化就比较缓慢了,这是一个收益递减法(Law of Diminishing Returns)的例子

即每个样本对结果的收益少于后面一个,这个是MC的一个缺点,咱们能够经过对样本进行分层来减轻这种递减收益,此法一般称为抖动

咱们进行网格划分,并在每一个网格中选取一个样本:

 

咱们采用边长为1e4的方框进行测试

void stratify()
{
    size_t inside{ 0 };
    size_t circle_stratified{ 0 };
    size_t sqrtAll = 1e4;
    for (int i = 0; i < sqrtAll; ++i)
        for (int j = 0; j < sqrtAll; ++j)
        {
            double x = 2 * rand01() - 1;
            double y = 2 * rand01() - 1;
            if (x*x + y*y < 1)
                inside++;
            x = 2 * ((i + rand01()) / sqrtAll) - 1;
            y = 2 * ((j + rand01()) / sqrtAll) - 1;
            if (x*x + y*y < 1)
                circle_stratified++;
        }
    stds cout << "Regular Estimate of π by 1e8 test points is " << 4 * double(inside) / 1e8 << stds endl;
    stds cout << "Stratified Estimate of π by 1e8 test points is " << 4 * double(circle_stratified) / 1e8 << stds endl;
}

 

图片渲染运算读写文件的时候慢。。现在控制台运算输出也整不动了。。。。

有意思~

 

分层方法能更好地收敛于渐近率。不足之处是,这个优点随着问题的维度而下降(例如,对于3D球体积版本,差距会更小)。 这被称为维度诅咒(=.=)。 咱们的工程将是很是高的维度(每一个反射增长两个维度),因此我不会在本书中进行分层。

可是,若是你作的是单反射或阴影或某些严格的2D问题,分层是个很好的选择

 

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

相关文章
相关标签/搜索