《学一辈子光线追踪》 一 引言和一个简单的蒙特卡洛程序

2024-04-07 20:38

本文主要是介绍《学一辈子光线追踪》 一 引言和一个简单的蒙特卡洛程序,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

蒙特卡洛光线追踪技术系列 见 蒙特卡洛光线追踪技术

引言:

在一个周末的光线跟踪和光线跟踪:下周,你建立了一个“真正的”光线跟踪器。

在本卷中,我假设您将从事与光线跟踪相关的职业,我们将深入研究创建非常严肃的光线跟踪器的数学。完成后,您应该准备好开始处理电影和产品设计行业中许多重要的商业光线跟踪器。在这本小册子中,我没有介绍很多东西;我只探讨了编写Monte Carlo渲染程序的多种方法中的一种。我不做阴影光线(相反,我使光线更有可能朝向灯光)、双向方法bidirectional methods、Metropolis方法或光子贴图photon mapping。我所做的就是用研究这些方法的领域的语言来说话。我认为这本书可以是你以后工作的一个深入的接触,它将装备你的一些概念,数学和术语,你将需要学习其他知识。

一个简单的蒙特卡洛程序:

让我们从最简单的Monte Carlo(MC)程序开始。MC程序给出一个答案的统计估计,这个估计值随着运行时间的延长而变得越来越精确。简单程序产生噪音但得到更好的答案的这一基本特征就是MC的全部内容,它尤其适用于不需要高精度的图形等应用。

作为一个例子,我们来估计Pi。有很多方法可以做到这一点,Buffon针问题是一个典型的案例研究。我们将做一个受此启发的变化。假设你在一个正方形内有一个内接圆:

现在,假设你在正方形内随机选取点。那些最终进入圆内的随机点的分数应该与圆的面积成比例。确切的分数应该是圆面积与平方面积的比值。

Fraction = (Pi*R*R) / ((2R)*(2R)) = Pi/4
因为R被抵消了,我们可以选择任何计算上方便的R。让R=1以原点为中心:

#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include "time.h"double myRandom() {return rand() / (RAND_MAX + 1.0);
}int main() {srand(time(NULL));int N = 1000;int inside_circle = 0;for (int i = 0;i < N;i++) {float x = 2 * myRandom() - 1;float y = 2 * myRandom() - 1;if (x*x + y*y < 1)inside_circle++;}printf("Estimate of PI = %f \n",4*float(inside_circle)/N);system("pause");
}

这给出了pi=3.196的答案估计值

如果我们将程序更改为永久运行并打印出运行估计,我们会得到很接近的估计。

我们很快接近圆周率,然后慢慢地接近它。这是收益递减定律的一个例子,其中每个样本的帮助小于上一个样本,这是MC最糟糕的部分。我们可以通过对样本进行分层(通常称为抖动)来缓解这种递减的回报,在这种情况下,我们不是随机抽取样本,而是在每个样本中抽取一个网格并抽取一个样本:

#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include "time.h"
double myRandom() {return rand() / (RAND_MAX + 1.0);
}
int main() {srand(time(NULL));int inside_circle = 0;int inside_circle_stratified = 0;int sqrt_N = 10000;for (int i = 0;i < sqrt_N;i++) {for (int j = 0;j < sqrt_N;i++) {float x = 2 * myRandom() - 1;float y = 2 * myRandom() - 1;if (x*x + y*y < 1)inside_circle++;x = 2 * ((i + myRandom()) / sqrt_N) - 1;y = 2 * ((j + myRandom()) / sqrt_N) - 1;if (x*x + y*y < 1)inside_circle_stratified++;}}printf("Regular Estimate of PI = %f \n", 4 * float(inside_circle) / (sqrt_N*sqrt_N));printf("Stratified Estimate of PI = %f \n", 4 * float(inside_circle_stratified) / (sqrt_N*sqrt_N));system("pause");
}

得到结果:

有趣的是,分层方法不仅更好,而且收敛速度更快!不幸的是,这一优势随着问题的规模而减小(例如,对于3D球体体积版本,优势差距会更小)。这叫做维度诅咒。我们的MC光线追踪将是非常高的维度(每个反射增加两个维度),所以我不会在这本书分层。但是如果你曾经做过单次反射或阴影,或者一些严格的二维问题,你肯定想分层。

