《学一辈子光线追踪》 四 重要性采样材料

2024-04-07 20:38

本文主要是介绍《学一辈子光线追踪》 四 重要性采样材料,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

在接下来的两章中,我们的目标是利用我们的程序向光源发送一束额外的光线,这样我们的图片噪声就不会太多了。假设我们可以使用pdf pLight(direction) 向光源发送一束光线。假设我们有一个与s相关的pdf,我们称之为pSurface(direction)。pdf 的一个优点是,可以使用它们的线性混合来形成混合密度,这也是pdf。

例如,最简单的方法是:

p(direction) = 0.5*pLight(direction) + 0.5*pSurface(direction)

只要权重是正的并且加起来是1,任何这种pdf的混合都是pdf。记住,我们可以使用任何pdf-它不会改变我们的答案!所以,目标是要找出当乘积 s(direction)*color(direction) 更大的时候,如何使pdf更大。对于漫反射曲面,这主要是猜测颜色(方向)高的地方。对于镜子来说,s()只在一个方向附近是巨大的,所以它更重要。事实上,大多数渲染器都会将镜面作为一种特殊情况,而只是将s/p隐式化——我们的代码目前就是这样做的。

让我们做一个简单的重构,暂时删除所有不是Lambertian的材质(不想删除也得改改里面继承的函数)。我们可以再次使用康奈尔盒子场景,还是使用之前的视点:

vec3 lookfrom(278, 278, -800);//
vec3 lookat(278, 278, 0);

框架也是我在上本书的最后实现的每次渲染都输出结果的框架。

减少噪音是我们的目标。我们将通过构建一个pdf来实现这一点,它可以向光发送更多的光线。

首先,让我们测试代码,以便它显式地对一些 pdf 进行采样,然后对其进行规范化。记住MC基础:积分 f(x) 大约等于 f(r)/p(r)。对于朗伯材料,让我们像现在这样取样:p(direction)=cos(theta)/Pi。

我们修改材料以启用此重要性采样:

class material {
public:virtual bool scatter(const ray &r_in, const hit_record& rec, vec3& albedo, ray& scattered,float &pdf)const {return false;}virtual float scattering_pdf(const ray &r_in, const hit_record& rec, const ray& scattered)const {return false;}virtual vec3 emitted(float u, float v, const vec3&p)const {return vec3(0, 0, 0);}};class lambertian :public material {
public:lambertian(texture*a):albedo(a){}virtual float scattering_pdf(const ray& r_in, const hit_record& rec, ray& scattered)const {float cosine = dot(rec.normal, unitVector(scattered.direction()));if (cosine < 0)cosine = 0;return cosine / M_PI;}virtual bool scatter(const ray& r_in, const hit_record& rec, vec3& alb, ray& scattered, float &pdf)const {vec3 target = rec.p + rec.normal + random_in_unit_sphere();scattered = ray(rec.p, unitVector(target - rec.p));//r_in.time()alb = albedo->value(rec.u, rec.v, rec.p);pdf = dot(rec.normal, unitVector(scattered.direction())) / M_PI;return true;}texture* albedo;
};

注意修改一些其他代码,因为凡是继承后的类,都需要修改继承的虚函数。

vec3 color(const ray&r, hitable *world, int depth) {hit_record rec;if (world->hit(r, 0.001, MAXFLOAT, rec)) {ray scattered;vec3 emitted = rec.mat_ptr->emitted(rec.u, rec.v, rec.p);float pdf;vec3 albedo;if (depth < 50 && rec.mat_ptr->scatter(r, rec, albedo, scattered,pdf)) {return emitted + albedo* rec.mat_ptr->scattering_pdf(r,rec,scattered) *color(scattered, world, depth + 1);}else {return emitted;}}else {return vec3(0, 0, 0);}
}

结果竟然只显示一个灯,物体和墙都没有了。我们开始调试,首先修改一下color函数:

vec3 color(const ray&r, hitable *world, int depth) {hit_record rec;if (world->hit(r, 0.001, MAXFLOAT, rec)) {ray scattered;vec3 emitted = rec.mat_ptr->emitted(rec.u, rec.v, rec.p);float pdf;vec3 albedo;if (depth < 50 && rec.mat_ptr->scatter(r, rec, albedo, scattered,pdf)) {return emitted + color(scattered, world, depth + 1);}//albedo* rec.mat_ptr->scattering_pdf(r,rec,scattered) *else {return emitted;}}else {return vec3(0, 0, 0);}
}

得到结果:

隐约能看到物体,说明是 albedo* rec.mat_ptr->scattering_pdf(r,rec,scattered) 出了问题。

深入检查,发现

virtual float scattering_pdf(const ray& r_in, const hit_record& rec, ray& scattered)const

的最后一个参数 ray 竟然少了一个const修饰符。改过来以后就可以了。效果和前面的一样。

 

现在,为了体验,尝试不同的抽样策略。让我们从高于表面的半球中随机选择。这就是p(direction) = 1/(2*Pi)

	virtual bool scatter(const ray& r_in, const hit_record& rec, vec3& alb, ray& scattered, float &pdf)const {vec3 direction;do {direction = random_in_unit_sphere();} while (dot(direction, rec.normal) < 0);scattered = ray(rec.p, unitVector(direction), r_in.time());alb = albedo->value(rec.u, rec.v, rec.p);pdf = 0.5 / M_PI;return true;}

得到结果:

 

相同背景物体和光照条件下的对比:

 

再说一遍,我应该得到相同的图片,除了不同的变化幅度,但并没有。第二张照片的长方体非常均匀,这是为什么呢?

它很接近我们的老照片,但有一些差异不是噪声。这个高盒子的正面颜色要均匀得多。所以我有最难在蒙特卡罗程序中找到的一种错误——一种能产生合理外观图像的错误。我不知道这个bug是程序的第一个版本还是第二个版本,甚至两者都是!

让我们建立一些基础设施来解决这个问题。

这篇关于《学一辈子光线追踪》 四 重要性采样材料的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

可测试,可维护,可移植:上位机软件分层设计的重要性

互联网中,软件工程师岗位会分前端工程师,后端工程师。这是由于互联网软件规模庞大,从业人员众多。前后端分别根据各自需求发展不一样的技术栈。那么上位机软件呢?它规模小,通常一个人就能开发一个项目。它还有必要分前后端吗? 有必要。本文从三个方面论述。分别是可测试,可维护,可移植。 可测试 软件黑盒测试更普遍,但很难覆盖所有应用场景。于是有了接口测试、模块化测试以及单元测试。都是通过降低测试对象

Temu官方宣导务必将所有的点位材料进行检测-RSL资质检测

关于饰品类产品合规问题宣导: 产品法规RSL要求 RSL测试是根据REACH法规及附录17的要求进行测试。REACH法规是欧洲一项重要的法规,其中包含许多对化学物质进行限制的规定和高度关注物质。 为了确保珠宝首饰的安全性,欧盟REACH法规规定,珠宝首饰上架各大电商平台前必须进行RSLReport(欧盟禁限用化学物质检测报告)资质认证,以确保产品不含对人体有害的化学物质。 RSL-铅,

代码随想录训练营day37|52. 携带研究材料,518.零钱兑换II,377. 组合总和 Ⅳ,70. 爬楼梯

52. 携带研究材料 这是一个完全背包问题,就是每个物品可以无限放。 在一维滚动数组的时候规定了遍历顺序是要从后往前的,就是因为不能多次放物体。 所以这里能多次放物体只需要把遍历顺序改改就好了 # include<iostream># include<vector>using namespace std;int main(){int n,m;cin>>n>>m;std::vector<i

临床基础两手抓!这个12+神经网络模型太贪了,免疫治疗预测、通路重要性、基因重要性、通路交互作用性全部拿下!

生信碱移 IRnet介绍 用于预测病人免疫治疗反应类型的生物过程嵌入神经网络,提供通路、通路交互、基因重要性的多重可解释性评估。 临床实践中常常遇到许多复杂的问题,常见的两种是: 二分类或多分类:预测患者对治疗有无耐受(二分类)、判断患者的疾病分级(多分类); 连续数值的预测:预测癌症病人的风险、预测患者的白细胞数值水平; 尽管传统的机器学习提供了高效的建模预测与初步的特征重

DTO类实现Serializable接口的重要性

所谓序列化,简单一点理解,就是将对象转换成字节数组,反序列化是将字节数组恢复为对象。凡是要在网络上传输的对象、要写入文件的对象、要保存到数据库中的对象都要进行序列化。Java对象是无法直接保存到文件中,或是存入数据库中的。如果要保存到文件中,或是存入数据库中,就要将对象序列化,即转换为字节数组才能保存到文件中或是数据库中。文件或者数据库中的字节数组拿出来之后要转换为对象才能被我们识别,即反序列化。

HDU2523(论scanf的重要性)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2523 解题思路: 先把a数组排个序,然后把| xi - xj |的所有组合值求出来,把b数组在排个序。这时候要考虑出现1、1、1、2、2、3这种相邻两个一样的情况,开一个vis标记数组把相邻的数进行合并,这样就可以顺利取到第k大的值。 特别说明,论scanf和printf的重要性,用cin

论互联网安全的重要性

论互联网安全的重要性 当今,计算机领域什么最火?当属人工智能了,纵观各大IT巨头google,facebook,apple,Baidu都有自己的人工智能实验室,google有谷歌大脑,其主要计划是研究当今最顶级的技术,比如无人驾驶汽车,google眼镜,百度成立IDL深度研究院等等。这是不是代表,未来我们的生活将因人工智能的发展而发生巨大变化?我想是的。人工智能要基于海量数据处理,这些数据包含大

重复采样魔法:用更多样本击败单次尝试的最强模型

这篇文章探讨了通过增加生成样本的数量来扩展大型语言模型(LLMs)在推理任务中的表现。 研究发现,重复采样可以显著提高模型的覆盖率,特别是在具有自动验证工具的任务中。研究还发现,覆盖率与样本数量之间的关系可以用指数幂律建模,揭示了推理时间的扩展规律。尽管多数投票和奖励模型在样本数量增加时趋于饱和,但在没有自动验证工具的任务中,识别正确样本仍然是一个重要的研究方向。 总体而言,重复采样提供了一种

高精度治具加工的重要性和创新性

在现代制造业中,高精度治具加工扮演着至关重要的角色。它不仅是生产过程中的关键环节,更是推动行业不断创新和发展的重要力量。时利和将解析高精度治具加工的重要性和创新性。   一、高精度治具加工的重要性   1.确保产品质量   高精度治具能够为生产过程提供准确的定位、夹紧和导向功能,从而确保产品的尺寸精度、形状精度和表面质量。例如,在电子制造领域,高精度的治具可以保证芯片的精确安装,提高电子

研究纹理采样器在像素级别的采样位置

问题 【纹理采样器】是一个基础的概念。假设有一个正方形面片,顶点的UV范围是0.0~1.0,那么在这个正方形面片上采样一张纹理时,会呈现出完整的纹理。 但我现在关注的问题是,在像素级别上,采样的位置是怎样的。具体来讲:对于UV值是(0.0,0.0)的点,它对应的采样位置是纹理最左上角像素的中心?还是纹理最左上角像素的左上角?即,下面左右哪个是正确的情况? 在宏观上,尤其是像素较多的时候,二者