后记:

还记得我在这个系列中前几节关于《MCRT》书中讲到的关于分层方法 蒙特卡洛光线追踪 (准)蒙特卡洛积分,当时我在记录了一大堆数学公式以后,写了一个结论:

分层抽样的效果会比较好。

等我把下一节一维MC相关内容整理完以后,我再重新阐述一下MC分层抽样的原理。

这篇关于《学一辈子光线追踪》 一 引言和一个简单的蒙特卡洛程序的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/883611

相关文章

SpringBoot项目注入 traceId 追踪整个请求的日志链路(过程详解)

《SpringBoot项目注入traceId追踪整个请求的日志链路(过程详解)》本文介绍了如何在单体SpringBoot项目中通过手动实现过滤器或拦截器来注入traceId,以追踪整个请求的日志链... SpringBoot项目注入 traceId 来追踪整个请求的日志链路,有了 traceId, 我们在排

将java程序打包成可执行文件的实现方式

《将java程序打包成可执行文件的实现方式》本文介绍了将Java程序打包成可执行文件的三种方法:手动打包(将编译后的代码及JRE运行环境一起打包),使用第三方打包工具(如Launch4j)和JDK自带... 目录1.问题提出2.如何将Java程序打包成可执行文件2.1将编译后的代码及jre运行环境一起打包2

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::

redis群集简单部署过程

《redis群集简单部署过程》文章介绍了Redis,一个高性能的键值存储系统,其支持多种数据结构和命令,它还讨论了Redis的服务器端架构、数据存储和获取、协议和命令、高可用性方案、缓存机制以及监控和... 目录Redis介绍1. 基本概念2. 服务器端3. 存储和获取数据4. 协议和命令5. 高可用性6.

在不同系统间迁移Python程序的方法与教程

《在不同系统间迁移Python程序的方法与教程》本文介绍了几种将Windows上编写的Python程序迁移到Linux服务器上的方法,包括使用虚拟环境和依赖冻结、容器化技术(如Docker)、使用An... 目录使用虚拟环境和依赖冻结1. 创建虚拟环境2. 冻结依赖使用容器化技术(如 docker)1. 创

JAVA调用Deepseek的api完成基本对话简单代码示例

《JAVA调用Deepseek的api完成基本对话简单代码示例》:本文主要介绍JAVA调用Deepseek的api完成基本对话的相关资料,文中详细讲解了如何获取DeepSeekAPI密钥、添加H... 获取API密钥首先,从DeepSeek平台获取API密钥,用于身份验证。添加HTTP客户端依赖使用Jav

利用Python编写一个简单的聊天机器人

《利用Python编写一个简单的聊天机器人》这篇文章主要为大家详细介绍了如何利用Python编写一个简单的聊天机器人,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 使用 python 编写一个简单的聊天机器人可以从最基础的逻辑开始,然后逐步加入更复杂的功能。这里我们将先实现一个简单的

SpringBoot如何使用TraceId日志链路追踪

《SpringBoot如何使用TraceId日志链路追踪》文章介绍了如何使用TraceId进行日志链路追踪,通过在日志中添加TraceId关键字,可以将同一次业务调用链上的日志串起来,本文通过实例代码... 目录项目场景:实现步骤1、pom.XML 依赖2、整合logback,打印日志,logback-sp

使用IntelliJ IDEA创建简单的Java Web项目完整步骤

《使用IntelliJIDEA创建简单的JavaWeb项目完整步骤》:本文主要介绍如何使用IntelliJIDEA创建一个简单的JavaWeb项目,实现登录、注册和查看用户列表功能,使用Se... 目录前置准备项目功能实现步骤1. 创建项目2. 配置 Tomcat3. 项目文件结构4. 创建数据库和表5.

使用PyQt5编写一个简单的取色器

《使用PyQt5编写一个简单的取色器》:本文主要介绍PyQt5搭建的一个取色器,一共写了两款应用,一款使用快捷键捕获鼠标附近图像的RGB和16进制颜色编码,一款跟随鼠标刷新图像的RGB和16... 目录取色器1取色器2PyQt5搭建的一个取色器,一共写了两款应用,一款使用快捷键捕获鼠标附近图像的RGB和16